This commit was manufactured by cvs2svn to create branch 'ckrm'.
authorPlanet-Lab Support <support@planet-lab.org>
Tue, 29 Mar 2005 19:23:58 +0000 (19:23 +0000)
committerPlanet-Lab Support <support@planet-lab.org>
Tue, 29 Mar 2005 19:23:58 +0000 (19:23 +0000)
1030 files changed:
Documentation/DocBook/librs.tmpl [new file with mode: 0644]
Documentation/DocBook/mtdnand.tmpl [new file with mode: 0644]
Documentation/ManagementStyle [new file with mode: 0644]
Documentation/RCU/RTFP.txt [new file with mode: 0644]
Documentation/RCU/UP.txt [new file with mode: 0644]
Documentation/RCU/arrayRCU.txt [new file with mode: 0644]
Documentation/RCU/checklist.txt [new file with mode: 0644]
Documentation/RCU/listRCU.txt [new file with mode: 0644]
Documentation/RCU/rcu.txt [new file with mode: 0644]
Documentation/arm/IXP2000 [new file with mode: 0644]
Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt [new file with mode: 0644]
Documentation/arm/Samsung-S3C24XX/GPIO.txt [new file with mode: 0644]
Documentation/arm/Samsung-S3C24XX/Overview.txt [new file with mode: 0644]
Documentation/arm/Samsung-S3C24XX/Suspend.txt [new file with mode: 0644]
Documentation/cdrom/packet-writing.txt [new file with mode: 0644]
Documentation/ckrm/numtasks [new file with mode: 0644]
Documentation/cpu-freq/cpufreq-nforce2.txt [new file with mode: 0644]
Documentation/dvb/README.dibusb [new file with mode: 0644]
Documentation/dvb/get_dvb_firmware [new file with mode: 0644]
Documentation/dvb/udev.txt [new file with mode: 0644]
Documentation/i2c/i2c-stub [new file with mode: 0644]
Documentation/i2o/README [new file with mode: 0644]
Documentation/i2o/ioctl [new file with mode: 0644]
Documentation/ia64/serial.txt [new file with mode: 0644]
Documentation/ibm-acpi.txt [new file with mode: 0644]
Documentation/ioctl/cdrom.txt [new file with mode: 0644]
Documentation/ioctl/hdio.txt [new file with mode: 0644]
Documentation/keys.txt [new file with mode: 0644]
Documentation/networking/gen_stats.txt [new file with mode: 0644]
Documentation/networking/proc_net_tcp.txt [new file with mode: 0644]
Documentation/power/kernel_threads.txt [new file with mode: 0644]
Documentation/power/video_extension.txt [new file with mode: 0644]
Documentation/prio_tree.txt [new file with mode: 0644]
Documentation/s390/monreader.txt [new file with mode: 0644]
Documentation/sched-stats.txt [new file with mode: 0644]
Documentation/scsi/megaraid.txt [new file with mode: 0644]
Documentation/seclvl.txt [new file with mode: 0644]
Documentation/stable_api_nonsense.txt [new file with mode: 0644]
Documentation/time_interpolators.txt [new file with mode: 0644]
Documentation/tty.txt [new file with mode: 0644]
Documentation/usb/gadget_serial.txt [new file with mode: 0644]
arch/alpha/Kconfig.debug [new file with mode: 0644]
arch/alpha/kernel/io.c [new file with mode: 0644]
arch/arm/Kconfig.debug [new file with mode: 0644]
arch/arm/boot/compressed/big-endian.S [new file with mode: 0644]
arch/arm/common/icst307.c [new file with mode: 0644]
arch/arm/common/rtctime.c [new file with mode: 0644]
arch/arm/configs/enp2611_defconfig [new file with mode: 0644]
arch/arm/configs/ep80219_defconfig [new file with mode: 0644]
arch/arm/configs/h7201_defconfig [new file with mode: 0644]
arch/arm/configs/h7202_defconfig [new file with mode: 0644]
arch/arm/configs/iq31244_defconfig [new file with mode: 0644]
arch/arm/configs/iq80331_defconfig [new file with mode: 0644]
arch/arm/configs/ixdp2400_defconfig [new file with mode: 0644]
arch/arm/configs/ixdp2401_defconfig [new file with mode: 0644]
arch/arm/configs/ixdp2800_defconfig [new file with mode: 0644]
arch/arm/configs/ixdp2801_defconfig [new file with mode: 0644]
arch/arm/configs/mx1ads_defconfig [new file with mode: 0644]
arch/arm/configs/simpad_defconfig [new file with mode: 0644]
arch/arm/kernel/iwmmxt.S [new file with mode: 0644]
arch/arm/lib/io-readsl.S [new file with mode: 0644]
arch/arm/mach-clps711x/Makefile.boot [new file with mode: 0644]
arch/arm/mach-clps711x/common.h [new file with mode: 0644]
arch/arm/mach-clps7500/Makefile.boot [new file with mode: 0644]
arch/arm/mach-ebsa110/Makefile.boot [new file with mode: 0644]
arch/arm/mach-epxa10db/Makefile.boot [new file with mode: 0644]
arch/arm/mach-footbridge/Makefile.boot [new file with mode: 0644]
arch/arm/mach-footbridge/co285.c [new file with mode: 0644]
arch/arm/mach-footbridge/common.c [new file with mode: 0644]
arch/arm/mach-footbridge/common.h [new file with mode: 0644]
arch/arm/mach-footbridge/dc21285-timer.c [new file with mode: 0644]
arch/arm/mach-footbridge/ebsa285.c [new file with mode: 0644]
arch/arm/mach-footbridge/isa-timer.c [new file with mode: 0644]
arch/arm/mach-footbridge/isa.c [new file with mode: 0644]
arch/arm/mach-footbridge/personal.c [new file with mode: 0644]
arch/arm/mach-h720x/Kconfig [new file with mode: 0644]
arch/arm/mach-h720x/Makefile [new file with mode: 0644]
arch/arm/mach-h720x/Makefile.boot [new file with mode: 0644]
arch/arm/mach-h720x/common.c [new file with mode: 0644]
arch/arm/mach-h720x/common.h [new file with mode: 0644]
arch/arm/mach-h720x/cpu-h7201.c [new file with mode: 0644]
arch/arm/mach-h720x/cpu-h7202.c [new file with mode: 0644]
arch/arm/mach-h720x/h7201-eval.c [new file with mode: 0644]
arch/arm/mach-h720x/h7202-eval.c [new file with mode: 0644]
arch/arm/mach-imx/Kconfig [new file with mode: 0644]
arch/arm/mach-imx/Makefile [new file with mode: 0644]
arch/arm/mach-imx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-imx/dma.c [new file with mode: 0644]
arch/arm/mach-imx/generic.c [new file with mode: 0644]
arch/arm/mach-imx/generic.h [new file with mode: 0644]
arch/arm/mach-imx/irq.c [new file with mode: 0644]
arch/arm/mach-imx/leds-mx1ads.c [new file with mode: 0644]
arch/arm/mach-imx/leds.c [new file with mode: 0644]
arch/arm/mach-imx/leds.h [new file with mode: 0644]
arch/arm/mach-imx/mx1ads.c [new file with mode: 0644]
arch/arm/mach-imx/time.c [new file with mode: 0644]
arch/arm/mach-integrator/Makefile.boot [new file with mode: 0644]
arch/arm/mach-integrator/common.h [new file with mode: 0644]
arch/arm/mach-iop3xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-iop3xx/common.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iop321-setup.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iop331-irq.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iop331-pci.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iop331-setup.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iop331-time.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iq31244-mm.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iq31244-pci.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iq80321-mm.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iq80331-mm.c [new file with mode: 0644]
arch/arm/mach-iop3xx/iq80331-pci.c [new file with mode: 0644]
arch/arm/mach-ixp2000/Kconfig [new file with mode: 0644]
arch/arm/mach-ixp2000/Makefile [new file with mode: 0644]
arch/arm/mach-ixp2000/Makefile.boot [new file with mode: 0644]
arch/arm/mach-ixp2000/core.c [new file with mode: 0644]
arch/arm/mach-ixp2000/enp2611.c [new file with mode: 0644]
arch/arm/mach-ixp2000/ixdp2400.c [new file with mode: 0644]
arch/arm/mach-ixp2000/ixdp2800.c [new file with mode: 0644]
arch/arm/mach-ixp2000/ixdp2x00.c [new file with mode: 0644]
arch/arm/mach-ixp2000/ixdp2x01.c [new file with mode: 0644]
arch/arm/mach-ixp2000/pci.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-ixp4xx/ixdpg425-pci.c [new file with mode: 0644]
arch/arm/mach-l7200/Makefile.boot [new file with mode: 0644]
arch/arm/mach-lh7a40x/Makefile.boot [new file with mode: 0644]
arch/arm/mach-lh7a40x/common.h [new file with mode: 0644]
arch/arm/mach-omap/Makefile.boot [new file with mode: 0644]
arch/arm/mach-omap/board-h2.c [new file with mode: 0644]
arch/arm/mach-omap/board-h3.c [new file with mode: 0644]
arch/arm/mach-omap/clock.c [new file with mode: 0644]
arch/arm/mach-omap/clock.h [new file with mode: 0644]
arch/arm/mach-omap/leds-h2p2-debug.c [new file with mode: 0644]
arch/arm/mach-omap/mcbsp.c [new file with mode: 0644]
arch/arm/mach-omap/pm.c [new file with mode: 0644]
arch/arm/mach-omap/sleep.S [new file with mode: 0644]
arch/arm/mach-omap/usb.c [new file with mode: 0644]
arch/arm/mach-pxa/Makefile.boot [new file with mode: 0644]
arch/arm/mach-pxa/ssp.c [new file with mode: 0644]
arch/arm/mach-rpc/Makefile.boot [new file with mode: 0644]
arch/arm/mach-s3c2410/Makefile.boot [new file with mode: 0644]
arch/arm/mach-s3c2410/clock.c [new file with mode: 0644]
arch/arm/mach-s3c2410/clock.h [new file with mode: 0644]
arch/arm/mach-s3c2410/cpu.c [new file with mode: 0644]
arch/arm/mach-s3c2410/cpu.h [new file with mode: 0644]
arch/arm/mach-s3c2410/devs.c [new file with mode: 0644]
arch/arm/mach-s3c2410/devs.h [new file with mode: 0644]
arch/arm/mach-s3c2410/dma.c [new file with mode: 0644]
arch/arm/mach-s3c2410/mach-rx3715.c [new file with mode: 0644]
arch/arm/mach-s3c2410/pm.c [new file with mode: 0644]
arch/arm/mach-s3c2410/pm.h [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c2440-dsc.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c2440.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c2440.h [new file with mode: 0644]
arch/arm/mach-s3c2410/sleep.S [new file with mode: 0644]
arch/arm/mach-s3c2410/usb-simtec.c [new file with mode: 0644]
arch/arm/mach-s3c2410/usb-simtec.h [new file with mode: 0644]
arch/arm/mach-sa1100/Makefile.boot [new file with mode: 0644]
arch/arm/mach-shark/Makefile.boot [new file with mode: 0644]
arch/arm/mach-versatile/Kconfig [new file with mode: 0644]
arch/arm/mach-versatile/Makefile.boot [new file with mode: 0644]
arch/arm/mach-versatile/core.h [new file with mode: 0644]
arch/arm/mach-versatile/versatile_ab.c [new file with mode: 0644]
arch/arm/mach-versatile/versatile_pb.c [new file with mode: 0644]
arch/arm/mm/flush.c [new file with mode: 0644]
arch/arm26/Kconfig.debug [new file with mode: 0644]
arch/cris/Kconfig.debug [new file with mode: 0644]
arch/cris/arch-v10/kernel/crisksyms.c [new file with mode: 0644]
arch/h8300/Kconfig.debug [new file with mode: 0644]
arch/i386/Kconfig.debug [new file with mode: 0644]
arch/i386/kernel/acpi/earlyquirk.c [new file with mode: 0644]
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c [new file with mode: 0644]
arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c [new file with mode: 0644]
arch/i386/kernel/cpu/intel_cacheinfo.c [new file with mode: 0644]
arch/i386/kernel/kprobes.c [new file with mode: 0644]
arch/i386/kernel/quirks.c [new file with mode: 0644]
arch/i386/kernel/vsyscall.lds.S [new file with mode: 0644]
arch/ia64/Kconfig.debug [new file with mode: 0644]
arch/ia64/configs/bigsur_defconfig [new file with mode: 0644]
arch/ia64/configs/tiger_defconfig [new file with mode: 0644]
arch/ia64/kernel/domain.c [new file with mode: 0644]
arch/ia64/kernel/mca_drv.c [new file with mode: 0644]
arch/ia64/kernel/mca_drv.h [new file with mode: 0644]
arch/ia64/kernel/mca_drv_asm.S [new file with mode: 0644]
arch/ia64/oprofile/perfmon.c [new file with mode: 0644]
arch/ia64/sn/include/pci/pcibr_provider.h [new file with mode: 0644]
arch/ia64/sn/include/pci/pcibus_provider_defs.h [new file with mode: 0644]
arch/ia64/sn/include/pci/pcidev.h [new file with mode: 0644]
arch/ia64/sn/include/pci/pic.h [new file with mode: 0644]
arch/ia64/sn/include/pci/tiocp.h [new file with mode: 0644]
arch/ia64/sn/include/shub.h [new file with mode: 0644]
arch/ia64/sn/include/shubio.h [new file with mode: 0644]
arch/ia64/sn/kernel/huberror.c [new file with mode: 0644]
arch/ia64/sn/kernel/io_init.c [new file with mode: 0644]
arch/ia64/sn/kernel/iomv.c [new file with mode: 0644]
arch/ia64/sn/kernel/sn2/sn_hwperf.c [new file with mode: 0644]
arch/ia64/sn/pci/pci_dma.c [new file with mode: 0644]
arch/ia64/sn/pci/pcibr/pcibr_ate.c [new file with mode: 0644]
arch/ia64/sn/pci/pcibr/pcibr_dma.c [new file with mode: 0644]
arch/ia64/sn/pci/pcibr/pcibr_provider.c [new file with mode: 0644]
arch/m32r/Kconfig [new file with mode: 0644]
arch/m32r/Kconfig.debug [new file with mode: 0644]
arch/m32r/Makefile [new file with mode: 0644]
arch/m32r/boot/Makefile [new file with mode: 0644]
arch/m32r/boot/compressed/Makefile [new file with mode: 0644]
arch/m32r/boot/compressed/boot.h [new file with mode: 0644]
arch/m32r/boot/compressed/head.S [new file with mode: 0644]
arch/m32r/boot/compressed/install.sh [new file with mode: 0644]
arch/m32r/boot/compressed/m32r_sio.c [new file with mode: 0644]
arch/m32r/boot/compressed/misc.c [new file with mode: 0644]
arch/m32r/boot/compressed/vmlinux.lds.S [new file with mode: 0644]
arch/m32r/boot/compressed/vmlinux.scr [new file with mode: 0644]
arch/m32r/boot/setup.S [new file with mode: 0644]
arch/m32r/defconfig [new file with mode: 0644]
arch/m32r/kernel/Makefile [new file with mode: 0644]
arch/m32r/kernel/align.c [new file with mode: 0644]
arch/m32r/kernel/entry.S [new file with mode: 0644]
arch/m32r/kernel/head.S [new file with mode: 0644]
arch/m32r/kernel/init_task.c [new file with mode: 0644]
arch/m32r/kernel/io_m32700ut.c [new file with mode: 0644]
arch/m32r/kernel/io_mappi.c [new file with mode: 0644]
arch/m32r/kernel/io_mappi2.c [new file with mode: 0644]
arch/m32r/kernel/io_oaks32r.c [new file with mode: 0644]
arch/m32r/kernel/io_opsput.c [new file with mode: 0644]
arch/m32r/kernel/io_usrv.c [new file with mode: 0644]
arch/m32r/kernel/irq.c [new file with mode: 0644]
arch/m32r/kernel/m32r_ksyms.c [new file with mode: 0644]
arch/m32r/kernel/module.c [new file with mode: 0644]
arch/m32r/kernel/process.c [new file with mode: 0644]
arch/m32r/kernel/ptrace.c [new file with mode: 0644]
arch/m32r/kernel/semaphore.c [new file with mode: 0644]
arch/m32r/kernel/setup.c [new file with mode: 0644]
arch/m32r/kernel/setup_m32700ut.c [new file with mode: 0644]
arch/m32r/kernel/setup_mappi.c [new file with mode: 0644]
arch/m32r/kernel/setup_mappi2.c [new file with mode: 0644]
arch/m32r/kernel/setup_oaks32r.c [new file with mode: 0644]
arch/m32r/kernel/setup_opsput.c [new file with mode: 0644]
arch/m32r/kernel/setup_usrv.c [new file with mode: 0644]
arch/m32r/kernel/signal.c [new file with mode: 0644]
arch/m32r/kernel/smp.c [new file with mode: 0644]
arch/m32r/kernel/smpboot.c [new file with mode: 0644]
arch/m32r/kernel/sys_m32r.c [new file with mode: 0644]
arch/m32r/kernel/time.c [new file with mode: 0644]
arch/m32r/kernel/traps.c [new file with mode: 0644]
arch/m32r/kernel/vmlinux.lds.S [new file with mode: 0644]
arch/m32r/lib/Makefile [new file with mode: 0644]
arch/m32r/lib/ashxdi3.S [new file with mode: 0644]
arch/m32r/lib/checksum.S [new file with mode: 0644]
arch/m32r/lib/csum_partial_copy.c [new file with mode: 0644]
arch/m32r/lib/delay.c [new file with mode: 0644]
arch/m32r/lib/getuser.S [new file with mode: 0644]
arch/m32r/lib/memcpy.S [new file with mode: 0644]
arch/m32r/lib/memset.S [new file with mode: 0644]
arch/m32r/lib/putuser.S [new file with mode: 0644]
arch/m32r/lib/strlen.S [new file with mode: 0644]
arch/m32r/lib/usercopy.c [new file with mode: 0644]
arch/m32r/m32700ut/defconfig.m32700ut.smp [new file with mode: 0644]
arch/m32r/m32700ut/defconfig.m32700ut.up [new file with mode: 0644]
arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB [new file with mode: 0644]
arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB [new file with mode: 0644]
arch/m32r/m32700ut/dot.gdbinit_400MHz_32MB [new file with mode: 0644]
arch/m32r/mappi/defconfig.nommu [new file with mode: 0644]
arch/m32r/mappi/defconfig.smp [new file with mode: 0644]
arch/m32r/mappi/defconfig.up [new file with mode: 0644]
arch/m32r/mappi/dot.gdbinit [new file with mode: 0644]
arch/m32r/mappi/dot.gdbinit.nommu [new file with mode: 0644]
arch/m32r/mappi/dot.gdbinit.smp [new file with mode: 0644]
arch/m32r/mappi2/defconfig.vdec2 [new file with mode: 0644]
arch/m32r/mappi2/dot.gdbinit.vdec2 [new file with mode: 0644]
arch/m32r/mm/Makefile [new file with mode: 0644]
arch/m32r/mm/cache.c [new file with mode: 0644]
arch/m32r/mm/discontig.c [new file with mode: 0644]
arch/m32r/mm/extable.c [new file with mode: 0644]
arch/m32r/mm/fault-nommu.c [new file with mode: 0644]
arch/m32r/mm/fault.c [new file with mode: 0644]
arch/m32r/mm/init.c [new file with mode: 0644]
arch/m32r/mm/ioremap-nommu.c [new file with mode: 0644]
arch/m32r/mm/ioremap.c [new file with mode: 0644]
arch/m32r/mm/mmu.S [new file with mode: 0644]
arch/m32r/mm/page.S [new file with mode: 0644]
arch/m32r/oaks32r/defconfig.nommu [new file with mode: 0644]
arch/m32r/oaks32r/dot.gdbinit.nommu [new file with mode: 0644]
arch/m32r/oprofile/Kconfig [new file with mode: 0644]
arch/m32r/oprofile/Makefile [new file with mode: 0644]
arch/m32r/oprofile/init.c [new file with mode: 0644]
arch/m32r/opsput/defconfig.opsput [new file with mode: 0644]
arch/m32r/opsput/dot.gdbinit [new file with mode: 0644]
arch/m68k/Kconfig.debug [new file with mode: 0644]
arch/m68k/configs/amiga_defconfig [new file with mode: 0644]
arch/m68k/configs/apollo_defconfig [new file with mode: 0644]
arch/m68k/configs/atari_defconfig [new file with mode: 0644]
arch/m68k/configs/bvme6000_defconfig [new file with mode: 0644]
arch/m68k/configs/hp300_defconfig [new file with mode: 0644]
arch/m68k/configs/mac_defconfig [new file with mode: 0644]
arch/m68k/configs/mvme147_defconfig [new file with mode: 0644]
arch/m68k/configs/mvme16x_defconfig [new file with mode: 0644]
arch/m68k/configs/q40_defconfig [new file with mode: 0644]
arch/m68k/configs/sun3_defconfig [new file with mode: 0644]
arch/m68k/configs/sun3x_defconfig [new file with mode: 0644]
arch/m68knommu/Kconfig.debug [new file with mode: 0644]
arch/m68knommu/lib/delay.c [new file with mode: 0644]
arch/m68knommu/platform/5272/CANCam/crt0_ram.S [new file with mode: 0644]
arch/m68knommu/platform/5272/SCALES/crt0_ram.S [new file with mode: 0644]
arch/m68knommu/platform/527x/M5271EVB/crt0_ram.S [new file with mode: 0644]
arch/m68knommu/platform/527x/M5275EVB/crt0_ram.S [new file with mode: 0644]
arch/m68knommu/platform/527x/Makefile [new file with mode: 0644]
arch/m68knommu/platform/527x/config.c [new file with mode: 0644]
arch/m68knommu/platform/528x/M5282EVB/crt0_ram.S [new file with mode: 0644]
arch/m68knommu/platform/528x/Makefile [new file with mode: 0644]
arch/m68knommu/platform/528x/config.c [new file with mode: 0644]
arch/m68knommu/platform/528x/senTec/crt0_ram.S [new file with mode: 0644]
arch/m68knommu/platform/5307/pit.c [new file with mode: 0644]
arch/mips/Kconfig.debug [new file with mode: 0644]
arch/mips/au1000/common/platform.c [new file with mode: 0644]
arch/mips/configs/db1550_defconfig [new file with mode: 0644]
arch/mips/configs/ocelot_3_defconfig [new file with mode: 0644]
arch/mips/kernel/irq-msc01.c [new file with mode: 0644]
arch/mips/mm/tlbex.c [new file with mode: 0644]
arch/mips/mm/tlbex32-mips32.S [new file with mode: 0644]
arch/mips/momentum/ocelot_3/Makefile [new file with mode: 0644]
arch/mips/momentum/ocelot_3/int-handler.S [new file with mode: 0644]
arch/mips/momentum/ocelot_3/irq.c [new file with mode: 0644]
arch/mips/momentum/ocelot_3/ocelot_3_fpga.h [new file with mode: 0644]
arch/mips/momentum/ocelot_3/prom.c [new file with mode: 0644]
arch/mips/momentum/ocelot_3/reset.c [new file with mode: 0644]
arch/mips/momentum/ocelot_3/setup.c [new file with mode: 0644]
arch/mips/pci/fixup-ocelot3.c [new file with mode: 0644]
arch/parisc/Kconfig.debug [new file with mode: 0644]
arch/parisc/install.sh [new file with mode: 0644]
arch/parisc/kernel/topology.c [new file with mode: 0644]
arch/parisc/lib/fixup.S [new file with mode: 0644]
arch/parisc/lib/memcpy.c [new file with mode: 0644]
arch/ppc/Kconfig.debug [new file with mode: 0644]
arch/ppc/boot/include/serial.h [new file with mode: 0644]
arch/ppc/boot/simple/chrpmap.c [new file with mode: 0644]
arch/ppc/boot/simple/pibs.c [new file with mode: 0644]
arch/ppc/boot/simple/prepmap.c [new file with mode: 0644]
arch/ppc/kernel/head_booke.h [new file with mode: 0644]
arch/ppc/platforms/4xx/virtex-ii_pro.c [new file with mode: 0644]
arch/ppc/platforms/4xx/virtex-ii_pro.h [new file with mode: 0644]
arch/ppc/platforms/4xx/xilinx_ml300.c [new file with mode: 0644]
arch/ppc/platforms/4xx/xilinx_ml300.h [new file with mode: 0644]
arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h [new file with mode: 0644]
arch/ppc/platforms/lopec.c [new file with mode: 0644]
arch/ppc/platforms/lopec.h [new file with mode: 0644]
arch/ppc/platforms/mvme5100.c [new file with mode: 0644]
arch/ppc/platforms/pq2ads.c [new file with mode: 0644]
arch/ppc/syslib/gen550.h [new file with mode: 0644]
arch/ppc/syslib/m8xx_wdt.c [new file with mode: 0644]
arch/ppc/syslib/m8xx_wdt.h [new file with mode: 0644]
arch/ppc/syslib/xilinx_pic.c [new file with mode: 0644]
arch/ppc64/Kconfig.debug [new file with mode: 0644]
arch/ppc64/configs/maple_defconfig [new file with mode: 0644]
arch/ppc64/kernel/iSeries_smp.c [new file with mode: 0644]
arch/ppc64/kernel/iomap.c [new file with mode: 0644]
arch/ppc64/kernel/maple_pci.c [new file with mode: 0644]
arch/ppc64/kernel/maple_setup.c [new file with mode: 0644]
arch/ppc64/kernel/maple_time.c [new file with mode: 0644]
arch/ppc64/kernel/mpic.c [new file with mode: 0644]
arch/ppc64/kernel/mpic.h [new file with mode: 0644]
arch/ppc64/kernel/pSeries_setup.c [new file with mode: 0644]
arch/ppc64/kernel/pSeries_smp.c [new file with mode: 0644]
arch/ppc64/kernel/prom_init.c [new file with mode: 0644]
arch/ppc64/kernel/u3_iommu.c [new file with mode: 0644]
arch/ppc64/lib/sstep.c [new file with mode: 0644]
arch/ppc64/mm/hash_native.c [new file with mode: 0644]
arch/ppc64/mm/stab.c [new file with mode: 0644]
arch/s390/Kconfig.debug [new file with mode: 0644]
arch/s390/kernel/irq.c [new file with mode: 0644]
arch/sh/Kconfig.debug [new file with mode: 0644]
arch/sh/boards/renesas/edosk7705/Makefile [new file with mode: 0644]
arch/sh/boards/renesas/edosk7705/io.c [new file with mode: 0644]
arch/sh/boards/renesas/edosk7705/setup.c [new file with mode: 0644]
arch/sh/boards/se/73180/Makefile [new file with mode: 0644]
arch/sh/boards/se/73180/io.c [new file with mode: 0644]
arch/sh/boards/se/73180/irq.c [new file with mode: 0644]
arch/sh/boards/se/73180/led.c [new file with mode: 0644]
arch/sh/boards/se/73180/setup.c [new file with mode: 0644]
arch/sh/boards/sh03/Makefile [new file with mode: 0644]
arch/sh/boards/sh03/led.c [new file with mode: 0644]
arch/sh/boards/sh03/rtc.c [new file with mode: 0644]
arch/sh/boards/sh03/setup.c [new file with mode: 0644]
arch/sh/boards/superh/microdev/Makefile [new file with mode: 0644]
arch/sh/boards/superh/microdev/io.c [new file with mode: 0644]
arch/sh/boards/superh/microdev/irq.c [new file with mode: 0644]
arch/sh/boards/superh/microdev/led.c [new file with mode: 0644]
arch/sh/boards/superh/microdev/setup.c [new file with mode: 0644]
arch/sh/configs/microdev_defconfig [new file with mode: 0644]
arch/sh/configs/se73180_defconfig [new file with mode: 0644]
arch/sh/configs/se7705_defconfig [new file with mode: 0644]
arch/sh/configs/sh03_defconfig [new file with mode: 0644]
arch/sh/drivers/pci/fixups-sh03.c [new file with mode: 0644]
arch/sh/drivers/pci/ops-sh03.c [new file with mode: 0644]
arch/sh/kernel/asm-offsets.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/probe.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/probe.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4/probe.c [new file with mode: 0644]
arch/sh/lib/memcpy-sh4.S [new file with mode: 0644]
arch/sh/mm/cache-sh7705.c [new file with mode: 0644]
arch/sh/mm/pg-sh7705.c [new file with mode: 0644]
arch/sh/oprofile/op_model_sh7750.c [new file with mode: 0644]
arch/sh/tools/gen-mach-types [new file with mode: 0644]
arch/sh64/Kconfig.debug [new file with mode: 0644]
arch/sparc/Kconfig.debug [new file with mode: 0644]
arch/sparc64/Kconfig.debug [new file with mode: 0644]
arch/sparc64/kernel/kprobes.c [new file with mode: 0644]
arch/sparc64/lib/U1copy_from_user.S [new file with mode: 0644]
arch/sparc64/lib/U1copy_to_user.S [new file with mode: 0644]
arch/sparc64/lib/U1memcpy.S [new file with mode: 0644]
arch/sparc64/lib/U3patch.S [new file with mode: 0644]
arch/sparc64/lib/copy_in_user.S [new file with mode: 0644]
arch/sparc64/lib/delay.c [new file with mode: 0644]
arch/sparc64/lib/iomap.c [new file with mode: 0644]
arch/sparc64/lib/memmove.S [new file with mode: 0644]
arch/sparc64/lib/user_fixup.c [new file with mode: 0644]
arch/um/Kconfig.debug [new file with mode: 0644]
arch/um/Makefile-x86_64 [new file with mode: 0644]
arch/um/drivers/cow_sys.h [new file with mode: 0644]
arch/um/kernel/dyn.lds.S [new file with mode: 0644]
arch/um/kernel/main.c [new file with mode: 0644]
arch/um/kernel/skas/include/mmu-skas.h [new file with mode: 0644]
arch/um/kernel/skas/include/mode-skas.h [new file with mode: 0644]
arch/um/kernel/skas/include/mode_kern-skas.h [new file with mode: 0644]
arch/um/kernel/skas/include/uaccess-skas.h [new file with mode: 0644]
arch/um/kernel/tt/include/mmu-tt.h [new file with mode: 0644]
arch/um/kernel/tt/include/mode-tt.h [new file with mode: 0644]
arch/um/kernel/tt/include/mode_kern-tt.h [new file with mode: 0644]
arch/um/kernel/tt/include/uaccess-tt.h [new file with mode: 0644]
arch/um/kernel/uml.lds.S [new file with mode: 0644]
arch/um/os-Linux/time.c [new file with mode: 0644]
arch/v850/Kconfig.debug [new file with mode: 0644]
arch/x86_64/Kconfig.debug [new file with mode: 0644]
arch/x86_64/kernel/genapic.c [new file with mode: 0644]
arch/x86_64/kernel/genapic_cluster.c [new file with mode: 0644]
arch/x86_64/kernel/genapic_flat.c [new file with mode: 0644]
arch/x86_64/kernel/kprobes.c [new file with mode: 0644]
arch/x86_64/lib/bitops.c [new file with mode: 0644]
arch/x86_64/pci/Makefile-BUS [new file with mode: 0644]
arch/x86_64/pci/k8-bus.c [new file with mode: 0644]
crypto/anubis.c [new file with mode: 0644]
crypto/wp512.c [new file with mode: 0644]
drivers/acpi/ibm_acpi.c [new file with mode: 0644]
drivers/acpi/motherboard.c [new file with mode: 0644]
drivers/acpi/sleep/wakeup.c [new file with mode: 0644]
drivers/acpi/video.c [new file with mode: 0644]
drivers/block/pktcdvd.c [new file with mode: 0644]
drivers/block/ub.c [new file with mode: 0644]
drivers/char/drm/drm_core.h [new file with mode: 0644]
drivers/char/drm/i915.h [new file with mode: 0644]
drivers/char/drm/i915_dma.c [new file with mode: 0644]
drivers/char/drm/i915_drm.h [new file with mode: 0644]
drivers/char/drm/i915_drv.c [new file with mode: 0644]
drivers/char/drm/i915_drv.h [new file with mode: 0644]
drivers/char/drm/i915_irq.c [new file with mode: 0644]
drivers/char/drm/i915_mem.c [new file with mode: 0644]
drivers/char/ds1302.c [new file with mode: 0644]
drivers/char/hvsi.c [new file with mode: 0644]
drivers/char/ipmi/ipmi_poweroff.c [new file with mode: 0644]
drivers/char/mmtimer.c [new file with mode: 0644]
drivers/char/mxser.h [new file with mode: 0644]
drivers/char/s3c2410-rtc.c [new file with mode: 0644]
drivers/char/snsc.c [new file with mode: 0644]
drivers/char/snsc.h [new file with mode: 0644]
drivers/char/watchdog/mpc8xx_wdt.c [new file with mode: 0644]
drivers/char/watchdog/s3c2410_wdt.c [new file with mode: 0644]
drivers/cpufreq/cpufreq_ondemand.c [new file with mode: 0644]
drivers/dio/dio-driver.c [new file with mode: 0644]
drivers/dio/dio-sysfs.c [new file with mode: 0644]
drivers/i2c/algos/i2c-algo-pca.c [new file with mode: 0644]
drivers/i2c/algos/i2c-algo-pca.h [new file with mode: 0644]
drivers/i2c/busses/i2c-amd756-s4882.c [new file with mode: 0644]
drivers/i2c/busses/i2c-ixp2000.c [new file with mode: 0644]
drivers/i2c/busses/i2c-mpc.c [new file with mode: 0644]
drivers/i2c/busses/i2c-pca-isa.c [new file with mode: 0644]
drivers/i2c/busses/i2c-s3c2410.c [new file with mode: 0644]
drivers/i2c/busses/i2c-stub.c [new file with mode: 0644]
drivers/i2c/chips/adm1026.c [new file with mode: 0644]
drivers/i2c/chips/isp1301_omap.c [new file with mode: 0644]
drivers/i2c/chips/lm63.c [new file with mode: 0644]
drivers/i2c/chips/lm87.c [new file with mode: 0644]
drivers/i2c/chips/pc87360.c [new file with mode: 0644]
drivers/i2c/chips/smsc47m1.c [new file with mode: 0644]
drivers/i2c/i2c-sensor-detect.c [new file with mode: 0644]
drivers/i2c/i2c-sensor-vid.c [new file with mode: 0644]
drivers/ide/arm/bast-ide.c [new file with mode: 0644]
drivers/ide/cris/Makefile [new file with mode: 0644]
drivers/ide/cris/ide-v10.c [new file with mode: 0644]
drivers/input/serio/serio_raw.c [new file with mode: 0644]
drivers/md/faulty.c [new file with mode: 0644]
drivers/md/raid10.c [new file with mode: 0644]
drivers/media/dvb/b2c2/b2c2-common.c [new file with mode: 0644]
drivers/media/dvb/b2c2/b2c2-usb-core.c [new file with mode: 0644]
drivers/media/dvb/bt8xx/dst.c [new file with mode: 0644]
drivers/media/dvb/bt8xx/dst.h [new file with mode: 0644]
drivers/media/dvb/bt8xx/dst_priv.h [new file with mode: 0644]
drivers/media/dvb/cinergyT2/Kconfig [new file with mode: 0644]
drivers/media/dvb/cinergyT2/Makefile [new file with mode: 0644]
drivers/media/dvb/cinergyT2/cinergyT2.c [new file with mode: 0644]
drivers/media/dvb/dibusb/Kconfig [new file with mode: 0644]
drivers/media/dvb/dibusb/Makefile [new file with mode: 0644]
drivers/media/dvb/dibusb/dvb-dibusb.c [new file with mode: 0644]
drivers/media/dvb/dibusb/dvb-dibusb.h [new file with mode: 0644]
drivers/media/dvb/frontends/at76c651.h [new file with mode: 0644]
drivers/media/dvb/frontends/cx22700.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx22700.h [new file with mode: 0644]
drivers/media/dvb/frontends/cx22702.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx22702.h [new file with mode: 0644]
drivers/media/dvb/frontends/cx24110.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000-common.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000-common.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000mb.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000mb_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000mc.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib3000mc_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/dvb_dummy_fe.h [new file with mode: 0644]
drivers/media/dvb/frontends/l64781.c [new file with mode: 0644]
drivers/media/dvb/frontends/l64781.h [new file with mode: 0644]
drivers/media/dvb/frontends/mt312_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/mt352.c [new file with mode: 0644]
drivers/media/dvb/frontends/mt352.h [new file with mode: 0644]
drivers/media/dvb/frontends/mt352_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/nxt6000_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/sp8870.c [new file with mode: 0644]
drivers/media/dvb/frontends/sp8870.h [new file with mode: 0644]
drivers/media/dvb/frontends/sp887x.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0297.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv0297.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0299.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda10021.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda10021.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda1004x.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda8083.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda8083.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda80xx.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda80xx.h [new file with mode: 0644]
drivers/media/dvb/frontends/ves1820.h [new file with mode: 0644]
drivers/media/dvb/frontends/ves1x93.h [new file with mode: 0644]
drivers/media/dvb/ttusb-dec/ttusbdecfe.c [new file with mode: 0644]
drivers/media/dvb/ttusb-dec/ttusbdecfe.h [new file with mode: 0644]
drivers/media/video/arv.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-blackbird.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-dvb.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-mpeg.c [new file with mode: 0644]
drivers/media/video/saa7134/saa7134-dvb.c [new file with mode: 0644]
drivers/media/video/saa7134/saa7134-empress.c [new file with mode: 0644]
drivers/media/video/video-buf-dvb.c [new file with mode: 0644]
drivers/message/i2o/debug.c [new file with mode: 0644]
drivers/message/i2o/device.c [new file with mode: 0644]
drivers/message/i2o/driver.c [new file with mode: 0644]
drivers/message/i2o/exec-osm.c [new file with mode: 0644]
drivers/message/i2o/i2o_block.h [new file with mode: 0644]
drivers/message/i2o/iop.c [new file with mode: 0644]
drivers/message/i2o/pci.c [new file with mode: 0644]
drivers/mmc/Kconfig [new file with mode: 0644]
drivers/mmc/Makefile [new file with mode: 0644]
drivers/mmc/mmc.c [new file with mode: 0644]
drivers/mmc/mmc.h [new file with mode: 0644]
drivers/mmc/mmc_block.c [new file with mode: 0644]
drivers/mmc/mmc_queue.c [new file with mode: 0644]
drivers/mmc/mmc_queue.h [new file with mode: 0644]
drivers/mmc/mmc_sysfs.c [new file with mode: 0644]
drivers/mmc/mmci.c [new file with mode: 0644]
drivers/mmc/mmci.h [new file with mode: 0644]
drivers/mmc/pxamci.c [new file with mode: 0644]
drivers/mmc/pxamci.h [new file with mode: 0644]
drivers/mmc/wbsd.c [new file with mode: 0644]
drivers/mmc/wbsd.h [new file with mode: 0644]
drivers/mtd/chips/fwh_lock.h [new file with mode: 0644]
drivers/mtd/maps/bast-flash.c [new file with mode: 0644]
drivers/mtd/maps/ipaq-flash.c [new file with mode: 0644]
drivers/mtd/maps/ixp2000.c [new file with mode: 0644]
drivers/mtd/maps/ocotea.c [new file with mode: 0644]
drivers/mtd/maps/ts5500_flash.c [new file with mode: 0644]
drivers/mtd/nand/h1910.c [new file with mode: 0644]
drivers/mtd/nand/rtc_from4.c [new file with mode: 0644]
drivers/mtd/nand/s3c2410.c [new file with mode: 0644]
drivers/net/cris/Makefile [new file with mode: 0644]
drivers/net/cris/eth_v10.c [new file with mode: 0644]
drivers/net/gt64240eth.h [new file with mode: 0644]
drivers/net/mv643xx_eth.c [new file with mode: 0644]
drivers/net/mv643xx_eth.h [new file with mode: 0644]
drivers/pci/hotplug/acpiphp_ibm.c [new file with mode: 0644]
drivers/pci/pci-acpi.c [new file with mode: 0644]
drivers/pci/rom.c [new file with mode: 0644]
drivers/pcmcia/m32r_cfc.c [new file with mode: 0644]
drivers/pcmcia/m32r_cfc.h [new file with mode: 0644]
drivers/pcmcia/m32r_pcc.c [new file with mode: 0644]
drivers/pcmcia/m32r_pcc.h [new file with mode: 0644]
drivers/pcmcia/pcmcia_compat.c [new file with mode: 0644]
drivers/pnp/pnpacpi/Kconfig [new file with mode: 0644]
drivers/pnp/pnpacpi/Makefile [new file with mode: 0644]
drivers/pnp/pnpacpi/core.c [new file with mode: 0644]
drivers/pnp/pnpacpi/pnpacpi.h [new file with mode: 0644]
drivers/pnp/pnpacpi/rsparser.c [new file with mode: 0644]
drivers/s390/char/monreader.c [new file with mode: 0644]
drivers/s390/char/vmlogrdr.c [new file with mode: 0644]
drivers/s390/char/vmwatchdog.c [new file with mode: 0644]
drivers/scsi/a100u2w.c [new file with mode: 0644]
drivers/scsi/a100u2w.h [new file with mode: 0644]
drivers/scsi/aic7xxx/aic79xx_pci.h [new file with mode: 0644]
drivers/scsi/aic7xxx/aic7xxx_pci.h [new file with mode: 0644]
drivers/scsi/ibmvscsi/Makefile [new file with mode: 0644]
drivers/scsi/ibmvscsi/ibmvscsi.c [new file with mode: 0644]
drivers/scsi/ibmvscsi/ibmvscsi.h [new file with mode: 0644]
drivers/scsi/ibmvscsi/iseries_vscsi.c [new file with mode: 0644]
drivers/scsi/ibmvscsi/rpa_vscsi.c [new file with mode: 0644]
drivers/scsi/ibmvscsi/srp.h [new file with mode: 0644]
drivers/scsi/ibmvscsi/viosrp.h [new file with mode: 0644]
drivers/scsi/initio.c [new file with mode: 0644]
drivers/scsi/initio.h [new file with mode: 0644]
drivers/scsi/megaraid/Kconfig.megaraid [new file with mode: 0644]
drivers/scsi/megaraid/Makefile [new file with mode: 0644]
drivers/scsi/megaraid/mbox_defs.h [new file with mode: 0644]
drivers/scsi/megaraid/mega_common.h [new file with mode: 0644]
drivers/scsi/megaraid/megaraid_ioctl.h [new file with mode: 0644]
drivers/scsi/megaraid/megaraid_mbox.c [new file with mode: 0644]
drivers/scsi/megaraid/megaraid_mbox.h [new file with mode: 0644]
drivers/scsi/megaraid/megaraid_mm.c [new file with mode: 0644]
drivers/scsi/megaraid/megaraid_mm.h [new file with mode: 0644]
drivers/scsi/ql1040_fw.h [new file with mode: 0644]
drivers/serial/8250_early.c [new file with mode: 0644]
drivers/serial/8250_hp300.c [new file with mode: 0644]
drivers/serial/crisv10.c [new file with mode: 0644]
drivers/serial/crisv10.h [new file with mode: 0644]
drivers/serial/icom.c [new file with mode: 0644]
drivers/serial/icom.h [new file with mode: 0644]
drivers/serial/imx.c [new file with mode: 0644]
drivers/serial/m32r_sio.c [new file with mode: 0644]
drivers/serial/m32r_sio.h [new file with mode: 0644]
drivers/serial/m32r_sio_reg.h [new file with mode: 0644]
drivers/usb/atm/Kconfig [new file with mode: 0644]
drivers/usb/core/otg_whitelist.h [new file with mode: 0644]
drivers/usb/gadget/lh7a40x_udc.c [new file with mode: 0644]
drivers/usb/gadget/lh7a40x_udc.h [new file with mode: 0644]
drivers/usb/gadget/omap_udc.c [new file with mode: 0644]
drivers/usb/gadget/omap_udc.h [new file with mode: 0644]
drivers/usb/host/hc_crisv10.c [new file with mode: 0644]
drivers/usb/host/hc_crisv10.h [new file with mode: 0644]
drivers/usb/host/ohci-pxa27x.c [new file with mode: 0644]
drivers/usb/host/sl811-hcd.c [new file with mode: 0644]
drivers/usb/host/sl811.h [new file with mode: 0644]
drivers/usb/media/sn9c102_pas202bcb.c [new file with mode: 0644]
drivers/usb/misc/phidgetkit.c [new file with mode: 0644]
drivers/usb/serial/cypress_m8.c [new file with mode: 0644]
drivers/usb/serial/cypress_m8.h [new file with mode: 0644]
drivers/usb/serial/ipw.c [new file with mode: 0644]
drivers/video/amba-clcd.c [new file with mode: 0644]
drivers/video/console/bitblit.c [new file with mode: 0644]
drivers/video/console/tileblit.c [new file with mode: 0644]
drivers/video/intelfb/Makefile [new file with mode: 0644]
drivers/video/intelfb/intelfb.h [new file with mode: 0644]
drivers/video/intelfb/intelfbdrv.c [new file with mode: 0644]
drivers/video/intelfb/intelfbdrv.h [new file with mode: 0644]
drivers/video/intelfb/intelfbhw.c [new file with mode: 0644]
drivers/video/intelfb/intelfbhw.h [new file with mode: 0644]
drivers/video/savage/Makefile [new file with mode: 0644]
drivers/video/savage/savagefb-i2c.c [new file with mode: 0644]
drivers/video/savage/savagefb.c [new file with mode: 0644]
drivers/video/savage/savagefb.h [new file with mode: 0644]
drivers/video/savage/savagefb_accel.c [new file with mode: 0644]
drivers/w1/ds_w1_bridge.c [new file with mode: 0644]
drivers/w1/dscore.c [new file with mode: 0644]
drivers/w1/dscore.h [new file with mode: 0644]
drivers/w1/w1_smem.c [new file with mode: 0644]
fs/cifs/readdir.c [new file with mode: 0644]
fs/hfs/attr.c [new file with mode: 0644]
fs/nfs/callback.c [new file with mode: 0644]
fs/nfs/callback.h [new file with mode: 0644]
fs/nfs/callback_proc.c [new file with mode: 0644]
fs/nfs/callback_xdr.c [new file with mode: 0644]
fs/nfs/delegation.c [new file with mode: 0644]
fs/nfs/delegation.h [new file with mode: 0644]
fs/nfsd/nfs4acl.c [new file with mode: 0644]
fs/ntfs/aops.h [new file with mode: 0644]
fs/ntfs/bitmap.c [new file with mode: 0644]
fs/ntfs/bitmap.h [new file with mode: 0644]
fs/ntfs/lcnalloc.c [new file with mode: 0644]
fs/ntfs/lcnalloc.h [new file with mode: 0644]
fs/ntfs/runlist.c [new file with mode: 0644]
fs/ntfs/runlist.h [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_ioctl32.c [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_ioctl32.h [new file with mode: 0644]
include/asm-alpha/io_trivial.h [new file with mode: 0644]
include/asm-arm/arch-h720x/boards.h [new file with mode: 0644]
include/asm-arm/arch-h720x/dma.h [new file with mode: 0644]
include/asm-arm/arch-h720x/h7201-regs.h [new file with mode: 0644]
include/asm-arm/arch-h720x/h7202-regs.h [new file with mode: 0644]
include/asm-arm/arch-h720x/hardware.h [new file with mode: 0644]
include/asm-arm/arch-h720x/io.h [new file with mode: 0644]
include/asm-arm/arch-h720x/irq.h [new file with mode: 0644]
include/asm-arm/arch-h720x/irqs.h [new file with mode: 0644]
include/asm-arm/arch-h720x/memory.h [new file with mode: 0644]
include/asm-arm/arch-h720x/param.h [new file with mode: 0644]
include/asm-arm/arch-h720x/system.h [new file with mode: 0644]
include/asm-arm/arch-h720x/timex.h [new file with mode: 0644]
include/asm-arm/arch-h720x/uncompress.h [new file with mode: 0644]
include/asm-arm/arch-h720x/vmalloc.h [new file with mode: 0644]
include/asm-arm/arch-imx/dma.h [new file with mode: 0644]
include/asm-arm/arch-imx/hardware.h [new file with mode: 0644]
include/asm-arm/arch-imx/imx-regs.h [new file with mode: 0644]
include/asm-arm/arch-imx/io.h [new file with mode: 0644]
include/asm-arm/arch-imx/irq.h [new file with mode: 0644]
include/asm-arm/arch-imx/irqs.h [new file with mode: 0644]
include/asm-arm/arch-imx/memory.h [new file with mode: 0644]
include/asm-arm/arch-imx/mx1ads.h [new file with mode: 0644]
include/asm-arm/arch-imx/param.h [new file with mode: 0644]
include/asm-arm/arch-imx/system.h [new file with mode: 0644]
include/asm-arm/arch-imx/timex.h [new file with mode: 0644]
include/asm-arm/arch-imx/uncompress.h [new file with mode: 0644]
include/asm-arm/arch-imx/vmalloc.h [new file with mode: 0644]
include/asm-arm/arch-iop3xx/iop331-irqs.h [new file with mode: 0644]
include/asm-arm/arch-iop3xx/iop331.h [new file with mode: 0644]
include/asm-arm/arch-iop3xx/iq31244.h [new file with mode: 0644]
include/asm-arm/arch-iop3xx/iq80331.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/dma.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/enp2611.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/gpio.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/hardware.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/io.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/irq.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/irqs.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/ixdp2x00.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/ixdp2x01.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/ixp2000-regs.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/memory.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/param.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/platform.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/system.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/timex.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/uncompress.h [new file with mode: 0644]
include/asm-arm/arch-ixp2000/vmalloc.h [new file with mode: 0644]
include/asm-arm/arch-omap/cpu.h [new file with mode: 0644]
include/asm-arm/arch-omap/mcbsp.h [new file with mode: 0644]
include/asm-arm/arch-omap/omap16xx.h [new file with mode: 0644]
include/asm-arm/arch-omap/tc.h [new file with mode: 0644]
include/asm-arm/arch-omap/tps65010.h [new file with mode: 0644]
include/asm-arm/arch-omap/usb.h [new file with mode: 0644]
include/asm-arm/arch-pxa/mmc.h [new file with mode: 0644]
include/asm-arm/arch-pxa/ssp.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/bast-pmu.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/idle.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/iic.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/nand.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-dsc.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-gpioj.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-iic.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-mem.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-nand.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-sdi.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-spi.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/regs-udc.h [new file with mode: 0644]
include/asm-arm/arch-s3c2410/usb-control.h [new file with mode: 0644]
include/asm-arm/hardware/amba_clcd.h [new file with mode: 0644]
include/asm-arm/hardware/icst307.h [new file with mode: 0644]
include/asm-arm/mach/irda.h [new file with mode: 0644]
include/asm-arm/mach/mmc.h [new file with mode: 0644]
include/asm-arm/rtc.h [new file with mode: 0644]
include/asm-generic/bug.h [new file with mode: 0644]
include/asm-generic/iomap.h [new file with mode: 0644]
include/asm-generic/uaccess.h [new file with mode: 0644]
include/asm-i386/kdebug.h [new file with mode: 0644]
include/asm-i386/kprobes.h [new file with mode: 0644]
include/asm-i386/pci-direct.h [new file with mode: 0644]
include/asm-ia64/sn/l1.h [new file with mode: 0644]
include/asm-ia64/sn/sn2/sn_hwperf.h [new file with mode: 0644]
include/asm-m32r/a.out.h [new file with mode: 0644]
include/asm-m32r/addrspace.h [new file with mode: 0644]
include/asm-m32r/assembler.h [new file with mode: 0644]
include/asm-m32r/atomic.h [new file with mode: 0644]
include/asm-m32r/bitops.h [new file with mode: 0644]
include/asm-m32r/bug.h [new file with mode: 0644]
include/asm-m32r/bugs.h [new file with mode: 0644]
include/asm-m32r/byteorder.h [new file with mode: 0644]
include/asm-m32r/cache.h [new file with mode: 0644]
include/asm-m32r/cachectl.h [new file with mode: 0644]
include/asm-m32r/cacheflush.h [new file with mode: 0644]
include/asm-m32r/checksum.h [new file with mode: 0644]
include/asm-m32r/current.h [new file with mode: 0644]
include/asm-m32r/delay.h [new file with mode: 0644]
include/asm-m32r/div64.h [new file with mode: 0644]
include/asm-m32r/dma-mapping.h [new file with mode: 0644]
include/asm-m32r/dma.h [new file with mode: 0644]
include/asm-m32r/elf.h [new file with mode: 0644]
include/asm-m32r/errno.h [new file with mode: 0644]
include/asm-m32r/fcntl.h [new file with mode: 0644]
include/asm-m32r/flat.h [new file with mode: 0644]
include/asm-m32r/hardirq.h [new file with mode: 0644]
include/asm-m32r/hdreg.h [new file with mode: 0644]
include/asm-m32r/hw_irq.h [new file with mode: 0644]
include/asm-m32r/ide.h [new file with mode: 0644]
include/asm-m32r/io.h [new file with mode: 0644]
include/asm-m32r/ioctl.h [new file with mode: 0644]
include/asm-m32r/ioctls.h [new file with mode: 0644]
include/asm-m32r/ipc.h [new file with mode: 0644]
include/asm-m32r/ipcbuf.h [new file with mode: 0644]
include/asm-m32r/irq.h [new file with mode: 0644]
include/asm-m32r/kmap_types.h [new file with mode: 0644]
include/asm-m32r/linkage.h [new file with mode: 0644]
include/asm-m32r/local.h [new file with mode: 0644]
include/asm-m32r/m32102.h [new file with mode: 0644]
include/asm-m32r/m32102peri.h [new file with mode: 0644]
include/asm-m32r/m32700ut/m32700ut_lan.h [new file with mode: 0644]
include/asm-m32r/m32700ut/m32700ut_lcd.h [new file with mode: 0644]
include/asm-m32r/m32700ut/m32700ut_pld.h [new file with mode: 0644]
include/asm-m32r/m32r.h [new file with mode: 0644]
include/asm-m32r/m32r_mp_fpga.h [new file with mode: 0644]
include/asm-m32r/mappi2/mappi2_pld.h [new file with mode: 0644]
include/asm-m32r/mc146818rtc.h [new file with mode: 0644]
include/asm-m32r/mman.h [new file with mode: 0644]
include/asm-m32r/mmu.h [new file with mode: 0644]
include/asm-m32r/mmu_context.h [new file with mode: 0644]
include/asm-m32r/mmzone.h [new file with mode: 0644]
include/asm-m32r/module.h [new file with mode: 0644]
include/asm-m32r/msgbuf.h [new file with mode: 0644]
include/asm-m32r/namei.h [new file with mode: 0644]
include/asm-m32r/numnodes.h [new file with mode: 0644]
include/asm-m32r/opsput/opsput_lan.h [new file with mode: 0644]
include/asm-m32r/opsput/opsput_lcd.h [new file with mode: 0644]
include/asm-m32r/opsput/opsput_pld.h [new file with mode: 0644]
include/asm-m32r/page.h [new file with mode: 0644]
include/asm-m32r/param.h [new file with mode: 0644]
include/asm-m32r/pci.h [new file with mode: 0644]
include/asm-m32r/percpu.h [new file with mode: 0644]
include/asm-m32r/pgalloc.h [new file with mode: 0644]
include/asm-m32r/pgtable-2level.h [new file with mode: 0644]
include/asm-m32r/pgtable.h [new file with mode: 0644]
include/asm-m32r/poll.h [new file with mode: 0644]
include/asm-m32r/posix_types.h [new file with mode: 0644]
include/asm-m32r/processor.h [new file with mode: 0644]
include/asm-m32r/ptrace.h [new file with mode: 0644]
include/asm-m32r/resource.h [new file with mode: 0644]
include/asm-m32r/rtc.h [new file with mode: 0644]
include/asm-m32r/scatterlist.h [new file with mode: 0644]
include/asm-m32r/sections.h [new file with mode: 0644]
include/asm-m32r/segment.h [new file with mode: 0644]
include/asm-m32r/semaphore.h [new file with mode: 0644]
include/asm-m32r/sembuf.h [new file with mode: 0644]
include/asm-m32r/serial.h [new file with mode: 0644]
include/asm-m32r/setup.h [new file with mode: 0644]
include/asm-m32r/shmbuf.h [new file with mode: 0644]
include/asm-m32r/shmparam.h [new file with mode: 0644]
include/asm-m32r/sigcontext.h [new file with mode: 0644]
include/asm-m32r/siginfo.h [new file with mode: 0644]
include/asm-m32r/signal.h [new file with mode: 0644]
include/asm-m32r/smp.h [new file with mode: 0644]
include/asm-m32r/socket.h [new file with mode: 0644]
include/asm-m32r/sockios.h [new file with mode: 0644]
include/asm-m32r/spinlock.h [new file with mode: 0644]
include/asm-m32r/stat.h [new file with mode: 0644]
include/asm-m32r/statfs.h [new file with mode: 0644]
include/asm-m32r/string.h [new file with mode: 0644]
include/asm-m32r/syscall.h [new file with mode: 0644]
include/asm-m32r/system.h [new file with mode: 0644]
include/asm-m32r/termbits.h [new file with mode: 0644]
include/asm-m32r/termios.h [new file with mode: 0644]
include/asm-m32r/thread_info.h [new file with mode: 0644]
include/asm-m32r/timex.h [new file with mode: 0644]
include/asm-m32r/tlb.h [new file with mode: 0644]
include/asm-m32r/tlbflush.h [new file with mode: 0644]
include/asm-m32r/topology.h [new file with mode: 0644]
include/asm-m32r/types.h [new file with mode: 0644]
include/asm-m32r/uaccess.h [new file with mode: 0644]
include/asm-m32r/ucontext.h [new file with mode: 0644]
include/asm-m32r/unaligned.h [new file with mode: 0644]
include/asm-m32r/unistd.h [new file with mode: 0644]
include/asm-m32r/user.h [new file with mode: 0644]
include/asm-m32r/vga.h [new file with mode: 0644]
include/asm-m32r/xor.h [new file with mode: 0644]
include/asm-m68k/hp300hw.h [new file with mode: 0644]
include/asm-m68knommu/m527xsim.h [new file with mode: 0644]
include/asm-m68knommu/m528xsim.h [new file with mode: 0644]
include/asm-mips/compiler.h [new file with mode: 0644]
include/asm-mips/cpu-info.h [new file with mode: 0644]
include/asm-mips/dec/serial.h [new file with mode: 0644]
include/asm-mips/interrupt.h [new file with mode: 0644]
include/asm-mips/mach-ip22/spaces.h [new file with mode: 0644]
include/asm-mips/mach-ip32/spaces.h [new file with mode: 0644]
include/asm-mips/mach-mips/cpu-feature-overrides.h [new file with mode: 0644]
include/asm-mips/mach-ocelot3/cpu-feature-overrides.h [new file with mode: 0644]
include/asm-mips/mach-sibyte/cpu-feature-overrides.h [new file with mode: 0644]
include/asm-mips/msc01_ic.h [new file with mode: 0644]
include/asm-mips/tx4927/smsc_fdc37m81x.h [new file with mode: 0644]
include/asm-ppc/8253pit.h [new file with mode: 0644]
include/asm-ppc/xparameters.h [new file with mode: 0644]
include/asm-ppc64/8253pit.h [new file with mode: 0644]
include/asm-ppc64/plpar_wrappers.h [new file with mode: 0644]
include/asm-ppc64/sstep.h [new file with mode: 0644]
include/asm-sh/edosk7705/io.h [new file with mode: 0644]
include/asm-sh/irq-sh73180.h [new file with mode: 0644]
include/asm-sh/microdev/io.h [new file with mode: 0644]
include/asm-sh/microdev/irq.h [new file with mode: 0644]
include/asm-sh/se73180/io.h [new file with mode: 0644]
include/asm-sh/se73180/se73180.h [new file with mode: 0644]
include/asm-sh/sh03/io.h [new file with mode: 0644]
include/asm-sh/sh03/sh03.h [new file with mode: 0644]
include/asm-sparc64/kprobes.h [new file with mode: 0644]
include/asm-um/module-i386.h [new file with mode: 0644]
include/asm-x86_64/genapic.h [new file with mode: 0644]
include/asm-x86_64/ipi.h [new file with mode: 0644]
include/asm-x86_64/kprobes.h [new file with mode: 0644]
include/asm-x86_64/mach_apic.h [new file with mode: 0644]
include/asm-x86_64/swiotlb.h [new file with mode: 0644]
include/linux/ckrm_events.h [new file with mode: 0644]
include/linux/gen_stats.h [new file with mode: 0644]
include/linux/hardirq.h [new file with mode: 0644]
include/linux/i2c-algo-pca.h [new file with mode: 0644]
include/linux/key-ui.h [new file with mode: 0644]
include/linux/key.h [new file with mode: 0644]
include/linux/keyctl.h [new file with mode: 0644]
include/linux/kfifo.h [new file with mode: 0644]
include/linux/kobject_uevent.h [new file with mode: 0644]
include/linux/kprobes.h [new file with mode: 0644]
include/linux/mmc/card.h [new file with mode: 0644]
include/linux/mmc/host.h [new file with mode: 0644]
include/linux/mmc/mmc.h [new file with mode: 0644]
include/linux/mmc/protocol.h [new file with mode: 0644]
include/linux/mmtimer.h [new file with mode: 0644]
include/linux/mv643xx.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ip_conntrack_sctp.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_CLUSTERIP.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_CONNMARK.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_comment.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_connmark.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_hashlimit.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_sctp.h [new file with mode: 0644]
include/linux/netfilter_ipv6/ip6t_physdev.h [new file with mode: 0644]
include/linux/nfs4_acl.h [new file with mode: 0644]
include/linux/nodemask.h [new file with mode: 0644]
include/linux/pci-acpi.h [new file with mode: 0644]
include/linux/pktcdvd.h [new file with mode: 0644]
include/linux/raid/raid10.h [new file with mode: 0644]
include/linux/ramfs.h [new file with mode: 0644]
include/linux/rslib.h [new file with mode: 0644]
include/linux/scatterlist.h [new file with mode: 0644]
include/linux/serial_8250.h [new file with mode: 0644]
include/linux/sunrpc/gss_spkm3.h [new file with mode: 0644]
include/linux/tc_act/tc_gact.h [new file with mode: 0644]
include/linux/tc_act/tc_ipt.h [new file with mode: 0644]
include/linux/tc_act/tc_mirred.h [new file with mode: 0644]
include/linux/tc_act/tc_pedit.h [new file with mode: 0644]
include/linux/usb_otg.h [new file with mode: 0644]
include/linux/usb_sl811.h [new file with mode: 0644]
include/linux/via.h [new file with mode: 0644]
include/media/video-buf-dvb.h [new file with mode: 0644]
include/net/act_api.h [new file with mode: 0644]
include/net/gen_stats.h [new file with mode: 0644]
include/net/sch_generic.h [new file with mode: 0644]
include/net/tc_act/tc_gact.h [new file with mode: 0644]
include/net/tc_act/tc_ipt.h [new file with mode: 0644]
include/net/tc_act/tc_mirred.h [new file with mode: 0644]
include/net/tc_act/tc_pedit.h [new file with mode: 0644]
include/net/x25device.h [new file with mode: 0644]
include/sound/pcm-indirect.h [new file with mode: 0644]
include/video/epson1355.h [new file with mode: 0644]
kernel/ckrm/ckrm_events.c [new file with mode: 0644]
kernel/irq/Makefile [new file with mode: 0644]
kernel/irq/autoprobe.c [new file with mode: 0644]
kernel/irq/handle.c [new file with mode: 0644]
kernel/irq/internals.h [new file with mode: 0644]
kernel/irq/manage.c [new file with mode: 0644]
kernel/irq/proc.c [new file with mode: 0644]
kernel/irq/spurious.c [new file with mode: 0644]
kernel/kfifo.c [new file with mode: 0644]
kernel/kprobes.c [new file with mode: 0644]
kernel/ksysfs.c [new file with mode: 0644]
kernel/spinlock.c [new file with mode: 0644]
kernel/sys_ni.c [new file with mode: 0644]
kernel/wait.c [new file with mode: 0644]
lib/Kconfig.debug [new file with mode: 0644]
lib/iomap.c [new file with mode: 0644]
lib/kernel_lock.c [new file with mode: 0644]
lib/kobject_uevent.c [new file with mode: 0644]
lib/reed_solomon/Makefile [new file with mode: 0644]
lib/reed_solomon/decode_rs.c [new file with mode: 0644]
lib/reed_solomon/encode_rs.c [new file with mode: 0644]
lib/reed_solomon/reed_solomon.c [new file with mode: 0644]
lib/zlib_inflate/inflate_sync.c [new file with mode: 0644]
mm/thrash.c [new file with mode: 0644]
mm/tiny-shmem.c [new file with mode: 0644]
net/appletalk/dev.c [new file with mode: 0644]
net/core/gen_estimator.c [new file with mode: 0644]
net/core/gen_stats.c [new file with mode: 0644]
net/ipv4/fib_lookup.h [new file with mode: 0644]
net/ipv4/netfilter/ip_conntrack_proto_sctp.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_CLUSTERIP.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_CONNMARK.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_comment.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_connmark.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_hashlimit.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_sctp.c [new file with mode: 0644]
net/ipv6/netfilter/ip6t_physdev.c [new file with mode: 0644]
net/sched/gact.c [new file with mode: 0644]
net/sched/ipt.c [new file with mode: 0644]
net/sched/mirred.c [new file with mode: 0644]
net/sched/pedit.c [new file with mode: 0644]
net/sunrpc/auth_gss/gss_spkm3_mech.c [new file with mode: 0644]
net/sunrpc/auth_gss/gss_spkm3_seal.c [new file with mode: 0644]
net/sunrpc/auth_gss/gss_spkm3_token.c [new file with mode: 0644]
net/sunrpc/auth_gss/gss_spkm3_unseal.c [new file with mode: 0644]
scripts/Makefile.host [new file with mode: 0644]
scripts/gen_initramfs_list.sh [new file with mode: 0644]
scripts/mksysmap [new file with mode: 0644]
scripts/namespace.pl [new file with mode: 0644]
security/keys/Makefile [new file with mode: 0644]
security/keys/compat.c [new file with mode: 0644]
security/keys/internal.h [new file with mode: 0644]
security/keys/key.c [new file with mode: 0644]
security/keys/keyctl.c [new file with mode: 0644]
security/keys/keyring.c [new file with mode: 0644]
security/keys/proc.c [new file with mode: 0644]
security/keys/process_keys.c [new file with mode: 0644]
security/keys/request_key.c [new file with mode: 0644]
security/keys/user_defined.c [new file with mode: 0644]
security/seclvl.c [new file with mode: 0644]
sound/pci/atiixp_modem.c [new file with mode: 0644]
sound/pci/ice1712/pontis.c [new file with mode: 0644]
sound/pci/ice1712/pontis.h [new file with mode: 0644]
sound/pci/ice1712/prodigy192.c [new file with mode: 0644]
sound/pci/ice1712/prodigy192.h [new file with mode: 0644]
sound/pci/ice1712/stac946x.h [new file with mode: 0644]
sound/pci/ice1712/vt1720_mobo.c [new file with mode: 0644]
sound/pci/ice1712/vt1720_mobo.h [new file with mode: 0644]
sound/ppc/beep.c [new file with mode: 0644]
sound/usb/usx2y/Makefile [new file with mode: 0644]
sound/usb/usx2y/usX2Yhwdep.c [new file with mode: 0644]
sound/usb/usx2y/usX2Yhwdep.h [new file with mode: 0644]
sound/usb/usx2y/usbus428ctldefs.h [new file with mode: 0644]
sound/usb/usx2y/usbusx2y.c [new file with mode: 0644]
sound/usb/usx2y/usbusx2y.h [new file with mode: 0644]
sound/usb/usx2y/usbusx2yaudio.c [new file with mode: 0644]
sound/usb/usx2y/usx2y.h [new file with mode: 0644]

diff --git a/Documentation/DocBook/librs.tmpl b/Documentation/DocBook/librs.tmpl
new file mode 100644 (file)
index 0000000..be482c0
--- /dev/null
@@ -0,0 +1,287 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="Reed-Solomon-Library-Guide">
+ <bookinfo>
+  <title>Reed-Solomon Library Programming Interface</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Thomas</firstname>
+    <surname>Gleixner</surname>
+    <affiliation>
+     <address>
+      <email>tglx@linutronix.de</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2004</year>
+   <holder>Thomas Gleixner</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+      <title>Introduction</title>
+  <para>
+       The generic Reed-Solomon Library provides encoding, decoding
+       and error correction functions.
+  </para>
+  <para>
+       Reed-Solomon codes are used in communication and storage
+       applications to ensure data integrity. 
+  </para>
+  <para>
+       This documentation is provided for developers who want to utilize
+       the functions provided by the library.
+  </para>
+  </chapter>
+  
+  <chapter id="bugs">
+     <title>Known Bugs And Assumptions</title>
+  <para>
+       None.   
+  </para>
+  </chapter>
+
+  <chapter id="usage">
+       <title>Usage</title>
+       <para>
+               This chapter provides examples how to use the library.
+       </para>
+       <sect1>
+               <title>Initializing</title>
+               <para>
+                       The init function init_rs returns a pointer to a
+                       rs decoder structure, which holds the necessary
+                       information for encoding, decoding and error correction
+                       with the given polynomial. It either uses an existing
+                       matching decoder or creates a new one. On creation all
+                       the lookup tables for fast en/decoding are created.
+                       The function may take a while, so make sure not to 
+                       call it in critical code paths.
+               </para>
+               <programlisting>
+/* the Reed Solomon control structure */
+static struct rs_control *rs_decoder;
+
+/* Symbolsize is 10 (bits)
+ * Primitve polynomial is x^10+x^3+1
+ * first consecutive root is 0
+ * primitve element to generate roots = 1
+ * generator polinomial degree (number of roots) = 6
+ */
+rs_decoder = init_rs (10, 0x409, 0, 1, 6);
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Encoding</title>
+               <para>
+                       The encoder calculates the Reed-Solomon code over
+                       the given data length and stores the result in 
+                       the parity buffer. Note that the parity buffer must
+                       be initialized before calling the encoder.
+               </para>
+               <para>
+                       The expanded data can be inverted on the fly by
+                       providing a non zero inversion mask. The expanded data is
+                       XOR'ed with the mask. This is used e.g. for FLASH
+                       ECC, where the all 0xFF is inverted to an all 0x00.
+                       The Reed-Solomon code for all 0x00 is all 0x00. The
+                       code is inverted before storing to FLASH so it is 0xFF
+                       too. This prevent's that reading from an erased FLASH
+                       results in ECC errors.
+               </para>
+               <para>
+                       The databytes are expanded to the given symbol size
+                       on the fly. There is no support for encoding continuous
+                       bitstreams with a symbol size != 8 at the moment. If
+                       it is necessary it should be not a big deal to implement
+                       such functionality.
+               </para>
+               <programlisting>
+/* Parity buffer. Size = number of roots */
+uint16_t par[6];
+/* Initialize the parity buffer */
+memset(par, 0, sizeof(par));
+/* Encode 512 byte in data8. Store parity in buffer par */
+encode_rs8 (rs_decoder, data8, 512, par, 0);
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Decoding</title>
+               <para>
+                       The decoder calculates the syndrome over
+                       the given data length and the received parity symbols
+                       and corrects errors in the data.
+               </para>
+               <para>
+                       If a syndrome is available from a hardware decoder
+                       then the syndrome calculation is skipped.
+               </para>
+               <para>
+                       The correction of the data buffer can be suppressed
+                       by providing a correction pattern buffer and an error
+                       location buffer to the decoder. The decoder stores the
+                       calculated error location and the correction bitmask
+                       in the given buffers. This is useful for hardware
+                       decoders which use a weird bit ordering scheme.
+               </para>
+               <para>
+                       The databytes are expanded to the given symbol size
+                       on the fly. There is no support for decoding continuous
+                       bitstreams with a symbolsize != 8 at the moment. If
+                       it is necessary it should be not a big deal to implement
+                       such functionality.
+               </para>
+               
+               <sect2>
+               <title>
+                       Decoding with syndrome calculation, direct data correction
+               </title>
+               <programlisting>
+/* Parity buffer. Size = number of roots */
+uint16_t par[6];
+uint8_t  data[512];
+int numerr;
+/* Receive data */
+.....
+/* Receive parity */
+.....
+/* Decode 512 byte in data8.*/
+numerr = decode_rs8 (rs_decoder, data8, par, 512, NULL, 0, NULL, 0, NULL);
+               </programlisting>
+               </sect2>
+
+               <sect2>
+               <title>
+                       Decoding with syndrome given by hardware decoder, direct data correction
+               </title>
+               <programlisting>
+/* Parity buffer. Size = number of roots */
+uint16_t par[6], syn[6];
+uint8_t  data[512];
+int numerr;
+/* Receive data */
+.....
+/* Receive parity */
+.....
+/* Get syndrome from hardware decoder */
+.....
+/* Decode 512 byte in data8.*/
+numerr = decode_rs8 (rs_decoder, data8, par, 512, syn, 0, NULL, 0, NULL);
+               </programlisting>
+               </sect2>
+
+               <sect2>
+               <title>
+                       Decoding with syndrome given by hardware decoder, no direct data correction.
+               </title>
+               <para>
+                       Note: It's not necessary to give data and received parity to the decoder.
+               </para>
+               <programlisting>
+/* Parity buffer. Size = number of roots */
+uint16_t par[6], syn[6], corr[8];
+uint8_t  data[512];
+int numerr, errpos[8];
+/* Receive data */
+.....
+/* Receive parity */
+.....
+/* Get syndrome from hardware decoder */
+.....
+/* Decode 512 byte in data8.*/
+numerr = decode_rs8 (rs_decoder, NULL, NULL, 512, syn, 0, errpos, 0, corr);
+for (i = 0; i < numerr; i++) {
+       do_error_correction_in_your_buffer(errpos[i], corr[i]);
+}
+               </programlisting>
+               </sect2>
+       </sect1>
+       <sect1>
+               <title>Cleanup</title>
+               <para>
+                       The function free_rs frees the allocated resources,
+                       if the caller is the last user of the decoder.
+               </para>
+               <programlisting>
+/* Release resources */
+free_rs(rs_decoder);
+               </programlisting>
+       </sect1>
+
+  </chapter>
+       
+  <chapter id="structs">
+     <title>Structures</title>
+     <para>
+     This chapter contains the autogenerated documentation of the structures which are
+     used in the Reed-Solomon Library and are relevant for a developer.
+     </para>
+!Iinclude/linux/rslib.h
+  </chapter>
+
+  <chapter id="pubfunctions">
+     <title>Public Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the Reed-Solomon functions
+     which are exported.
+     </para>
+!Elib/reed_solomon/reed_solomon.c
+  </chapter>
+  
+  <chapter id="credits">
+     <title>Credits</title>
+       <para>
+               The library code for encoding and decoding was written by Phil Karn.
+       </para>
+       <programlisting>
+               Copyright 2002, Phil Karn, KA9Q
+               May be used under the terms of the GNU General Public License (GPL)
+       </programlisting>
+       <para>
+               The wrapper functions and interfaces are written by Thomas Gleixner
+       </para>
+       <para>
+               Many users have provided bugfixes, improvements and helping hands for testing.
+               Thanks a lot.
+       </para>
+       <para>
+               The following people have contributed to this document:
+       </para>
+       <para>
+               Thomas Gleixner<email>tglx@linutronix.de</email>
+       </para>
+  </chapter>
+</book>
diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl
new file mode 100644 (file)
index 0000000..435bb52
--- /dev/null
@@ -0,0 +1,1318 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="MTD-NAND-Guide">
+ <bookinfo>
+  <title>MTD NAND Driver Programming Interface</title>
+  
+  <authorgroup>
+   <author>
+    <firstname>Thomas</firstname>
+    <surname>Gleixner</surname>
+    <affiliation>
+     <address>
+      <email>tglx@linutronix.de</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2004</year>
+   <holder>Thomas Gleixner</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+      <title>Introduction</title>
+  <para>
+       The generic NAND driver supports almost all NAND and AG-AND based
+       chips and connects them to the Memory Technology Devices (MTD)
+       subsystem of the Linux Kernel.
+  </para>
+  <para>
+       This documentation is provided for developers who want to implement
+       board drivers or filesystem drivers suitable for NAND devices.
+  </para>
+  </chapter>
+  
+  <chapter id="bugs">
+     <title>Known Bugs And Assumptions</title>
+  <para>
+       None.   
+  </para>
+  </chapter>
+
+  <chapter id="dochints">
+     <title>Documentation hints</title>
+     <para>
+     The function and structure docs are autogenerated. Each function and 
+     struct member has a short description which is marked with an [XXX] identifier.
+     The following chapters explain the meaning of those identifiers.
+     </para>
+     <sect1>   
+       <title>Function identifiers [XXX]</title>
+       <para>
+       The functions are marked with [XXX] identifiers in the short
+       comment. The identifiers explain the usage and scope of the
+       functions. Following identifiers are used:
+       </para>
+       <itemizedlist>
+               <listitem><para>
+               [MTD Interface]</para><para>
+               These functions provide the interface to the MTD kernel API. 
+               They are not replacable and provide functionality
+               which is complete hardware independent.
+               </para></listitem>
+               <listitem><para>
+               [NAND Interface]</para><para>
+               These functions are exported and provide the interface to the NAND kernel API. 
+               </para></listitem>
+               <listitem><para>
+               [GENERIC]</para><para>
+               Generic functions are not replacable and provide functionality
+               which is complete hardware independent.
+               </para></listitem>
+               <listitem><para>
+               [DEFAULT]</para><para>
+               Default functions provide hardware related functionality which is suitable
+               for most of the implementations. These functions can be replaced by the
+               board driver if neccecary. Those functions are called via pointers in the
+               NAND chip description structure. The board driver can set the functions which
+               should be replaced by board dependend functions before calling nand_scan().
+               If the function pointer is NULL on entry to nand_scan() then the pointer
+               is set to the default function which is suitable for the detected chip type.
+               </para></listitem>
+       </itemizedlist>
+     </sect1>
+     <sect1>   
+       <title>Struct member identifiers [XXX]</title>
+       <para>
+       The struct members are marked with [XXX] identifiers in the 
+       comment. The identifiers explain the usage and scope of the
+       members. Following identifiers are used:
+       </para>
+       <itemizedlist>
+               <listitem><para>
+               [INTERN]</para><para>
+               These members are for NAND driver internal use only and must not be
+               modified. Most of these values are calculated from the chip geometry
+               information which is evaluated during nand_scan().
+               </para></listitem>
+               <listitem><para>
+               [REPLACEABLE]</para><para>
+               Replaceable members hold hardware related functions which can be 
+               provided by the board driver. The board driver can set the functions which
+               should be replaced by board dependend functions before calling nand_scan().
+               If the function pointer is NULL on entry to nand_scan() then the pointer
+               is set to the default function which is suitable for the detected chip type.
+               </para></listitem>
+               <listitem><para>
+               [BOARDSPECIFIC]</para><para>
+               Board specific members hold hardware related information which must
+               be provided by the board driver. The board driver must set the function
+               pointers and datafields before calling nand_scan().
+               </para></listitem>
+               <listitem><para>
+               [OPTIONAL]</para><para>
+               Optional members can hold information relevant for the board driver. The
+               generic NAND driver code does not use this information.
+               </para></listitem>
+       </itemizedlist>
+     </sect1>
+  </chapter>   
+
+  <chapter id="basicboarddriver">
+       <title>Basic board driver</title>
+       <para>
+               For most boards it will be sufficient to provide just the
+               basic functions and fill out some really board dependend
+               members in the nand chip description structure.
+               See drivers/mtd/nand/skeleton for reference.
+       </para>
+       <sect1>
+               <title>Basic defines</title>
+               <para>
+                       At least you have to provide a mtd structure and
+                       a storage for the ioremap'ed chip address.
+                       You can allocate the mtd structure using kmalloc
+                       or you can allocate it statically.
+                       In case of static allocation you have to allocate
+                       a nand_chip structure too.
+               </para>
+               <para>
+                       Kmalloc based example
+               </para>
+               <programlisting>
+static struct mtd_info *board_mtd;
+static unsigned long baseaddr;
+               </programlisting>
+               <para>
+                       Static example
+               </para>
+               <programlisting>
+static struct mtd_info board_mtd;
+static struct nand_chip board_chip;
+static unsigned long baseaddr;
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Partition defines</title>
+               <para>
+                       If you want to divide your device into parititions, then
+                       enable the configuration switch CONFIG_MTD_PARITIONS and define
+                       a paritioning scheme suitable to your board.
+               </para>
+               <programlisting>
+#define NUM_PARTITIONS 2
+static struct mtd_partition partition_info[] = {
+       { .name = "Flash partition 1",
+         .offset =  0,
+         .size =    8 * 1024 * 1024 },
+       { .name = "Flash partition 2",
+         .offset =  MTDPART_OFS_NEXT,
+         .size =    MTDPART_SIZ_FULL },
+};
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Hardware control function</title>
+               <para>
+                       The hardware control function provides access to the 
+                       control pins of the NAND chip(s). 
+                       The access can be done by GPIO pins or by address lines.
+                       If you use address lines, make sure that the timing
+                       requirements are met.
+               </para>
+               <para>
+                       <emphasis>GPIO based example</emphasis>
+               </para>
+               <programlisting>
+static void board_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+       switch(cmd){
+               case NAND_CTL_SETCLE: /* Set CLE pin high */ break;
+               case NAND_CTL_CLRCLE: /* Set CLE pin low */ break;
+               case NAND_CTL_SETALE: /* Set ALE pin high */ break;
+               case NAND_CTL_CLRALE: /* Set ALE pin low */ break;
+               case NAND_CTL_SETNCE: /* Set nCE pin low */ break;
+               case NAND_CTL_CLRNCE: /* Set nCE pin high */ break;
+       }
+}
+               </programlisting>
+               <para>
+                       <emphasis>Address lines based example.</emphasis> It's assumed that the
+                       nCE pin is driven by a chip select decoder.
+               </para>
+               <programlisting>
+static void board_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+       struct nand_chip *this = (struct nand_chip *) mtd->priv;
+       switch(cmd){
+               case NAND_CTL_SETCLE: this->IO_ADDR_W |= CLE_ADRR_BIT;  break;
+               case NAND_CTL_CLRCLE: this->IO_ADDR_W &= ~CLE_ADRR_BIT; break;
+               case NAND_CTL_SETALE: this->IO_ADDR_W |= ALE_ADRR_BIT;  break;
+               case NAND_CTL_CLRALE: this->IO_ADDR_W &= ~ALE_ADRR_BIT; break;
+       }
+}
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Device ready function</title>
+               <para>
+                       If the hardware interface has the ready busy pin of the NAND chip connected to a
+                       GPIO or other accesible I/O pin, this function is used to read back the state of the
+                       pin. The function has no arguments and should return 0, if the device is busy (R/B pin 
+                       is low) and 1, if the device is ready (R/B pin is high).
+                       If the hardware interface does not give access to the ready busy pin, then
+                       the function must not be defined and the function pointer this->dev_ready is set to NULL.               
+               </para>
+       </sect1>
+       <sect1>
+               <title>Init function</title>
+               <para>
+                       The init function allocates memory and sets up all the board
+                       specific parameters and function pointers. When everything
+                       is set up nand_scan() is called. This function tries to
+                       detect and identify then chip. If a chip is found all the
+                       internal data fields are initialized accordingly.
+                       The structure(s) have to be zeroed out first and then filled with the neccecary 
+                       information about the device.
+               </para>
+               <programlisting>
+int __init board_init (void)
+{
+       struct nand_chip *this;
+       int err = 0;
+
+       /* Allocate memory for MTD device structure and private data */
+       board_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
+       if (!board_mtd) {
+               printk ("Unable to allocate NAND MTD device structure.\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Initialize structures */
+       memset ((char *) board_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip));
+
+       /* map physical adress */
+       baseaddr = (unsigned long)ioremap(CHIP_PHYSICAL_ADDRESS, 1024);
+       if(!baseaddr){
+               printk("Ioremap to access NAND chip failed\n");
+               err = -EIO;
+               goto out_mtd;
+       }
+
+       /* Get pointer to private data */
+       this = (struct nand_chip *) ();
+       /* Link the private data with the MTD structure */
+       board_mtd->priv = this;
+
+       /* Set address of NAND IO lines */
+       this->IO_ADDR_R = baseaddr;
+       this->IO_ADDR_W = baseaddr;
+       /* Reference hardware control function */
+       this->hwcontrol = board_hwcontrol;
+       /* Set command delay time, see datasheet for correct value */
+       this->chip_delay = CHIP_DEPENDEND_COMMAND_DELAY;
+       /* Assign the device ready function, if available */
+       this->dev_ready = board_dev_ready;
+       this->eccmode = NAND_ECC_SOFT;
+
+       /* Scan to find existance of the device */
+       if (nand_scan (board_mtd, 1)) {
+               err = -ENXIO;
+               goto out_ior;
+       }
+       
+       add_mtd_partitions(board_mtd, partition_info, NUM_PARTITIONS);
+       goto out;
+
+out_ior:
+       iounmap((void *)baseaddr);
+out_mtd:
+       kfree (board_mtd);
+out:
+       return err;
+}
+module_init(board_init);
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Exit function</title>
+               <para>
+                       The exit function is only neccecary if the driver is
+                       compiled as a module. It releases all resources which
+                       are held by the chip driver and unregisters the partitions
+                       in the MTD layer.
+               </para>
+               <programlisting>
+#ifdef MODULE
+static void __exit board_cleanup (void)
+{
+       /* Release resources, unregister device */
+       nand_release (board_mtd);
+
+       /* unmap physical adress */
+       iounmap((void *)baseaddr);
+       
+       /* Free the MTD device structure */
+       kfree (board_mtd);
+}
+module_exit(board_cleanup);
+#endif
+               </programlisting>
+       </sect1>
+  </chapter>
+
+  <chapter id="boarddriversadvanced">
+       <title>Advanced board driver functions</title>
+       <para>
+               This chapter describes the advanced functionality of the NAND
+               driver. For a list of functions which can be overridden by the board
+               driver see the documentation of the nand_chip structure.
+       </para>
+       <sect1>
+               <title>Multiple chip control</title>
+               <para>
+                       The nand driver can control chip arrays. Therefor the
+                       board driver must provide an own select_chip function. This
+                       function must (de)select the requested chip.
+                       The function pointer in the nand_chip structure must
+                       be set before calling nand_scan(). The maxchip parameter
+                       of nand_scan() defines the maximum number of chips to
+                       scan for. Make sure that the select_chip function can
+                       handle the requested number of chips.
+               </para>
+               <para>
+                       The nand driver concatenates the chips to one virtual
+                       chip and provides this virtual chip to the MTD layer.
+               </para>
+               <para>
+                       <emphasis>Note: The driver can only handle linear chip arrays
+                       of equally sized chips. There is no support for
+                       parallel arrays which extend the buswidth.</emphasis>
+               </para>
+               <para>
+                       <emphasis>GPIO based example</emphasis>
+               </para>
+               <programlisting>
+static void board_select_chip (struct mtd_info *mtd, int chip)
+{
+       /* Deselect all chips, set all nCE pins high */
+       GPIO(BOARD_NAND_NCE) |= 0xff;   
+       if (chip >= 0)
+               GPIO(BOARD_NAND_NCE) &= ~ (1 << chip);  
+}
+               </programlisting>
+               <para>
+                       <emphasis>Address lines based example.</emphasis>
+                       Its assumed that the nCE pins are connected to an
+                       address decoder.
+               </para>
+               <programlisting>
+static void board_select_chip (struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *this = (struct nand_chip *) mtd->priv;
+       
+       /* Deselect all chips */
+       this->IO_ADDR_R &= ~BOARD_NAND_ADDR_MASK;
+       this->IO_ADDR_W &= ~BOARD_NAND_ADDR_MASK;
+       switch (chip) {
+       case 0:
+               this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIP0;
+               this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIP0;
+               break;
+       ....    
+       case n:
+               this->IO_ADDR_R |= BOARD_NAND_ADDR_CHIPn;
+               this->IO_ADDR_W |= BOARD_NAND_ADDR_CHIPn;
+               break;
+       }       
+}
+               </programlisting>
+       </sect1>
+       <sect1>
+               <title>Hardware ECC support</title>
+               <sect2>
+                       <title>Functions and constants</title>
+                       <para>
+                               The nand driver supports three different types of
+                               hardware ECC.
+                               <itemizedlist>
+                               <listitem><para>NAND_ECC_HW3_256</para><para>
+                               Hardware ECC generator providing 3 bytes ECC per
+                               256 byte.
+                               </para> </listitem>
+                               <listitem><para>NAND_ECC_HW3_512</para><para>
+                               Hardware ECC generator providing 3 bytes ECC per
+                               512 byte.
+                               </para> </listitem>
+                               <listitem><para>NAND_ECC_HW6_512</para><para>
+                               Hardware ECC generator providing 6 bytes ECC per
+                               512 byte.
+                               </para> </listitem>
+                               <listitem><para>NAND_ECC_HW8_512</para><para>
+                               Hardware ECC generator providing 6 bytes ECC per
+                               512 byte.
+                               </para> </listitem>
+                               </itemizedlist>
+                               If your hardware generator has a different functionality
+                               add it at the appropriate place in nand_base.c
+                       </para>
+                       <para>
+                               The board driver must provide following functions:
+                               <itemizedlist>
+                               <listitem><para>enable_hwecc</para><para>
+                               This function is called before reading / writing to
+                               the chip. Reset or initialize the hardware generator
+                               in this function. The function is called with an
+                               argument which let you distinguish between read 
+                               and write operations.
+                               </para> </listitem>
+                               <listitem><para>calculate_ecc</para><para>
+                               This function is called after read / write from / to
+                               the chip. Transfer the ECC from the hardware to
+                               the buffer. If the option NAND_HWECC_SYNDROME is set
+                               then the function is only called on write. See below.
+                               </para> </listitem>
+                               <listitem><para>correct_data</para><para>
+                               In case of an ECC error this function is called for
+                               error detection and correction. Return 1 respectively 2
+                               in case the error can be corrected. If the error is
+                               not correctable return -1. If your hardware generator
+                               matches the default algorithm of the nand_ecc software
+                               generator then use the correction function provided
+                               by nand_ecc instead of implementing duplicated code.
+                               </para> </listitem>
+                               </itemizedlist>
+                       </para>
+               </sect2>
+               <sect2>
+               <title>Hardware ECC with syndrome calculation</title>
+                       <para>
+                               Many hardware ECC implementations provide Reed-Solomon
+                               codes and calculate an error syndrome on read. The syndrome
+                               must be converted to a standard Reed-Solomon syndrome
+                               before calling the error correction code in the generic
+                               Reed-Solomon library.
+                       </para>
+                       <para>
+                               The ECC bytes must be placed immidiately after the data
+                               bytes in order to make the syndrome generator work. This
+                               is contrary to the usual layout used by software ECC. The
+                               seperation of data and out of band area is not longer
+                               possible. The nand driver code handles this layout and
+                               the remaining free bytes in the oob area are managed by 
+                               the autoplacement code. Provide a matching oob-layout
+                               in this case. See rts_from4.c and diskonchip.c for 
+                               implementation reference. In those cases we must also
+                               use bad block tables on FLASH, because the ECC layout is
+                               interferring with the bad block marker positions.
+                               See bad block table support for details.
+                       </para>
+               </sect2>
+       </sect1>
+       <sect1>
+               <title>Bad block table support</title>
+               <para>
+                       Most NAND chips mark the bad blocks at a defined
+                       position in the spare area. Those blocks must 
+                       not be erased under any circumstances as the bad 
+                       block information would be lost.
+                       It is possible to check the bad block mark each
+                       time when the blocks are accessed by reading the
+                       spare area of the first page in the block. This
+                       is time consuming so a bad block table is used.
+               </para>
+               <para>
+                       The nand driver supports various types of bad block
+                       tables.
+                       <itemizedlist>
+                       <listitem><para>Per device</para><para>
+                       The bad block table contains all bad block information
+                       of the device which can consist of multiple chips.
+                       </para> </listitem>
+                       <listitem><para>Per chip</para><para>
+                       A bad block table is used per chip and contains the
+                       bad block information for this particular chip.
+                       </para> </listitem>
+                       <listitem><para>Fixed offset</para><para>
+                       The bad block table is located at a fixed offset
+                       in the chip (device). This applies to various
+                       DiskOnChip devices.
+                       </para> </listitem>
+                       <listitem><para>Automatic placed</para><para>
+                       The bad block table is automatically placed and
+                       detected either at the end or at the beginning
+                       of a chip (device)
+                       </para> </listitem>
+                       <listitem><para>Mirrored tables</para><para>
+                       The bad block table is mirrored on the chip (device) to
+                       allow updates of the bad block table without data loss.
+                       </para> </listitem>
+                       </itemizedlist>
+               </para>
+               <para>  
+                       nand_scan() calls the function nand_default_bbt(). 
+                       nand_default_bbt() selects appropriate default
+                       bad block table desriptors depending on the chip information
+                       which was retrieved by nand_scan().
+               </para>
+               <para>
+                       The standard policy is scanning the device for bad 
+                       blocks and build a ram based bad block table which
+                       allows faster access than always checking the
+                       bad block information on the flash chip itself.
+               </para>
+               <sect2>
+                       <title>Flash based tables</title>
+                       <para>
+                               It may be desired or neccecary to keep a bad block table in FLASH. 
+                               For AG-AND chips this is mandatory, as they have no factory marked
+                               bad blocks. They have factory marked good blocks. The marker pattern
+                               is erased when the block is erased to be reused. So in case of
+                               powerloss before writing the pattern back to the chip this block 
+                               would be lost and added to the bad blocks. Therefor we scan the 
+                               chip(s) when we detect them the first time for good blocks and 
+                               store this information in a bad block table before erasing any 
+                               of the blocks.
+                       </para>
+                       <para>
+                               The blocks in which the tables are stored are procteted against
+                               accidental access by marking them bad in the memory bad block
+                               table. The bad block table managment functions are allowed
+                               to circumvernt this protection.
+                       </para>
+                       <para>
+                               The simplest way to activate the FLASH based bad block table support 
+                               is to set the option NAND_USE_FLASH_BBT in the option field of
+                               the nand chip structure before calling nand_scan(). For AG-AND
+                               chips is this done by default.
+                               This activates the default FLASH based bad block table functionality 
+                               of the NAND driver. The default bad block table options are
+                               <itemizedlist>
+                               <listitem><para>Store bad block table per chip</para></listitem>
+                               <listitem><para>Use 2 bits per block</para></listitem>
+                               <listitem><para>Automatic placement at the end of the chip</para></listitem>
+                               <listitem><para>Use mirrored tables with version numbers</para></listitem>
+                               <listitem><para>Reserve 4 blocks at the end of the chip</para></listitem>
+                               </itemizedlist>
+                       </para>
+               </sect2>
+               <sect2>
+                       <title>User defined tables</title>
+                       <para>
+                               User defined tables are created by filling out a 
+                               nand_bbt_descr structure and storing the pointer in the
+                               nand_chip structure member bbt_td before calling nand_scan(). 
+                               If a mirror table is neccecary a second structure must be
+                               created and a pointer to this structure must be stored
+                               in bbt_md inside the nand_chip structure. If the bbt_md 
+                               member is set to NULL then only the main table is used
+                               and no scan for the mirrored table is performed.
+                       </para>
+                       <para>
+                               The most important field in the nand_bbt_descr structure
+                               is the options field. The options define most of the 
+                               table properties. Use the predefined constants from
+                               nand.h to define the options.
+                               <itemizedlist>
+                               <listitem><para>Number of bits per block</para>
+                               <para>The supported number of bits is 1, 2, 4, 8.</para></listitem>
+                               <listitem><para>Table per chip</para>
+                               <para>Setting the constant NAND_BBT_PERCHIP selects that
+                               a bad block table is managed for each chip in a chip array.
+                               If this option is not set then a per device bad block table
+                               is used.</para></listitem>
+                               <listitem><para>Table location is absolute</para>
+                               <para>Use the option constant NAND_BBT_ABSPAGE and
+                               define the absolute page number where the bad block
+                               table starts in the field pages. If you have selected bad block
+                               tables per chip and you have a multi chip array then the start page
+                               must be given for each chip in the chip array. Note: there is no scan
+                               for a table ident pattern performed, so the fields 
+                               pattern, veroffs, offs, len can be left uninitialized</para></listitem>
+                               <listitem><para>Table location is automatically detected</para>
+                               <para>The table can either be located in the first or the last good
+                               blocks of the chip (device). Set NAND_BBT_LASTBLOCK to place
+                               the bad block table at the end of the chip (device). The
+                               bad block tables are marked and identified by a pattern which
+                               is stored in the spare area of the first page in the block which
+                               holds the bad block table. Store a pointer to the pattern  
+                               in the pattern field. Further the length of the pattern has to be 
+                               stored in len and the offset in the spare area must be given
+                               in the offs member of the nand_bbt_descr stucture. For mirrored
+                               bad block tables different patterns are mandatory.</para></listitem>
+                               <listitem><para>Table creation</para>
+                               <para>Set the option NAND_BBT_CREATE to enable the table creation
+                               if no table can be found during the scan. Usually this is done only 
+                               once if a new chip is found. </para></listitem>
+                               <listitem><para>Table write support</para>
+                               <para>Set the option NAND_BBT_WRITE to enable the table write support.
+                               This allows the update of the bad block table(s) in case a block has
+                               to be marked bad due to wear. The MTD interface function block_markbad
+                               is calling the update function of the bad block table. If the write
+                               support is enabled then the table is updated on FLASH.</para>
+                               <para>
+                               Note: Write support should only be enabled for mirrored tables with
+                               version control.
+                               </para></listitem>
+                               <listitem><para>Table version control</para>
+                               <para>Set the option NAND_BBT_VERSION to enable the table version control.
+                               It's highly recommended to enable this for mirrored tables with write
+                               support. It makes sure that the risk of loosing the bad block
+                               table information is reduced to the loss of the information about the
+                               one worn out block which should be marked bad. The version is stored in
+                               4 consecutive bytes in the spare area of the device. The position of
+                               the version number is defined by the member veroffs in the bad block table
+                               descriptor.</para></listitem>
+                               <listitem><para>Save block contents on write</para>
+                               <para>
+                               In case that the block which holds the bad block table does contain
+                               other useful information, set the option NAND_BBT_SAVECONTENT. When
+                               the bad block table is written then the whole block is read the bad
+                               block table is updated and the block is erased and everything is 
+                               written back. If this option is not set only the bad block table
+                               is written and everything else in the block is ignored and erased.
+                               </para></listitem>
+                               <listitem><para>Number of reserved blocks</para>
+                               <para>
+                               For automatic placement some blocks must be reserved for
+                               bad block table storage. The number of reserved blocks is defined 
+                               in the maxblocks member of the babd block table description structure.
+                               Reserving 4 blocks for mirrored tables should be a reasonable number. 
+                               This also limits the number of blocks which are scanned for the bad
+                               block table ident pattern.
+                               </para></listitem>
+                               </itemizedlist>
+                       </para>
+               </sect2>
+       </sect1>
+       <sect1>
+               <title>Spare area (auto)placement</title>
+               <para>
+                       The nand driver implements different possibilities for
+                       placement of filesystem data in the spare area, 
+                       <itemizedlist>
+                       <listitem><para>Placement defined by fs driver</para></listitem>
+                       <listitem><para>Automatic placement</para></listitem>
+                       </itemizedlist>
+                       The default placement function is automatic placement. The
+                       nand driver has built in default placement schemes for the
+                       various chiptypes. If due to hardware ECC functionality the
+                       default placement does not fit then the board driver can
+                       provide a own placement scheme.
+               </para>
+               <para>
+                       File system drivers can provide a own placement scheme which
+                       is used instead of the default placement scheme.
+               </para>
+               <para>
+                       Placement schemes are defined by a nand_oobinfo structure
+                       <programlisting>
+struct nand_oobinfo {
+       int     useecc;
+       int     eccbytes;
+       int     eccpos[24];
+       int     oobfree[8][2];
+};
+                       </programlisting>
+                       <itemizedlist>
+                       <listitem><para>useecc</para><para>
+                               The useecc member controls the ecc and placement function. The header
+                               file include/mtd/mtd-abi.h contains constants to select ecc and
+                               placement. MTD_NANDECC_OFF switches off the ecc complete. This is
+                               not recommended and available for testing and diagnosis only.
+                               MTD_NANDECC_PLACE selects caller defined placement, MTD_NANDECC_AUTOPLACE
+                               selects automatic placement.
+                       </para></listitem>
+                       <listitem><para>eccbytes</para><para>
+                               The eccbytes member defines the number of ecc bytes per page.
+                       </para></listitem>
+                       <listitem><para>eccpos</para><para>
+                               The eccpos array holds the byte offsets in the spare area where
+                               the ecc codes are placed.
+                       </para></listitem>
+                       <listitem><para>oobfree</para><para>
+                               The oobfree array defines the areas in the spare area which can be
+                               used for automatic placement. The information is given in the format
+                               {offset, size}. offset defines the start of the usable area, size the
+                               length in bytes. More than one area can be defined. The list is terminated
+                               by an {0, 0} entry.
+                       </para></listitem>
+                       </itemizedlist>
+               </para>
+               <sect2>
+                       <title>Placement defined by fs driver</title>
+                       <para>
+                               The calling function provides a pointer to a nand_oobinfo
+                               structure which defines the ecc placement. For writes the
+                               caller must provide a spare area buffer along with the
+                               data buffer. The spare area buffer size is (number of pages) *
+                               (size of spare area). For reads the buffer size is
+                               (number of pages) * ((size of spare area) + (number of ecc
+                               steps per page) * sizeof (int)). The driver stores the
+                               result of the ecc check for each tuple in the spare buffer.
+                               The storage sequence is 
+                       </para>
+                       <para>
+                               &lt;spare data page 0&gt;&lt;ecc result 0&gt;...&lt;ecc result n&gt;
+                       </para>
+                       <para>
+                               ...
+                       </para>
+                       <para>
+                               &lt;spare data page n&gt;&lt;ecc result 0&gt;...&lt;ecc result n&gt;
+                       </para>
+                       <para>
+                               This is a legacy mode used by YAFFS1.
+                       </para>
+                       <para>
+                               If the spare area buffer is NULL then only the ECC placement is
+                               done according to the given scheme in the nand_oobinfo structure.
+                       </para>
+               </sect2>
+               <sect2>
+                       <title>Automatic placement</title>
+                       <para>
+                               Automatic placement uses the built in defaults to place the
+                               ecc bytes in the spare area. If filesystem data have to be stored /
+                               read into the spare area then the calling function must provide a
+                               buffer. The buffer size per page is determined by the oobfree array in
+                               the nand_oobinfo structure.
+                       </para>
+                       <para>
+                               If the spare area buffer is NULL then only the ECC placement is
+                               done according to the default builtin scheme.
+                       </para>
+               </sect2>
+               <sect2>
+                       <title>User space placement selection</title>
+               <para>
+                       All non ecc functions like mtd->read and mtd->write use an internal 
+                       structure, which can be set by an ioctl. This structure is preset 
+                       to the autoplacement default.
+                       <programlisting>
+       ioctl (fd, MEMSETOOBSEL, oobsel);
+                       </programlisting>
+                       oobsel is a pointer to a user supplied structure of type
+                       nand_oobconfig. The contents of this structure must match the 
+                       criteria of the filesystem, which will be used. See an example in utils/nandwrite.c.
+               </para>
+               </sect2>
+       </sect1>        
+       <sect1>
+               <title>Spare area autoplacement default schemes</title>
+               <sect2>
+                       <title>256 byte pagesize</title>
+<informaltable><tgroup cols="3"><tbody>
+<row>
+<entry>Offset</entry>
+<entry>Content</entry>
+<entry>Comment</entry>
+</row>
+<row>
+<entry>0x00</entry>
+<entry>ECC byte 0</entry>
+<entry>Error correction code byte 0</entry>
+</row>
+<row>
+<entry>0x01</entry>
+<entry>ECC byte 1</entry>
+<entry>Error correction code byte 1</entry>
+</row>
+<row>
+<entry>0x02</entry>
+<entry>ECC byte 2</entry>
+<entry>Error correction code byte 2</entry>
+</row>
+<row>
+<entry>0x03</entry>
+<entry>Autoplace 0</entry>
+<entry></entry>
+</row>
+<row>
+<entry>0x04</entry>
+<entry>Autoplace 1</entry>
+<entry></entry>
+</row>
+<row>
+<entry>0x05</entry>
+<entry>Bad block marker</entry>
+<entry>If any bit in this byte is zero, then this block is bad.
+This applies only to the first page in a block. In the remaining
+pages this byte is reserved</entry>
+</row>
+<row>
+<entry>0x06</entry>
+<entry>Autoplace 2</entry>
+<entry></entry>
+</row>
+<row>
+<entry>0x07</entry>
+<entry>Autoplace 3</entry>
+<entry></entry>
+</row>
+</tbody></tgroup></informaltable>
+               </sect2>
+               <sect2>
+                       <title>512 byte pagesize</title>
+<informaltable><tgroup cols="3"><tbody>
+<row>
+<entry>Offset</entry>
+<entry>Content</entry>
+<entry>Comment</entry>
+</row>
+<row>
+<entry>0x00</entry>
+<entry>ECC byte 0</entry>
+<entry>Error correction code byte 0 of the lower 256 Byte data in
+this page</entry>
+</row>
+<row>
+<entry>0x01</entry>
+<entry>ECC byte 1</entry>
+<entry>Error correction code byte 1 of the lower 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x02</entry>
+<entry>ECC byte 2</entry>
+<entry>Error correction code byte 2 of the lower 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x03</entry>
+<entry>ECC byte 3</entry>
+<entry>Error correction code byte 0 of the upper 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x04</entry>
+<entry>reserved</entry>
+<entry>reserved</entry>
+</row>
+<row>
+<entry>0x05</entry>
+<entry>Bad block marker</entry>
+<entry>If any bit in this byte is zero, then this block is bad.
+This applies only to the first page in a block. In the remaining
+pages this byte is reserved</entry>
+</row>
+<row>
+<entry>0x06</entry>
+<entry>ECC byte 4</entry>
+<entry>Error correction code byte 1 of the upper 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x07</entry>
+<entry>ECC byte 5</entry>
+<entry>Error correction code byte 2 of the upper 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x08 - 0x0F</entry>
+<entry>Autoplace 0 - 7</entry>
+<entry></entry>
+</row>
+</tbody></tgroup></informaltable>
+               </sect2>
+               <sect2>
+                       <title>2048 byte pagesize</title>
+<informaltable><tgroup cols="3"><tbody>
+<row>
+<entry>Offset</entry>
+<entry>Content</entry>
+<entry>Comment</entry>
+</row>
+<row>
+<entry>0x00</entry>
+<entry>Bad block marker</entry>
+<entry>If any bit in this byte is zero, then this block is bad.
+This applies only to the first page in a block. In the remaining
+pages this byte is reserved</entry>
+</row>
+<row>
+<entry>0x01</entry>
+<entry>Reserved</entry>
+<entry>Reserved</entry>
+</row>
+<row>
+<entry>0x02-0x27</entry>
+<entry>Autoplace 0 - 37</entry>
+<entry></entry>
+</row>
+<row>
+<entry>0x28</entry>
+<entry>ECC byte 0</entry>
+<entry>Error correction code byte 0 of the first 256 Byte data in
+this page</entry>
+</row>
+<row>
+<entry>0x29</entry>
+<entry>ECC byte 1</entry>
+<entry>Error correction code byte 1 of the first 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x2A</entry>
+<entry>ECC byte 2</entry>
+<entry>Error correction code byte 2 of the first 256 Bytes data in
+this page</entry>
+</row>
+<row>
+<entry>0x2B</entry>
+<entry>ECC byte 3</entry>
+<entry>Error correction code byte 0 of the second 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x2C</entry>
+<entry>ECC byte 4</entry>
+<entry>Error correction code byte 1 of the second 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x2D</entry>
+<entry>ECC byte 5</entry>
+<entry>Error correction code byte 2 of the second 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x2E</entry>
+<entry>ECC byte 6</entry>
+<entry>Error correction code byte 0 of the third 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x2F</entry>
+<entry>ECC byte 7</entry>
+<entry>Error correction code byte 1 of the third 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x30</entry>
+<entry>ECC byte 8</entry>
+<entry>Error correction code byte 2 of the third 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x31</entry>
+<entry>ECC byte 9</entry>
+<entry>Error correction code byte 0 of the fourth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x32</entry>
+<entry>ECC byte 10</entry>
+<entry>Error correction code byte 1 of the fourth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x33</entry>
+<entry>ECC byte 11</entry>
+<entry>Error correction code byte 2 of the fourth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x34</entry>
+<entry>ECC byte 12</entry>
+<entry>Error correction code byte 0 of the fifth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x35</entry>
+<entry>ECC byte 13</entry>
+<entry>Error correction code byte 1 of the fifth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x36</entry>
+<entry>ECC byte 14</entry>
+<entry>Error correction code byte 2 of the fifth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x37</entry>
+<entry>ECC byte 15</entry>
+<entry>Error correction code byte 0 of the sixt 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x38</entry>
+<entry>ECC byte 16</entry>
+<entry>Error correction code byte 1 of the sixt 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x39</entry>
+<entry>ECC byte 17</entry>
+<entry>Error correction code byte 2 of the sixt 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x3A</entry>
+<entry>ECC byte 18</entry>
+<entry>Error correction code byte 0 of the seventh 256 Bytes of
+data in this page</entry>
+</row>
+<row>
+<entry>0x3B</entry>
+<entry>ECC byte 19</entry>
+<entry>Error correction code byte 1 of the seventh 256 Bytes of
+data in this page</entry>
+</row>
+<row>
+<entry>0x3C</entry>
+<entry>ECC byte 20</entry>
+<entry>Error correction code byte 2 of the seventh 256 Bytes of
+data in this page</entry>
+</row>
+<row>
+<entry>0x3D</entry>
+<entry>ECC byte 21</entry>
+<entry>Error correction code byte 0 of the eigth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x3E</entry>
+<entry>ECC byte 22</entry>
+<entry>Error correction code byte 1 of the eigth 256 Bytes of data
+in this page</entry>
+</row>
+<row>
+<entry>0x3F</entry>
+<entry>ECC byte 23</entry>
+<entry>Error correction code byte 2 of the eigth 256 Bytes of data
+in this page</entry>
+</row>
+</tbody></tgroup></informaltable>
+               </sect2>
+       </sect1>
+  </chapter>
+
+  <chapter id="filesystems">
+       <title>Filesystem support</title>
+       <para>
+               The NAND driver provides all neccecary functions for a
+               filesystem via the MTD interface.
+       </para>
+       <para>
+               Filesystems must be aware of the NAND pecularities and
+               restrictions. One major restrictions of NAND Flash is, that you cannot 
+               write as often as you want to a page. The consecutive writes to a page, 
+               before erasing it again, are restricted to 1-3 writes, depending on the 
+               manufacturers specifications. This applies similar to the spare area. 
+       </para>
+       <para>
+               Therefor NAND aware filesystems must either write in page size chunks
+               or hold a writebuffer to collect smaller writes until they sum up to 
+               pagesize. Available NAND aware filesystems: JFFS2, YAFFS.               
+       </para>
+       <para>
+               The spare area usage to store filesystem data is controlled by
+               the spare area placement functionality which is described in one
+               of the earlier chapters.
+       </para>
+  </chapter>   
+  <chapter id="tools">
+       <title>Tools</title>
+       <para>
+               The MTD project provides a couple of helpful tools to handle NAND Flash.
+               <itemizedlist>
+               <listitem><para>flasherase, flasheraseall: Erase and format FLASH partitions</para></listitem>
+               <listitem><para>nandwrite: write filesystem images to NAND FLASH</para></listitem>
+               <listitem><para>nanddump: dump the contents of a NAND FLASH partitions</para></listitem>
+               </itemizedlist>
+       </para>
+       <para>
+               These tools are aware of the NAND restrictions. Please use those tools
+               instead of complaining about errors which are caused by non NAND aware
+               access methods.
+       </para>
+  </chapter>   
+
+  <chapter id="defines">
+     <title>Constants</title>
+     <para>
+     This chapter describes the constants which might be relevant for a driver developer.
+     </para>
+     <sect1>   
+       <title>Chip option constants</title>
+       <sect2>   
+               <title>Constants for chip id table</title>
+               <para>
+               These constants are defined in nand.h. They are ored together to describe
+               the chip functionality.
+               <programlisting>
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR       0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16       0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING                0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG          0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK          0x00000010
+/* AND Chip which has 4 banks and a confusing page / block 
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND            0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY       0x00000040 
+               </programlisting>
+               </para>
+       </sect2>
+       <sect2>   
+               <title>Constants for runtime options</title>
+               <para>
+               These constants are defined in nand.h. They are ored together to describe
+               the functionality.
+               <programlisting>
+/* Use a flash based bad block table. This option is parsed by the
+ * default bad block table function (nand_default_bbt). */
+#define NAND_USE_FLASH_BBT     0x00010000
+/* The hw ecc generator provides a syndrome instead a ecc value on read 
+ * This can only work if we have the ecc bytes directly behind the 
+ * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
+#define NAND_HWECC_SYNDROME    0x00020000
+               </programlisting>
+               </para>
+       </sect2>
+     </sect1>  
+
+     <sect1>   
+       <title>ECC selection constants</title>
+       <para>
+       Use these constants to select the ECC algorithm.
+       <programlisting>
+/* No ECC. Usage is not recommended ! */
+#define NAND_ECC_NONE          0
+/* Software ECC 3 byte ECC per 256 Byte data */
+#define NAND_ECC_SOFT          1
+/* Hardware ECC 3 byte ECC per 256 Byte data */
+#define NAND_ECC_HW3_256       2
+/* Hardware ECC 3 byte ECC per 512 Byte data */
+#define NAND_ECC_HW3_512       3
+/* Hardware ECC 6 byte ECC per 512 Byte data */
+#define NAND_ECC_HW6_512       4
+/* Hardware ECC 6 byte ECC per 512 Byte data */
+#define NAND_ECC_HW8_512       6
+       </programlisting>
+       </para>
+     </sect1>  
+
+     <sect1>   
+       <title>Hardware control related constants</title>
+       <para>
+       These constants describe the requested hardware access function when
+       the boardspecific hardware control function is called
+       <programlisting>
+/* Select the chip by setting nCE to low */
+#define NAND_CTL_SETNCE        1
+/* Deselect the chip by setting nCE to high */
+#define NAND_CTL_CLRNCE                2
+/* Select the command latch by setting CLE to high */
+#define NAND_CTL_SETCLE                3
+/* Deselect the command latch by setting CLE to low */
+#define NAND_CTL_CLRCLE                4
+/* Select the address latch by setting ALE to high */
+#define NAND_CTL_SETALE                5
+/* Deselect the address latch by setting ALE to low */
+#define NAND_CTL_CLRALE                6
+/* Set write protection by setting WP to high. Not used! */
+#define NAND_CTL_SETWP         7
+/* Clear write protection by setting WP to low. Not used! */
+#define NAND_CTL_CLRWP         8
+       </programlisting>
+       </para>
+     </sect1>  
+
+     <sect1>   
+       <title>Bad block table related constants</title>
+       <para>
+       These constants describe the options used for bad block
+       table descriptors.
+       <programlisting>
+/* Options for the bad block table descriptors */
+
+/* The number of bits used per block in the bbt on the device */
+#define NAND_BBT_NRBITS_MSK    0x0000000F
+#define NAND_BBT_1BIT          0x00000001
+#define NAND_BBT_2BIT          0x00000002
+#define NAND_BBT_4BIT          0x00000004
+#define NAND_BBT_8BIT          0x00000008
+/* The bad block table is in the last good block of the device */
+#define        NAND_BBT_LASTBLOCK      0x00000010
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_ABSPAGE       0x00000020
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_SEARCH                0x00000040
+/* bbt is stored per chip on multichip devices */
+#define NAND_BBT_PERCHIP       0x00000080
+/* bbt has a version counter at offset veroffs */
+#define NAND_BBT_VERSION       0x00000100
+/* Create a bbt if none axists */
+#define NAND_BBT_CREATE                0x00000200
+/* Search good / bad pattern through all pages of a block */
+#define NAND_BBT_SCANALLPAGES  0x00000400
+/* Scan block empty during good / bad block scan */
+#define NAND_BBT_SCANEMPTY     0x00000800
+/* Write bbt if neccecary */
+#define NAND_BBT_WRITE         0x00001000
+/* Read and write back block contents when writing bbt */
+#define NAND_BBT_SAVECONTENT   0x00002000
+       </programlisting>
+       </para>
+     </sect1>  
+
+  </chapter>
+       
+  <chapter id="structs">
+     <title>Structures</title>
+     <para>
+     This chapter contains the autogenerated documentation of the structures which are
+     used in the NAND driver and might be relevant for a driver developer. Each  
+     struct member has a short description which is marked with an [XXX] identifier.
+     See the chapter "Documentation hints" for an explanation.
+     </para>
+!Iinclude/linux/mtd/nand.h
+  </chapter>
+
+  <chapter id="pubfunctions">
+     <title>Public Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the NAND kernel API functions
+      which are exported. Each function has a short description which is marked with an [XXX] identifier.
+     See the chapter "Documentation hints" for an explanation.
+     </para>
+!Edrivers/mtd/nand/nand_base.c
+!Edrivers/mtd/nand/nand_bbt.c
+!Edrivers/mtd/nand/nand_ecc.c
+  </chapter>
+  
+  <chapter id="intfunctions">
+     <title>Internal Functions Provided</title>
+     <para>
+     This chapter contains the autogenerated documentation of the NAND driver internal functions.
+     Each function has a short description which is marked with an [XXX] identifier.
+     See the chapter "Documentation hints" for an explanation.
+     The functions marked with [DEFAULT] might be relevant for a board driver developer.
+     </para>
+!Idrivers/mtd/nand/nand_base.c
+!Idrivers/mtd/nand/nand_bbt.c
+!Idrivers/mtd/nand/nand_ecc.c
+  </chapter>
+
+  <chapter id="credits">
+     <title>Credits</title>
+       <para>
+               The following people have contributed to the NAND driver:
+               <orderedlist>
+                       <listitem><para>Steven J. Hill<email>sjhill@realitydiluted.com</email></para></listitem>
+                       <listitem><para>David Woodhouse<email>dwmw2@infradead.org</email></para></listitem>
+                       <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
+               </orderedlist>
+               A lot of users have provided bugfixes, improvements and helping hands for testing.
+               Thanks a lot.
+       </para>
+       <para>
+               The following people have contributed to this document:
+               <orderedlist>
+                       <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem>
+               </orderedlist>
+       </para>
+  </chapter>
+</book>
diff --git a/Documentation/ManagementStyle b/Documentation/ManagementStyle
new file mode 100644 (file)
index 0000000..cbbebfb
--- /dev/null
@@ -0,0 +1,276 @@
+
+                Linux kernel management style
+
+This is a short document describing the preferred (or made up, depending
+on who you ask) management style for the linux kernel.  It's meant to
+mirror the CodingStyle document to some degree, and mainly written to
+avoid answering (*) the same (or similar) questions over and over again. 
+
+Management style is very personal and much harder to quantify than
+simple coding style rules, so this document may or may not have anything
+to do with reality.  It started as a lark, but that doesn't mean that it
+might not actually be true. You'll have to decide for yourself.
+
+Btw, when talking about "kernel manager", it's all about the technical
+lead persons, not the people who do traditional management inside
+companies.  If you sign purchase orders or you have any clue about the
+budget of your group, you're almost certainly not a kernel manager. 
+These suggestions may or may not apply to you. 
+
+First off, I'd suggest buying "Seven Habits of Highly Successful
+People", and NOT read it.  Burn it, it's a great symbolic gesture. 
+
+(*) This document does so not so much by answering the question, but by
+making it painfully obvious to the questioner that we don't have a clue
+to what the answer is. 
+
+Anyway, here goes:
+
+
+               Chapter 1: Decisions
+
+Everybody thinks managers make decisions, and that decision-making is
+important.  The bigger and more painful the decision, the bigger the
+manager must be to make it.  That's very deep and obvious, but it's not
+actually true. 
+
+The name of the game is to _avoid_ having to make a decision.  In
+particular, if somebody tells you "choose (a) or (b), we really need you
+to decide on this", you're in trouble as a manager.  The people you
+manage had better know the details better than you, so if they come to
+you for a technical decision, you're screwed.  You're clearly not
+competent to make that decision for them. 
+
+(Corollary:if the people you manage don't know the details better than
+you, you're also screwed, although for a totally different reason. 
+Namely that you are in the wrong job, and that _they_ should be managing
+your brilliance instead). 
+
+So the name of the game is to _avoid_ decisions, at least the big and
+painful ones.  Making small and non-consequential decisions is fine, and
+makes you look like you know what you're doing, so what a kernel manager
+needs to do is to turn the big and painful ones into small things where
+nobody really cares. 
+
+It helps to realize that the key difference between a big decision and a
+small one is whether you can fix your decision afterwards.  Any decision
+can be made small by just always making sure that if you were wrong (and
+you _will_ be wrong), you can always undo the damage later by
+backtracking.  Suddenly, you get to be doubly managerial for making
+_two_ inconsequential decisions - the wrong one _and_ the right one. 
+
+And people will even see that as true leadership (*cough* bullshit
+*cough*).
+
+Thus the key to avoiding big decisions becomes to just avoiding to do
+things that can't be undone.  Don't get ushered into a corner from which
+you cannot escape.  A cornered rat may be dangerous - a cornered manager
+is just pitiful. 
+
+It turns out that since nobody would be stupid enough to ever really let
+a kernel manager have huge fiscal responsibility _anyway_, it's usually
+fairly easy to backtrack.  Since you're not going to be able to waste
+huge amounts of money that you might not be able to repay, the only
+thing you can backtrack on is a technical decision, and there
+back-tracking is very easy: just tell everybody that you were an
+incompetent nincompoop, say you're sorry, and undo all the worthless
+work you had people work on for the last year.  Suddenly the decision
+you made a year ago wasn't a big decision after all, since it could be
+easily undone. 
+
+It turns out that some people have trouble with this approach, for two
+reasons:
+ - admitting you were an idiot is harder than it looks.  We all like to
+   maintain appearances, and coming out in public to say that you were
+   wrong is sometimes very hard indeed. 
+ - having somebody tell you that what you worked on for the last year
+   wasn't worthwhile after all can be hard on the poor lowly engineers
+   too, and while the actual _work_ was easy enough to undo by just
+   deleting it, you may have irrevocably lost the trust of that
+   engineer.  And remember: "irrevocable" was what we tried to avoid in
+   the first place, and your decision ended up being a big one after
+   all. 
+
+Happily, both of these reasons can be mitigated effectively by just
+admitting up-front that you don't have a friggin' clue, and telling
+people ahead of the fact that your decision is purely preliminary, and
+might be the wrong thing.  You should always reserve the right to change
+your mind, and make people very _aware_ of that.  And it's much easier
+to admit that you are stupid when you haven't _yet_ done the really
+stupid thing.
+
+Then, when it really does turn out to be stupid, people just roll their
+eyes and say "Oops, he did it again".  
+
+This preemptive admission of incompetence might also make the people who
+actually do the work also think twice about whether it's worth doing or
+not.  After all, if _they_ aren't certain whether it's a good idea, you
+sure as hell shouldn't encourage them by promising them that what they
+work on will be included.  Make them at least think twice before they
+embark on a big endeavor. 
+
+Remember: they'd better know more about the details than you do, and
+they usually already think they have the answer to everything.  The best
+thing you can do as a manager is not to instill confidence, but rather a
+healthy dose of critical thinking on what they do. 
+
+Btw, another way to avoid a decision is to plaintively just whine "can't
+we just do both?" and look pitiful.  Trust me, it works.  If it's not
+clear which approach is better, they'll eventually figure it out.  The
+answer may end up being that both teams get so frustrated by the
+situation that they just give up. 
+
+That may sound like a failure, but it's usually a sign that there was
+something wrong with both projects, and the reason the people involved
+couldn't decide was that they were both wrong.  You end up coming up
+smelling like roses, and you avoided yet another decision that you could
+have screwed up on. 
+
+
+               Chapter 2: People
+
+Most people are idiots, and being a manager means you'll have to deal
+with it, and perhaps more importantly, that _they_ have to deal with
+_you_. 
+
+It turns out that while it's easy to undo technical mistakes, it's not
+as easy to undo personality disorders.  You just have to live with
+theirs - and yours. 
+
+However, in order to prepare yourself as a kernel manager, it's best to
+remember not to burn any bridges, bomb any innocent villagers, or
+alienate too many kernel developers. It turns out that alienating people
+is fairly easy, and un-alienating them is hard. Thus "alienating"
+immediately falls under the heading of "not reversible", and becomes a
+no-no according to Chapter 1.
+
+There's just a few simple rules here:
+ (1) don't call people d*ckheads (at least not in public)
+ (2) learn how to apologize when you forgot rule (1)
+
+The problem with #1 is that it's very easy to do, since you can say
+"you're a d*ckhead" in millions of different ways (*), sometimes without
+even realizing it, and almost always with a white-hot conviction that
+you are right. 
+
+And the more convinced you are that you are right (and let's face it,
+you can call just about _anybody_ a d*ckhead, and you often _will_ be
+right), the harder it ends up being to apologize afterwards. 
+
+To solve this problem, you really only have two options:
+ - get really good at apologies
+ - spread the "love" out so evenly that nobody really ends up feeling
+   like they get unfairly targeted.  Make it inventive enough, and they
+   might even be amused. 
+
+The option of being unfailingly polite really doesn't exist. Nobody will
+trust somebody who is so clearly hiding his true character.
+
+(*) Paul Simon sang "Fifty Ways to Lose Your Lover", because quite
+frankly, "A Million Ways to Tell a Developer He Is a D*ckhead" doesn't
+scan nearly as well.  But I'm sure he thought about it. 
+
+
+               Chapter 3: People II - the Good Kind
+
+While it turns out that most people are idiots, the corollary to that is
+sadly that you are one too, and that while we can all bask in the secure
+knowledge that we're better than the average person (let's face it,
+nobody ever believes that they're average or below-average), we should
+also admit that we're not the sharpest knife around, and there will be
+other people that are less of an idiot that you are. 
+
+Some people react badly to smart people.  Others take advantage of them. 
+
+Make sure that you, as a kernel maintainer, are in the second group. 
+Suck up to them, because they are the people who will make your job
+easier. In particular, they'll be able to make your decisions for you,
+which is what the game is all about.
+
+So when you find somebody smarter than you are, just coast along.  Your
+management responsibilities largely become ones of saying "Sounds like a
+good idea - go wild", or "That sounds good, but what about xxx?".  The
+second version in particular is a great way to either learn something
+new about "xxx" or seem _extra_ managerial by pointing out something the
+smarter person hadn't thought about.  In either case, you win.
+
+One thing to look out for is to realize that greatness in one area does
+not necessarily translate to other areas.  So you might prod people in
+specific directions, but let's face it, they might be good at what they
+do, and suck at everything else.  The good news is that people tend to
+naturally gravitate back to what they are good at, so it's not like you
+are doing something irreversible when you _do_ prod them in some
+direction, just don't push too hard.
+
+
+               Chapter 4: Placing blame
+
+Things will go wrong, and people want somebody to blame. Tag, you're it.
+
+It's not actually that hard to accept the blame, especially if people
+kind of realize that it wasn't _all_ your fault.  Which brings us to the
+best way of taking the blame: do it for another guy. You'll feel good
+for taking the fall, he'll feel good about not getting blamed, and the
+guy who lost his whole 36GB porn-collection because of your incompetence
+will grudgingly admit that you at least didn't try to weasel out of it.
+
+Then make the developer who really screwed up (if you can find him) know
+_in_private_ that he screwed up.  Not just so he can avoid it in the
+future, but so that he knows he owes you one.  And, perhaps even more
+importantly, he's also likely the person who can fix it.  Because, let's
+face it, it sure ain't you. 
+
+Taking the blame is also why you get to be manager in the first place. 
+It's part of what makes people trust you, and allow you the potential
+glory, because you're the one who gets to say "I screwed up".  And if
+you've followed the previous rules, you'll be pretty good at saying that
+by now. 
+
+
+               Chapter 5: Things to avoid
+
+There's one thing people hate even more than being called "d*ckhead",
+and that is being called a "d*ckhead" in a sanctimonious voice.  The
+first you can apologize for, the second one you won't really get the
+chance.  They likely will no longer be listening even if you otherwise
+do a good job. 
+
+We all think we're better than anybody else, which means that when
+somebody else puts on airs, it _really_ rubs us the wrong way.  You may
+be morally and intellectually superior to everybody around you, but
+don't try to make it too obvious unless you really _intend_ to irritate
+somebody (*). 
+
+Similarly, don't be too polite or subtle about things. Politeness easily
+ends up going overboard and hiding the problem, and as they say, "On the
+internet, nobody can hear you being subtle". Use a big blunt object to
+hammer the point in, because you can't really depend on people getting
+your point otherwise.
+
+Some humor can help pad both the bluntness and the moralizing.  Going
+overboard to the point of being ridiculous can drive a point home
+without making it painful to the recipient, who just thinks you're being
+silly.  It can thus help get through the personal mental block we all
+have about criticism. 
+
+(*) Hint: internet newsgroups that are not directly related to your work
+are great ways to take out your frustrations at other people. Write
+insulting posts with a sneer just to get into a good flame every once in
+a while, and you'll feel cleansed. Just don't crap too close to home.
+
+
+               Chapter 6: Why me?
+
+Since your main responsibility seems to be to take the blame for other
+peoples mistakes, and make it painfully obvious to everybody else that
+you're incompetent, the obvious question becomes one of why do it in the
+first place?
+
+First off, while you may or may not get screaming teenage girls (or
+boys, let's not be judgmental or sexist here) knocking on your dressing
+room door, you _will_ get an immense feeling of personal accomplishment
+for being "in charge".  Never mind the fact that you're really leading
+by trying to keep up with everybody else and running after them as fast
+as you can.  Everybody will still think you're the person in charge. 
+
+It's a great job if you can hack it.
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
new file mode 100644 (file)
index 0000000..12250b3
--- /dev/null
@@ -0,0 +1,387 @@
+Read the F-ing Papers!
+
+
+This document describes RCU-related publications, and is followed by
+the corresponding bibtex entries.
+
+The first thing resembling RCU was published in 1980, when Kung and Lehman
+[Kung80] recommended use of a garbage collector to defer destruction
+of nodes in a parallel binary search tree in order to simplify its
+implementation.  This works well in environments that have garbage
+collectors, but current production garbage collectors incur significant
+read-side overhead.
+
+In 1982, Manber and Ladner [Manber82,Manber84] recommended deferring
+destruction until all threads running at that time have terminated, again
+for a parallel binary search tree.  This approach works well in systems
+with short-lived threads, such as the K42 research operating system.
+However, Linux has long-lived tasks, so more is needed.
+
+In 1986, Hennessy, Osisek, and Seigh [Hennessy89] introduced passive
+serialization, which is an RCU-like mechanism that relies on the presence
+of "quiescent states" in the VM/XA hypervisor that are guaranteed not
+to be referencing the data structure.  However, this mechanism was not
+optimized for modern computer systems, which is not surprising given
+that these overheads were not so expensive in the mid-80s.  Nonetheless,
+passive serialization appears to be the first deferred-destruction
+mechanism to be used in production.  Furthermore, the relevant patent has
+lapsed, so this approach may be used in non-GPL software, if desired.
+(In contrast, use of RCU is permitted only in software licensed under
+GPL.  Sorry!!!)
+
+In 1990, Pugh [Pugh90] noted that explicitly tracking which threads
+were reading a given data structure permitted deferred free to operate
+in the presence of non-terminating threads.  However, this explicit
+tracking imposes significant read-side overhead, which is undesirable
+in read-mostly situations.  This algorithm does take pains to avoid
+write-side contention and parallelize the other write-side overheads by
+providing a fine-grained locking design, however, it would be interesting
+to see how much of the performance advantage reported in 1990 remains
+in 2004.
+
+At about this same time, Adams [Adams91] described ``chaotic relaxation'',
+where the normal barriers between successive iterations of convergent
+numerical algorithms are relaxed, so that iteration $n$ might use
+data from iteration $n-1$ or even $n-2$.  This introduces error,
+which typically slows convergence and thus increases the number of
+iterations required.  However, this increase is sometimes more than made
+up for by a reduction in the number of expensive barrier operations,
+which are otherwise required to synchronize the threads at the end
+of each iteration.  Unfortunately, chaotic relaxation requires highly
+structured data, such as the matrices used in scientific programs, and
+is thus inapplicable to most data structures in operating-system kernels.
+
+In 1993, Jacobson [Jacobson93] verbally described what is perhaps the
+simplest deferred-free technique: simply waiting a fixed amount of time
+before freeing blocks awaiting deferred free.  Jacobson did not describe
+any write-side changes he might have made in this work using SGI's Irix
+kernel.  Aju John published a similar technique in 1995 [AjuJohn95].
+This works well if there is a well-defined upper bound on the length of
+time that reading threads can hold references, as there might well be in
+hard real-time systems.  However, if this time is exceeded, perhaps due
+to preemption, excessive interrupts, or larger-than-anticipated load,
+memory corruption can ensue, with no reasonable means of diagnosis.
+Jacobson's technique is therefore inappropriate for use in production
+operating-system kernels, except when such kernels can provide hard
+real-time response guarantees for all operations.
+
+Also in 1995, Pu et al. [Pu95a] applied a technique similar to that of Pugh's
+read-side-tracking to permit replugging of algorithms within a commercial
+Unix operating system.  However, this replugging permitted only a single
+reader at a time.  The following year, this same group of researchers
+extended their technique to allow for multiple readers [Cowan96a].
+Their approach requires memory barriers (and thus pipeline stalls),
+but reduces memory latency, contention, and locking overheads.
+
+1995 also saw the first publication of DYNIX/ptx's RCU mechanism
+[Slingwine95], which was optimized for modern CPU architectures,
+and was successfully applied to a number of situations within the
+DYNIX/ptx kernel.  The corresponding conference paper appeared in 1998
+[McKenney98].
+
+In 1999, the Tornado and K42 groups described their "generations"
+mechanism, which quite similar to RCU [Gamsa99].  These operating systems
+made pervasive use of RCU in place of "existence locks", which greatly
+simplifies locking hierarchies.
+
+2001 saw the first RCU presentation involving Linux [McKenney01a]
+at OLS.  The resulting abundance of RCU patches was presented the
+following year [McKenney02a], and use of RCU in dcache was first
+described that same year [Linder02a].
+
+Also in 2002, Michael [Michael02b,Michael02a] presented techniques
+that defer the destruction of data structures to simplify non-blocking
+synchronization (wait-free synchronization, lock-free synchronization,
+and obstruction-free synchronization are all examples of non-blocking
+synchronization).  In particular, this technique eliminates locking,
+reduces contention, reduces memory latency for readers, and parallelizes
+pipeline stalls and memory latency for writers.  However, these
+techniques still impose significant read-side overhead in the form of
+memory barriers.  Researchers at Sun worked along similar lines in the
+same timeframe [HerlihyLM02,HerlihyLMS03].
+
+In 2003, the K42 group described how RCU could be used to create
+hot-pluggable implementations of operating-system functions.  Later that
+year saw a paper describing an RCU implementation of System V IPC
+[Arcangeli03], and an introduction to RCU in Linux Journal [McKenney03a].
+
+2004 has seen a Linux-Journal article on use of RCU in dcache
+[McKenney04a], a performance comparison of locking to RCU on several
+different CPUs [McKenney04b], a dissertation describing use of RCU in a
+number of operating-system kernels [PaulEdwardMcKenneyPhD], and a paper
+describing how to make RCU safe for soft-realtime applications [Sarma04c].
+
+
+Bibtex Entries
+
+@article{Kung80
+,author="H. T. Kung and Q. Lehman"
+,title="Concurrent Maintenance of Binary Search Trees"
+,Year="1980"
+,Month="September"
+,journal="ACM Transactions on Database Systems"
+,volume="5"
+,number="3"
+,pages="354-382"
+}
+
+@techreport{Manber82
+,author="Udi Manber and Richard E. Ladner"
+,title="Concurrency Control in a Dynamic Search Structure"
+,institution="Department of Computer Science, University of Washington"
+,address="Seattle, Washington"
+,year="1982"
+,number="82-01-01"
+,month="January"
+,pages="28"
+}
+
+@article{Manber84
+,author="Udi Manber and Richard E. Ladner"
+,title="Concurrency Control in a Dynamic Search Structure"
+,Year="1984"
+,Month="September"
+,journal="ACM Transactions on Database Systems"
+,volume="9"
+,number="3"
+,pages="439-455"
+}
+
+@techreport{Hennessy89
+,author="James P. Hennessy and Damian L. Osisek and Joseph W. {Seigh II}"
+,title="Passive Serialization in a Multitasking Environment"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="1989"
+,number="US Patent 4,809,168 (lapsed)"
+,month="February"
+,pages="11"
+}
+
+@techreport{Pugh90
+,author="William Pugh"
+,title="Concurrent Maintenance of Skip Lists"
+,institution="Institute of Advanced Computer Science Studies, Department of Computer Science, University of Maryland"
+,address="College Park, Maryland"
+,year="1990"
+,number="CS-TR-2222.1"
+,month="June"
+}
+
+@Book{Adams91
+,Author="Gregory R. Adams"
+,title="Concurrent Programming, Principles, and Practices"
+,Publisher="Benjamin Cummins"
+,Year="1991"
+}
+
+@unpublished{Jacobson93
+,author="Van Jacobson"
+,title="Avoid Read-Side Locking Via Delayed Free"
+,year="1993"
+,month="September"
+,note="Verbal discussion"
+}
+
+@Conference{AjuJohn95
+,Author="Aju John"
+,Title="Dynamic vnodes -- Design and Implementation"
+,Booktitle="{USENIX Winter 1995}"
+,Publisher="USENIX Association"
+,Month="January"
+,Year="1995"
+,pages="11-23"
+,Address="New Orleans, LA"
+}
+
+@techreport{Slingwine95
+,author="John D. Slingwine and Paul E. McKenney"
+,title="Apparatus and Method for Achieving Reduced Overhead Mutual
+Exclusion and Maintaining Coherency in a Multiprocessor System
+Utilizing Execution History and Thread Monitoring"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="1995"
+,number="US Patent 5,442,758 (contributed under GPL)"
+,month="August"
+}
+
+@techreport{Slingwine97
+,author="John D. Slingwine and Paul E. McKenney"
+,title="Method for maintaining data coherency using thread
+activity summaries in a multicomputer system"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="1997"
+,number="US Patent 5,608,893 (contributed under GPL)"
+,month="March"
+}
+
+@techreport{Slingwine98
+,author="John D. Slingwine and Paul E. McKenney"
+,title="Apparatus and method for achieving reduced overhead
+mutual exclusion and maintaining coherency in a multiprocessor
+system utilizing execution history and thread monitoring"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="1998"
+,number="US Patent 5,727,209 (contributed under GPL)"
+,month="March"
+}
+
+@Conference{McKenney98
+,Author="Paul E. McKenney and John D. Slingwine"
+,Title="Read-Copy Update: Using Execution History to Solve Concurrency
+Problems"
+,Booktitle="{Parallel and Distributed Computing and Systems}"
+,Month="October"
+,Year="1998"
+,pages="509-518"
+,Address="Las Vegas, NV"
+}
+
+@Conference{Gamsa99
+,Author="Ben Gamsa and Orran Krieger and Jonathan Appavoo and Michael Stumm"
+,Title="Tornado: Maximizing Locality and Concurrency in a Shared Memory
+Multiprocessor Operating System"
+,Booktitle="{Proceedings of the 3\textsuperscript{rd} Symposium on
+Operating System Design and Implementation}"
+,Month="February"
+,Year="1999"
+,pages="87-100"
+,Address="New Orleans, LA"
+}
+
+@techreport{Slingwine01
+,author="John D. Slingwine and Paul E. McKenney"
+,title="Apparatus and method for achieving reduced overhead
+mutual exclusion and maintaining coherency in a multiprocessor
+system utilizing execution history and thread monitoring"
+,institution="US Patent and Trademark Office"
+,address="Washington, DC"
+,year="2001"
+,number="US Patent 5,219,690 (contributed under GPL)"
+,month="April"
+}
+
+@Conference{McKenney01a
+,Author="Paul E. McKenney and Jonathan Appavoo and Andi Kleen and
+Orran Krieger and Rusty Russell and Dipankar Sarma and Maneesh Soni"
+,Title="Read-Copy Update"
+,Booktitle="{Ottawa Linux Symposium}"
+,Month="July"
+,Year="2001"
+,note="Available:
+\url{http://www.linuxsymposium.org/2001/abstracts/readcopy.php}
+\url{http://www.rdrop.com/users/paulmck/rclock/rclock_OLS.2001.05.01c.pdf}
+[Viewed June 23, 2004]"
+annotation="
+Described RCU, and presented some patches implementing and using it in
+the Linux kernel.
+"
+}
+
+@Conference{Linder02a
+,Author="Hanna Linder and Dipankar Sarma and Maneesh Soni"
+,Title="Scalability of the Directory Entry Cache"
+,Booktitle="{Ottawa Linux Symposium}"
+,Month="June"
+,Year="2002"
+,pages="289-300"
+}
+
+@Conference{McKenney02a
+,Author="Paul E. McKenney and Dipankar Sarma and
+Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell"
+,Title="Read-Copy Update"
+,Booktitle="{Ottawa Linux Symposium}"
+,Month="June"
+,Year="2002"
+,pages="338-367"
+,note="Available:
+\url{http://www.linux.org.uk/~ajh/ols2002_proceedings.pdf.gz}
+[Viewed June 23, 2004]"
+}
+
+@article{Appavoo03a
+,author="J. Appavoo and K. Hui and C. A. N. Soules and R. W. Wisniewski and
+D. M. {Da Silva} and O. Krieger and M. A. Auslander and D. J. Edelsohn and
+B. Gamsa and G. R. Ganger and P. McKenney and M. Ostrowski and
+B. Rosenburg and M. Stumm and J. Xenidis"
+,title="Enabling Autonomic Behavior in Systems Software With Hot Swapping"
+,Year="2003"
+,Month="January"
+,journal="IBM Systems Journal"
+,volume="42"
+,number="1"
+,pages="60-76"
+}
+
+@Conference{Arcangeli03
+,Author="Andrea Arcangeli and Mingming Cao and Paul E. McKenney and
+Dipankar Sarma"
+,Title="Using Read-Copy Update Techniques for {System V IPC} in the
+{Linux} 2.5 Kernel"
+,Booktitle="Proceedings of the 2003 USENIX Annual Technical Conference
+(FREENIX Track)"
+,Publisher="USENIX Association"
+,year="2003"
+,month="June"
+,pages="297-310"
+}
+
+@article{McKenney03a
+,author="Paul E. McKenney"
+,title="Using {RCU} in the {Linux} 2.5 Kernel"
+,Year="2003"
+,Month="October"
+,journal="Linux Journal"
+,volume="1"
+,number="114"
+,pages="18-26"
+}
+
+@article{McKenney04a
+,author="Paul E. McKenney and Dipankar Sarma and Maneesh Soni"
+,title="Scaling dcache with {RCU}"
+,Year="2004"
+,Month="January"
+,journal="Linux Journal"
+,volume="1"
+,number="118"
+,pages="38-46"
+}
+
+@Conference{McKenney04b
+,Author="Paul E. McKenney"
+,Title="{RCU} vs. Locking Performance on Different {CPUs}"
+,Booktitle="{linux.conf.au}"
+,Month="January"
+,Year="2004"
+,Address="Adelaide, Australia"
+,note="Available:
+\url{http://www.linux.org.au/conf/2004/abstracts.html#90}
+\url{http://www.rdrop.com/users/paulmck/rclock/lockperf.2004.01.17a.pdf}
+[Viewed June 23, 2004]"
+}
+
+@phdthesis{PaulEdwardMcKenneyPhD
+,author="Paul E. McKenney"
+,title="Exploiting Deferred Destruction:
+An Analysis of Read-Copy-Update Techniques
+in Operating System Kernels"
+,school="OGI School of Science and Engineering at
+Oregon Health and Sciences University"
+,year="2004"
+}
+
+@Conference{Sarma04c
+,Author="Dipankar Sarma and Paul E. McKenney"
+,Title="Making RCU Safe for Deep Sub-Millisecond Response Realtime Applications"
+,Booktitle="Proceedings of the 2004 USENIX Annual Technical Conference
+(FREENIX Track)"
+,Publisher="USENIX Association"
+,year="2004"
+,month="June"
+,pages="182-191"
+}
diff --git a/Documentation/RCU/UP.txt b/Documentation/RCU/UP.txt
new file mode 100644 (file)
index 0000000..551a803
--- /dev/null
@@ -0,0 +1,64 @@
+RCU on Uniprocessor Systems
+
+
+A common misconception is that, on UP systems, the call_rcu() primitive
+may immediately invoke its function, and that the synchronize_kernel
+primitive may return immediately.  The basis of this misconception
+is that since there is only one CPU, it should not be necessary to
+wait for anything else to get done, since there are no other CPUs for
+anything else to be happening on.  Although this approach will sort of
+work a surprising amount of the time, it is a very bad idea in general.
+This document presents two examples that demonstrate exactly how bad an
+idea this is.
+
+
+Example 1: softirq Suicide
+
+Suppose that an RCU-based algorithm scans a linked list containing
+elements A, B, and C in process context, and can delete elements from
+this same list in softirq context.  Suppose that the process-context scan
+is referencing element B when it is interrupted by softirq processing,
+which deletes element B, and then invokes call_rcu() to free element B
+after a grace period.
+
+Now, if call_rcu() were to directly invoke its arguments, then upon return
+from softirq, the list scan would find itself referencing a newly freed
+element B.  This situation can greatly decrease the life expectancy of
+your kernel.
+
+
+Example 2: Function-Call Fatality
+
+Of course, one could avert the suicide described in the preceding example
+by having call_rcu() directly invoke its arguments only if it was called
+from process context.  However, this can fail in a similar manner.
+
+Suppose that an RCU-based algorithm again scans a linked list containing
+elements A, B, and C in process contexts, but that it invokes a function
+on each element as it is scanned.  Suppose further that this function
+deletes element B from the list, then passes it to call_rcu() for deferred
+freeing.  This may be a bit unconventional, but it is perfectly legal
+RCU usage, since call_rcu() must wait for a grace period to elapse.
+Therefore, in this case, allowing call_rcu() to immediately invoke
+its arguments would cause it to fail to make the fundamental guarantee
+underlying RCU, namely that call_rcu() defers invoking its arguments until
+all RCU read-side critical sections currently executing have completed.
+
+Quick Quiz: why is it -not- legal to invoke synchronize_kernel() in
+this case?
+
+
+Summary
+
+Permitting call_rcu() to immediately invoke its arguments or permitting
+synchronize_kernel() to immediately return breaks RCU, even on a UP system.
+So do not do it!  Even on a UP system, the RCU infrastructure -must-
+respect grace periods.
+
+
+Answer to Quick Quiz
+
+The calling function is scanning an RCU-protected linked list, and
+is therefore within an RCU read-side critical section.  Therefore,
+the called function has been invoked within an RCU read-side critical
+section, and is not permitted to block.
diff --git a/Documentation/RCU/arrayRCU.txt b/Documentation/RCU/arrayRCU.txt
new file mode 100644 (file)
index 0000000..453ebe6
--- /dev/null
@@ -0,0 +1,141 @@
+Using RCU to Protect Read-Mostly Arrays
+
+
+Although RCU is more commonly used to protect linked lists, it can
+also be used to protect arrays.  Three situations are as follows:
+
+1.  Hash Tables
+
+2.  Static Arrays
+
+3.  Resizeable Arrays
+
+Each of these situations are discussed below.
+
+
+Situation 1: Hash Tables
+
+Hash tables are often implemented as an array, where each array entry
+has a linked-list hash chain.  Each hash chain can be protected by RCU
+as described in the listRCU.txt document.  This approach also applies
+to other array-of-list situations, such as radix trees.
+
+
+Situation 2: Static Arrays
+
+Static arrays, where the data (rather than a pointer to the data) is
+located in each array element, and where the array is never resized,
+have not been used with RCU.  Rik van Riel recommends using seqlock in
+this situation, which would also have minimal read-side overhead as long
+as updates are rare.
+
+Quick Quiz:  Why is it so important that updates be rare when
+            using seqlock?
+
+
+Situation 3: Resizeable Arrays
+
+Use of RCU for resizeable arrays is demonstrated by the grow_ary()
+function used by the System V IPC code.  The array is used to map from
+semaphore, message-queue, and shared-memory IDs to the data structure
+that represents the corresponding IPC construct.  The grow_ary()
+function does not acquire any locks; instead its caller must hold the
+ids->sem semaphore.
+
+The grow_ary() function, shown below, does some limit checks, allocates a
+new ipc_id_ary, copies the old to the new portion of the new, initializes
+the remainder of the new, updates the ids->entries pointer to point to
+the new array, and invokes ipc_rcu_putref() to free up the old array.
+Note that rcu_assign_pointer() is used to update the ids->entries pointer,
+which includes any memory barriers required on whatever architecture
+you are running on.
+
+       static int grow_ary(struct ipc_ids* ids, int newsize)
+       {
+               struct ipc_id_ary* new;
+               struct ipc_id_ary* old;
+               int i;
+               int size = ids->entries->size;
+
+               if(newsize > IPCMNI)
+                       newsize = IPCMNI;
+               if(newsize <= size)
+                       return newsize;
+
+               new = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*newsize +
+                                   sizeof(struct ipc_id_ary));
+               if(new == NULL)
+                       return size;
+               new->size = newsize;
+               memcpy(new->p, ids->entries->p,
+                      sizeof(struct kern_ipc_perm *)*size +
+                      sizeof(struct ipc_id_ary));
+               for(i=size;i<newsize;i++) {
+                       new->p[i] = NULL;
+               }
+               old = ids->entries;
+
+               /*
+                * Use rcu_assign_pointer() to make sure the memcpyed
+                * contents of the new array are visible before the new
+                * array becomes visible.
+                */
+               rcu_assign_pointer(ids->entries, new);
+
+               ipc_rcu_putref(old);
+               return newsize;
+       }
+
+The ipc_rcu_putref() function decrements the array's reference count
+and then, if the reference count has dropped to zero, uses call_rcu()
+to free the array after a grace period has elapsed.
+
+The array is traversed by the ipc_lock() function.  This function
+indexes into the array under the protection of rcu_read_lock(),
+using rcu_dereference() to pick up the pointer to the array so
+that it may later safely be dereferenced -- memory barriers are
+required on the Alpha CPU.  Since the size of the array is stored
+with the array itself, there can be no array-size mismatches, so
+a simple check suffices.  The pointer to the structure corresponding
+to the desired IPC object is placed in "out", with NULL indicating
+a non-existent entry.  After acquiring "out->lock", the "out->deleted"
+flag indicates whether the IPC object is in the process of being
+deleted, and, if not, the pointer is returned.
+
+       struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
+       {
+               struct kern_ipc_perm* out;
+               int lid = id % SEQ_MULTIPLIER;
+               struct ipc_id_ary* entries;
+
+               rcu_read_lock();
+               entries = rcu_dereference(ids->entries);
+               if(lid >= entries->size) {
+                       rcu_read_unlock();
+                       return NULL;
+               }
+               out = entries->p[lid];
+               if(out == NULL) {
+                       rcu_read_unlock();
+                       return NULL;
+               }
+               spin_lock(&out->lock);
+
+               /* ipc_rmid() may have already freed the ID while ipc_lock
+                * was spinning: here verify that the structure is still valid
+                */
+               if (out->deleted) {
+                       spin_unlock(&out->lock);
+                       rcu_read_unlock();
+                       return NULL;
+               }
+               return out;
+       }
+
+
+Answer to Quick Quiz:
+
+       The reason that it is important that updates be rare when
+       using seqlock is that frequent updates can livelock readers.
+       One way to avoid this problem is to assign a seqlock for
+       each array entry rather than to the entire array.
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
new file mode 100644 (file)
index 0000000..b3a568a
--- /dev/null
@@ -0,0 +1,157 @@
+Review Checklist for RCU Patches
+
+
+This document contains a checklist for producing and reviewing patches
+that make use of RCU.  Violating any of the rules listed below will
+result in the same sorts of problems that leaving out a locking primitive
+would cause.  This list is based on experiences reviewing such patches
+over a rather long period of time, but improvements are always welcome!
+
+0.     Is RCU being applied to a read-mostly situation?  If the data
+       structure is updated more than about 10% of the time, then
+       you should strongly consider some other approach, unless
+       detailed performance measurements show that RCU is nonetheless
+       the right tool for the job.
+
+       The other exception would be where performance is not an issue,
+       and RCU provides a simpler implementation.  An example of this
+       situation is the dynamic NMI code in the Linux 2.6 kernel,
+       at least on architectures where NMIs are rare.
+
+1.     Does the update code have proper mutual exclusion?
+
+       RCU does allow -readers- to run (almost) naked, but -writers- must
+       still use some sort of mutual exclusion, such as:
+
+       a.      locking,
+       b.      atomic operations, or
+       c.      restricting updates to a single task.
+
+       If you choose #b, be prepared to describe how you have handled
+       memory barriers on weakly ordered machines (pretty much all of
+       them -- even x86 allows reads to be reordered), and be prepared
+       to explain why this added complexity is worthwhile.  If you
+       choose #c, be prepared to explain how this single task does not
+       become a major bottleneck on big multiprocessor machines.
+
+2.     Do the RCU read-side critical sections make proper use of
+       rcu_read_lock() and friends?  These primitives are needed
+       to suppress preemption (or bottom halves, in the case of
+       rcu_read_lock_bh()) in the read-side critical sections,
+       and are also an excellent aid to readability.
+
+3.     Does the update code tolerate concurrent accesses?
+
+       The whole point of RCU is to permit readers to run without
+       any locks or atomic operations.  This means that readers will
+       be running while updates are in progress.  There are a number
+       of ways to handle this concurrency, depending on the situation:
+
+       a.      Make updates appear atomic to readers.  For example,
+               pointer updates to properly aligned fields will appear
+               atomic, as will individual atomic primitives.  Operations
+               performed under a lock and sequences of multiple atomic
+               primitives will -not- appear to be atomic.
+
+               This is almost always the best approach.
+
+       b.      Carefully order the updates and the reads so that
+               readers see valid data at all phases of the update.
+               This is often more difficult than it sounds, especially
+               given modern CPUs' tendency to reorder memory references.
+               One must usually liberally sprinkle memory barriers
+               (smp_wmb(), smp_rmb(), smp_mb()) through the code,
+               making it difficult to understand and to test.
+
+               It is usually better to group the changing data into
+               a separate structure, so that the change may be made
+               to appear atomic by updating a pointer to reference
+               a new structure containing updated values.
+
+4.     Weakly ordered CPUs pose special challenges.  Almost all CPUs
+       are weakly ordered -- even i386 CPUs allow reads to be reordered.
+       RCU code must take all of the following measures to prevent
+       memory-corruption problems:
+
+       a.      Readers must maintain proper ordering of their memory
+               accesses.  The rcu_dereference() primitive ensures that
+               the CPU picks up the pointer before it picks up the data
+               that the pointer points to.  This really is necessary
+               on Alpha CPUs.  If you don't believe me, see:
+
+                       http://www.openvms.compaq.com/wizard/wiz_2637.html
+
+               The rcu_dereference() primitive is also an excellent
+               documentation aid, letting the person reading the code
+               know exactly which pointers are protected by RCU.
+
+               The rcu_dereference() primitive is used by the various
+               "_rcu()" list-traversal primitives, such as the
+               list_for_each_entry_rcu().
+
+       b.      If the list macros are being used, the list_del_rcu(),
+               list_add_tail_rcu(), and list_del_rcu() primitives must
+               be used in order to prevent weakly ordered machines from
+               misordering structure initialization and pointer planting.
+               Similarly, if the hlist macros are being used, the
+               hlist_del_rcu() and hlist_add_head_rcu() primitives
+               are required.
+
+       c.      Updates must ensure that initialization of a given
+               structure happens before pointers to that structure are
+               publicized.  Use the rcu_assign_pointer() primitive
+               when publicizing a pointer to a structure that can
+               be traversed by an RCU read-side critical section.
+
+               [The rcu_assign_pointer() primitive is in process.]
+
+5.     If call_rcu(), or a related primitive such as call_rcu_bh(),
+       is used, the callback function must be written to be called
+       from softirq context.  In particular, it cannot block.
+
+6.     Since synchronize_kernel() blocks, it cannot be called from
+       any sort of irq context.
+
+7.     If the updater uses call_rcu(), then the corresponding readers
+       must use rcu_read_lock() and rcu_read_unlock().  If the updater
+       uses call_rcu_bh(), then the corresponding readers must use
+       rcu_read_lock_bh() and rcu_read_unlock_bh().  Mixing things up
+       will result in confusion and broken kernels.
+
+       One exception to this rule: rcu_read_lock() and rcu_read_unlock()
+       may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
+       in cases where local bottom halves are already known to be
+       disabled, for example, in irq or softirq context.  Commenting
+       such cases is a must, of course!  And the jury is still out on
+       whether the increased speed is worth it.
+
+8.     Although synchronize_kernel() is a bit slower than is call_rcu(),
+       it usually results in simpler code.  So, unless update performance
+       is important or the updaters cannot block, synchronize_kernel()
+       should be used in preference to call_rcu().
+
+9.     All RCU list-traversal primitives, which include
+       list_for_each_rcu(), list_for_each_entry_rcu(),
+       list_for_each_continue_rcu(), and list_for_each_safe_rcu(),
+       must be within an RCU read-side critical section.  RCU
+       read-side critical sections are delimited by rcu_read_lock()
+       and rcu_read_unlock(), or by similar primitives such as
+       rcu_read_lock_bh() and rcu_read_unlock_bh().
+
+       Use of the _rcu() list-traversal primitives outside of an
+       RCU read-side critical section causes no harm other than
+       a slight performance degradation on Alpha CPUs and some
+       confusion on the part of people trying to read the code.
+
+       Another way of thinking of this is "If you are holding the
+       lock that prevents the data structure from changing, why do
+       you also need RCU-based protection?"  That said, there may
+       well be situations where use of the _rcu() list-traversal
+       primitives while the update-side lock is held results in
+       simpler and more maintainable code.  The jury is still out
+       on this question.
+
+10.    Conversely, if you are in an RCU read-side critical section,
+       you -must- use the "_rcu()" variants of the list macros.
+       Failing to do so will break Alpha and confuse people reading
+       your code.
diff --git a/Documentation/RCU/listRCU.txt b/Documentation/RCU/listRCU.txt
new file mode 100644 (file)
index 0000000..46950af
--- /dev/null
@@ -0,0 +1,307 @@
+Using RCU to Protect Read-Mostly Linked Lists
+
+
+One of the best applications of RCU is to protect read-mostly linked lists
+("struct list_head" in list.h).  One big advantage of this approach
+is that all of the required memory barriers are included for you in
+the list macros.  This document describes several applications of RCU,
+with the best fits first.
+
+
+Example 1: Read-Side Action Taken Outside of Lock, No In-Place Updates
+
+The best applications are cases where, if reader-writer locking were
+used, the read-side lock would be dropped before taking any action
+based on the results of the search.  The most celebrated example is
+the routing table.  Because the routing table is tracking the state of
+equipment outside of the computer, it will at times contain stale data.
+Therefore, once the route has been computed, there is no need to hold
+the routing table static during transmission of the packet.  After all,
+you can hold the routing table static all you want, but that won't keep
+the external Internet from changing, and it is the state of the external
+Internet that really matters.  In addition, routing entries are typically
+added or deleted, rather than being modified in place.
+
+A straightforward example of this use of RCU may be found in the
+system-call auditing support.  For example, a reader-writer locked
+implementation of audit_filter_task() might be as follows:
+
+       static enum audit_state audit_filter_task(struct task_struct *tsk)
+       {
+               struct audit_entry *e;
+               enum audit_state   state;
+
+               read_lock(&auditsc_lock);
+               list_for_each_entry(e, &audit_tsklist, list) {
+                       if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+                               read_unlock(&auditsc_lock);
+                               return state;
+                       }
+               }
+               read_unlock(&auditsc_lock);
+               return AUDIT_BUILD_CONTEXT;
+       }
+
+Here the list is searched under the lock, but the lock is dropped before
+the corresponding value is returned.  By the time that this value is acted
+on, the list may well have been modified.  This makes sense, since if
+you are turning auditing off, it is OK to audit a few extra system calls.
+
+This means that RCU can be easily applied to the read side, as follows:
+
+       static enum audit_state audit_filter_task(struct task_struct *tsk)
+       {
+               struct audit_entry *e;
+               enum audit_state   state;
+
+               rcu_read_lock();
+               list_for_each_entry_rcu(e, &audit_tsklist, list) {
+                       if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+                               rcu_read_unlock();
+                               return state;
+                       }
+               }
+               rcu_read_unlock();
+               return AUDIT_BUILD_CONTEXT;
+       }
+
+The read_lock() and read_unlock() calls have become rcu_read_lock()
+and rcu_read_unlock(), respectively, and the list_for_each_entry() has
+become list_for_each_entry_rcu().  The _rcu() list-traversal primitives
+insert the read-side memory barriers that are required on DEC Alpha CPUs.
+
+The changes to the update side are also straightforward.  A reader-writer
+lock might be used as follows for deletion and insertion:
+
+       static inline int audit_del_rule(struct audit_rule *rule,
+                                        struct list_head *list)
+       {
+               struct audit_entry  *e;
+
+               write_lock(&auditsc_lock);
+               list_for_each_entry(e, list, list) {
+                       if (!audit_compare_rule(rule, &e->rule)) {
+                               list_del(&e->list);
+                               call_rcu(&e->rcu, audit_free_rule, e);
+                               return 0;
+                       }
+               }
+               write_unlock(&auditsc_lock);
+               return -EFAULT;         /* No matching rule */
+       }
+
+       static inline int audit_add_rule(struct audit_entry *entry,
+                                        struct list_head *list)
+       {
+               write_lock(&auditsc_lock);
+               if (entry->rule.flags & AUDIT_PREPEND) {
+                       entry->rule.flags &= ~AUDIT_PREPEND;
+                       list_add(&entry->list, list);
+               } else {
+                       list_add_tail(&entry->list, list);
+               }
+               write_unlock(&auditsc_lock);
+               return 0;
+       }
+
+Following are the RCU equivalents for these two functions:
+
+       static inline int audit_del_rule(struct audit_rule *rule,
+                                        struct list_head *list)
+       {
+               struct audit_entry  *e;
+
+               /* Do not use the _rcu iterator here, since this is the only
+                * deletion routine. */
+               list_for_each_entry(e, list, list) {
+                       if (!audit_compare_rule(rule, &e->rule)) {
+                               list_del_rcu(&e->list);
+                               call_rcu(&e->rcu, audit_free_rule, e);
+                               return 0;
+                       }
+               }
+               return -EFAULT;         /* No matching rule */
+       }
+
+       static inline int audit_add_rule(struct audit_entry *entry,
+                                        struct list_head *list)
+       {
+               if (entry->rule.flags & AUDIT_PREPEND) {
+                       entry->rule.flags &= ~AUDIT_PREPEND;
+                       list_add_rcu(&entry->list, list);
+               } else {
+                       list_add_tail_rcu(&entry->list, list);
+               }
+               return 0;
+       }
+
+Normally, the write_lock() and write_unlock() would be replaced by
+a spin_lock() and a spin_unlock(), but in this case, all callers hold
+audit_netlink_sem, so no additional locking is required.  The auditsc_lock
+can therefore be eliminated, since use of RCU eliminates the need for
+writers to exclude readers.
+
+The list_del(), list_add(), and list_add_tail() primitives have been
+replaced by list_del_rcu(), list_add_rcu(), and list_add_tail_rcu().
+The _rcu() list-manipulation primitives add memory barriers that are
+needed on weakly ordered CPUs (most of them!).
+
+So, when readers can tolerate stale data and when entries are either added
+or deleted, without in-place modification, it is very easy to use RCU!
+
+
+Example 2: Handling In-Place Updates
+
+The system-call auditing code does not update auditing rules in place.
+However, if it did, reader-writer-locked code to do so might look as
+follows (presumably, the field_count is only permitted to decrease,
+otherwise, the added fields would need to be filled in):
+
+       static inline int audit_upd_rule(struct audit_rule *rule,
+                                        struct list_head *list,
+                                        __u32 newaction,
+                                        __u32 newfield_count)
+       {
+               struct audit_entry  *e;
+               struct audit_newentry *ne;
+
+               write_lock(&auditsc_lock);
+               list_for_each_entry(e, list, list) {
+                       if (!audit_compare_rule(rule, &e->rule)) {
+                               e->rule.action = newaction;
+                               e->rule.file_count = newfield_count;
+                               write_unlock(&auditsc_lock);
+                               return 0;
+                       }
+               }
+               write_unlock(&auditsc_lock);
+               return -EFAULT;         /* No matching rule */
+       }
+
+The RCU version creates a copy, updates the copy, then replaces the old
+entry with the newly updated entry.  This sequence of actions, allowing
+concurrent reads while doing a copy to perform an update, is what gives
+RCU ("read-copy update") its name.  The RCU code is as follows:
+
+       static inline int audit_upd_rule(struct audit_rule *rule,
+                                        struct list_head *list,
+                                        __u32 newaction,
+                                        __u32 newfield_count)
+       {
+               struct audit_entry  *e;
+               struct audit_newentry *ne;
+
+               list_for_each_entry(e, list, list) {
+                       if (!audit_compare_rule(rule, &e->rule)) {
+                               ne = kmalloc(sizeof(*entry), GFP_ATOMIC);
+                               if (ne == NULL)
+                                       return -ENOMEM;
+                               audit_copy_rule(&ne->rule, &e->rule);
+                               ne->rule.action = newaction;
+                               ne->rule.file_count = newfield_count;
+                               list_add_rcu(ne, e);
+                               list_del(e);
+                               call_rcu(&e->rcu, audit_free_rule, e);
+                               return 0;
+                       }
+               }
+               return -EFAULT;         /* No matching rule */
+       }
+
+Again, this assumes that the caller holds audit_netlink_sem.  Normally,
+the reader-writer lock would become a spinlock in this sort of code.
+
+
+Example 3: Eliminating Stale Data
+
+The auditing examples above tolerate stale data, as do most algorithms
+that are tracking external state.  Because there is a delay from the
+time the external state changes before Linux becomes aware of the change,
+additional RCU-induced staleness is normally not a problem.
+
+However, there are many examples where stale data cannot be tolerated.
+One example in the Linux kernel is the System V IPC (see the ipc_lock()
+function in ipc/util.c).  This code checks a "deleted" flag under a
+per-entry spinlock, and, if the "deleted" flag is set, pretends that the
+entry does not exist.  For this to be helpful, the search function must
+return holding the per-entry spinlock, as ipc_lock() does in fact do.
+
+Quick Quiz:  Why does the search function need to return holding the
+per-entry lock for this deleted-flag technique to be helpful?
+
+If the system-call audit module were to ever need to reject stale data,
+one way to accomplish this would be to add a "deleted" flag and a "lock"
+spinlock to the audit_entry structure, and modify audit_filter_task()
+as follows:
+
+       static enum audit_state audit_filter_task(struct task_struct *tsk)
+       {
+               struct audit_entry *e;
+               enum audit_state   state;
+
+               rcu_read_lock();
+               list_for_each_entry_rcu(e, &audit_tsklist, list) {
+                       if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
+                               spin_lock(&e->lock);
+                               if (e->deleted) {
+                                       spin_unlock(&e->lock);
+                                       rcu_read_unlock();
+                                       return AUDIT_BUILD_CONTEXT;
+                               }
+                               rcu_read_unlock();
+                               return state;
+                       }
+               }
+               rcu_read_unlock();
+               return AUDIT_BUILD_CONTEXT;
+       }
+
+Note that this example assumes that entries are only added and deleted.
+Additional mechanism is required to deal correctly with the
+update-in-place performed by audit_upd_rule().  For one thing,
+audit_upd_rule() would need additional memory barriers to ensure
+that the list_add_rcu() was really executed before the list_del_rcu().
+
+The audit_del_rule() function would need to set the "deleted"
+flag under the spinlock as follows:
+
+       static inline int audit_del_rule(struct audit_rule *rule,
+                                        struct list_head *list)
+       {
+               struct audit_entry  *e;
+
+               /* Do not use the _rcu iterator here, since this is the only
+                * deletion routine. */
+               list_for_each_entry(e, list, list) {
+                       if (!audit_compare_rule(rule, &e->rule)) {
+                               spin_lock(&e->lock);
+                               list_del_rcu(&e->list);
+                               e->deleted = 1;
+                               spin_unlock(&e->lock);
+                               call_rcu(&e->rcu, audit_free_rule, e);
+                               return 0;
+                       }
+               }
+               return -EFAULT;         /* No matching rule */
+       }
+
+
+Summary
+
+Read-mostly list-based data structures that can tolerate stale data are
+the most amenable to use of RCU.  The simplest case is where entries are
+either added or deleted from the data structure (or atomically modified
+in place), but non-atomic in-place modifications can be handled by making
+a copy, updating the copy, then replacing the original with the copy.
+If stale data cannot be tolerated, then a "deleted" flag may be used
+in conjunction with a per-entry spinlock in order to allow the search
+function to reject newly deleted data.
+
+
+Answer to Quick Quiz
+
+If the search function drops the per-entry lock before returning, then
+the caller will be processing stale data in any case.  If it is really
+OK to be processing stale data, then you don't need a "deleted" flag.
+If processing stale data really is a problem, then you need to hold the
+per-entry lock across all of the code that uses the value looked up.
diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
new file mode 100644 (file)
index 0000000..7e0c2ab
--- /dev/null
@@ -0,0 +1,67 @@
+RCU Concepts
+
+
+The basic idea behind RCU (read-copy update) is to split destructive
+operations into two parts, one that prevents anyone from seeing the data
+item being destroyed, and one that actually carries out the destruction.
+A "grace period" must elapse between the two parts, and this grace period
+must be long enough that any readers accessing the item being deleted have
+since dropped their references.  For example, an RCU-protected deletion
+from a linked list would first remove the item from the list, wait for
+a grace period to elapse, then free the element.  See the listRCU.txt
+file for more information on using RCU with linked lists.
+
+
+Frequently Asked Questions
+
+o      Why would anyone want to use RCU?
+
+       The advantage of RCU's two-part approach is that RCU readers need
+       not acquire any locks, perform any atomic instructions, write to
+       shared memory, or (on CPUs other than Alpha) execute any memory
+       barriers.  The fact that these operations are quite expensive
+       on modern CPUs is what gives RCU its performance advantages
+       in read-mostly situations.  The fact that RCU readers need not
+       acquire locks can also greatly simplify deadlock-avoidance code.
+
+o      How can the updater tell when a grace period has completed
+       if the RCU readers give no indication when they are done?
+
+       Just as with spinlocks, RCU readers are not permitted to
+       block, switch to user-mode execution, or enter the idle loop.
+       Therefore, as soon as a CPU is seen passing through any of these
+       three states, we know that that CPU has exited any previous RCU
+       read-side critical sections.  So, if we remove an item from a
+       linked list, and then wait until all CPUs have switched context,
+       executed in user mode, or executed in the idle loop, we can
+       safely free up that item.
+
+o      If I am running on a uniprocessor kernel, which can only do one
+       thing at a time, why should I wait for a grace period?
+
+       See the UP.txt file in this directory.
+
+o      How can I see where RCU is currently used in the Linux kernel?
+
+       Search for "rcu_read_lock", "call_rcu", and "synchronize_kernel".
+
+o      What guidelines should I follow when writing code that uses RCU?
+
+       See the checklist.txt file in this directory.
+
+o      Why the name "RCU"?
+
+       "RCU" stands for "read-copy update".  The file listRCU.txt has
+       more information on where this name came from, search for
+       "read-copy update" to find it.
+
+o      I hear that RCU is patented?  What is with that?
+
+       Yes, it is.  There are several known patents related to RCU,
+       search for the string "Patent" in RTFP.txt to find them.
+       Of these, one was allowed to lapse by the assignee, and the
+       others have been contributed to the Linux kernel under GPL.
+
+o      Where can I find more information on RCU?
+
+       See the RTFP.txt file in this directory.
diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000
new file mode 100644 (file)
index 0000000..48ba502
--- /dev/null
@@ -0,0 +1,69 @@
+
+-------------------------------------------------------------------------
+Release Notes for Linux on Intel's IXP2000 Network Processor
+
+Maintained by Deepak Saxena <dsaxena@plexity.net>
+-------------------------------------------------------------------------
+
+1. Overview
+
+Intel's IXP2000 family of NPUs (IXP2400, IXP2800, IXP2850) is designed
+for high-performance network applications such high-availability
+telecom systems. In addition to an XScale core, it contains up to 8
+"MicroEngines" that run special code, several high-end networking 
+interfaces (UTOPIA, SPI, etc), a PCI host bridge, one serial port,
+flash interface, and some other odds and ends. For more information, see:
+
+http://developer.intel.com/design/network/products/npfamily/ixp2xxx.htm
+
+2. Linux Support
+
+Linux currently supports the following features on the IXP2000 NPUS:
+
+- On-chip serial
+- PCI
+- Flash (MTD/JFFS2)
+- I2C through GPIO
+- Timers (watchdog, OS)
+
+That is about all we can support under Linux ATM b/c the core networking
+components of the chip are accessed via Intel's closed source SDK. 
+Please contact Intel directly on issues with using those. There is
+also a mailing list run by some folks at Princeton University that might
+be of helpful:  https://lists.cs.princeton.edu/mailman/listinfo/ixp2xxx
+
+WHATEVER YOU DO, DO NOT POST EMAIL TO THE LINUX-ARM OR LINUX-ARM-KERNEL
+MAILINNG LISTS REGARDING THE INTEL SDK.
+
+3. Supported Platforms
+
+- Intel IXDP2400 Reference Platform
+- Intel IXDP2800 Reference Platform
+- Intel IXDP2401 Reference Platform
+- Intel IXDP2801 Reference Platform
+- RadiSys ENP-2611
+
+4. Usage Notes
+
+- The IXP2000 platforms ususally have rather complex PCI bus topologies
+  with large memory space requirements. In addition, b/c of the way the
+  Intel SDK is designed, devices are enumerated in a vert specific
+  way. B/c of this this, we use "pci=firmware" option in the kernel
+  command line so that we do not re-enumerate the bus.
+
+- IXDP2x01 systems have variable clock tick rates that we cannot determine 
+  via HW registers. The "ixdp2x01_clk=XXX" cmd line options allows you
+  to pass the clock rate to the board port.
+
+5. Thanks
+
+The IXP2000 work has been funded by Intel Corp. and MontaVista Software, Inc.
+
+The following people have contributed patches/comments/etc:
+
+Naeem F. Afzal
+Lennert Buytenhek
+Jeffrey Daly
+
+-------------------------------------------------------------------------
+Last Update: 8/09/2004
diff --git a/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt b/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
new file mode 100644 (file)
index 0000000..831b98c
--- /dev/null
@@ -0,0 +1,44 @@
+               Simtec Electronics EB2410ITX (BAST)
+               ===================================
+
+       http://www.simtec.co.uk/products/EB2410ITX/
+
+Introduction
+------------
+
+  The EB2410ITX is a S3C2410 based development board with a variety of
+  peripherals and expansion connectors. This board is also known by
+  the shortened name of Bast.
+
+
+Configuration
+-------------
+
+  To set the default configuration, use `make bast_defconfig` which
+  supports the commonly used features of this board
+
+
+Support
+-------
+
+  Official support information can be found on the Simtec Electronics
+  website, at the product page http://www.simtec.co.uk/products/EB2410ITX/
+  and http://www.simtec.co.uk/products/EB2410ITX/resources.html
+
+
+MTD
+---
+
+  The NAND and NOR onboard are currently supported in the linux-mtd cvs,
+  and are awaiting merge in the mainline. see the linux-mtd project at
+  http://www.linux-mtd.infradead.org/ for more information.
+
+
+IDE
+---
+
+  Both onboard IDE ports are supported, however there is no support for
+  changing speed of devices, PIO Mode 4 capable drives should be used.
+
+
+(c) 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
new file mode 100644 (file)
index 0000000..0822764
--- /dev/null
@@ -0,0 +1,122 @@
+                       S3C2410 GPIO Control
+                       ====================
+
+Introduction
+------------
+
+  The s3c2410 kernel provides an interface to configure and
+  manipulate the state of the GPIO pins, and find out other
+  information about them.
+
+  There are a number of conditions attached to the configuration
+  of the s3c2410 GPIO system, please read the Samsung provided
+  data-sheet/users manual to find out the complete list.
+
+
+Headers
+-------
+
+  See include/asm-arm/arch-s3c2410/regs-gpio.h for the list
+  of GPIO pins, and the configuration values for them. This
+  is included by using #include <asm/arch/regs-gpio.h>
+
+  The GPIO management functions are defined in the hardware
+  header include/asm-arm/arch-s3c2410/hardware.h which can be
+  included by #include <asm/arch/hardware.h>
+
+  A useful ammount of documentation can be found in the hardware
+  header on how the GPIO functions (and others) work.
+
+  Whilst a number of these functions do make some checks on what
+  is passed to them, for speed of use, they may not always ensure
+  that the user supplied data to them is correct.
+
+
+PIN Numbers
+-----------
+
+  Each pin has an unique number associated with it in regs-gpio.h,
+  eg S3C2410_GPA0 or S3C2410_GPF1. These defines are used to tell
+  the GPIO functions which pin is to be used.
+
+
+Configuring a pin
+-----------------
+
+  The following function allows the configuration of a given pin to
+  be changed.
+
+    void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function);
+
+  Eg:
+
+     s3c2410_gpio_cfgpin(S3C2410_GPA0, S3C2410_GPA0_ADDR0);
+     s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
+
+   which would turn GPA0 into the lowest Address line A0, and set
+   GPE8 to be connected to the SDIO/MMC controller's SDDAT1 line.
+
+
+Reading the current configuration
+---------------------------------
+
+  The current configuration of a pin can be read by using:
+
+  s3c2410_gpio_getcfg(unsigned int pin);
+
+  The return value will be from the same set of values which can be
+  passed to s3c2410_gpio_cfgpin().
+
+
+Configuring a pull-up resistor
+------------------------------
+
+  A large proportion of the GPIO pins on the S3C2410 can have weak
+  pull-up resistors enabled. This can be configured by the following
+  function:
+
+    void s3c2410_gpio_pullup(unsigned int pin, unsigned int to);
+
+  Where the to value is zero to set the pull-up off, and 1 to enable
+  the specified pull-up. Any other values are currently undefined.
+
+
+Getting the state of a PIN
+--------------------------
+
+  The state of a pin can be read by using the function:
+
+    unsigned int s3c2410_gpio_getpin(unsigned int pin);
+
+  This will return either zero or non-zero. Do not count on this
+  function returning 1 if the pin is set.
+
+
+Setting the state of a PIN
+--------------------------
+
+  The value an pin is outputing can be modified by using the following:
+
+    void s3c2410_gpio_setpin(unsigned int pin, unsigned int to);
+
+  Which sets the given pin to the value. Use 0 to write 0, and 1 to
+  set the output to 1.
+
+
+Getting the IRQ number associated with a PIN
+--------------------------------------------
+
+  The following function can map the given pin number to an IRQ
+  number to pass to the IRQ system.
+
+   int s3c2410_gpio_getirq(unsigned int pin);
+
+  Note, not all pins have an IRQ.
+
+
+Authour
+-------
+
+
+Ben Dooks, 03 October 2004
+(c) 2004 Ben Dooks, Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
new file mode 100644 (file)
index 0000000..aa3f83a
--- /dev/null
@@ -0,0 +1,97 @@
+                       S3C24XX ARM Linux Overview
+                       ==========================
+
+
+
+Introduction
+------------
+
+  The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
+  by the 's3c2410' architecture of ARM Linux. Currently the S3C2410 is
+  the only supported CPU in this range.
+
+
+Configuration
+-------------
+
+  A generic S3C2410 configuration is provided, and can be used as the
+  default by `make s3c2410_defconfig`. This configuration has support
+  for all the machines, and the commonly used features on them.
+
+  Certain machines may have their own default configurations as well,
+  please check the machine specific documentation.
+
+
+Machines
+--------
+
+  The currently supported machines are as follows:
+
+  Simtec Electronics EB2410ITX (BAST)
+
+    A general purpose development board, see EB2410ITX.txt for further
+    details
+
+  Samsung SMDK2410
+
+    Samsung's own development board, geared for PDA work.
+
+  Thorcom VR1000
+
+    Custom embedded board
+
+  HP IPAQ 1940
+
+    Handheld (IPAQ), available in several varieties
+
+
+NAND
+----
+
+  The current kernels do not have direct support for the NAND
+  controller, the latest linux-mtd CVS has support for this.
+  See http://www.linux-mtd.infradead.org/
+
+
+Serial
+------
+
+  The s3c2410 serial driver provides support for the internal
+  serial ports. These devices appear as /dev/ttySAC0 through 3.
+
+  To create device nodes for these, use the following commands
+
+    mknod ttySAC0 c 204 64
+    mknod ttySAC1 c 204 65
+    mknod ttySAC2 c 204 66
+
+
+GPIO
+----
+
+  The core contains support for manipulating the GPIO, see the
+  documentation in GPIO.txt in the same directory as this file.
+
+
+Clock Management
+----------------
+
+  The core provides the interface defined in the header file
+  include/asm-arm/hardware/clock.h, to allow control over the
+  various clock units
+
+
+Port Contributors
+-----------------
+
+  Ben Dooks
+  Vincent Sanders
+  Herbert Potzl
+  Arnaud Patard
+  Roc Wu
+
+
+Document Author
+---------------
+
+Ben Dooks, (c) 2004 Simtec Electronics
diff --git a/Documentation/arm/Samsung-S3C24XX/Suspend.txt b/Documentation/arm/Samsung-S3C24XX/Suspend.txt
new file mode 100644 (file)
index 0000000..e12bc32
--- /dev/null
@@ -0,0 +1,106 @@
+                       S3C24XX Suspend Support
+                       =======================
+
+
+Introduction
+------------
+
+  The S3C2410 supports a low-power suspend mode, where the SDRAM is kept
+  in Self-Refresh mode, and all but the essential peripheral blocks are
+  powered down. For more information on how this works, please look
+  at the S3C2410 datasheets from Samsung.
+
+
+Requirements
+------------
+
+  1) A bootloader that can support the necessary resume operation
+
+  2) Support for at least 1 source for resume
+
+  3) CONFIG_PM enabled in the kernel
+
+  4) Any peripherals that are going to be powered down at the same
+     time require suspend/resume support.
+
+
+Resuming
+--------
+
+  The S3C2410 user manual defines the process of sending the CPU to
+  sleep and how it resumes. The default behaviour of the Linux code
+  is to set the GSTATUS3 register to the physical address of the
+  code to resume Linux operation.
+
+  GSTATUS4 is currently left alone by the sleep code, and is free to
+  use for any other purposes (for example, the EB2410ITX uses this to
+  save memory configuration in).
+
+
+Machine Support
+---------------
+
+  The machine specific functions must call the s3c2410_pm_init() function
+  to say that its bootloader is capable of resuming. This can be as
+  simple as adding the following to the machine's definition:
+
+  INITMACHINE(s3c2410_pm_init)
+
+  A board can do its own setup before calling s3c2410_pm_init, if it
+  needs to setup anything else for power management support.
+
+  There is currently no support for over-riding the default method of
+  saving the resume address, if your board requires it, then contact
+  the maintainer and discuss what is required.
+
+  Note, the original method of adding an late_initcall() is wrong,
+  and will end up initialising all compiled machines' pm init!
+
+
+Debugging
+---------
+
+  There are several important things to remember when using PM suspend:
+
+  1) The uart drivers will disable the clocks to the UART blocks when
+     suspending, which means that use of printascii() or similar direct
+     access to the UARTs will cause the debug to stop.
+
+  2) Whilst the pm code itself will attempt to re-enable the UART clocks,
+     care should be taken that any external clock sources that the UARTs
+     rely on are still enabled at that point.
+
+
+Configuration
+-------------
+
+  The S3C2410 specific configuration in `System Type` defines various
+  aspects of how the S3C2410 suspend and resume support is configured
+
+  `S3C2410 PM Suspend debug`
+
+    This option prints messages to the serial console before and after
+    the actual suspend, giving detailed information on what is
+    happening
+
+
+  `S3C2410 PM Suspend Memory CRC`
+
+    Allows the entire memory to be checksummed before and after the
+    suspend to see if there has been any corruption of the contents.
+
+    This support requires the CRC32 function to be enabled.
+
+
+  `S3C2410 PM Suspend CRC Chunksize (KiB)`
+
+    Defines the size of memory each CRC chunk covers. A smaller value
+    will mean that the CRC data block will take more memory, but will
+    identify any faults with better precision
+
+
+Document Author
+---------------
+
+Ben Dooks, (c) 2004 Simtec Electronics
+
diff --git a/Documentation/cdrom/packet-writing.txt b/Documentation/cdrom/packet-writing.txt
new file mode 100644 (file)
index 0000000..d34fcbc
--- /dev/null
@@ -0,0 +1,86 @@
+Getting started quick
+---------------------
+
+- Select packet support in the block device section and UDF support in
+  the file system section.
+
+- Compile and install kernel and modules, reboot.
+
+- You need the udftools package (pktsetup, mkudffs, cdrwtool).
+  Download from http://sourceforge.net/projects/linux-udf/
+
+- Grab a new CD-RW disc and format it (assuming CD-RW is hdc, substitute
+  as appropriate):
+       # cdrwtool -d /dev/hdc -q
+
+- Setup your writer
+       # pktsetup dev_name /dev/hdc
+
+- Now you can mount /dev/pktcdvd/dev_name and copy files to it. Enjoy!
+       # mount /dev/pktcdvd/dev_name /cdrom -t udf -o rw,noatime
+
+
+Packet writing for DVD-RW media
+-------------------------------
+
+DVD-RW discs can be written to much like CD-RW discs if they are in
+the so called "restricted overwrite" mode. To put a disc in restricted
+overwrite mode, run:
+
+       # dvd+rw-format /dev/hdc
+
+You can then use the disc the same way you would use a CD-RW disc:
+
+       # pktsetup dev_name /dev/hdc
+       # mount /dev/pktcdvd/dev_name /cdrom -t udf -o rw,noatime
+
+
+Packet writing for DVD+RW media
+-------------------------------
+
+According to the DVD+RW specification, a drive supporting DVD+RW discs
+shall implement "true random writes with 2KB granularity", which means
+that it should be possible to put any filesystem with a block size >=
+2KB on such a disc. For example, it should be possible to do:
+
+       # mkudffs /dev/hdc
+       # mount /dev/hdc /cdrom -t udf -o rw,noatime
+
+However, some drives don't follow the specification and expect the
+host to perform aligned writes at 32KB boundaries. Other drives do
+follow the specification, but suffer bad performance problems if the
+writes are not 32KB aligned.
+
+Both problems can be solved by using the pktcdvd driver, which always
+generates aligned writes.
+
+       # pktsetup dev_name /dev/hdc
+       # mkudffs /dev/pktcdvd/dev_name
+       # mount /dev/pktcdvd/dev_name /cdrom -t udf -o rw,noatime
+
+
+Notes
+-----
+
+- CD-RW media can usually not be overwritten more than about 1000
+  times, so to avoid unnecessary wear on the media, you should always
+  use the noatime mount option.
+
+- Defect management (ie automatic remapping of bad sectors) has not
+  been implemented yet, so you are likely to get at least some
+  filesystem corruption if the disc wears out.
+
+- Since the pktcdvd driver makes the disc appear as a regular block
+  device with a 2KB block size, you can put any filesystem you like on
+  the disc. For example, run:
+
+       # /sbin/mke2fs /dev/pktcdvd/dev_name
+
+  to create an ext2 filesystem on the disc.
+
+
+Links
+-----
+
+See http://fy.chalmers.se/~appro/linux/DVD+RW/ for more information
+about DVD writing.
diff --git a/Documentation/ckrm/numtasks b/Documentation/ckrm/numtasks
new file mode 100644 (file)
index 0000000..94b4b09
--- /dev/null
@@ -0,0 +1,122 @@
+Introduction
+-------------
+
+Numtasks is a resource controller under the CKRM framework that allows the 
+user/sysadmin to manage the number of tasks a class can create. It also allows
+one to limit the fork rate across the system.
+
+As with any other resource under the CKRM framework, numtasks also assigns
+all the resources to the detault class(/rcfs/taskclass). Since , the number
+of tasks in a system is not limited, this resource controller provides a
+way to set the total number of tasks available in the system through the config
+file. By default this value is 128k(131072). In other words, if not changed,
+the total number of tasks allowed in a system is 131072.
+
+The config variable that affect this is sys_total_tasks.
+
+This resource controller also allows the sysadmin to limit the number of forks
+that are allowed in the system within the specified number of seconds. This
+can be acheived by changing the attributes forkrate and forkrate_interval in 
+the config file. Through this feature one can protect the system from being
+attacked by fork bomb type applications.
+
+Installation
+-------------
+
+1. Configure "Number of Tasks Resource Manager" under CKRM (see
+      Documentation/ckrm/installation). This can be configured as a module
+      also. But, when inserted as a module it cannot be removed.
+
+2. Reboot the system with the new kernel. Insert the module, if compiled
+      as a module.
+
+3. Verify that the memory controller is present by reading the file
+   /rcfs/taskclass/config (should show a line with res=numtasks)
+
+Usage
+-----
+
+For brevity, unless otherwise specified all the following commands are
+executed in the default class (/rcfs/taskclass).
+
+As explained above the config file shows sys_total_tasks and forkrate
+info.
+
+   # cd /rcfs/taskclass
+   # cat config
+   res=numtasks,sys_total_tasks=131072,forkrate=1000000,forkrate_interval=3600
+
+By default, the sys_total_tasks is set to 131072(128k), and forkrate is set
+to 1 million and forkrate_interval is set to 3600 seconds. Which means the
+total number of tasks in a system is limited to 131072 and the forks are 
+limited to 1 million per hour.
+
+sysadmin can change these values by just writing the attribute/value pair
+to the config file.
+
+   # echo res=numtasks,forkrate=100,forkrate_interval=10 > config
+   # cat config
+   res=numtasks,sys_total_tasks=1000,forkrate=100,forkrate_interval=10
+
+   # echo res=numtasks,forkrate=100,forkrate_interval=10 > config
+   # cat config
+   res=numtasks,sys_total_tasks=1000,forkrate=100,forkrate_interval=10
+
+By making total_guarantee and max_limit to be same as sys_total_tasks, 
+sysadmin can make the numbers in shares file be same as the number of tasks
+for a class.
+
+   # echo res=numtasks,total_guarantee=131072,max_limit=131072 > shares
+   # cat shares
+   res=numtasks,guarantee=-2,limit=-2,total_guarantee=131072,max_limit=131072
+
+
+Class creation 
+--------------
+
+   # mkdir c1
+
+Its initial share is don't care. The parent's share values will be unchanged.
+
+Setting a new class share
+-------------------------
+
+'guarantee' specifies the number of tasks this class is entitled to get
+'limit' is the maximum number of tasks this class can get.
+
+Following command will set the guarantee of class c1 to be 25000 and the limit 
+to be 50000
+
+   # echo 'res=numtasks,guarantee=25000,limit=50000' > c1/shares
+   # cat c1/shares     
+   res=numtasks,guarantee=25000,limit=50000,total_guarantee=100,max_limit=100
+
+Limiting forks in a time period
+-------------------------------
+By default, this resource controller allows forking of 1 million tasks in
+an hour.
+
+Folowing command would change it to allow only 100 forks per 10 seconds
+
+   # echo res=numtasks,forkrate=100,forkrate_interval=10 > config
+   # cat config
+   res=numtasks,sys_total_tasks=1000,forkrate=100,forkrate_interval=10
+
+Note that the same set of values is used across the system. In other words,
+each individual class will be allowed 'forkrate' forks in 'forkrate_interval'
+seconds.
+
+Monitoring
+----------
+
+stats file shows statistics of the number of tasks usage of a class
+[root@localhost taskclass]# cat stats
+Number of tasks resource:
+Total Over limit failures: 0
+Total Over guarantee sucesses: 0
+Total Over guarantee failures: 0
+Maximum Over limit failures: 0
+Maximum Over guarantee sucesses: 0
+Maximum Over guarantee failures: 0
+cur_alloc 38; borrowed 0; cnt_guar 131072; cnt_limit 131072 cnt_unused 131072, unused_guarantee 100, cur_max_limit 0
+
diff --git a/Documentation/cpu-freq/cpufreq-nforce2.txt b/Documentation/cpu-freq/cpufreq-nforce2.txt
new file mode 100644 (file)
index 0000000..9188337
--- /dev/null
@@ -0,0 +1,19 @@
+
+The cpufreq-nforce2 driver changes the FSB on nVidia nForce2 plattforms.
+
+This works better than on other plattforms, because the FSB of the CPU
+can be controlled independently from the PCI/AGP clock.
+
+The module has two options:
+
+       fid:     multiplier * 10 (for example 8.5 = 85)
+       min_fsb: minimum FSB
+
+If not set, fid is calculated from the current CPU speed and the FSB.
+min_fsb defaults to FSB at boot time - 50 MHz.
+
+IMPORTANT: The available range is limited downwards!
+           Also the minimum available FSB can differ, for systems 
+           booting with 200 MHz, 150 should always work.
+
+
diff --git a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb
new file mode 100644 (file)
index 0000000..e3d650b
--- /dev/null
@@ -0,0 +1,247 @@
+Documentation for dib3000mb frontend driver and dibusb device driver
+====================================================================
+
+Copyright (C) 2004 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)
+       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 and AN2235)
+       http://82.161.246.249/products-tvbox.html
+
+- Compro Videomate DVB-U2000 - DVB-T USB
+       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
+========================
+- Twinhan MagicBox II
+       http://www.twinhan.com/product_terrestrial_7.asp
+
+- Yakumo DVB-T mobile
+       http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
+
+- DiBcom USB2.0 DVB-T reference device (non-public)
+
+
+0. NEWS:
+  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, 2.6.8.1, 2.6.9 .
+
+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 :).
+
+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://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain
+
+for USB1.1 (AN2235) (a few Artec T1 devices)
+http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-an2235-1.fw?rev=1.1&content-type=text/plain
+
+for USB2.0 (FX2)
+http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-6.0.0.5.fw?rev=1.1&content-type=text/plain
+
+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 dvb-dibusb
+
+modprobe dib3000mb 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
+as a slave device in vdr, was not working for me. Some work has to be done
+(patches and comments are very welcome).
+
+2. Known problems and bugs
+
+TODO:
+- signal-quality and strength calculations
+
+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.h-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 current 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, but watching a channel while
+recording another channel on the same frequency simply does not work.
+This applies to all USB1.1 DVB-T devices.
+
+A special problem of the dibusb for the USB1.1 is, that the USB control
+IC has a problem with write accesses while having MPEG2-streaming
+enabled. When you set another pid while receiving MPEG2-TS it happens, that
+the stream is disturbed and probably data is lost (results in distortions of
+the video or strange beeps within the audio stream). DiBcom is preparing a
+firmware especially for Linux which perhaps solves the problem.
+
+Especially VDR users are victoms of this bug. VDR frequently requests new PIDs
+due the automatic scanning (introduced in 1.3.x, afaik) and epg-scan. Disabling
+these features is maybe a solution. Additionally this behaviour of VDR exceeds
+the USB1.1 bandwidth.
+
+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 and dib3000mb 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.
+
+   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/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
new file mode 100644 (file)
index 0000000..e9964b7
--- /dev/null
@@ -0,0 +1,339 @@
+#!/usr/bin/perl
+#     DVB firmware extractor
+#
+#     (c) 2004 Andrew de Quincey
+#
+#     This 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.
+
+use File::Temp qw/ tempdir /;
+use IO::Handle;
+
+@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" );
+
+# Check args
+syntax() if (scalar(@ARGV) != 1);
+$cid = $ARGV[0];
+
+# Do it!
+for($i=0; $i < scalar(@components); $i++) {
+    if ($cid eq $components[$i]) {
+       $outfile = eval($cid);
+       die $@ if $@;
+       print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n";
+       exit(0);
+    }
+}
+
+# If we get here, it wasn't found
+print STDERR "Unknown component \"$cid\"\n";
+syntax();
+
+
+
+
+# ---------------------------------------------------------------
+# Firmware-specific extraction subroutines
+
+sub sp8870 {
+    my $sourcefile = "tt_Premium_217g.zip";
+    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $hash = "53970ec17a538945a6d8cb608a7b3899";
+    my $outfile = "dvb-fe-sp8870.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $hash);
+    copy("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $outfile);
+
+    $outfile;
+}
+
+sub sp887x {
+    my $sourcefile = "Dvbt1.3.57.6.zip";
+    my $url = "http://www.avermedia.com/software/$sourcefile";
+    my $cabfile = "DVBT Net  Ver1.3.57.6/disk1/data1.cab";
+    my $hash = "237938d53a7f834c05c42b894ca68ac3";
+    my $outfile = "dvb-fe-sp887x.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+    checkunshield();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    unshield("$tmpdir/$cabfile", $tmpdir);
+    verify("$tmpdir/sc_main.mc", $hash);
+    copy("$tmpdir/sc_main.mc", $outfile);
+
+    $outfile;
+}
+
+sub tda10045 {
+    my $sourcefile = "tt_budget_217g.zip";
+    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $hash = "2105fd5bf37842fbcdfa4bfd58f3594a";
+    my $outfile = "dvb-fe-tda10045.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x37ef9, 30555, "$tmpdir/fwtmp");
+    verify("$tmpdir/fwtmp", $hash);
+    copy("$tmpdir/fwtmp", $outfile);
+
+    $outfile;
+}
+
+sub tda10046 {
+    my $sourcefile = "tt_budget_217g.zip";
+    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+    my $hash = "a25b579e37109af60f4a36c37893957c";
+    my $outfile = "dvb-fe-tda10046.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x3f731, 24479, "$tmpdir/fwtmp");
+    verify("$tmpdir/fwtmp", $hash);
+    copy("$tmpdir/fwtmp", $outfile);
+
+    $outfile;
+}
+
+sub av7110 {
+    my $sourcefile = "dvb-ttpci-01.fw-261c";
+    my $url = "http://www.linuxtv.org/download/dvb/firmware/$sourcefile";
+    my $hash = "7b263de6b0b92d2347319c65adc7d4fb";
+    my $outfile = "dvb-ttpci-01.fw";
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    verify($sourcefile, $hash);
+    copy($sourcefile, $outfile);
+
+    $outfile;
+}
+
+sub dec2000t {
+    my $sourcefile = "dec217g.exe";
+    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
+    my $hash = "bd86f458cee4a8f0a8ce2d20c66215a9";
+    my $outfile = "dvb-ttusb-dec-2000t.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $hash);
+    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $outfile);
+
+    $outfile;
+}
+
+sub dec2540t {
+    my $sourcefile = "dec217g.exe";
+    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
+    my $hash = "53e58f4f5b5c2930beee74a7681fed92";
+    my $outfile = "dvb-ttusb-dec-2540t.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $hash);
+    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $outfile);
+
+    $outfile;
+}
+
+sub dec3000s {
+    my $sourcefile = "dec217g.exe";
+    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
+    my $hash = "b013ececea83f4d6d8d2a29ac7c1b448";
+    my $outfile = "dvb-ttusb-dec-3000s.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $hash);
+    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $outfile);
+
+    $outfile;
+}
+
+sub vp7041 {
+    my $sourcefile = "2.422.zip";
+    my $url = "http://www.twinhan.com/files/driver/USB-Ter/$sourcefile";
+    my $hash = "e88c9372d1f66609a3e7b072c53fbcfe";
+    my $outfile = "dvb-vp7041-2.422.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 12503, 3036, "$tmpdir/fwtmp1");
+    extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 2207, 10274, "$tmpdir/fwtmp2");
+
+    my $CMD = "\000\001\000\222\177\000";
+    my $PAD = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
+    my ($FW);
+    open $FW, ">$tmpdir/fwtmp3";
+    print $FW "$CMD\001$PAD";
+    print $FW "$CMD\001$PAD";
+    appendfile($FW, "$tmpdir/fwtmp1");
+    print $FW "$CMD\000$PAD";
+    print $FW "$CMD\001$PAD";
+    appendfile($FW, "$tmpdir/fwtmp2");
+    print $FW "$CMD\001$PAD";
+    print $FW "$CMD\000$PAD";
+    close($FW);
+
+    verify("$tmpdir/fwtmp3", $hash);
+    copy("$tmpdir/fwtmp3", $outfile);
+
+    $outfile;
+}
+
+sub dibusb {
+       my $url = "http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain";
+       my $outfile = "dvb-dibusb-5.0.0.11.fw";
+       my $hash = "fa490295a527360ca16dcdf3224ca243";
+
+       checkstandard();
+
+       wgetfile($outfile, $url);
+       verify($outfile,$hash);
+
+       $outfile;
+}
+
+# ---------------------------------------------------------------
+# Utilities
+
+sub checkstandard {
+    if (system("which unzip > /dev/null 2>&1")) {
+       die "This firmware requires the unzip command - see ftp://ftp.info-zip.org/pub/infozip/UnZip.html\n";
+    }
+    if (system("which md5sum > /dev/null 2>&1")) {
+       die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n";
+    }
+    if (system("which wget > /dev/null 2>&1")) {
+       die "This firmware requires the wget command - see http://wget.sunsite.dk/\n";
+    }
+}
+
+sub checkunshield {
+    if (system("which unshield > /dev/null 2>&1")) {
+       die "This firmware requires the unshield command - see http://sourceforge.net/projects/synce/\n";
+    }
+}
+
+sub wgetfile {
+    my ($sourcefile, $url) = @_;
+
+    if (! -f $sourcefile) {
+       system("wget -O \"$sourcefile\" \"$url\"") and die "wget failed - unable to download firmware";
+    }
+}
+
+sub unzip {
+    my ($sourcefile, $todir) = @_;
+
+    $status = system("unzip -q -o -d \"$todir\" \"$sourcefile\" 2>/dev/null" );
+    if ((($status >> 8) > 2) || (($status & 0xff) != 0)) {
+       die ("unzip failed - unable to extract firmware");
+    }
+}
+
+sub unshield {
+    my ($sourcefile, $todir) = @_;
+
+    system("unshield -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
+}
+
+sub verify {
+    my ($filename, $hash) = @_;
+    my ($testhash);
+
+    open(CMD, "md5sum \"$filename\"|");
+    $testhash = <CMD>;
+    $testhash =~ /([a-zA-Z0-9]*)/;
+    $testhash = $1;
+    close CMD;
+    die "Hash of extracted file does not match!\n" if ($testhash ne $hash);
+}
+
+sub copy {
+    my ($from, $to) = @_;
+
+    system("cp -f \"$from\" \"$to\"") and die ("cp failed");
+}
+
+sub extract {
+    my ($infile, $offset, $length, $outfile) = @_;
+    my ($chunklength, $buf, $rcount);
+
+    open INFILE, "<$infile";
+    open OUTFILE, ">$outfile";
+    sysseek(INFILE, $offset, SEEK_SET);
+    while($length > 0) {
+       # Calc chunk size
+       $chunklength = 2048;
+       $chunklength = $length if ($chunklength > $length);
+
+       $rcount = sysread(INFILE, $buf, $chunklength);
+       die "Ran out of data\n" if ($rcount != $chunklength);
+       syswrite(OUTFILE, $buf);
+       $length -= $rcount;
+    }
+    close INFILE;
+    close OUTFILE;
+}
+
+sub appendfile {
+    my ($FH, $infile) = @_;
+    my ($buf);
+
+    open INFILE, "<$infile";
+    while(1) {
+       $rcount = sysread(INFILE, $buf, 2048);
+       last if ($rcount == 0);
+       print $FH $buf;
+    }
+    close(INFILE);
+}
+
+sub syntax() {
+    print STDERR "syntax: get_dvb_firmware <component>\n";
+    print STDERR "Supported components:\n";
+    for($i=0; $i < scalar(@components); $i++) {
+       print STDERR "\t" . $components[$i] . "\n";
+    }
+    exit(1);
+}
diff --git a/Documentation/dvb/udev.txt b/Documentation/dvb/udev.txt
new file mode 100644 (file)
index 0000000..68ee224
--- /dev/null
@@ -0,0 +1,46 @@
+The DVB subsystem currently registers to the sysfs subsystem using the
+"class_simple" interface.
+
+This means that only the basic informations like module loading parameters
+are presented through sysfs. Other things that might be interesting are
+currently *not* available.
+
+Nevertheless it's now possible to add proper udev rules so that the
+DVB device nodes are created automatically.
+
+We assume that you have udev already up and running and that have been
+creating the DVB device nodes manually up to now due to the missing sysfs
+support.
+
+0. Don't forget to disable your current method of creating the
+device nodes manually.
+
+1. Unfortunately, you'll need a helper script to transform the kernel
+sysfs device name into the well known dvb adapter / device naming scheme.
+The script should be called "dvb.sh" and should be placed into a script
+dir where udev can execute it, most likely /etc/udev/scripts/
+
+So, create a new file /etc/udev/scripts/dvb.sh and add the following:
+------------------------------schnipp------------------------------------------------
+#!/bin/sh
+/bin/echo $1 | /bin/sed -e 's,dvb\([0-9]\)\.\([^0-9]*\)\([0-9]\),dvb/adapter\1/\2\3,'
+------------------------------schnipp------------------------------------------------
+
+Don't forget to make the script executable with "chmod".
+
+1. You need to create a proper udev rule that will create the device nodes
+like you know them. All real distributions out there scan the /etc/udev/rules.d
+directory for rule files. The main udev configuration file /etc/udev/udev.conf
+will tell you the directory where the rules are, most likely it's /etc/udev/rules.d/
+
+Create a new rule file in that directory called "dvb.rule" and add the following line:
+------------------------------schnipp------------------------------------------------
+KERNEL="dvb*", PROGRAM="/etc/udev/scripts/dvb.sh %k", NAME="%c"
+------------------------------schnipp------------------------------------------------
+
+If you want more control over the device nodes (for example a special group membership)
+have a look at "man udev".
+
+For every device that registers to the sysfs subsystem with a "dvb" prefix,
+the helper script /etc/udev/scripts/dvb.sh is invoked, which will then
+create the proper device node in your /dev/ directory.
diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub
new file mode 100644 (file)
index 0000000..2626ba9
--- /dev/null
@@ -0,0 +1,33 @@
+MODULE: i2c-stub
+
+DESCRIPTION:
+
+This module is a very simple fake I2C/SMBus driver.  It implements three
+types of SMBus commands: write quick, (r/w) byte data, and (r/w) word data.
+
+No hardware is needed nor associated with this module.  It will accept write
+quick commands to all addresses; it will respond to the other commands (also
+to all addresses) by reading from or writing to an array in memory.  It will
+also spam the kernel logs for every command it handles.
+
+The typical use-case is like this:
+       1. load this module
+       2. use i2cset (from lm_sensors project) to pre-load some data
+       3. load the target sensors chip driver module
+       4. observe its behavior in the kernel log
+
+CAVEATS:
+
+There are independent arrays for byte/data and word/data commands.  Depending
+on if/how a target driver mixes them, you'll need to be careful.
+
+If your target driver polls some byte or word waiting for it to change, the
+stub could lock it up.  Use i2cset to unlock it.
+
+If the hardware for your driver has banked registers (e.g. Winbond sensors
+chips) this module will not work well - although it could be extended to
+support that pretty easily.
+
+If you spam it hard enough, printk can be lossy.  This module really wants
+something like relayfs.
+
diff --git a/Documentation/i2o/README b/Documentation/i2o/README
new file mode 100644 (file)
index 0000000..9aa6ddb
--- /dev/null
@@ -0,0 +1,63 @@
+
+       Linux I2O Support       (c) Copyright 1999 Red Hat Software
+                                       and others.
+
+       This 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 (so far)
+
+Alan Cox, Building Number Three Ltd.
+       Core code, SCSI and Block OSMs
+
+Steve Ralston, LSI Logic Corp.
+       Debugging SCSI and Block OSM
+
+Deepak Saxena, Intel Corp.
+       Various core/block extensions
+       /proc interface, bug fixes
+       Ioctl interfaces for control
+       Debugging LAN OSM
+
+Philip Rumpf
+       Fixed assorted dumb SMP locking bugs
+
+Juha Sievanen, University of Helsinki Finland
+       LAN OSM code
+       /proc interface to LAN class
+       Bug fixes
+       Core code extensions
+
+Auvo Häkkinen, University of Helsinki Finland
+       LAN OSM code
+       /Proc interface to LAN class
+       Bug fixes
+       Core code extensions
+
+Taneli Vähäkangas, University of Helsinki Finland
+       Fixes to i2o_config
+
+CREDITS
+
+       This work was made possible by
+
+Red Hat Software
+       Funding for the Building #3 part of the project
+
+Symbios Logic (Now LSI)
+       Host adapters, hints, known to work platforms when I hit
+       compatibility problems
+
+BoxHill Corporation
+       Loan of initial FibreChannel disk array used for development work.
+
+European Comission
+       Funding the work done by the University of Helsinki
+
+SysKonnect
+        Loan of FDDI and Gigabit Ethernet cards
+
+ASUSTeK
+        Loan of I2O motherboard
diff --git a/Documentation/i2o/ioctl b/Documentation/i2o/ioctl
new file mode 100644 (file)
index 0000000..3e17497
--- /dev/null
@@ -0,0 +1,394 @@
+
+Linux I2O User Space Interface
+rev 0.3 - 04/20/99
+
+=============================================================================
+Originally written by Deepak Saxena(deepak@plexity.net)
+Currently maintained by Deepak Saxena(deepak@plexity.net)
+=============================================================================
+
+I. Introduction
+
+The Linux I2O subsystem provides a set of ioctl() commands that can be
+utilized by user space applications to communicate with IOPs and devices
+on individual IOPs. This document defines the specific ioctl() commands
+that are available to the user and provides examples of their uses.
+
+This document assumes the reader is familiar with or has access to the
+I2O specification as no I2O message parameters are outlined.  For information
+on the specification, see http://www.i2osig.org
+
+This document and the I2O user space interface are currently maintained
+by Deepak Saxena.  Please send all comments, errata, and bug fixes to
+deepak@csociety.purdue.edu
+
+II. IOP Access
+
+Access to the I2O subsystem is provided through the device file named
+/dev/i2o/ctl.  This file is a character file with major number 10 and minor
+number 166.  It can be created through the following command:
+
+   mknod /dev/i2o/ctl c 10 166
+
+III. Determining the IOP Count
+
+   SYNOPSIS
+
+   ioctl(fd, I2OGETIOPS,  int *count);
+
+   u8 count[MAX_I2O_CONTROLLERS];
+
+   DESCRIPTION
+
+   This function returns the system's active IOP table.  count should
+   point to a buffer containing MAX_I2O_CONTROLLERS entries.  Upon
+   returning, each entry will contain a non-zero value if the given
+   IOP unit is active, and NULL if it is inactive or non-existent.
+
+   RETURN VALUE.
+
+   Returns 0 if no errors occur, and -1 otherwise.  If an error occurs,
+   errno is set appropriately:
+
+     EFAULT   Invalid user space pointer was passed
+
+IV. Getting Hardware Resource Table
+
+   SYNOPSIS
+
+   ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function returns the Hardware Resource Table of the IOP specified
+   by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of
+   the data is written into *(hrt->reslen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1
+   is returned and errno is set appropriately:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(hrt->reslen)
+
+V. Getting Logical Configuration Table
+
+   SYNOPSIS
+
+   ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct);
+
+      struct i2o_cmd_hrtlct
+      {
+         u32   iop;      /* IOP unit number */
+         void  *resbuf;  /* Buffer for result */
+         u32   *reslen;  /* Buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function returns the Logical Configuration Table of the IOP specified
+   by lct->iop in the buffer pointed to by lct->resbuf. The actual size of
+   the data is written into *(lct->reslen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur. If an error occurs, -1
+   is returned and errno is set appropriately:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(lct->reslen)
+
+VI. Settting Parameters
+
+   SYNOPSIS
+
+   ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops);
+
+      struct i2o_cmd_psetget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsSet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is
+   sent through the ops->opbuf buffer, and the result list is written
+   into the buffer pointed to by ops->resbuf.  The number of bytes
+   written is placed into *(ops->reslen).
+
+   RETURNS
+
+   The return value is the size in bytes of the data written into
+   ops->resbuf if no errors occur.  If an error occurs, -1 is returned
+   and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+   A return value of 0 does not mean that the value was actually
+   changed properly on the IOP.  The user should check the result
+   list to determine the specific status of the transaction.
+
+VII. Getting Parameters
+
+   SYNOPSIS
+
+   ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops);
+
+      struct i2o_parm_setget
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device TID */
+         void  *opbuf;   /* Operation List buffer */
+         u32   oplen;    /* Operation List buffer length in bytes */
+         void  *resbuf;  /* Result List buffer */
+         u32   *reslen;  /* Result List buffer length in bytes */
+      };
+
+   DESCRIPTION
+
+   This function posts a UtilParamsGet message to the device identified
+   by ops->iop and ops->tid.  The operation list for the message is
+   sent through the ops->opbuf buffer, and the result list is written
+   into the buffer pointed to by ops->resbuf.  The actual size of data
+   written is placed into *(ops->reslen).
+
+   RETURNS
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+   A return value of 0 does not mean that the value was actually
+   properly retreived.  The user should check the result list
+   to determine the specific status of the transaction.
+
+VIII. Downloading Software
+
+   SYNOPSIS
+
+   ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;       /* IOP unit number */
+         u8    flags;     /* DownloadFlags field */
+         u8    sw_type;   /* Software type */
+         u32   sw_id;     /* Software ID */
+         void  *buf;      /* Pointer to software buffer */
+         u32   *swlen;    /* Length of software buffer */
+         u32   *maxfrag;  /* Number of fragments */
+         u32   *curfrag;  /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function downloads a software fragment pointed by sw->buf
+   to the iop identified by sw->iop. The DownloadFlags, SwID, SwType
+   and SwSize fields of the ExecSwDownload message are filled in with
+   the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be sent in order and be 8K in size. The last
+   fragment _may_ be shorter, however. The kernel will compute its
+   size based on information in the sw->swlen field.
+
+   Please note that SW transfers can take a long time.
+
+   RETURNS
+
+   This function returns 0 no errors occur. If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+IX. Uploading Software
+
+   SYNOPSIS
+
+   ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags;   /* UploadFlags */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Pointer to software buffer */
+         u32   *swlen;   /* Length of software buffer */
+         u32   *maxfrag; /* Number of fragments */
+         u32   *curfrag; /* Current fragment number */
+      };
+
+   DESCRIPTION
+
+   This function uploads a software fragment from the IOP identified
+   by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields.
+   The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload
+   message are filled in with the values of sw->flags, sw->sw_id,
+   sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be requested in order and be 8K in size. The
+   user is responsible for allocating memory pointed by sw->buf. The
+   last fragment _may_ be shorter.
+
+   Please note that SW transfers can take a long time.
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+X. Removing Software
+
+   SYNOPSIS
+
+   ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw);
+
+      struct i2o_sw_xfer
+      {
+         u32   iop;      /* IOP unit number */
+         u8    flags;   /* RemoveFlags */
+         u8    sw_type;  /* Software type */
+         u32   sw_id;    /* Software ID */
+         void  *buf;     /* Unused */
+         u32   *swlen;   /* Length of the software data */
+         u32   *maxfrag; /* Unused */
+         u32   *curfrag; /* Unused */
+      };
+
+   DESCRIPTION
+
+   This function removes software from the IOP identified by sw->iop.
+   The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message
+   are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and
+   *(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses
+   *(sw->swlen) value to verify correct identication of the module to remove.
+   The actual size of the module is written into *(sw->swlen).
+
+   RETURNS
+
+   This function returns 0 if no errors occur.  If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+X. Validating Configuration
+
+   SYNOPSIS
+
+   ioctl(fd, I2OVALIDATE, int *iop);
+       u32 iop;
+
+   DESCRIPTION
+
+   This function posts an ExecConfigValidate message to the controller
+   identified by iop. This message indicates that the current
+   configuration is accepted. The iop changes the status of suspect drivers
+   to valid and may delete old drivers from its store.
+
+   RETURNS
+
+   This function returns 0 if no erro occur.  If an error occurs, -1 is
+   returned and errno is set appropriatly:
+
+      ETIMEDOUT   Timeout waiting for reply message
+      ENXIO       Invalid IOP number
+
+XI. Configuration Dialog
+
+   SYNOPSIS
+
+   ioctl(fd, I2OHTML, struct i2o_html *htquery);
+      struct i2o_html
+      {
+         u32   iop;      /* IOP unit number */
+         u32   tid;      /* Target device ID */
+         u32   page;     /* HTML page */
+         void  *resbuf;  /* Buffer for reply HTML page */
+         u32   *reslen;  /* Length in bytes of reply buffer */
+         void  *qbuf;    /* Pointer to HTTP query string */
+         u32   qlen;     /* Length in bytes of query string buffer */
+      };
+
+   DESCRIPTION
+
+   This function posts an UtilConfigDialog message to the device identified
+   by htquery->iop and htquery->tid.  The requested HTML page number is
+   provided by the htquery->page field, and the resultant data is stored
+   in the buffer pointed to by htquery->resbuf.  If there is an HTTP query
+   string that is to be sent to the device, it should be sent in the buffer
+   pointed to by htquery->qbuf.  If there is no query string, this field
+   should be set to NULL. The actual size of the reply received is written
+   into *(htquery->reslen).
+
+   RETURNS
+
+   This function returns 0 if no error occur. If an error occurs, -1
+   is returned and errno is set appropriatly:
+
+      EFAULT      Invalid user space pointer was passed
+      ENXIO       Invalid IOP number
+      ENOBUFS     Buffer not large enough.  If this occurs, the required
+                  buffer length is written into *(ops->reslen)
+      ETIMEDOUT   Timeout waiting for reply message
+      ENOMEM      Kernel memory allocation error
+
+XII. Events
+
+    In the process of determining this.  Current idea is to have use
+    the select() interface to allow user apps to periodically poll
+    the /dev/i2o/ctl device for events.  When select() notifies the user
+    that an event is available, the user would call read() to retrieve
+    a list of all the events that are pending for the specific device.
+
+=============================================================================
+Revision History
+=============================================================================
+
+Rev 0.1 - 04/01/99
+- Initial revision
+
+Rev 0.2 - 04/06/99
+- Changed return values to match UNIX ioctl() standard.  Only return values
+  are 0 and -1.  All errors are reported through errno.
+- Added summary of proposed possible event interfaces
+
+Rev 0.3 - 04/20/99
+- Changed all ioctls() to use pointers to user data instead of actual data
+- Updated error values to match the code
diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt
new file mode 100644 (file)
index 0000000..f51eb4b
--- /dev/null
@@ -0,0 +1,144 @@
+SERIAL DEVICE NAMING
+
+    As of 2.6.10, serial devices on ia64 are named based on the
+    order of ACPI and PCI enumeration.  The first device in the
+    ACPI namespace (if any) becomes /dev/ttyS0, the second becomes
+    /dev/ttyS1, etc., and PCI devices are named sequentially
+    starting after the ACPI devices.
+
+    Prior to 2.6.10, there were confusing exceptions to this:
+
+       - Firmware on some machines (mostly from HP) provides an HCDP
+         table[1] that tells the kernel about devices that can be used
+         as a serial console.  If the user specified "console=ttyS0"
+         or the EFI ConOut path contained only UART devices, the
+         kernel registered the device described by the HCDP as
+         /dev/ttyS0.
+
+       - If there was no HCDP, we assumed there were UARTs at the
+         legacy COM port addresses (I/O ports 0x3f8 and 0x2f8), so
+         the kernel registered those as /dev/ttyS0 and /dev/ttyS1.
+
+    Any additional ACPI or PCI devices were registered sequentially
+    after /dev/ttyS0 as they were discovered.
+
+    With an HCDP, device names changed depending on EFI configuration
+    and "console=" arguments.  Without an HCDP, device names didn't
+    change, but we registered devices that might not really exist.
+
+    For example, an HP rx1600 with a single built-in serial port
+    (described in the ACPI namespace) plus an MP[2] (a PCI device) has
+    these ports:
+
+                                  pre-2.6.10      pre-2.6.10
+                    MMIO         (EFI console    (EFI console
+                   address        on builtin)     on MP port)    2.6.10
+                  ==========      ==========      ==========     ======
+      builtin     0xff5e0000        ttyS0           ttyS1         ttyS0
+      MP UPS      0xf8031000        ttyS1           ttyS2         ttyS1
+      MP Console  0xf8030000        ttyS2           ttyS0         ttyS2
+      MP 2        0xf8030010        ttyS3           ttyS3         ttyS3
+      MP 3        0xf8030038        ttyS4           ttyS4         ttyS4
+
+CONSOLE SELECTION
+
+    EFI knows what your console devices are, but it doesn't tell the
+    kernel quite enough to actually locate them.  The DIG64 HCDP
+    table[1] does tell the kernel where potential serial console
+    devices are, but not all firmware supplies it.  Also, EFI supports
+    multiple simultaneous consoles and doesn't tell the kernel which
+    should be the "primary" one.
+
+    So how do you tell Linux which console device to use?
+
+       - If your firmware supplies the HCDP, it is simplest to
+         configure EFI with a single device (either a UART or a VGA
+         card) as the console.  Then you don't need to tell Linux
+         anything; the kernel will automatically use the EFI console.
+
+         (This works only in 2.6.6 or later; prior to that you had
+         to specify "console=ttyS0" to get a serial console.)
+
+       - Without an HCDP, Linux defaults to a VGA console unless you
+         specify a "console=" argument.
+
+    NOTE: Don't assume that a serial console device will be /dev/ttyS0.
+    It might be ttyS1, ttyS2, etc.  Make sure you have the appropriate
+    entries in /etc/inittab (for getty) and /etc/securetty (to allow
+    root login).
+
+EARLY SERIAL CONSOLE
+
+    The kernel can't start using a serial console until it knows where
+    the device lives.  Normally this happens when the driver enumerates
+    all the serial devices, which can happen a minute or more after the
+    kernel starts booting.
+
+    2.6.10 and later kernels have an "early uart" driver that works
+    very early in the boot process.  The kernel will automatically use
+    this if the user supplies an argument like "console=uart,io,0x3f8",
+    or if the EFI console path contains only a UART device and the
+    firmware supplies an HCDP.
+
+TROUBLESHOOTING SERIAL CONSOLE PROBLEMS
+
+    No kernel output after elilo prints "Uncompressing Linux... done":
+
+       - You specified "console=ttyS0" but Linux changed the device
+         to which ttyS0 refers.  Configure exactly one EFI console
+         device[3] and remove the "console=" option.
+
+       - The EFI console path contains both a VGA device and a UART.
+         EFI and elilo use both, but Linux defaults to VGA.  Remove
+         the VGA device from the EFI console path[3].
+
+       - Multiple UARTs selected as EFI console devices.  EFI and
+         elilo use all selected devices, but Linux uses only one.
+         Make sure only one UART is selected in the EFI console
+         path[3].
+
+       - You're connected to an HP MP port[2] but have a non-MP UART
+         selected as EFI console device.  EFI uses the MP as a
+         console device even when it isn't explicitly selected.
+         Either move the console cable to the non-MP UART, or change
+         the EFI console path[3] to the MP UART.
+
+    Long pause (60+ seconds) between "Uncompressing Linux... done" and
+    start of kernel output:
+
+       - No early console because you used "console=ttyS<n>".  Remove
+         the "console=" option if your firmware supplies an HCDP.
+
+       - If you don't have an HCDP, the kernel doesn't know where
+         your console lives until the driver discovers serial
+         devices.  Use "console=uart, io,0x3f8" (or appropriate
+         address for your machine).
+
+    Kernel and init script output works fine, but no "login:" prompt:
+
+       - Add getty entry to /etc/inittab for console tty.  Look for
+         the "Adding console on ttyS<n>" message that tells you which
+         device is the console.
+
+    "login:" prompt, but can't login as root:
+
+       - Add entry to /etc/securetty for console tty.
+
+
+
+[1] http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
+    The table was originally defined as the "HCDP" for "Headless
+    Console/Debug Port."  The current version is the "PCDP" for
+    "Primary Console and Debug Port Devices."
+
+[2] The HP MP (management processor) is a PCI device that provides
+    several UARTs.  One of the UARTs is often used as a console; the
+    EFI Boot Manager identifies it as "Acpi(HWP0002,700)/Pci(...)/Uart".
+    The external connection is usually a 25-pin connector, and a
+    special dongle converts that to three 9-pin connectors, one of
+    which is labelled "Console."
+
+[3] EFI console devices are configured using the EFI Boot Manager
+    "Boot option maintenance" menu.  You may have to interrupt the
+    boot sequence to use this menu, and you will have to reset the
+    box after changing console configuration.
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
new file mode 100644 (file)
index 0000000..c437b1a
--- /dev/null
@@ -0,0 +1,474 @@
+                   IBM ThinkPad ACPI Extras Driver
+
+                            Version 0.8
+                          8 November 2004
+
+               Borislav Deianov <borislav@users.sf.net>
+                     http://ibm-acpi.sf.net/
+
+
+This is a Linux ACPI driver for the IBM ThinkPad laptops. It aims to
+support various features of these laptops which are accessible through
+the ACPI framework but not otherwise supported by the generic Linux
+ACPI drivers.
+
+
+Status
+------
+
+The features currently supported are the following (see below for
+detailed description):
+
+       - Fn key combinations
+       - Bluetooth enable and disable
+       - video output switching, expansion control     
+       - ThinkLight on and off
+       - limited docking and undocking
+       - UltraBay eject
+       - Experimental: CMOS control
+       - Experimental: LED control
+       - Experimental: ACPI sounds
+
+A compatibility table by model and feature is maintained on the web
+site, http://ibm-acpi.sf.net/. I appreciate any success or failure
+reports, especially if they add to or correct the compatibility table.
+Please include the following information in your report:
+
+       - ThinkPad model name
+       - a copy of your DSDT, from /proc/acpi/dsdt
+       - which driver features work and which don't
+       - the observed behavior of non-working features
+
+Any other comments or patches are also more than welcome.
+
+
+Installation
+------------
+
+If you are compiling this driver as included in the Linux kernel
+sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
+ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes
+how to install this driver when downloaded from the web site.
+
+First, you need to get a kernel with ACPI support up and running.
+Please refer to http://acpi.sourceforge.net/ for help with this
+step. How successful you will be depends a lot on you ThinkPad model,
+the kernel you are using and any additional patches applied. The
+kernel provided with your distribution may not be good enough. I
+needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get
+ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not
+be supported at all.
+
+Assuming you have the basic ACPI support working (e.g. you can see the
+/proc/acpi directory), follow the following steps to install this
+driver:
+
+       - unpack the archive:
+
+               tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y
+
+       - compile the driver:
+
+               make
+
+       - install the module in your kernel modules directory:
+
+               make install
+
+       - load the module:
+
+               modprobe ibm_acpi
+
+After loading the module, check the "dmesg" output for any error messages.
+
+
+Features
+--------
+
+The driver creates the /proc/acpi/ibm directory. There is a file under
+that directory for each feature described below. Note that while the
+driver is still in the alpha stage, the exact proc file format and
+commands supported by the various features is guaranteed to change
+frequently.
+
+Driver Version -- /proc/acpi/ibm/driver
+--------------------------------------
+
+The driver name and version. No commands can be written to this file.
+
+Hot Keys -- /proc/acpi/ibm/hotkey
+---------------------------------
+
+Without this driver, only the Fn-F4 key (sleep button) generates an
+ACPI event. With the driver loaded, the hotkey feature enabled and the
+mask set (see below), the various hot keys generate ACPI events in the
+following format:
+
+       ibm/hotkey HKEY 00000080 0000xxxx
+
+The last four digits vary depending on the key combination pressed.
+All labeled Fn-Fx key combinations generate distinct events. In
+addition, the lid microswitch and some docking station buttons may
+also generate such events.
+
+The following commands can be written to this file:
+
+       echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
+       echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
+       echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
+       echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+       ... any other 4-hex-digit mask ...
+       echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
+
+The bit mask allows some control over which hot keys generate ACPI
+events. Not all bits in the mask can be modified. Not all bits that
+can be modified do anything. Not all hot keys can be individually
+controlled by the mask. Most recent ThinkPad models honor the
+following bits (assuming the hot keys feature has been enabled):
+
+       key     bit     behavior when set       behavior when unset
+
+       Fn-F3                   always generates ACPI event
+       Fn-F4                   always generates ACPI event
+       Fn-F5   0010    generate ACPI event     enable/disable Bluetooth
+       Fn-F7   0040    generate ACPI event     switch LCD and external display
+       Fn-F8   0080    generate ACPI event     expand screen or none
+       Fn-F9   0100    generate ACPI event     none
+       Fn-F12                  always generates ACPI event
+
+Some models do not support all of the above. For example, the T30 does
+not support Fn-F5 and Fn-F9. Other models do not support the mask at
+all. On those models, hot keys cannot be controlled individually.
+
+Note that enabling ACPI events for some keys prevents their default
+behavior. For example, if events for Fn-F5 are enabled, that key will
+no longer enable/disable Bluetooth by itself. This can still be done
+from an acpid handler for the ibm/hotkey event.
+
+Note also that not all Fn key combinations are supported through
+ACPI. For example, on the X40, the brightness, volume and "Access IBM"
+buttons do not generate ACPI events even with this driver. They *can*
+be used through the "ThinkPad Buttons" utility, see
+http://www.nongnu.org/tpb/
+
+Bluetooth -- /proc/acpi/ibm/bluetooth
+-------------------------------------
+
+This feature shows the presence and current state of a Bluetooth
+device. If Bluetooth is installed, the following commands can be used:
+
+       echo enable > /proc/acpi/ibm/bluetooth
+       echo disable > /proc/acpi/ibm/bluetooth
+
+Video output control -- /proc/acpi/ibm/video
+--------------------------------------------
+
+This feature allows control over the devices used for video output -
+LCD, CRT or DVI (if available). The following commands are available:
+
+       echo lcd_enable > /proc/acpi/ibm/video
+       echo lcd_disable > /proc/acpi/ibm/video
+       echo crt_enable > /proc/acpi/ibm/video
+       echo crt_disable > /proc/acpi/ibm/video
+       echo dvi_enable > /proc/acpi/ibm/video
+       echo dvi_disable > /proc/acpi/ibm/video
+       echo auto_enable > /proc/acpi/ibm/video
+       echo auto_disable > /proc/acpi/ibm/video
+       echo expand_toggle > /proc/acpi/ibm/video
+       echo video_switch > /proc/acpi/ibm/video
+
+Each video output device can be enabled or disabled individually.
+Reading /proc/acpi/ibm/video shows the status of each device.
+
+Automatic video switching can be enabled or disabled.  When automatic
+video switching is enabled, certain events (e.g. opening the lid,
+docking or undocking) cause the video output device to change
+automatically. While this can be useful, it also causes flickering
+and, on the X40, video corruption. By disabling automatic switching,
+the flickering or video corruption can be avoided.
+
+The video_switch command cycles through the available video outputs
+(it sumulates the behavior of Fn-F7).
+
+Video expansion can be toggled through this feature. This controls
+whether the display is expanded to fill the entire LCD screen when a
+mode with less than full resolution is used. Note that the current
+video expansion status cannot be determined through this feature.
+
+Note that on many models (particularly those using Radeon graphics
+chips) the X driver configures the video card in a way which prevents
+Fn-F7 from working. This also disables the video output switching
+features of this driver, as it uses the same ACPI methods as
+Fn-F7. Video switching on the console should still work.
+
+ThinkLight control -- /proc/acpi/ibm/light
+------------------------------------------
+
+The current status of the ThinkLight can be found in this file. A few
+models which do not make the status available will show it as
+"unknown". The available commands are:
+
+       echo on  > /proc/acpi/ibm/light
+       echo off > /proc/acpi/ibm/light
+
+Docking / Undocking -- /proc/acpi/ibm/dock
+------------------------------------------
+
+Docking and undocking (e.g. with the X4 UltraBase) requires some
+actions to be taken by the operating system to safely make or break
+the electrical connections with the dock.
+
+The docking feature of this driver generates the following ACPI events:
+
+       ibm/dock GDCK 00000003 00000001 -- eject request
+       ibm/dock GDCK 00000003 00000002 -- undocked
+       ibm/dock GDCK 00000000 00000003 -- docked
+
+NOTE: These events will only be generated if the laptop was docked
+when originally booted. This is due to the current lack of support for
+hot plugging of devices in the Linux ACPI framework. If the laptop was
+booted while not in the dock, the following message is shown in the
+logs: "ibm_acpi: dock device not present". No dock-related events are
+generated but the dock and undock commands described below still
+work. They can be executed manually or triggered by Fn key
+combinations (see the example acpid configuration files included in
+the driver tarball package available on the web site).
+
+When the eject request button on the dock is pressed, the first event
+above is generated. The handler for this event should issue the
+following command:
+
+       echo undock > /proc/acpi/ibm/dock
+
+After the LED on the dock goes off, it is safe to eject the laptop.
+Note: if you pressed this key by mistake, go ahead and eject the
+laptop, then dock it back in. Otherwise, the dock may not function as
+expected.
+
+When the laptop is docked, the third event above is generated. The
+handler for this event should issue the following command to fully
+enable the dock:
+
+       echo dock > /proc/acpi/ibm/dock
+
+The contents of the /proc/acpi/ibm/dock file shows the current status
+of the dock, as provided by the ACPI framework.
+
+The docking support in this driver does not take care of enabling or
+disabling any other devices you may have attached to the dock. For
+example, a CD drive plugged into the UltraBase needs to be disabled or
+enabled separately. See the provided example acpid configuration files
+for how this can be accomplished.
+
+There is no support yet for PCI devices that may be attached to a
+docking station, e.g. in the ThinkPad Dock II. The driver currently
+does not recognize, enable or disable such devices. This means that
+the only docking stations currently supported are the X-series
+UltraBase docks and "dumb" port replicators like the Mini Dock (the
+latter don't need any ACPI support, actually).
+
+UltraBay Eject -- /proc/acpi/ibm/bay
+------------------------------------
+
+Inserting or ejecting an UltraBay device requires some actions to be
+taken by the operating system to safely make or break the electrical
+connections with the device.
+
+This feature generates the following ACPI events:
+
+       ibm/bay MSTR 00000003 00000000 -- eject request
+       ibm/bay MSTR 00000001 00000000 -- eject lever inserted
+
+NOTE: These events will only be generated if the UltraBay was present
+when the laptop was originally booted (on the X series, the UltraBay
+is in the dock, so it may not be present if the laptop was undocked).
+This is due to the current lack of support for hot plugging of devices
+in the Linux ACPI framework. If the laptop was booted without the
+UltraBay, the following message is shown in the logs: "ibm_acpi: bay
+device not present". No bay-related events are generated but the eject
+command described below still works. It can be executed manually or
+triggered by a hot key combination.
+
+Sliding the eject lever generates the first event shown above. The
+handler for this event should take whatever actions are necessary to
+shut down the device in the UltraBay (e.g. call idectl), then issue
+the following command:
+
+       echo eject > /proc/acpi/ibm/bay
+
+After the LED on the UltraBay goes off, it is safe to pull out the
+device.
+
+When the eject lever is inserted, the second event above is
+generated. The handler for this event should take whatever actions are
+necessary to enable the UltraBay device (e.g. call idectl).
+
+The contents of the /proc/acpi/ibm/bay file shows the current status
+of the UltraBay, as provided by the ACPI framework.
+
+Experimental Features
+---------------------
+
+The following features are marked experimental because using them
+involves guessing the correct values of some parameters. Guessing
+incorrectly may have undesirable effects like crashing your
+ThinkPad. USE THESE WITH CAUTION! To activate them, you'll need to
+supply the experimental=1 parameter when loading the module.
+
+Experimental: CMOS control - /proc/acpi/ibm/cmos
+------------------------------------------------
+
+This feature is used internally by the ACPI firmware to control the
+ThinkLight on most newer ThinkPad models. It appears that it can also
+control LCD brightness, sounds volume and more, but only on some
+models.
+
+The commands are non-negative integer numbers:
+
+       echo 0 >/proc/acpi/ibm/cmos
+       echo 1 >/proc/acpi/ibm/cmos
+       echo 2 >/proc/acpi/ibm/cmos
+       ...
+
+The range of numbers which are used internally by various models is 0
+to 21, but it's possible that numbers outside this range have
+interesting behavior. Here is the behavior on the X40 (tpb is the
+ThinkPad Buttons utility):
+
+       0 - no effect but tpb reports "Volume down"
+       1 - no effect but tpb reports "Volume up"
+       2 - no effect but tpb reports "Mute on"
+       3 - simulate pressing the "Access IBM" button
+       4 - LCD brightness up
+       5 - LCD brightness down
+       11 - toggle screen expansion
+       12 - ThinkLight on
+       13 - ThinkLight off
+       14 - no effect but tpb reports ThinkLight status change
+
+If you try this feature, please send me a report similar to the
+above. On models which allow control of LCD brightness or sound
+volume, I'd like to provide this functionality in an user-friendly
+way, but first I need a way to identify the models which this is
+possible.
+
+Experimental: LED control - /proc/acpi/ibm/LED
+----------------------------------------------
+
+Some of the LED indicators can be controlled through this feature. The
+available commands are:
+
+       echo <led number> on >/proc/acpi/ibm/led
+       echo <led number> off >/proc/acpi/ibm/led
+       echo <led number> blink >/proc/acpi/ibm/led
+
+The <led number> parameter is a non-negative integer. The range of LED
+numbers used internally by various models is 0 to 7 but it's possible
+that numbers outside this range are also valid. Here is the mapping on
+the X40:
+
+       0 - power
+       1 - battery (orange)
+       2 - battery (green)
+       3 - UltraBase
+       4 - UltraBay
+       7 - standby
+
+All of the above can be turned on and off and can be made to blink.
+
+If you try this feature, please send me a report similar to the
+above. I'd like to provide this functionality in an user-friendly way,
+but first I need to identify the which numbers correspond to which
+LEDs on various models.
+
+Experimental: ACPI sounds - /proc/acpi/ibm/beep
+-----------------------------------------------
+
+The BEEP method is used internally by the ACPI firmware to provide
+audible alerts in various situtation. This feature allows the same
+sounds to be triggered manually.
+
+The commands are non-negative integer numbers:
+
+       echo 0 >/proc/acpi/ibm/beep
+       echo 1 >/proc/acpi/ibm/beep
+       echo 2 >/proc/acpi/ibm/beep
+       ...
+
+The range of numbers which are used internally by various models is 0
+to 17, but it's possible that numbers outside this range are also
+valid. Here is the behavior on the X40:
+
+       2 - two beeps, pause, third beep
+       3 - single beep
+       4 - "unable"    
+       5 - single beep
+       6 - "AC/DC"
+       7 - high-pitched beep
+       9 - three short beeps
+       10 - very long beep
+       12 - low-pitched beep
+
+(I've only been able to identify a couple of them).
+
+If you try this feature, please send me a report similar to the
+above. I'd like to provide this functionality in an user-friendly way,
+but first I need to identify the which numbers correspond to which
+sounds on various models.
+
+
+Multiple Command, Module Parameters
+-----------------------------------
+
+Multiple commands can be written to the proc files in one shot by
+separating them with commas, for example:
+
+       echo enable,0xffff > /proc/acpi/ibm/hotkey
+       echo lcd_disable,crt_enable > /proc/acpi/ibm/video
+
+Commands can also be specified when loading the ibm_acpi module, for
+example:
+
+       modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
+
+
+Example Configuration
+---------------------
+
+The ACPI support in the kernel is intended to be used in conjunction
+with a user-space daemon, acpid. The configuration files for this
+daemon control what actions are taken in response to various ACPI
+events. An example set of configuration files are included in the
+config/ directory of the tarball package available on the web
+site. Note that these are provided for illustration purposes only and
+may need to be adapted to your particular setup.
+
+The following utility scripts are used by the example action
+scripts (included with ibm-acpi for completeness):
+
+       /usr/local/sbin/idectl -- from the hdparm source distribution,
+               see http://www.ibiblio.org/pub/Linux/system/hardware
+       /usr/local/sbin/laptop_mode -- from the Linux kernel source
+               distribution, see Documentation/laptop-mode.txt
+       /sbin/service -- comes with Redhat/Fedora distributions
+
+Toan T Nguyen <ntt@control.uchicago.edu> has written a SuSE powersave
+script for the X20, included in config/usr/sbin/ibm_hotkeys_X20
+
+Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
+handler script for the X31. You can get the latest version from
+http://dev.gentoo.org/~brix/files/x31.sh
+
+David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
+script which works on Debian systems, included in
+configs/etc/acpi/actions/blank-debian.sh
+
+
+TODO
+----
+
+I'd like to implement the following features but haven't yet found the
+time and/or I don't yet know how to implement them:
+
+- UltraBay floppy drive support
+
diff --git a/Documentation/ioctl/cdrom.txt b/Documentation/ioctl/cdrom.txt
new file mode 100644 (file)
index 0000000..4ccdcc6
--- /dev/null
@@ -0,0 +1,966 @@
+               Summary of CDROM ioctl calls.
+               ============================
+
+               Edward A. Falk <efalk@google.com>
+
+               November, 2004
+
+This document attempts to describe the ioctl(2) calls supported by
+the CDROM layer.  These are by-and-large implemented (as of Linux 2.6)
+in drivers/cdrom/cdrom.c and drivers/block/scsi_ioctl.c
+
+ioctl values are listed in <linux/cdrom.h>.  As of this writing, they
+are as follows:
+
+       CDROMPAUSE              Pause Audio Operation
+       CDROMRESUME             Resume paused Audio Operation
+       CDROMPLAYMSF            Play Audio MSF (struct cdrom_msf)
+       CDROMPLAYTRKIND         Play Audio Track/index (struct cdrom_ti)
+       CDROMREADTOCHDR         Read TOC header (struct cdrom_tochdr)
+       CDROMREADTOCENTRY       Read TOC entry (struct cdrom_tocentry)
+       CDROMSTOP               Stop the cdrom drive
+       CDROMSTART              Start the cdrom drive
+       CDROMEJECT              Ejects the cdrom media
+       CDROMVOLCTRL            Control output volume (struct cdrom_volctrl)
+       CDROMSUBCHNL            Read subchannel data (struct cdrom_subchnl)
+       CDROMREADMODE2          Read CDROM mode 2 data (2336 Bytes)
+                                          (struct cdrom_read)
+       CDROMREADMODE1          Read CDROM mode 1 data (2048 Bytes)
+                                          (struct cdrom_read)
+       CDROMREADAUDIO          (struct cdrom_read_audio)
+       CDROMEJECT_SW           enable(1)/disable(0) auto-ejecting
+       CDROMMULTISESSION       Obtain the start-of-last-session
+                                 address of multi session disks
+                                 (struct cdrom_multisession)
+       CDROM_GET_MCN           Obtain the "Universal Product Code"
+                                  if available (struct cdrom_mcn)
+       CDROM_GET_UPC           Deprecated, use CDROM_GET_MCN instead.
+       CDROMRESET              hard-reset the drive
+       CDROMVOLREAD            Get the drive's volume setting
+                                         (struct cdrom_volctrl)
+       CDROMREADRAW            read data in raw mode (2352 Bytes)
+                                          (struct cdrom_read)
+       CDROMREADCOOKED         read data in cooked mode
+       CDROMSEEK               seek msf address
+       CDROMPLAYBLK            scsi-cd only, (struct cdrom_blk)
+       CDROMREADALL            read all 2646 bytes
+       CDROMGETSPINDOWN        return 4-bit spindown value
+       CDROMSETSPINDOWN        set 4-bit spindown value
+       CDROMCLOSETRAY          pendant of CDROMEJECT
+       CDROM_SET_OPTIONS       Set behavior options
+       CDROM_CLEAR_OPTIONS     Clear behavior options
+       CDROM_SELECT_SPEED      Set the CD-ROM speed
+       CDROM_SELECT_DISC       Select disc (for juke-boxes)
+       CDROM_MEDIA_CHANGED     Check is media changed
+       CDROM_DRIVE_STATUS      Get tray position, etc.
+       CDROM_DISC_STATUS       Get disc type, etc.
+       CDROM_CHANGER_NSLOTS    Get number of slots
+       CDROM_LOCKDOOR          lock or unlock door
+       CDROM_DEBUG             Turn debug messages on/off
+       CDROM_GET_CAPABILITY    get capabilities
+       CDROMAUDIOBUFSIZ        set the audio buffer size
+       DVD_READ_STRUCT         Read structure
+       DVD_WRITE_STRUCT        Write structure
+       DVD_AUTH                Authentication
+       CDROM_SEND_PACKET       send a packet to the drive
+       CDROM_NEXT_WRITABLE     get next writable block
+       CDROM_LAST_WRITTEN      get last block written on disc
+
+
+The information that follows was determined from reading kernel source
+code.  It is likely that some corrections will be made over time.
+
+
+
+
+
+
+
+General:
+
+       Unless otherwise specified, all ioctl calls return 0 on success
+       and -1 with errno set to an appropriate value on error.  (Some
+       ioctls return non-negative data values.)
+
+       Unless otherwise specified, all ioctl calls return -1 and set
+       errno to EFAULT on a failed attempt to copy data to or from user
+       address space.
+
+       Individual drivers may return error codes not listed here.
+
+       Unless otherwise specified, all data structures and constants
+       are defined in <linux/cdrom.h>
+
+
+
+
+CDROMPAUSE                     Pause Audio Operation
+
+       usage:
+
+         ioctl(fd, CDROMPAUSE, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+
+CDROMRESUME                    Resume paused Audio Operation
+
+       usage:
+
+         ioctl(fd, CDROMRESUME, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+
+CDROMPLAYMSF                   Play Audio MSF (struct cdrom_msf)
+
+       usage:
+
+         struct cdrom_msf msf;
+         ioctl(fd, CDROMPLAYMSF, &msf);
+
+       inputs:
+         cdrom_msf structure, describing a segment of music to play
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+       notes:
+         MSF stands for minutes-seconds-frames
+         LBA stands for logical block address
+
+         Segment is described as start and end times, where each time
+         is described as minutes:seconds:frames.  A frame is 1/75 of
+         a second.
+
+
+CDROMPLAYTRKIND                        Play Audio Track/index (struct cdrom_ti)
+
+       usage:
+
+         struct cdrom_ti ti;
+         ioctl(fd, CDROMPLAYTRKIND, &ti);
+
+       inputs:
+         cdrom_ti structure, describing a segment of music to play
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+       notes:
+         Segment is described as start and end times, where each time
+         is described as a track and an index.
+
+
+
+CDROMREADTOCHDR                        Read TOC header (struct cdrom_tochdr)
+
+       usage:
+
+         cdrom_tochdr header;
+         ioctl(fd, CDROMREADTOCHDR, &header);
+
+       inputs:
+         cdrom_tochdr structure
+
+       outputs:
+         cdrom_tochdr structure
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+
+
+CDROMREADTOCENTRY              Read TOC entry (struct cdrom_tocentry)
+
+       usage:
+
+         struct cdrom_tocentry entry;
+         ioctl(fd, CDROMREADTOCENTRY, &entry);
+
+       inputs:
+         cdrom_tocentry structure
+
+       outputs:
+         cdrom_tocentry structure
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+         EINVAL        entry.cdte_format not CDROM_MSF or CDROM_LBA
+         EINVAL        requested track out of bounds
+         EIO           I/O error reading TOC
+
+       notes:
+         TOC stands for Table Of Contents
+         MSF stands for minutes-seconds-frames
+         LBA stands for logical block address
+
+
+
+CDROMSTOP                      Stop the cdrom drive
+
+       usage:
+
+         ioctl(fd, CDROMSTOP, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+       notes:
+         Exact interpretation of this ioctl depends on the device,
+         but most seem to spin the drive down.
+
+
+CDROMSTART                     Start the cdrom drive
+
+       usage:
+
+         ioctl(fd, CDROMSTART, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+       notes:
+         Exact interpretation of this ioctl depends on the device,
+         but most seem to spin the drive up and/or close the tray.
+         Other devices ignore the ioctl completely.
+
+
+CDROMEJECT                     Ejects the cdrom media
+
+       usage:
+
+         ioctl(fd, CDROMEJECT, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error returns:
+         ENOSYS        cd drive not capable of ejecting
+         EBUSY         other processes are accessing drive, or door is locked
+
+       notes:
+         See CDROM_LOCKDOOR, below.
+
+
+
+CDROMCLOSETRAY                 pendant of CDROMEJECT
+
+       usage:
+
+         ioctl(fd, CDROMEJECT, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error returns:
+         ENOSYS        cd drive not capable of ejecting
+         EBUSY         other processes are accessing drive, or door is locked
+
+       notes:
+         See CDROM_LOCKDOOR, below.
+
+
+
+CDROMVOLCTRL                   Control output volume (struct cdrom_volctrl)
+
+       usage:
+
+         struct cdrom_volctrl volume;
+         ioctl(fd, CDROMVOLCTRL, &volume);
+
+       inputs:
+         cdrom_volctrl structure containing volumes for up to 4
+         channels.
+
+       outputs:        none
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+
+
+CDROMVOLREAD                   Get the drive's volume setting
+                                         (struct cdrom_volctrl)
+
+       usage:
+
+         struct cdrom_volctrl volume;
+         ioctl(fd, CDROMVOLREAD, &volume);
+
+       inputs:         none
+
+       outputs:
+         The current volume settings.
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+
+
+
+CDROMSUBCHNL                   Read subchannel data (struct cdrom_subchnl)
+
+       usage:
+
+         struct cdrom_subchnl q;
+         ioctl(fd, CDROMSUBCHNL, &q);
+
+       inputs:
+         cdrom_subchnl structure
+
+       outputs:
+         cdrom_subchnl structure
+
+       error return:
+         ENOSYS        cd drive not audio-capable.
+         EINVAL        format not CDROM_MSF or CDROM_LBA
+
+       notes:
+         Format is converted to CDROM_MSF on return
+
+
+
+CDROMREADRAW                   read data in raw mode (2352 Bytes)
+                                          (struct cdrom_read)
+
+       usage:
+
+         union {
+           struct cdrom_msf msf;               /* input */
+           char buffer[CD_FRAMESIZE_RAW];      /* return */
+         } arg;
+         ioctl(fd, CDROMREADRAW, &arg);
+
+       inputs:
+         cdrom_msf structure indicating an address to read.
+         Only the start values are significant.
+
+       outputs:
+         Data written to address provided by user.
+
+       error return:
+         EINVAL        address less than 0, or msf less than 0:2:0
+         ENOMEM        out of memory
+
+       notes:
+         As of 2.6.8.1, comments in <linux/cdrom.h> indicate that this
+         ioctl accepts a cdrom_read structure, but actual source code
+         reads a cdrom_msf structure and writes a buffer of data to
+         the same address.
+
+         MSF values are converted to LBA values via this formula:
+
+           lba = (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+
+
+
+
+CDROMREADMODE1                 Read CDROM mode 1 data (2048 Bytes)
+                                          (struct cdrom_read)
+
+       notes:
+         Identical to CDROMREADRAW except that block size is
+         CD_FRAMESIZE (2048) bytes
+
+
+
+CDROMREADMODE2                 Read CDROM mode 2 data (2336 Bytes)
+                                          (struct cdrom_read)
+
+       notes:
+         Identical to CDROMREADRAW except that block size is
+         CD_FRAMESIZE_RAW0 (2336) bytes
+
+
+
+CDROMREADAUDIO                 (struct cdrom_read_audio)
+
+       usage:
+
+         struct cdrom_read_audio ra;
+         ioctl(fd, CDROMREADAUDIO, &ra);
+
+       inputs:
+         cdrom_read_audio structure containing read start
+         point and length
+
+       outputs:
+         audio data, returned to buffer indicated by ra
+
+       error return:
+         EINVAL        format not CDROM_MSF or CDROM_LBA
+         EINVAL        nframes not in range [1 75]
+         ENXIO         drive has no queue (probably means invalid fd)
+         ENOMEM        out of memory
+
+
+CDROMEJECT_SW                  enable(1)/disable(0) auto-ejecting
+
+       usage:
+
+         int val;
+         ioctl(fd, CDROMEJECT_SW, val);
+
+       inputs:
+         Flag specifying auto-eject flag.
+
+       outputs:        none
+
+       error return:
+         ENOSYS        Drive is not capable of ejecting.
+         EBUSY         Door is locked
+
+
+
+
+CDROMMULTISESSION              Obtain the start-of-last-session
+                                 address of multi session disks
+                                 (struct cdrom_multisession)
+       usage:
+
+         struct cdrom_multisession ms_info;
+         ioctl(fd, CDROMMULTISESSION, &ms_info);
+
+       inputs:
+         cdrom_multisession structure containing desired
+         format.
+
+       outputs:
+         cdrom_multisession structure is filled with last_session
+         information.
+
+       error return:
+         EINVAL        format not CDROM_MSF or CDROM_LBA
+
+
+CDROM_GET_MCN                  Obtain the "Universal Product Code"
+                                  if available (struct cdrom_mcn)
+
+       usage:
+
+         struct cdrom_mcn mcn;
+         ioctl(fd, CDROM_GET_MCN, &mcn);
+
+       inputs:         none
+
+       outputs:
+         Universal Product Code
+
+       error return:
+         ENOSYS        Drive is not capable of reading MCN data.
+
+       notes:
+         Source code comments state:
+
+           The following function is implemented, although very few
+           audio discs give Universal Product Code information, which
+           should just be the Medium Catalog Number on the box.  Note,
+           that the way the code is written on the CD is /not/ uniform
+           across all discs!
+
+
+
+
+CDROM_GET_UPC                  CDROM_GET_MCN  (deprecated)
+
+       Not implemented, as of 2.6.8.1
+
+
+
+CDROMRESET                     hard-reset the drive
+
+       usage:
+
+         ioctl(fd, CDROMRESET, 0);
+
+       inputs:         none
+
+       outputs:        none
+
+       error return:
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         ENOSYS        Drive is not capable of resetting.
+
+
+
+
+CDROMREADCOOKED                        read data in cooked mode
+
+       usage:
+
+         u8 buffer[CD_FRAMESIZE]
+         ioctl(fd, CDROMREADCOOKED, buffer);
+
+       inputs:         none
+
+       outputs:
+         2048 bytes of data, "cooked" mode.
+
+       notes:
+         Not implemented on all drives.
+
+
+
+
+CDROMREADALL                   read all 2646 bytes
+
+       Same as CDROMREADCOOKED, but reads 2646 bytes.
+
+
+
+CDROMSEEK                      seek msf address
+
+       usage:
+
+         struct cdrom_msf msf;
+         ioctl(fd, CDROMSEEK, &msf);
+
+       inputs:
+         MSF address to seek to.
+
+       outputs:        none
+
+
+
+CDROMPLAYBLK                   scsi-cd only, (struct cdrom_blk)
+
+       usage:
+
+         struct cdrom_blk blk;
+         ioctl(fd, CDROMPLAYBLK, &blk);
+
+       inputs:
+         Region to play
+
+       outputs:        none
+
+
+
+CDROMGETSPINDOWN
+
+       usage:
+
+         char spindown;
+         ioctl(fd, CDROMGETSPINDOWN, &spindown);
+
+       inputs:         none
+
+       outputs:
+         The value of the current 4-bit spindown value.
+
+
+
+
+CDROMSETSPINDOWN
+
+       usage:
+
+         char spindown
+         ioctl(fd, CDROMSETSPINDOWN, &spindown);
+
+       inputs:
+         4-bit value used to control spindown (TODO: more detail here)
+
+       outputs:        none
+
+
+
+
+
+CDROM_SET_OPTIONS              Set behavior options
+
+       usage:
+
+         int options;
+         ioctl(fd, CDROM_SET_OPTIONS, options);
+
+       inputs:
+         New values for drive options.  The logical 'or' of:
+           CDO_AUTO_CLOSE      close tray on first open(2)
+           CDO_AUTO_EJECT      open tray on last release
+           CDO_USE_FFLAGS      use O_NONBLOCK information on open
+           CDO_LOCK            lock tray on open files
+           CDO_CHECK_TYPE      check type on open for data
+
+       outputs:
+         Returns the resulting options settings in the
+         ioctl return value.  Returns -1 on error.
+
+       error return:
+         ENOSYS        selected option(s) not supported by drive.
+
+
+
+
+CDROM_CLEAR_OPTIONS            Clear behavior options
+
+       Same as CDROM_SET_OPTIONS, except that selected options are
+       turned off.
+
+
+
+CDROM_SELECT_SPEED             Set the CD-ROM speed
+
+       usage:
+
+         int speed;
+         ioctl(fd, CDROM_SELECT_SPEED, speed);
+
+       inputs:
+         New drive speed.
+
+       outputs:        none
+
+       error return:
+         ENOSYS        speed selection not supported by drive.
+
+
+
+CDROM_SELECT_DISC              Select disc (for juke-boxes)
+
+       usage:
+
+         int disk;
+         ioctl(fd, CDROM_SELECT_DISC, disk);
+
+       inputs:
+         Disk to load into drive.
+
+       outputs:        none
+
+       error return:
+         EINVAL        Disk number beyond capacity of drive
+
+
+
+CDROM_MEDIA_CHANGED            Check is media changed
+
+       usage:
+
+         int slot;
+         ioctl(fd, CDROM_MEDIA_CHANGED, slot);
+
+       inputs:
+         Slot number to be tested, always zero except for jukeboxes.
+         May also be special values CDSL_NONE or CDSL_CURRENT
+
+       outputs:
+         Ioctl return value is 0 or 1 depending on whether the media
+         has been changed, or -1 on error.
+
+       error returns:
+         ENOSYS        Drive can't detect media change
+         EINVAL        Slot number beyond capacity of drive
+         ENOMEM        Out of memory
+
+
+
+CDROM_DRIVE_STATUS             Get tray position, etc.
+
+       usage:
+
+         int slot;
+         ioctl(fd, CDROM_DRIVE_STATUS, slot);
+
+       inputs:
+         Slot number to be tested, always zero except for jukeboxes.
+         May also be special values CDSL_NONE or CDSL_CURRENT
+
+       outputs:
+         Ioctl return value will be one of the following values
+         from <linux/cdrom.h>:
+
+           CDS_NO_INFO         Information not available.
+           CDS_NO_DISC
+           CDS_TRAY_OPEN
+           CDS_DRIVE_NOT_READY
+           CDS_DISC_OK
+           -1                  error
+
+       error returns:
+         ENOSYS        Drive can't detect drive status
+         EINVAL        Slot number beyond capacity of drive
+         ENOMEM        Out of memory
+
+
+
+
+CDROM_DISC_STATUS              Get disc type, etc.
+
+       usage:
+
+         ioctl(fd, CDROM_DISC_STATUS, 0);
+
+       inputs:         none
+
+       outputs:
+         Ioctl return value will be one of the following values
+         from <linux/cdrom.h>:
+           CDS_NO_INFO
+           CDS_AUDIO
+           CDS_MIXED
+           CDS_XA_2_2
+           CDS_XA_2_1
+           CDS_DATA_1
+
+       error returns:  none at present
+
+       notes:
+         Source code comments state:
+
+           Ok, this is where problems start.  The current interface for
+           the CDROM_DISC_STATUS ioctl is flawed.  It makes the false
+           assumption that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.
+           Unfortunatly, while this is often the case, it is also
+           very common for CDs to have some tracks with data, and some
+           tracks with audio.  Just because I feel like it, I declare
+           the following to be the best way to cope.  If the CD has
+           ANY data tracks on it, it will be returned as a data CD.
+           If it has any XA tracks, I will return it as that.  Now I
+           could simplify this interface by combining these returns with
+           the above, but this more clearly demonstrates the problem
+           with the current interface.  Too bad this wasn't designed
+           to use bitmasks...         -Erik
+
+           Well, now we have the option CDS_MIXED: a mixed-type CD.
+           User level programmers might feel the ioctl is not very
+           useful.
+                       ---david
+
+
+
+
+CDROM_CHANGER_NSLOTS           Get number of slots
+
+       usage:
+
+         ioctl(fd, CDROM_CHANGER_NSLOTS, 0);
+
+       inputs:         none
+
+       outputs:
+         The ioctl return value will be the number of slots in a
+         CD changer.  Typically 1 for non-multi-disk devices.
+
+       error returns:  none
+
+
+
+CDROM_LOCKDOOR                 lock or unlock door
+
+       usage:
+
+         int lock;
+         ioctl(fd, CDROM_LOCKDOOR, lock);
+
+       inputs:
+         Door lock flag, 1=lock, 0=unlock
+
+       outputs:        none
+
+       error returns:
+         EDRIVE_CANT_DO_THIS   Door lock function not supported.
+         EBUSY                 Attempt to unlock when multiple users
+                               have the drive open and not CAP_SYS_ADMIN
+
+       notes:
+         As of 2.6.8.1, the lock flag is a global lock, meaning that
+         all CD drives will be locked or unlocked together.  This is
+         probably a bug.
+
+         The EDRIVE_CANT_DO_THIS value is defined in <linux/cdrom.h>
+         and is currently (2.6.8.1) the same as EOPNOTSUPP
+
+
+
+CDROM_DEBUG                    Turn debug messages on/off
+
+       usage:
+
+         int debug;
+         ioctl(fd, CDROM_DEBUG, debug);
+
+       inputs:
+         Cdrom debug flag, 0=disable, 1=enable
+
+       outputs:
+         The ioctl return value will be the new debug flag.
+
+       error return:
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+
+
+
+CDROM_GET_CAPABILITY           get capabilities
+
+       usage:
+
+         ioctl(fd, CDROM_GET_CAPABILITY, 0);
+
+       inputs:         none
+
+       outputs:
+         The ioctl return value is the current device capability
+         flags.  See CDC_CLOSE_TRAY, CDC_OPEN_TRAY, etc.
+
+
+
+CDROMAUDIOBUFSIZ               set the audio buffer size
+
+       usage:
+
+         int arg;
+         ioctl(fd, CDROMAUDIOBUFSIZ, val);
+
+       inputs:
+         New audio buffer size
+
+       outputs:
+         The ioctl return value is the new audio buffer size, or -1
+         on error.
+
+       error return:
+         ENOSYS        Not supported by this driver.
+
+       notes:
+         Not supported by all drivers.
+
+
+
+DVD_READ_STRUCT                        Read structure
+
+       usage:
+
+         dvd_struct s;
+         ioctl(fd, DVD_READ_STRUCT, &s);
+
+       inputs:
+         dvd_struct structure, containing:
+           type                specifies the information desired, one of
+                               DVD_STRUCT_PHYSICAL, DVD_STRUCT_COPYRIGHT,
+                               DVD_STRUCT_DISCKEY, DVD_STRUCT_BCA,
+                               DVD_STRUCT_MANUFACT
+           physical.layer_num  desired layer, indexed from 0
+           copyright.layer_num desired layer, indexed from 0
+           disckey.agid
+
+       outputs:
+         dvd_struct structure, containing:
+           physical            for type == DVD_STRUCT_PHYSICAL
+           copyright           for type == DVD_STRUCT_COPYRIGHT
+           disckey.value       for type == DVD_STRUCT_DISCKEY
+           bca.{len,value}     for type == DVD_STRUCT_BCA
+           manufact.{len,valu} for type == DVD_STRUCT_MANUFACT
+
+       error returns:
+         EINVAL        physical.layer_num exceeds number of layers
+         EIO           Recieved invalid response from drive
+
+
+
+DVD_WRITE_STRUCT               Write structure
+
+       Not implemented, as of 2.6.8.1
+
+
+
+DVD_AUTH                       Authentication
+
+       usage:
+
+         dvd_authinfo ai;
+         ioctl(fd, DVD_AUTH, &ai);
+
+       inputs:
+         dvd_authinfo structure.  See <linux/cdrom.h>
+
+       outputs:
+         dvd_authinfo structure.
+
+       error return:
+         ENOTTY        ai.type not recognized.
+
+
+
+CDROM_SEND_PACKET              send a packet to the drive
+
+       usage:
+
+         struct cdrom_generic_command cgc;
+         ioctl(fd, CDROM_SEND_PACKET, &cgc);
+
+       inputs:
+         cdrom_generic_command structure containing the packet to send.
+
+       outputs:        none
+         cdrom_generic_command structure containing results.
+
+       error return:
+         EIO           command failed.
+         EPERM         Operation not permitted, either because a
+                       write command was attempted on a drive which
+                       is opened read-only, or because the command
+                       requires CAP_SYS_RAWIO
+         EINVAL        cgc.data_direction not set
+
+
+
+CDROM_NEXT_WRITABLE            get next writable block
+
+       usage:
+
+         long next;
+         ioctl(fd, CDROM_NEXT_WRITABLE, &next);
+
+       inputs:         none
+
+       outputs:
+         The next writable block.
+
+       notes:
+         If the device does not support this ioctl directly, the
+         ioctl will return CDROM_LAST_WRITTEN + 7.
+
+
+
+CDROM_LAST_WRITTEN             get last block written on disc
+
+       usage:
+
+         long last;
+         ioctl(fd, CDROM_LAST_WRITTEN, &last);
+
+       inputs:         none
+
+       outputs:
+         The last block written on disc
+
+       notes:
+         If the device does not support this ioctl directly, the
+         result is derived from the disc's table of contents.  If the
+         table of contents can't be read, this ioctl returns an
+         error.
diff --git a/Documentation/ioctl/hdio.txt b/Documentation/ioctl/hdio.txt
new file mode 100644 (file)
index 0000000..c42d3b6
--- /dev/null
@@ -0,0 +1,965 @@
+               Summary of HDIO_ ioctl calls.
+               ============================
+
+               Edward A. Falk <efalk@google.com>
+
+               November, 2004
+
+This document attempts to describe the ioctl(2) calls supported by
+the HD/IDE layer.  These are by-and-large implemented (as of Linux 2.6)
+in drivers/ide/ide.c and drivers/block/scsi_ioctl.c
+
+ioctl values are listed in <linux/hdreg.h>.  As of this writing, they
+are as follows:
+
+    ioctls that pass argument pointers to user space:
+
+       HDIO_GETGEO             get device geometry
+       HDIO_GET_UNMASKINTR     get current unmask setting
+       HDIO_GET_MULTCOUNT      get current IDE blockmode setting
+       HDIO_GET_QDMA           get use-qdma flag
+       HDIO_SET_XFER           set transfer rate via proc
+       HDIO_OBSOLETE_IDENTITY  OBSOLETE, DO NOT USE
+       HDIO_GET_KEEPSETTINGS   get keep-settings-on-reset flag
+       HDIO_GET_32BIT          get current io_32bit setting
+       HDIO_GET_NOWERR         get ignore-write-error flag
+       HDIO_GET_DMA            get use-dma flag
+       HDIO_GET_NICE           get nice flags
+       HDIO_GET_IDENTITY       get IDE identification info
+       HDIO_GET_WCACHE         get write cache mode on|off
+       HDIO_GET_ACOUSTIC       get acoustic value
+       HDIO_GET_ADDRESS        get sector addressing mode
+       HDIO_GET_BUSSTATE       get the bus state of the hwif
+       HDIO_TRISTATE_HWIF      execute a channel tristate
+       HDIO_DRIVE_RESET        execute a device reset
+       HDIO_DRIVE_TASKFILE     execute raw taskfile
+       HDIO_DRIVE_TASK         execute task and special drive command
+       HDIO_DRIVE_CMD          execute a special drive command
+       HDIO_DRIVE_CMD_AEB      HDIO_DRIVE_TASK
+
+    ioctls that pass non-pointer values:
+
+       HDIO_SET_MULTCOUNT      change IDE blockmode
+       HDIO_SET_UNMASKINTR     permit other irqs during I/O
+       HDIO_SET_KEEPSETTINGS   keep ioctl settings on reset
+       HDIO_SET_32BIT          change io_32bit flags
+       HDIO_SET_NOWERR         change ignore-write-error flag
+       HDIO_SET_DMA            change use-dma flag
+       HDIO_SET_PIO_MODE       reconfig interface to new speed
+       HDIO_SCAN_HWIF          register and (re)scan interface
+       HDIO_SET_NICE           set nice flags
+       HDIO_UNREGISTER_HWIF    unregister interface
+       HDIO_SET_WCACHE         change write cache enable-disable
+       HDIO_SET_ACOUSTIC       change acoustic behavior
+       HDIO_SET_BUSSTATE       set the bus state of the hwif
+       HDIO_SET_QDMA           change use-qdma flag
+       HDIO_SET_ADDRESS        change lba addressing modes
+
+       HDIO_SET_IDE_SCSI       Set scsi emulation mode on/off
+       HDIO_SET_SCSI_IDE       not implemented yet
+
+
+The information that follows was determined from reading kernel source
+code.  It is likely that some corrections will be made over time.
+
+
+
+
+
+
+
+General:
+
+       Unless otherwise specified, all ioctl calls return 0 on success
+       and -1 with errno set to an appropriate value on error.
+
+       Unless otherwise specified, all ioctl calls return -1 and set
+       errno to EFAULT on a failed attempt to copy data to or from user
+       address space.
+
+       Unless otherwise specified, all data structures and constants
+       are defined in <linux/hdreg.h>
+
+
+
+HDIO_GETGEO                    get device geometry
+
+       usage:
+
+         struct hd_geometry geom;
+         ioctl(fd, HDIO_GETGEO, &geom);
+
+
+       inputs:         none
+
+       outputs:
+
+         hd_geometry structure containing:
+
+           heads       number of heads
+           sectors     number of sectors/track
+           cylinders   number of cylinders, mod 65536
+           start       starting sector of this partition.
+
+
+       error returns:
+         EINVAL        if the device is not a disk drive or floppy drive,
+                       or if the user passes a null pointer
+
+
+       notes:
+
+         Not particularly useful with modern disk drives, whose geometry
+         is a polite fiction anyway.  Modern drives are addressed
+         purely by sector number nowadays (lba addressing), and the
+         drive geometry is an abstraction which is actually subject
+         to change.  Currently (as of Nov 2004), the geometry values
+         are the "bios" values -- presumably the values the drive had
+         when Linux first booted.
+
+         In addition, the cylinders field of the hd_geometry is an
+         unsigned short, meaning that on most architectures, this
+         ioctl will not return a meaningful value on drives with more
+         than 65535 tracks.
+
+         The start field is unsigned long, meaning that it will not
+         contain a meaningful value for disks over 219 Gb in size.
+
+
+
+
+HDIO_GET_UNMASKINTR            get current unmask setting
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_UNMASKINTR, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the drive's current unmask setting
+
+
+
+HDIO_SET_UNMASKINTR            permit other irqs during I/O
+
+       usage:
+
+         unsigned long val;
+         ioctl(fd, HDIO_SET_UNMASKINTR, val);
+
+       inputs:
+         New value for unmask flag
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 1]
+         EBUSY         Controller busy
+
+
+
+
+HDIO_GET_MULTCOUNT             get current IDE blockmode setting
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_MULTCOUNT, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current IDE block mode setting.  This
+         controls how many sectors the drive will transfer per
+         interrupt.
+
+
+
+HDIO_SET_MULTCOUNT             change IDE blockmode
+
+       usage:
+
+         int val;
+         ioctl(fd, HDIO_SET_MULTCOUNT, val);
+
+       inputs:
+         New value for IDE block mode setting.  This controls how many
+         sectors the drive will transfer per interrupt.
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range supported by disk.
+         EBUSY         Controller busy or blockmode already set.
+         EIO           Drive did not accept new block mode.
+
+       notes:
+
+         Source code comments read:
+
+           This is tightly woven into the driver->do_special can not
+           touch.  DON'T do it again until a total personality rewrite
+           is committed.
+
+         If blockmode has already been set, this ioctl will fail with
+         EBUSY
+
+
+
+HDIO_GET_QDMA                  get use-qdma flag
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_XFER                  set transfer rate via proc
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_OBSOLETE_IDENTITY         OBSOLETE, DO NOT USE
+
+       Same as HDIO_GET_IDENTITY (see below), except that it only
+       returns the first 142 bytes of drive identity information.
+
+
+
+HDIO_GET_IDENTITY              get IDE identification info
+
+       usage:
+
+         unsigned char identity[512];
+         ioctl(fd, HDIO_GET_IDENTITY, identity);
+
+       inputs:         none
+
+       outputs:
+
+         ATA drive identity information.  For full description, see
+         the IDENTIFY DEVICE and IDENTIFY PACKET DEVICE commands in
+         the ATA specification.
+
+       error returns:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         ENOMSG        IDENTIFY DEVICE information not available
+
+       notes:
+
+         Returns information that was obtained when the drive was
+         probed.  Some of this information is subject to change, and
+         this ioctl does not re-probe the drive to update the
+         information.
+
+         This information is also available from /proc/ide/hdX/identify
+
+
+
+HDIO_GET_KEEPSETTINGS          get keep-settings-on-reset flag
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_KEEPSETTINGS, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current "keep settings" flag
+
+       notes:
+
+         When set, indicates that kernel should restore settings
+         after a drive reset.
+
+
+
+HDIO_SET_KEEPSETTINGS          keep ioctl settings on reset
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_SET_KEEPSETTINGS, val);
+
+       inputs:
+         New value for keep_settings flag
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 1]
+         EBUSY         Controller busy
+
+
+
+HDIO_GET_32BIT                 get current io_32bit setting
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_32BIT, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current io_32bit setting
+
+       notes:
+
+         0=16-bit, 1=32-bit, 2,3 = 32bit+sync
+
+
+
+HDIO_GET_NOWERR                        get ignore-write-error flag
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_NOWERR, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current ignore-write-error flag
+
+
+
+HDIO_GET_DMA                   get use-dma flag
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_DMA, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current use-dma flag
+
+
+
+HDIO_GET_NICE                  get nice flags
+
+       usage:
+
+         long nice;
+         ioctl(fd, HDIO_GET_NICE, &nice);
+
+       inputs:         none
+
+       outputs:
+
+         The drive's "nice" values.
+
+       notes:
+
+         Per-drive flags which determine when the system will give more
+         bandwidth to other devices sharing the same IDE bus.
+         See <linux/hdreg.h>, near symbol IDE_NICE_DSC_OVERLAP.
+
+
+
+
+HDIO_SET_NICE                  set nice flags
+
+       usage:
+
+         unsigned long nice;
+         ...
+         ioctl(fd, HDIO_SET_NICE, nice);
+
+       inputs:
+         bitmask of nice flags.
+
+       outputs:        none
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EPERM         Flags other than DSC_OVERLAP and NICE_1 set.
+         EPERM         DSC_OVERLAP specified but not supported by drive
+
+       notes:
+
+         This ioctl sets the DSC_OVERLAP and NICE_1 flags from values
+         provided by the user.
+
+         Nice flags are listed in <linux/hdreg.h>, starting with
+         IDE_NICE_DSC_OVERLAP.  These values represent shifts.
+
+
+
+
+
+HDIO_GET_WCACHE                        get write cache mode on|off
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_WCACHE, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current write cache mode
+
+
+
+HDIO_GET_ACOUSTIC              get acoustic value
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_ACOUSTIC, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current acoustic settings
+
+       notes:
+
+         See HDIO_SET_ACOUSTIC
+
+
+
+HDIO_GET_ADDRESS
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_GET_ADDRESS, &val);
+
+       inputs:         none
+
+       outputs:
+         The value of the current addressing mode:
+           0 = 28-bit
+           1 = 48-bit
+           2 = 48-bit doing 28-bit
+           3 = 64-bit
+
+
+
+HDIO_GET_BUSSTATE              get the bus state of the hwif
+
+       usage:
+
+         long state;
+         ioctl(fd, HDIO_SCAN_HWIF, &state);
+
+       inputs:         none
+
+       outputs:
+         Current power state of the IDE bus.  One of BUSSTATE_OFF,
+         BUSSTATE_ON, or BUSSTATE_TRISTATE
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+
+
+
+
+HDIO_SET_BUSSTATE              set the bus state of the hwif
+
+       usage:
+
+         int state;
+         ...
+         ioctl(fd, HDIO_SCAN_HWIF, state);
+
+       inputs:
+         Desired IDE power state.  One of BUSSTATE_OFF, BUSSTATE_ON,
+         or BUSSTATE_TRISTATE
+
+       outputs:        none
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_RAWIO
+         EOPNOTSUPP    Hardware interface does not support bus power control
+
+
+
+
+HDIO_TRISTATE_HWIF             execute a channel tristate
+
+       Not implemented, as of 2.6.8.1.  See HDIO_SET_BUSSTATE
+
+
+
+HDIO_DRIVE_RESET               execute a device reset
+
+       usage:
+
+         int args[3]
+         ...
+         ioctl(fd, HDIO_DRIVE_RESET, args);
+
+       inputs:         none
+
+       outputs:        none
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+
+       notes:
+
+         Abort any current command, prevent anything else from being
+         queued, execute a reset on the device, and issue BLKRRPART
+         ioctl on the block device.
+
+         Executes an ATAPI soft reset if applicable, otherwise
+         executes an ATA soft reset on the controller.
+
+
+
+HDIO_DRIVE_TASKFILE            execute raw taskfile
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       Execute an ATA disk command directly by writing the "taskfile"
+       registers of the drive.  Requires ADMIN and RAWIO access
+       privileges.
+
+       usage:
+
+         struct {
+           ide_task_request_t req_task;
+           u8 outbuf[OUTPUT_SIZE];
+           u8 inbuf[INPUT_SIZE];
+         } task;
+         memset(&task.req_task, 0, sizeof(task.req_task));
+         task.req_task.out_size = sizeof(task.outbuf);
+         task.req_task.in_size = sizeof(task.inbuf);
+         ...
+         ioctl(fd, HDIO_DRIVE_TASKFILE, &task);
+         ...
+
+       inputs:
+
+         (See below for details on memory area passed to ioctl.)
+
+         io_ports[8]   values to be written to taskfile registers
+         hob_ports[8]  high-order bytes, for extended commands.
+         out_flags     flags indicating which registers are valid
+         in_flags      flags indicating which registers should be returned
+         data_phase    see below
+         req_cmd       command type to be executed
+         out_size      size of output buffer
+         outbuf        buffer of data to be transmitted to disk
+         inbuf         buffer of data to be received from disk (see [1])
+
+       outputs:
+
+         io_ports[]    values returned in the taskfile registers
+         hob_ports[]   high-order bytes, for extended commands.
+         out_flags     flags indicating which registers are valid (see [2])
+         in_flags      flags indicating which registers should be returned
+         outbuf        buffer of data to be transmitted to disk (see [1])
+         inbuf         buffer of data to be received from disk
+
+       error returns:
+         EACCES        CAP_SYS_ADMIN or CAP_SYS_RAWIO privilege not set.
+         ENOMSG        Device is not a disk drive.
+         ENOMEM        Unable to allocate memory for task
+         EFAULT        req_cmd == TASKFILE_IN_OUT (not implemented as of 2.6.8)
+         EPERM         req_cmd == TASKFILE_MULTI_OUT and drive
+                       multi-count not yet set.
+
+
+       notes:
+
+         [1] Currently (2.6.8), both the input and output buffers are
+         copied from the user and written back to the user, even when
+         not used.  This may be a bug.
+
+         [2] The out_flags and in_flags are returned to the user after
+         the ioctl completes.  Currently (2.6.8) these are the same
+         as the input values, unchanged.  In the future, they may have
+         more significance.
+
+         Extreme caution should be used with using this ioctl.  A
+         mistake can easily corrupt data or hang the system.
+
+         The argument to the ioctl is a pointer to a region of memory
+         containing a ide_task_request_t structure, followed by an
+         optional buffer of data to be transmitted to the drive,
+         followed by an optional buffer to receive data from the drive.
+
+         Command is passed to the disk drive via the ide_task_request_t
+         structure, which contains these fields:
+
+           io_ports[8]         values for the taskfile registers
+           hob_ports[8]        high-order bytes, for extended commands
+           out_flags           flags indicating which entries in the
+                               io_ports[] and hob_ports[] arrays
+                               contain valid values.  Type ide_reg_valid_t.
+           in_flags            flags indicating which entries in the
+                               io_ports[] and hob_ports[] arrays
+                               are expected to contain valid values
+                               on return.
+           data_phase          See below
+           req_cmd             Command type, see below
+           out_size            output (user->drive) buffer size, bytes
+           in_size             input (drive->user) buffer size, bytes
+
+         This ioctl does not necessarily respect all flags in the
+         out_flags and in_flags values -- some taskfile registers
+         may be written or read even if not requested in the flags.
+         Unused fields of io_ports[] and hob_ports[] should be set
+         to zero.
+
+         The data_phase field describes the data transfer to be
+         performed.  Value is one of:
+
+           TASKFILE_IN
+           TASKFILE_MULTI_IN
+           TASKFILE_OUT
+           TASKFILE_MULTI_OUT
+           TASKFILE_IN_OUT
+           TASKFILE_IN_DMA
+           TASKFILE_IN_DMAQ
+           TASKFILE_OUT_DMA
+           TASKFILE_OUT_DMAQ
+           TASKFILE_P_IN
+           TASKFILE_P_IN_DMA
+           TASKFILE_P_IN_DMAQ
+           TASKFILE_P_OUT
+           TASKFILE_P_OUT_DMA
+           TASKFILE_P_OUT_DMAQ
+
+         The req_cmd field classifies the command type.  It may be
+         one of:
+
+           IDE_DRIVE_TASK_NO_DATA
+           IDE_DRIVE_TASK_SET_XFER
+           IDE_DRIVE_TASK_IN
+           IDE_DRIVE_TASK_OUT
+           IDE_DRIVE_TASK_RAW_WRITE
+
+
+
+
+
+
+HDIO_DRIVE_CMD                 execute a special drive command
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       usage:
+
+         u8 args[4+XFER_SIZE];
+         ...
+         ioctl(fd, HDIO_DRIVE_CMD, args);
+
+       inputs:
+
+         Taskfile register values:
+           args[0]     COMMAND
+           args[1]     SECTOR
+           args[2]     FEATURE
+           args[3]     NSECTOR
+
+       outputs:
+
+         args[] buffer is filled with register values followed by any
+         data returned by the disk.
+           args[0]     status
+           args[1]     error
+           args[2]     NSECTOR
+           args[3]     undefined
+           args[4+]    NSECTOR * 512 bytes of data returned by the command.
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_RAWIO
+         ENOMEM        Unable to allocate memory for task
+
+       notes:
+
+         Taskfile registers IDE_LCYL, IDE_HCYL, and IDE_SELECT are
+         set to zero before executing the command.
+
+
+
+HDIO_DRIVE_TASK                        execute task and special drive command
+
+       Note:  If you don't have a copy of the ANSI ATA specification
+       handy, you should probably ignore this ioctl.
+
+       usage:
+
+         u8 args[7];
+         ...
+         ioctl(fd, HDIO_DRIVE_TASK, args);
+
+       inputs:
+
+         Taskfile register values:
+           args[0]     COMMAND
+           args[1]     FEATURE
+           args[2]     NSECTOR
+           args[3]     SECTOR
+           args[4]     LCYL
+           args[5]     HCYL
+           args[6]     SELECT
+
+       outputs:
+
+         Taskfile register values:
+           args[0]     status
+           args[1]     error
+           args[2]     NSECTOR
+           args[3]     SECTOR
+           args[4]     LCYL
+           args[5]     HCYL
+           args[6]     SELECT
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_RAWIO
+         ENOMEM        Unable to allocate memory for task
+
+
+
+
+HDIO_DRIVE_CMD_AEB             HDIO_DRIVE_TASK
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_32BIT                 change io_32bit flags
+
+       usage:
+
+         int val;
+         ioctl(fd, HDIO_SET_32BIT, val);
+
+       inputs:
+         New value for io_32bit flag
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 3]
+         EBUSY         Controller busy
+
+
+
+
+HDIO_SET_NOWERR                        change ignore-write-error flag
+
+       usage:
+
+         int val;
+         ioctl(fd, HDIO_SET_NOWERR, val);
+
+       inputs:
+         New value for ignore-write-error flag.  Used for ignoring
+         WRERR_STAT
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 1]
+         EBUSY         Controller busy
+
+
+
+HDIO_SET_DMA                   change use-dma flag
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_SET_DMA, val);
+
+       inputs:
+         New value for use-dma flag
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 1]
+         EBUSY         Controller busy
+
+
+
+HDIO_SET_PIO_MODE              reconfig interface to new speed
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_SET_PIO_MODE, val);
+
+       inputs:
+         New interface speed.
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 255]
+         EBUSY         Controller busy
+
+
+
+HDIO_SCAN_HWIF                 register and (re)scan interface
+
+       usage:
+
+         int args[3]
+         ...
+         ioctl(fd, HDIO_SCAN_HWIF, args);
+
+       inputs:
+         args[0]       io address to probe
+         args[1]       control address to probe
+         args[2]       irq number
+
+       outputs:        none
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_RAWIO
+         EIO           Probe failed.
+
+       notes:
+
+         This ioctl initializes the addresses and irq for a disk
+         controller, probes for drives, and creates /proc/ide
+         interfaces as appropiate.
+
+
+
+HDIO_UNREGISTER_HWIF           unregister interface
+
+       usage:
+
+         int index;
+         ioctl(fd, HDIO_UNREGISTER_HWIF, index);
+
+       inputs:
+         index         index of hardware interface to unregister
+
+       outputs:        none
+
+       error returns:
+         EACCES        Access denied:  requires CAP_SYS_RAWIO
+
+       notes:
+
+         This ioctl removes a hardware interface from the kernel.
+
+         Currently (2.6.8) this ioctl silently fails if any drive on
+         the interface is busy.
+
+
+
+HDIO_SET_WCACHE                        change write cache enable-disable
+
+       usage:
+
+         int val;
+         ioctl(fd, HDIO_SET_WCACHE, val);
+
+       inputs:
+         New value for write cache enable
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 1]
+         EBUSY         Controller busy
+
+
+
+HDIO_SET_ACOUSTIC              change acoustic behavior
+
+       usage:
+
+         int val;
+         ioctl(fd, HDIO_SET_ACOUSTIC, val);
+
+       inputs:
+         New value for drive acoustic settings
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 254]
+         EBUSY         Controller busy
+
+
+
+HDIO_SET_QDMA                  change use-qdma flag
+
+       Not implemented, as of 2.6.8.1
+
+
+
+HDIO_SET_ADDRESS               change lba addressing modes
+
+       usage:
+
+         int val;
+         ioctl(fd, HDIO_SET_ADDRESS, val);
+
+       inputs:
+         New value for addressing mode
+           0 = 28-bit
+           1 = 48-bit
+           2 = 48-bit doing 28-bit
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 2]
+         EBUSY         Controller busy
+         EIO           Drive does not support lba48 mode.
+
+
+HDIO_SET_IDE_SCSI
+
+       usage:
+
+         long val;
+         ioctl(fd, HDIO_SET_IDE_SCSI, val);
+
+       inputs:
+         New value for scsi emulation mode (?)
+
+       outputs:        none
+
+       error return:
+         EINVAL        (bdev != bdev->bd_contains) (not sure what this means)
+         EACCES        Access denied:  requires CAP_SYS_ADMIN
+         EINVAL        value out of range [0 1]
+         EBUSY         Controller busy
+
+
+
+HDIO_SET_SCSI_IDE
+
+       Not implemented, as of 2.6.8.1
+
+
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
new file mode 100644 (file)
index 0000000..36cbb0d
--- /dev/null
@@ -0,0 +1,836 @@
+                        ============================
+                        KERNEL KEY RETENTION SERVICE
+                        ============================
+
+This service allows cryptographic keys, authentication tokens, cross-domain
+user mappings, and similar to be cached in the kernel for the use of
+filesystems other kernel services.
+
+Keyrings are permitted; these are a special type of key that can hold links to
+other keys. Processes each have three standard keyring subscriptions that a
+kernel service can search for relevant keys.
+
+The key service can be configured on by enabling:
+
+       "Security options"/"Enable access key retention support" (CONFIG_KEYS)
+
+This document has the following sections:
+
+       - Key overview
+       - Key service overview
+       - Key access permissions
+       - New procfs files
+       - Userspace system call interface
+       - Kernel services
+       - Defining a key type
+       - Request-key callback service
+       - Key access filesystem
+
+
+============
+KEY OVERVIEW
+============
+
+In this context, keys represent units of cryptographic data, authentication
+tokens, keyrings, etc.. These are represented in the kernel by struct key.
+
+Each key has a number of attributes:
+
+       - A serial number.
+       - A type.
+       - A description (for matching a key in a search).
+       - Access control information.
+       - An expiry time.
+       - A payload.
+       - 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.
+
+     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.
+
+     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
+     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
+     whether a kernel service will be able to find the key.
+
+ (*) 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.
+
+     Having a payload is not required; and the payload can, in fact, just be a
+     value stored in the struct key itself.
+
+     When a key is instantiated, the key type's instantiation function is
+     called with a blob of data, and that then creates the key's payload in
+     some way.
+
+     Similarly, when userspace wants to read back the contents of the key, if
+     permitted, another key type operation will be called to convert the key's
+     attached payload back into a blob of data.
+
+ (*) 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.
+
+     (*) Instantiated. This is the normal state. The key is fully formed, and
+        has data attached.
+
+     (*) Negative. This is a relatively short-lived state. The key acts as a
+        note saying that a previous call out to userspace failed, and acts as
+        a throttle on key lookups. A negative key can be updated to a normal
+        state.
+
+     (*) Expired. Keys can have lifetimes set. If their lifetime is exceeded,
+        they traverse to this state. An expired key can be updated back to a
+        normal state.
+
+     (*) Revoked. A key is put in this state by userspace action. It can't be
+        found or operated upon (apart from by unlinking it).
+
+     (*) Dead. The key's type was unregistered, and so the key is now useless.
+
+
+====================
+KEY SERVICE OVERVIEW
+====================
+
+The key service provides a number of features besides keys:
+
+ (*) The key service defines two special key types:
+
+     (+) "keyring"
+
+        Keyrings are special keys that contain a list of other keys. Keyring
+        lists can be modified using various system calls. Keyrings should not
+        be given a payload when created.
+
+     (+) "user"
+
+        A key of this type has a description and a payload that are arbitrary
+        blobs of data. These can be created, updated and read by userspace,
+        and aren't intended for use by kernel services.
+
+ (*) Each process subscribes to three keyrings: a thread-specific keyring, a
+     process-specific keyring, and a session-specific keyring.
+
+     The thread-specific keyring is discarded from the child when any sort of
+     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
+     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
+     process can, however, replace its current session keyring with a new one
+     by using PR_JOIN_SESSION_KEYRING. It is permitted to request an anonymous
+     new one, or to attempt to create or join one of a specific name.
+
+     The ownership of the thread and process-specific keyrings changes when
+     the real UID and GID of the thread changes.
+
+ (*) Each user ID resident in the system holds two special keyrings: a user
+     specific keyring and a default user session keyring. The default session
+     keyring is initialised with a link to the user-specific keyring.
+
+     When a process changes its real UID, if it used to have no session key, it
+     will be subscribed to the default session key for the new UID.
+
+     If a process attempts to access its session key when it doesn't have one,
+     it will be subscribed to the default for its current UID.
+
+ (*) Each user has two quotas against which the keys they own are tracked. One
+     limits the total number of keys and keyrings, the other limits the total
+     amount of description and payload space that can be consumed.
+
+     The user can view information on this and other statistics through procfs
+     files.
+
+     Process-specific and thread-specific keyrings are not counted towards a
+     user's quota.
+
+     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 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.
+
+ (*) An optional filesystem is available through which the key database can be
+     viewed and manipulated.
+
+
+======================
+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:
+
+ (*) View
+
+     This permits a key or keyring's attributes to be viewed - including key
+     type and description.
+
+ (*) Read
+
+     This permits a key's payload to be viewed or a keyring's list of linked
+     keys.
+
+ (*) Write
+
+     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
+
+     This permits keyrings to be searched and keys to be found. Searches can
+     only recurse into nested keyrings that have search permission set.
+
+ (*) Link
+
+     This permits a key or keyring to be linked to. To create a link from a
+     keyring to a key, a process must have Write permission on the keyring and
+     Link permission on the key.
+
+For changing the ownership, group ID or permissions mask, being the owner of
+the key or having the sysadmin capability is sufficient.
+
+
+================
+NEW PROCFS FILES
+================
+
+Two files have been added to procfs by which an administrator can find out
+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:
+
+       SERIAL   FLAGS  USAGE EXPY PERM   UID   GID   TYPE      DESCRIPTION: SUMMARY
+       00000001 I-----    39 perm 1f0000     0     0 keyring   _uid_ses.0: 1/4
+       00000002 I-----     2 perm 1f0000     0     0 keyring   _uid.0: empty
+       00000007 I-----     1 perm 1f0000     0     0 keyring   _pid.1: empty
+       0000018d I-----     1 perm 1f0000     0     0 keyring   _pid.412: empty
+       000004d2 I--Q--     1 perm 1f0000    32    -1 keyring   _uid.32: 1/4
+       000004d3 I--Q--     3 perm 1f0000    32    -1 keyring   _uid_ses.32: empty
+       00000892 I--QU-     1 perm 1f0000     0     0 user      metal:copper: 0
+       00000893 I--Q-N     1  35s 1f0000     0     0 user      metal:silver: 0
+       00000894 I--Q--     1  10h 1f0000     0     0 user      metal:gold: 0
+
+     The flags are:
+
+       I       Instantiated
+       R       Revoked
+       D       Dead
+       Q       Contributes to user's quota
+       U       Under contruction by callback to userspace
+       N       Negative key
+
+     This file must be enabled at kernel configuration time as it allows anyone
+     to list the keys database.
+
+ (*) /proc/key-users
+
+     This file lists the tracking data for each user that has at least one key
+     on the system. Such data includes quota information and statistics:
+
+       [root@andromeda root]# cat /proc/key-users
+       0:     46 45/45 1/100 13/10000
+       29:     2 2/2 2/100 40/10000
+       32:     2 2/2 2/100 40/10000
+       38:     2 2/2 2/100 40/10000
+
+     The format of each line is
+       <UID>:                  User ID to which this applies
+       <usage>                 Structure refcount
+       <inst>/<keys>           Total number of keys and number instantiated
+       <keys>/<max>            Key count quota
+       <bytes>/<max>           Key size quota
+
+
+===============================
+USERSPACE SYSTEM CALL INTERFACE
+===============================
+
+Userspace can manipulate keys directly through three new syscalls: add_key,
+request_key and keyctl. The latter provides a number of functions for
+manipulating keys.
+
+When referring to a key directly, userspace programs should use the key's
+serial number (a positive 32-bit integer). However, there are some special
+values available for referring to special keys and keyrings that relate to the
+process making the call:
+
+       CONSTANT                        VALUE   KEY REFERENCED
+       ==============================  ======  ===========================
+       KEY_SPEC_THREAD_KEYRING         -1      thread-specific keyring
+       KEY_SPEC_PROCESS_KEYRING        -2      process-specific keyring
+       KEY_SPEC_SESSION_KEYRING        -3      session-specific keyring
+       KEY_SPEC_USER_KEYRING           -4      UID-specific keyring
+       KEY_SPEC_USER_SESSION_KEYRING   -5      UID-session keyring
+       KEY_SPEC_GROUP_KEYRING          -6      GID-specific keyring
+
+
+The main syscalls are:
+
+ (*) Create a new key of given type, description and payload and add it to the
+     nominated keyring:
+
+       key_serial_t add_key(const char *type, const char *desc,
+                            const void *payload, size_t plen,
+                            key_serial_t keyring);
+
+     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.
+
+     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.
+
+     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
+     ID and a colon, such as "krb5tgt:" for a Kerberos 5 ticket granting
+     ticket.
+
+     Any other type must have been registered with the kernel in advance by a
+     kernel service such as a filesystem.
+
+     The ID of the new or updated key is returned if successful.
+
+
+ (*) Search the process's keyrings for a key, potentially calling out to
+     userspace to create it.
+
+       key_serial_t request_key(const char *type, const char *description,
+                                const char *callout_info,
+                                key_serial_t dest_keyring);
+
+     This function searches all the process's keyrings in the order thread,
+     process, session for a matching key. This works very much like
+     KEYCTL_SEARCH, including the optional attachment of the discovered key to
+     a keyring.
+
+     If a key cannot be found, and if callout_info is not NULL, then
+     /sbin/request-key will be invoked in an attempt to obtain a key. The
+     callout_info string will be passed as an argument to the program.
+
+
+The keyctl syscall functions are:
+
+ (*) Map a special key ID to a real key ID for this process:
+
+       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.
+
+     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.
+
+
+ (*) Replace the session keyring this process subscribes to with a new one:
+
+       key_serial_t keyctl(KEYCTL_JOIN_SESSION_KEYRING, const char *name);
+
+     If name is NULL, an anonymous keyring is created attached to the process
+     as its session keyring, displacing the old session keyring.
+
+     If name is not NULL, if a keyring of that name exists, the process
+     attempts to attach it as the session keyring, returning an error if that
+     is not permitted; otherwise a new keyring of that name is created and
+     attached as the session keyring.
+
+     To attach to a named keyring, the keyring must have search permission for
+     the process's ownership.
+
+     The ID of the new session keyring is returned if successful.
+
+
+ (*) Update the specified key:
+
+       long keyctl(KEYCTL_UPDATE, key_serial_t key, const void *payload,
+                   size_t plen);
+
+     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.
+
+     The payload is of length plen, and may be absent or empty as for
+     add_key().
+
+
+ (*) Revoke a key:
+
+       long keyctl(KEYCTL_REVOKE, key_serial_t key);
+
+     This makes a key unavailable for further operations. Further attempts to
+     use the key will be met with error EKEYREVOKED, and the key will no longer
+     be findable.
+
+
+ (*) Change the ownership of a key:
+
+       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.
+
+     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
+     group ID to something other than the calling process's group ID or one of
+     its group list members.
+
+
+ (*) Change the permissions mask on a key:
+
+       long keyctl(KEYCTL_SETPERM, key_serial_t key, key_perm_t perm);
+
+     This function permits the owner of a key or the superuser to change the
+     permissions mask on a key.
+
+     Only bits the available bits are permitted; if any other bits are set,
+     error EINVAL will be returned.
+
+
+ (*) Describe a key:
+
+       long keyctl(KEYCTL_DESCRIBE, key_serial_t key, char *buffer,
+                   size_t buflen);
+
+     This function returns a summary of the key's attributes (but not its
+     payload data) as a string in the buffer provided.
+
+     Unless there's an error, it always returns the amount of data it could
+     produce, even if that's too big for the buffer, but it won't copy more
+     than requested to userspace. If the buffer pointer is NULL then no copy
+     will take place.
+
+     A process must have view permission on the key for this function to be
+     successful.
+
+     If successful, a string is placed in the buffer in the following format:
+
+       <type>;<uid>;<gid>;<perm>;<description>
+
+     Where type and description are strings, uid and gid are decimal, and perm
+     is hexadecimal. A NUL character is included at the end of the string if
+     the buffer is sufficiently big.
+
+     This can be parsed with
+
+       sscanf(buffer, "%[^;];%d;%d;%o;%s", type, &uid, &gid, &mode, desc);
+
+
+ (*) Clear out a keyring:
+
+       long keyctl(KEYCTL_CLEAR, key_serial_t keyring);
+
+     This function clears the list of keys attached to a keyring. The calling
+     process must have write permission on the keyring, and it must be a
+     keyring (or else error ENOTDIR will result).
+
+
+ (*) Link a key into a keyring:
+
+       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.
+
+     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.
+
+
+ (*) Unlink a key or keyring from another keyring:
+
+       long keyctl(KEYCTL_UNLINK, key_serial_t keyring, key_serial_t key);
+
+     This function looks through the keyring for the first link to the
+     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.
+
+
+ (*) Search a keyring tree for a key:
+
+       key_serial_t keyctl(KEYCTL_SEARCH, key_serial_t keyring,
+                           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.
+
+     The process must have search permission on the top level keyring, or else
+     error EACCES will result. Only keyrings that the process has search
+     permission on will be recursed into, and only keys and keyrings for which
+     a process has search permission can be matched. If the specified keyring
+     is not a keyring, ENOTDIR will result.
+
+     If the search succeeds, the function will attempt to link the found key
+     into the destination keyring if one is supplied (non-zero ID). All the
+     constraints applicable to KEYCTL_LINK apply in this case too.
+
+     Error ENOKEY, EKEYREVOKED or EKEYEXPIRED will be returned if the search
+     fails. On success, the resulting key ID will be returned.
+
+
+ (*) Read the payload data from a key:
+
+       key_serial_t keyctl(KEYCTL_READ, key_serial_t keyring, char *buffer,
+                           size_t buflen);
+
+     This function attempts to read the payload data from the specified key
+     into the buffer. The process must have read permission on the key to
+     succeed.
+
+     The returned data will be processed for presentation by the key type. For
+     instance, a keyring will return an array of key_serial_t entries
+     representing the IDs of all the keys to which it is subscribed. The user
+     defined key type will return its data as is. If a key type does not
+     implement this function, error EOPNOTSUPP will result.
+
+     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.
+
+
+ (*) Instantiate a partially constructed key.
+
+       key_serial_t keyctl(KEYCTL_INSTANTIATE, key_serial_t key,
+                           const void *payload, size_t plen,
+                           key_serial_t keyring);
+
+     If the kernel calls back to userspace to complete the instantiation of a
+     key, userspace should use this call to supply data for the key before the
+     invoked process returns, or else the key will be marked negative
+     automatically.
+
+     The process must have write access on the key to be able to instantiate
+     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.
+
+     The payload and plen arguments describe the payload data as for add_key().
+
+
+ (*) Negatively instantiate a partially constructed key.
+
+       key_serial_t keyctl(KEYCTL_NEGATE, key_serial_t key,
+                           unsigned timeout, key_serial_t keyring);
+
+     If the kernel calls back to userspace to complete the instantiation of a
+     key, userspace should use this call mark the key as negative before the
+     invoked process returns if it is unable to fulfil the request.
+
+     The process must have write access on the key to be able to instantiate
+     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.
+
+
+===============
+KERNEL SERVICES
+===============
+
+The kernel services for key managment are fairly simple to deal with. They can
+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, the key->lock should be at least read
+locked, or else the data may be changed by update during the access.
+
+(*) To search for a key, call:
+
+       struct key *request_key(const struct key_type *type,
+                               const char *description,
+                               const char *callout_string);
+
+    This is used to request a key or keyring with a description that matches
+    the description specified according to the key type's match function. This
+    permits approximate matching to occur. If callout_string is not NULL, then
+    /sbin/request-key will be invoked in an attempt to obtain the key from
+    userspace. In that case, callout_string will be passed as an argument to
+    the program.
+
+    Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
+    returned.
+
+
+(*) When it is no longer required, the key should be released using:
+
+       void key_put(struct key *key);
+
+    This can be called from interrupt context. If CONFIG_KEYS is not set then
+    the argument will not be parsed.
+
+
+(*) Extra references can be made to a key by calling the following function:
+
+       struct key *key_get(struct key *key);
+
+    These need to be disposed of by calling key_put() when they've been
+    finished with. The key pointer passed in will be returned. If the pointer
+    is NULL or CONFIG_KEYS is not set then the key will not be dereferenced and
+    no increment will take place.
+
+
+(*) A key's serial number can be obtained by calling:
+
+       key_serial_t key_serial(struct key *key);
+
+    If key is NULL or if CONFIG_KEYS is not set then 0 will be returned (in the
+    latter case without parsing the argument).
+
+
+(*) If a keyring was found in the search, this can be further searched by:
+
+       struct key *keyring_search(struct key *keyring,
+                                  const struct key_type *type,
+                                  const char *description)
+
+    This searches the keyring tree specified for a matching key. Error ENOKEY
+    is returned upon failure. If successful, the returned key will need to be
+    released.
+
+
+(*) To check the validity of a key, this function can be called:
+
+       int validate_key(struct key *key);
+
+    This checks that the key in question hasn't expired or and hasn't been
+    revoked. Should the key be invalid, error EKEYEXPIRED or EKEYREVOKED will
+    be returned. If the key is NULL or if CONFIG_KEYS is not set then 0 will be
+    returned (in the latter case without parsing the argument).
+
+
+(*) To register a key type, the following function should be called:
+
+       int register_key_type(struct key_type *type);
+
+    This will return error EEXIST if a type of the same name is already
+    present.
+
+
+(*) To unregister a key type, call:
+
+       void unregister_key_type(struct key_type *type);
+
+
+===================
+DEFINING A KEY TYPE
+===================
+
+A kernel service may want to define its own key type. For instance, an AFS
+filesystem might want to define a Kerberos 5 ticket key type. To do this, it
+author fills in a struct key_type and registers it with the system.
+
+The structure has a number of fields, some of which are mandatory:
+
+ (*) const char *name
+
+     The name of the key type. This is used to translate a key type name
+     supplied by userspace into a pointer to the structure.
+
+
+ (*) size_t def_datalen
+
+     This is optional - it supplies the default payload data length as
+     contributed to the quota. If the key type's payload is always or almost
+     always the same size, then this is a more efficient way to do things.
+
+     The data length (and quota) on a particular key can always be changed
+     during instantiation or update by calling:
+
+       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.
+
+
+ (*) 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.
+
+     If the amount of data attached to the key differs from the size in
+     keytype->def_datalen, then key_payload_reserve() should be called.
+
+
+ (*) 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.
+
+     The source key will be locked against change on the source->sem, so it is
+     safe to sleep here.
+
+
+ (*) 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.
+
+     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.
+
+     The key will be locked against other changers on key->sem, so it is safe
+     to sleep here.
+
+     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.
+
+
+ (*) int (*match)(const struct key *key, const void *desc);
+
+     This method is called to match a key against a description. It should
+     return non-zero if the two match, zero if they don't.
+
+
+ (*) 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.
+
+
+ (*) void (*describe)(const struct key *key, struct seq_file *p);
+
+     This method is optional. It is called during /proc/keys reading to
+     summarise a key in text form.
+
+
+ (*) 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.
+
+     If successful, the blob size that could be produced should be returned
+     rather than the size copied.
+
+
+============================
+REQUEST-KEY CALLBACK SERVICE
+============================
+
+To create a new key, the kernel will attempt to execute the following command
+line:
+
+       /sbin/request-key create <key> <uid> <gid> \
+               <threadring> <processring> <sessionring> <callout_info>
+
+<key> is the key being constructed, and the three keyrings are the process
+keyrings from the process that caused the search to be issued. These are
+included for two reasons:
+
+  (1) There may be an authentication token in one of the keyrings that is
+      required to obtain the key, eg: a Kerberos Ticket-Granting Ticket.
+
+  (2) The new key should probably be cached in one of these rings.
+
+This program should set it UID and GID to those specified before attempting to
+access any more keys. It may then look around for a user specific process to
+hand the request off to (perhaps a path held in placed in another key by, for
+example, the KDE desktop manager).
+
+The program (or whatever it calls) should finish construction of the key by
+calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of
+the keyrings (probably the session ring) before returning. Alternatively, the
+key can be marked as negative with KEYCTL_NEGATE; this also permits the key to
+be cached in one of the keyrings.
+
+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
+information was made available, then "-" will be passed as this parameter
+instead.
+
+
+Similarly, the kernel may attempt to update an expired or a soon to expire key
+by executing:
+
+       /sbin/request-key update <key> <uid> <gid> \
+               <threadring> <processring> <sessionring>
+
+In this case, the program isn't required to actually attach the key to a ring;
+the rings are provided for reference.
diff --git a/Documentation/networking/gen_stats.txt b/Documentation/networking/gen_stats.txt
new file mode 100644 (file)
index 0000000..c3297f7
--- /dev/null
@@ -0,0 +1,117 @@
+Generic networking statistics for netlink users
+======================================================================
+
+Statistic counters are grouped into structs:
+
+Struct               TLV type              Description
+----------------------------------------------------------------------
+gnet_stats_basic     TCA_STATS_BASIC       Basic statistics
+gnet_stats_rate_est  TCA_STATS_RATE_EST    Rate estimator
+gnet_stats_queue     TCA_STATS_QUEUE       Queue statistics
+none                 TCA_STATS_APP         Application specific
+
+
+Collecting:
+-----------
+
+Declare the statistic structs you need:
+struct mystruct {
+       struct gnet_stats_basic bstats;
+       struct gnet_stats_queue qstats;
+       ...
+};
+
+Update statistics:
+mystruct->tstats.packet++;
+mystruct->qstats.backlog += skb->pkt_len;
+
+
+Export to userspace (Dump):
+---------------------------
+
+my_dumping_routine(struct sk_buff *skb, ...)
+{
+       struct gnet_dump dump;
+
+       if (gnet_stats_start_copy(skb, TCA_STATS2, &mystruct->lock, &dump) < 0)
+               goto rtattr_failure;
+
+       if (gnet_stats_copy_basic(&dump, &mystruct->bstats) < 0 ||
+           gnet_stats_copy_queue(&dump, &mystruct->qstats) < 0 ||
+               gnet_stats_copy_app(&dump, &xstats, sizeof(xstats)) < 0)
+               goto rtattr_failure;
+
+       if (gnet_stats_finish_copy(&dump) < 0)
+               goto rtattr_failure;
+       ...
+}
+
+TCA_STATS/TCA_XSTATS backward compatibility:
+--------------------------------------------
+
+Prior users of struct tc_stats and xstats can maintain backward
+compatibility by calling the compat wrappers to keep providing the
+existing TLV types.
+
+my_dumping_routine(struct sk_buff *skb, ...)
+{
+    if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
+               TCA_XSTATS, &mystruct->lock, &dump) < 0)
+               goto rtattr_failure;
+       ...
+}
+
+A struct tc_stats will be filled out during gnet_stats_copy_* calls
+and appended to the skb. TCA_XSTATS is provided if gnet_stats_copy_app
+was called.
+
+
+Locking:
+--------
+
+Locks are taken before writing and released once all statistics have
+been written. Locks are always released in case of an error. You
+are responsible for making sure that the lock is initialized.
+
+
+Rate Estimator:
+--------------
+
+0) Prepare an estimator attribute. Most likely this would be in user
+   space. The value of this TLV should contain a tc_estimator structure.
+   As usual, such a TLV nees to be 32 bit aligned and therefore the
+   length needs to be appropriately set etc. The estimator interval
+   and ewma log need to be converted to the appropriate values.
+   tc_estimator.c::tc_setup_estimator() is advisable to be used as the
+   conversion routine. It does a few clever things. It takes a time
+   interval in microsecs, a time constant also in microsecs and a struct
+   tc_estimator to  be populated. The returned tc_estimator can be
+   transported to the kernel.  Transfer such a structure in a TLV of type
+   TCA_RATE to your code in the kernel.
+
+In the kernel when setting up:
+1) make sure you have basic stats and rate stats setup first.
+2) make sure you have initialized stats lock that is used to setup such
+   stats.
+3) Now initialize a new estimator:
+
+   int ret = gen_new_estimator(my_basicstats,my_rate_est_stats,
+       mystats_lock, attr_with_tcestimator_struct);
+
+   if ret == 0
+       success
+   else
+       failed
+
+From now on, everytime you dump my_rate_est_stats it will contain
+uptodate info.
+
+Once you are done, call gen_kill_estimator(my_basicstats,
+my_rate_est_stats) Make sure that my_basicstats and my_rate_est_stats
+are still valid (i.e still exist) at the time of making this call.
+
+
+Authors:
+--------
+Thomas Graf <tgraf@suug.ch>
+Jamal Hadi Salim <hadi@cyberus.ca>
diff --git a/Documentation/networking/proc_net_tcp.txt b/Documentation/networking/proc_net_tcp.txt
new file mode 100644 (file)
index 0000000..59cb915
--- /dev/null
@@ -0,0 +1,47 @@
+This document describes the interfaces /proc/net/tcp and /proc/net/tcp6.
+
+These /proc interfaces provide information about currently active TCP 
+connections, and are implemented by tcp_get_info() in net/ipv4/tcp_ipv4.c and
+tcp6_get_info() in net/ipv6/tcp_ipv6.c, respectively.
+
+It will first list all listening TCP sockets, and next list all established
+TCP connections. A typical entry of /proc/net/tcp would look like this (split 
+up into 3 parts because of the length of the line):
+
+   46: 010310AC:9C4C 030310AC:1770 01 
+   |      |      |      |      |   |--> connection state
+   |      |      |      |      |------> remote TCP port number
+   |      |      |      |-------------> remote IPv4 address
+   |      |      |--------------------> local TCP port number
+   |      |---------------------------> local IPv4 address
+   |----------------------------------> number of entry
+
+   00000150:00000000 01:00000019 00000000  
+      |        |     |     |       |--> number of unrecovered RTO timeouts
+      |        |     |     |----------> number of jiffies until timer expires
+      |        |     |----------------> timer_active (see below)
+      |        |----------------------> receive-queue
+      |-------------------------------> transmit-queue
+
+   1000        0 54165785 4 cd1e6040 25 4 27 3 -1
+    |          |    |     |    |     |  | |  | |--> slow start size threshold, 
+    |          |    |     |    |     |  | |  |      or -1 if the treshold
+    |          |    |     |    |     |  | |  |      is >= 0xFFFF
+    |          |    |     |    |     |  | |  |----> sending congestion window
+    |          |    |     |    |     |  | |-------> (ack.quick<<1)|ack.pingpong
+    |          |    |     |    |     |  |---------> Predicted tick of soft clock
+    |          |    |     |    |     |              (delayed ACK control data)
+    |          |    |     |    |     |------------> retransmit timeout
+    |          |    |     |    |------------------> location of socket in memory
+    |          |    |     |-----------------------> socket reference count
+    |          |    |-----------------------------> inode
+    |          |----------------------------------> unanswered 0-window probes
+    |---------------------------------------------> uid
+
+timer_active:
+  0  no timer is pending
+  1  retransmit-timer is pending
+  2  another timer (e.g. delayed ack or keepalive) is pending
+  3  this is a socket in TIME_WAIT state. Not all fields will contain 
+     data (or even exist)
+  4  zero window probe timer is pending
diff --git a/Documentation/power/kernel_threads.txt b/Documentation/power/kernel_threads.txt
new file mode 100644 (file)
index 0000000..60b5481
--- /dev/null
@@ -0,0 +1,41 @@
+KERNEL THREADS
+
+
+Freezer
+
+Upon entering a suspended state the system will freeze all
+tasks. This is done by delivering pseudosignals. This affects
+kernel threads, too. To successfully freeze a kernel thread
+the thread has to check for the pseudosignal and enter the
+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);
+       } while (!signal_pending(current));
+
+from drivers/usb/core/hub.c::hub_thread()
+
+
+The Unfreezable
+
+Some kernel threads however, must not be frozen. The kernel must
+be able to finish pending IO operations and later on be able to
+write the memory image to disk. Kernel threads needed to do IO
+must stay awake. Such threads must mark themselves unfreezable
+like this:
+
+       /*
+        * This thread doesn't need any user-level access,
+        * so get rid of all our resources.
+        */
+       daemonize("usb-storage");
+
+       current->flags |= PF_NOFREEZE;
+
+from drivers/usb/storage/usb.c::usb_stor_control_thread()
+
+Such drivers are themselves responsible for staying quiet during
+the actual snapshotting.
diff --git a/Documentation/power/video_extension.txt b/Documentation/power/video_extension.txt
new file mode 100644 (file)
index 0000000..8e33d7c
--- /dev/null
@@ -0,0 +1,34 @@
+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/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.
+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/*/brightness : Used to get/set brightness of output device
+
+Notify event through /proc/acpi/event:
+
+#define ACPI_VIDEO_NOTIFY_SWITCH        0x80
+#define ACPI_VIDEO_NOTIFY_PROBE         0x81
+#define ACPI_VIDEO_NOTIFY_CYCLE         0x82
+#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT   0x83
+#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT   0x84
+
+#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS      0x82
+#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS        0x83
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS        0x84
+#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS       0x85
+#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF           0x86
+
diff --git a/Documentation/prio_tree.txt b/Documentation/prio_tree.txt
new file mode 100644 (file)
index 0000000..2fbb0c4
--- /dev/null
@@ -0,0 +1,107 @@
+The prio_tree.c code indexes vmas using 3 different indexes:
+       * heap_index  = vm_pgoff + vm_size_in_pages : end_vm_pgoff
+       * radix_index = vm_pgoff : start_vm_pgoff
+       * size_index = vm_size_in_pages
+
+A regular radix-priority-search-tree indexes vmas using only heap_index and
+radix_index. The conditions for indexing are:
+       * ->heap_index >= ->left->heap_index &&
+               ->heap_index >= ->right->heap_index
+       * if (->heap_index == ->left->heap_index)
+               then ->radix_index < ->left->radix_index;
+       * if (->heap_index == ->right->heap_index)
+               then ->radix_index < ->right->radix_index;
+       * nodes are hashed to left or right subtree using radix_index
+         similar to a pure binary radix tree.
+
+A regular radix-priority-search-tree helps to store and query
+intervals (vmas). However, a regular radix-priority-search-tree is only
+suitable for storing vmas with different radix indices (vm_pgoff).
+
+Therefore, the prio_tree.c extends the regular radix-priority-search-tree
+to handle many vmas with the same vm_pgoff. Such vmas are handled in
+2 different ways: 1) All vmas with the same radix _and_ heap indices are
+linked using vm_set.list, 2) if there are many vmas with the same radix
+index, but different heap indices and if the regular radix-priority-search
+tree cannot index them all, we build an overflow-sub-tree that indexes such
+vmas using heap and size indices instead of heap and radix indices. For
+example, in the figure below some vmas with vm_pgoff = 0 (zero) are
+indexed by regular radix-priority-search-tree whereas others are pushed
+into an overflow-subtree. Note that all vmas in an overflow-sub-tree have
+the same vm_pgoff (radix_index) and if necessary we build different
+overflow-sub-trees to handle each possible radix_index. For example,
+in figure we have 3 overflow-sub-trees corresponding to radix indices
+0, 2, and 4.
+
+In the final tree the first few (prio_tree_root->index_bits) levels
+are indexed using heap and radix indices whereas the overflow-sub-trees below
+those levels (i.e. levels prio_tree_root->index_bits + 1 and higher) are
+indexed using heap and size indices. In overflow-sub-trees the size_index
+is used for hashing the nodes to appropriate places.
+
+Now, an example prio_tree:
+
+  vmas are represented [radix_index, size_index, heap_index]
+                 i.e., [start_vm_pgoff, vm_size_in_pages, end_vm_pgoff]
+
+level  prio_tree_root->index_bits = 3
+-----
+                                                                                               _
+  0                                                    [0,7,7]                                  |
+                                                       /     \                                  |
+                                     ------------------       ------------                      |     Regular
+                                    /                                     \                     |  radix priority
+  1                            [1,6,7]                                   [4,3,7]                |   search tree
+                               /     \                                   /     \                |
+                        -------       -----                        ------       -----           |  heap-and-radix
+                       /                   \                      /                  \          |      indexed
+  2                [0,6,6]                [2,5,7]              [5,2,7]             [6,1,7]      |
+                   /     \                /     \              /     \             /     \      |
+  3            [0,5,5] [1,5,6]         [2,4,6] [3,4,7]     [4,2,6] [5,1,6]     [6,0,6] [7,0,7]  |
+                  /                       /                   /                                _
+                  /                      /                   /                                 _
+  4          [0,4,4]                 [2,3,5]              [4,1,5]                               |
+                /                       /                    /                                  |
+  5         [0,3,3]                 [2,2,4]              [4,0,4]                                |  Overflow-sub-trees
+               /                       /                                                        |
+  6        [0,2,2]                 [2,1,3]                                                      |    heap-and-size
+              /                       /                                                         |       indexed
+  7       [0,1,1]                 [2,0,2]                                                       |
+             /                                                                                  |
+  8      [0,0,0]                                                                                |
+                                                                                               _
+
+Note that we use prio_tree_root->index_bits to optimize the height
+of the heap-and-radix indexed tree. Since prio_tree_root->index_bits is
+set according to the maximum end_vm_pgoff mapped, we are sure that all
+bits (in vm_pgoff) above prio_tree_root->index_bits are 0 (zero). Therefore,
+we only use the first prio_tree_root->index_bits as radix_index.
+Whenever index_bits is increased in prio_tree_expand, we shuffle the tree
+to make sure that the first prio_tree_root->index_bits levels of the tree
+is indexed properly using heap and radix indices.
+
+We do not optimize the height of overflow-sub-trees using index_bits.
+The reason is: there can be many such overflow-sub-trees and all of
+them have to be suffled whenever the index_bits increases. This may involve
+walking the whole prio_tree in prio_tree_insert->prio_tree_expand code
+path which is not desirable. Hence, we do not optimize the height of the
+heap-and-size indexed overflow-sub-trees using prio_tree->index_bits.
+Instead the overflow sub-trees are indexed using full BITS_PER_LONG bits
+of size_index. This may lead to skewed sub-trees because most of the
+higher significant bits of the size_index are likely to be be 0 (zero). In
+the example above, all 3 overflow-sub-trees are skewed. This may marginally
+affect the performance. However, processes rarely map many vmas with the
+same start_vm_pgoff but different end_vm_pgoffs. Therefore, we normally
+do not require overflow-sub-trees to index all vmas.
+
+From the above discussion it is clear that the maximum height of
+a prio_tree can be prio_tree_root->index_bits + BITS_PER_LONG.
+However, in most of the common cases we do not need overflow-sub-trees,
+so the tree height in the common cases will be prio_tree_root->index_bits.
+
+It is fair to mention here that the prio_tree_root->index_bits
+is increased on demand, however, the index_bits is not decreased when
+vmas are removed from the prio_tree. That's tricky to do. Hence, it's
+left as a home work problem.
+
+
diff --git a/Documentation/s390/monreader.txt b/Documentation/s390/monreader.txt
new file mode 100644 (file)
index 0000000..d843bb0
--- /dev/null
@@ -0,0 +1,197 @@
+
+Date  : 2004-Nov-26
+Author: Gerald Schaefer (geraldsc@de.ibm.com)
+
+
+             Linux API for read access to z/VM Monitor Records
+             =================================================
+
+
+Description
+===========
+This item delivers a new Linux API in the form of a misc char device that is
+useable from user space and allows read access to the z/VM Monitor Records
+collected by the *MONITOR System Service of z/VM.
+
+
+User Requirements
+=================
+The z/VM guest on which you want to access this API needs to be configured in
+order to allow IUCV connections to the *MONITOR service, i.e. it needs the
+IUCV *MONITOR statement in its user entry. If the monitor DCSS to be used is
+restricted (likely), you also need the NAMESAVE <DCSS NAME> statement.
+This item will use the IUCV device driver to access the z/VM services, so you
+need a kernel with IUCV support. You also need z/VM version 4.4 or 5.1.
+
+There are two options for being able to load the monitor DCSS (examples assume
+that the monitor DCSS begins at 144 MB and ends at 152 MB). You can query the
+location of the monitor DCSS with the Class E privileged CP command Q NSS MAP
+(the values BEGPAG and ENDPAG are given in units of 4K pages).
+
+See also "CP Command and Utility Reference" (SC24-6081-00) for more information
+on the DEF STOR and Q NSS MAP commands, as well as "Saved Segments Planning
+and Administration" (SC24-6116-00) for more information on DCSSes.
+
+1st option:
+-----------
+You can use the CP command DEF STOR CONFIG to define a "memory hole" in your
+guest virtual storage around the address range of the DCSS.
+
+Example: DEF STOR CONFIG 0.140M 200M.200M
+
+This defines two blocks of storage, the first is 140MB in size an begins at
+address 0MB, the second is 200MB in size and begins at address 200MB,
+resulting in a total storage of 340MB. Note that the first block should
+always start at 0 and be at least 64MB in size.
+
+2nd option:
+-----------
+Your guest virtual storage has to end below the starting address of the DCSS
+and you have to specify the "mem=" kernel parameter in your parmfile with a
+value greater than the ending address of the DCSS.
+
+Example: DEF STOR 140M
+
+This defines 140MB storage size for your guest, the parameter "mem=160M" is
+added to the parmfile.
+
+
+User Interface
+==============
+The char device is implemented as a kernel module named "monreader",
+which can be loaded via the modprobe command, or it can be compiled into the
+kernel instead. There is one optional module (or kernel) parameter, "mondcss",
+to specify the name of the monitor DCSS. If the module is compiled into the
+kernel, the kernel parameter "monreader.mondcss=<DCSS NAME>" can be specified
+in the parmfile.
+
+The default name for the DCSS is "MONDCSS" if none is specified. In case that
+there are other users already connected to the *MONITOR service (e.g.
+Performance Toolkit), the monitor DCSS is already defined and you have to use
+the same DCSS. The CP command Q MONITOR (Class E privileged) shows the name
+of the monitor DCSS, if already defined, and the users connected to the
+*MONITOR service.
+Refer to the "z/VM Performance" book (SC24-6109-00) on how to create a monitor
+DCSS if your z/VM doesn't have one already, you need Class E privileges to
+define and save a DCSS.
+
+Example:
+--------
+modprobe monreader mondcss=MYDCSS
+
+This loads the module and sets the DCSS name to "MYDCSS".
+
+NOTE:
+-----
+This API provides no interface to control the *MONITOR service, e.g. specifiy
+which data should be collected. This can be done by the CP command MONITOR
+(Class E privileged), see "CP Command and Utility Reference".
+
+Device nodes with udev:
+-----------------------
+After loading the module, a char device will be created along with the device
+node /<udev directory>/monreader.
+
+Device nodes without udev:
+--------------------------
+If your distribution does not support udev, a device node will not be created
+automatically and you have to create it manually after loading the module.
+Therefore you need to know the major and minor numbers of the device. These
+numbers can be found in /sys/class/misc/monreader/dev.
+Typing cat /sys/class/misc/monreader/dev will give an output of the form
+<major>:<minor>. The device node can be created via the mknod command, enter
+mknod <name> c <major> <minor>, where <name> is the name of the device node
+to be created.
+
+Example:
+--------
+# modprobe monreader
+# cat /sys/class/misc/monreader/dev
+10:63
+# mknod /dev/monreader c 10 63
+
+This loads the module with the default monitor DCSS (MONDCSS) and creates a
+device node.
+
+File operations:
+----------------
+The following file operations are supported: open, release, read, poll.
+There are two alternative methods for reading: either non-blocking read in
+conjunction with polling, or blocking read without polling. IOCTLs are not
+supported.
+
+Read:
+-----
+Reading from the device provides a 12 Byte monitor control element (MCE),
+followed by a set of one or more contiguous monitor records (similar to the
+output of the CMS utility MONWRITE without the 4K control blocks). The MCE
+contains information on the type of the following record set (sample/event
+data), the monitor domains contained within it and the start and end address
+of the record set in the monitor DCSS. The start and end address can be used
+to determine the size of the record set, the end address is the address of the
+last byte of data. The start address is needed to handle "end-of-frame" records
+correctly (domain 1, record 13), i.e. it can be used to determine the record
+start offset relative to a 4K page (frame) boundary.
+
+See "Appendix A: *MONITOR" in the "z/VM Performance" document for a description
+of the monitor control element layout. The layout of the monitor records can
+be found here (z/VM 5.1): http://www.vm.ibm.com/pubs/mon510/index.html
+
+The layout of the data stream provided by the monreader device is as follows:
+...
+<0 byte read>
+<first MCE>              \
+<first set of records>    |
+...                       |- data set
+<last MCE>                |
+<last set of records>    /
+<0 byte read>
+...
+
+There may be more than one combination of MCE and corresponding record set
+within one data set and the end of each data set is indicated by a successful
+read with a return value of 0 (0 byte read).
+Any received data must be considered invalid until a complete set was
+read successfully, including the closing 0 byte read. Therefore you should
+always read the complete set into a buffer before processing the data.
+
+The maximum size of a data set can be as large as the size of the
+monitor DCSS, so design the buffer adequately or use dynamic memory allocation.
+The size of the monitor DCSS will be printed into syslog after loading the
+module. You can also use the (Class E privileged) CP command Q NSS MAP to
+list all available segments and information about them.
+
+As with most char devices, error conditions are indicated by returning a
+negative value for the number of bytes read. In this case, the errno variable
+indicates the error condition:
+
+EIO: reply failed, read data is invalid and the application
+     should discard the data read since the last successful read with 0 size.
+EFAULT: copy_to_user failed, read data is invalid and the application should
+        discard the data read since the last successful read with 0 size.
+EAGAIN: occurs on a non-blocking read if there is no data available at the
+        moment. There is no data missing or corrupted, just try again or rather
+        use polling for non-blocking reads.
+EOVERFLOW: message limit reached, the data read since the last successful
+           read with 0 size is valid but subsequent records may be missing.
+
+In the last case (EOVERFLOW) there may be missing data, in the first two cases
+(EIO, EFAULT) there will be missing data. It's up to the application if it will
+continue reading subsequent data or rather exit.
+
+Open:
+-----
+Only one user is allowed to open the char device. If it is already in use, the
+open function will fail (return a negative value) and set errno to EBUSY.
+The open function may also fail if an IUCV connection to the *MONITOR service
+cannot be established. In this case errno will be set to EIO and an error
+message with an IPUSER SEVER code will be printed into syslog. The IPUSER SEVER
+codes are described in the "z/VM Performance" book, Appendix A.
+
+NOTE:
+-----
+As soon as the device is opened, incoming messages will be accepted and they
+will account for the message limit, i.e. opening the device without reading
+from it will provoke the "message limit reached" error (EOVERFLOW error code)
+eventually.
+
diff --git a/Documentation/sched-stats.txt b/Documentation/sched-stats.txt
new file mode 100644 (file)
index 0000000..6f72021
--- /dev/null
@@ -0,0 +1,153 @@
+Version 10 of schedstats includes support for sched_domains, which
+hit the mainline kernel in 2.6.7.  Some counters make more sense to be
+per-runqueue; other to be per-domain.  Note that domains (and their associated
+information) will only be pertinent and available on machines utilizing
+CONFIG_SMP.
+
+In version 10 of schedstat, there is at least one level of domain
+statistics for each cpu listed, and there may well be more than one
+domain.  Domains have no particular names in this implementation, but
+the highest numbered one typically arbitrates balancing across all the
+cpus on the machine, while domain0 is the most tightly focused domain,
+sometimes balancing only between pairs of cpus.  At this time, there
+are no architectures which need more than three domain levels. The first
+field in the domain stats is a bit map indicating which cpus are affected
+by that domain.
+
+These fields are counters, and only increment.  Programs which make use
+of these will need to start with a baseline observation and then calculate
+the change in the counters at each subsequent observation.  A perl script
+which does this for many of the fields is available at
+
+    http://eaglet.rain.com/rick/linux/schedstat/
+
+Note that any such script will necessarily be version-specific, as the main
+reason to change versions is changes in the output format.  For those wishing
+to write their own scripts, the fields are described here.
+
+CPU statistics
+--------------
+cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
+
+NOTE: In the sched_yield() statistics, the active queue is considered empty
+    if it has only one process in it, since obviously the process calling
+    sched_yield() is that process.
+
+First four fields are sched_yield() statistics:
+     1) # of times both the active and the expired queue were empty
+     2) # of times just the active queue was empty
+     3) # of times just the expired queue was empty
+     4) # of times sched_yield() was called
+
+Next four are schedule() statistics:
+     5) # of times the active queue had at least one other process on it
+     6) # of times we switched to the expired queue and reused it
+     7) # of times schedule() was called
+     8) # of times schedule() left the processor idle
+
+Next four are active_load_balance() statistics:
+     9) # of times active_load_balance() was called
+    10) # of times active_load_balance() caused this cpu to gain a task
+    11) # of times active_load_balance() caused this cpu to lose a task
+    12) # of times active_load_balance() tried to move a task and failed
+
+Next three are try_to_wake_up() statistics:
+    13) # of times try_to_wake_up() was called
+    14) # of times try_to_wake_up() successfully moved the awakening task
+    15) # of times try_to_wake_up() attempted to move the awakening task
+
+Next two are wake_up_new_task() statistics:
+    16) # of times wake_up_new_task() was called
+    17) # of times wake_up_new_task() successfully moved the new task
+
+Next one is a sched_migrate_task() statistic:
+    18) # of times sched_migrate_task() was called
+
+Next one is a sched_balance_exec() statistic:
+    19) # of times sched_balance_exec() was called
+
+Next three are statistics describing scheduling latency:
+    20) sum of all time spent running by tasks on this processor (in ms)
+    21) sum of all time spent waiting to run by tasks on this processor (in ms)
+    22) # of tasks (not necessarily unique) given to the processor
+
+The last six are statistics dealing with pull_task():
+    23) # of times pull_task() moved a task to this cpu when newly idle
+    24) # of times pull_task() stole a task from this cpu when another cpu
+       was newly idle
+    25) # of times pull_task() moved a task to this cpu when idle
+    26) # of times pull_task() stole a task from this cpu when another cpu
+       was idle
+    27) # of times pull_task() moved a task to this cpu when busy
+    28) # of times pull_task() stole a task from this cpu when another cpu
+       was busy
+
+
+Domain statistics
+-----------------
+One of these is produced per domain for each cpu described. (Note that if
+CONFIG_SMP is not defined, *no* domains are utilized and these lines
+will not appear in the output.)
+
+domain<N> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+
+The first field is a bit mask indicating what cpus this domain operates over.
+
+The next fifteen are a variety of load_balance() statistics:
+
+     1) # of times in this domain load_balance() was called when the cpu
+       was idle
+     2) # of times in this domain load_balance() was called when the cpu
+       was busy
+     3) # of times in this domain load_balance() was called when the cpu
+       was just becoming idle
+     4) # of times in this domain load_balance() tried to move one or more
+       tasks and failed, when the cpu was idle
+     5) # of times in this domain load_balance() tried to move one or more
+       tasks and failed, when the cpu was busy
+     6) # of times in this domain load_balance() tried to move one or more
+       tasks and failed, when the cpu was just becoming idle
+     7) sum of imbalances discovered (if any) with each call to
+       load_balance() in this domain when the cpu was idle
+     8) sum of imbalances discovered (if any) with each call to
+       load_balance() in this domain when the cpu was busy
+     9) sum of imbalances discovered (if any) with each call to
+       load_balance() in this domain when the cpu was just becoming idle
+    10) # of times in this domain load_balance() was called but did not find
+       a busier queue while the cpu was idle
+    11) # of times in this domain load_balance() was called but did not find
+       a busier queue while the cpu was busy
+    12) # of times in this domain load_balance() was called but did not find
+       a busier queue while the cpu was just becoming idle
+    13) # of times in this domain a busier queue was found while the cpu was
+       idle but no busier group was found
+    14) # of times in this domain a busier queue was found while the cpu was
+       busy but no busier group was found
+    15) # of times in this domain a busier queue was found while the cpu was
+       just becoming idle but no busier group was found
+
+Next two are sched_balance_exec() statistics:
+    17) # of times in this domain sched_balance_exec() successfully pushed
+       a task to a new cpu
+    18) # of times in this domain sched_balance_exec() tried but failed to
+       push a task to a new cpu
+
+Next two are try_to_wake_up() statistics:
+    19) # of times in this domain try_to_wake_up() tried to move a task based
+       on affinity and cache warmth
+    20) # of times in this domain try_to_wake_up() tried to move a task based
+       on load balancing
+
+
+/proc/<pid>/schedstat
+----------------
+schedstats also adds a new /proc/<pid/schedstat file to include some of
+the same information on a per-process level.  There are three fields in
+this file correlating to fields 20, 21, and 22 in the CPU fields, but
+they only apply for that process.
+
+A program could be easily written to make use of these extra fields to
+report on how well a particular process or set of processes is faring
+under the scheduler's policies.  A simple version of such a program is
+available at
+    http://eaglet.rain.com/rick/linux/schedstat/v10/latency.c
diff --git a/Documentation/scsi/megaraid.txt b/Documentation/scsi/megaraid.txt
new file mode 100644 (file)
index 0000000..ff864c0
--- /dev/null
@@ -0,0 +1,70 @@
+                       Notes on Management Module
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Overview:
+--------
+
+Different classes of controllers from LSI Logic, accept and respond to the
+user applications in a similar way. They understand the same firmware control
+commands. Furthermore, the applications also can treat different classes of
+the controllers uniformly. Hence it is logical to have a single module that
+interefaces with the applications on one side and all the low level drivers
+on the other.
+
+The advantages, though obvious, are listed for completeness:
+
+       i.      Avoid duplicate code from the low level drivers.
+       ii.     Unburden the low level drivers from having to export the
+               character node device and related handling.
+       iii.    Implement any policy mechanisms in one place.
+       iv.     Applications have to interface with only module instead of
+               multiple low level drivers.
+
+Currently this module (called Common Management Module) is used only to issue
+ioctl commands. But this module is envisioned to handle all user space level
+interactions. So any 'proc', 'sysfs' implementations will be localized in this
+common module.
+
+Credits:
+-------
+
+"Shared code in a third module, a "library module", is an acceptable
+solution. modprobe automatically loads dependent modules, so users
+running "modprobe driver1" or "modprobe driver2" would automatically
+load the shared library module."
+
+               - Jeff Garzik (jgarzik@pobox.com), 02.25.2004 LKML
+
+"As Jeff hinted, if your userspace<->driver API is consistent between
+your new MPT-based RAID controllers and your existing megaraid driver,
+then perhaps you need a single small helper module (lsiioctl or some
+better name), loaded by both mptraid and megaraid automatically, which
+handles registering the /dev/megaraid node dynamically. In this case,
+both mptraid and megaraid would register with lsiioctl for each
+adapter discovered, and lsiioctl would essentially be a switch,
+redirecting userspace tool ioctls to the appropriate driver."
+
+               - Matt Domsch, (Matt_Domsch@dell.com), 02.25.2004 LKML
+
+Design:
+------
+
+The Common Management Module is implemented in megaraid_mm.[ch] files. This
+module acts as a registry for low level hba drivers. The low level drivers
+(currently only megaraid) register each controller with the common module.
+
+The applications interface with the common module via the character device
+node exported by the module.
+
+The lower level drivers now understand only a new improved ioctl packet called
+uioc_t. The management module converts the older ioctl packets from the older
+applications into uioc_t. After driver handles the uioc_t, the common module
+will convert that back into the old format before returning to applications.
+
+As new applications evolve and replace the old ones, the old packet format 
+will be retired.
+
+Common module dedicates one uioc_t packet to each controller registered. This
+can easily be more than one. But since megaraid is the only low level driver
+today, and it can handle only one ioctl, there is no reason to have more. But
+as new controller classes get added, this will be tuned appropriately.
diff --git a/Documentation/seclvl.txt b/Documentation/seclvl.txt
new file mode 100644 (file)
index 0000000..97274d1
--- /dev/null
@@ -0,0 +1,97 @@
+BSD Secure Levels Linux Security Module
+Michael A. Halcrow <mike@halcrow.us>
+
+
+Introduction
+
+Under the BSD Secure Levels security model, sets of policies are
+associated with levels. Levels range from -1 to 2, with -1 being the
+weakest and 2 being the strongest. These security policies are
+enforced at the kernel level, so not even the superuser is able to
+disable or circumvent them. This hardens the machine against attackers
+who gain root access to the system.
+
+
+Levels and Policies
+
+Level -1 (Permanently Insecure):
+ - Cannot increase the secure level
+
+Level 0 (Insecure):
+ - Cannot ptrace the init process
+
+Level 1 (Default):
+ - /dev/mem and /dev/kmem are read-only
+ - IMMUTABLE and APPEND extended attributes, if set, may not be unset
+ - Cannot load or unload kernel modules
+ - Cannot write directly to a mounted block device
+ - Cannot perform raw I/O operations
+ - Cannot perform network administrative tasks
+ - Cannot setuid any file
+
+Level 2 (Secure):
+ - Cannot decrement the system time
+ - Cannot write to any block device, whether mounted or not
+ - Cannot unmount any mounted filesystems
+
+
+Compilation
+
+To compile the BSD Secure Levels LSM, seclvl.ko, enable the
+SECURITY_SECLVL configuration option.  This is found under Security
+options -> BSD Secure Levels in the kernel configuration menu.
+
+
+Basic Usage
+
+Once the machine is in a running state, with all the necessary modules
+loaded and all the filesystems mounted, you can load the seclvl.ko
+module:
+
+# insmod seclvl.ko
+
+The module defaults to secure level 1, except when compiled directly
+into the kernel, in which case it defaults to secure level 0. To raise
+the secure level to 2, the administrator writes ``2'' to the
+seclvl/seclvl file under the sysfs mount point (assumed to be /sys in
+these examples):
+
+# echo -n "2" > /sys/seclvl/seclvl
+
+Alternatively, you can initialize the module at secure level 2 with
+the initlvl module parameter:
+
+# insmod seclvl.ko initlvl=2
+
+At this point, it is impossible to remove the module or reduce the
+secure level.  If the administrator wishes to have the option of doing
+so, he must provide a module parameter, sha1_passwd, that specifies
+the SHA1 hash of the password that can be used to reduce the secure
+level to 0.
+
+To generate this SHA1 hash, the administrator can use OpenSSL:
+
+# echo -n "boogabooga" | openssl sha1
+abeda4e0f33defa51741217592bf595efb8d289c
+
+In order to use password-instigated secure level reduction, the SHA1
+crypto module must be loaded or compiled into the kernel:
+
+# insmod sha1.ko
+
+The administrator can then insmod the seclvl module, including the
+SHA1 hash of the password:
+
+# insmod seclvl.ko
+         sha1_passwd=abeda4e0f33defa51741217592bf595efb8d289c
+
+To reduce the secure level, write the password to seclvl/passwd under
+your sysfs mount point:
+
+# echo -n "boogabooga" > /sys/seclvl/passwd
+
+The September 2004 edition of Sys Admin Magazine has an article about
+the BSD Secure Levels LSM.  I encourage you to refer to that article
+for a more in-depth treatment of this security module:
+
+http://www.samag.com/documents/s=9304/sam0409a/0409a.htm
diff --git a/Documentation/stable_api_nonsense.txt b/Documentation/stable_api_nonsense.txt
new file mode 100644 (file)
index 0000000..c33c99c
--- /dev/null
@@ -0,0 +1,193 @@
+The Linux Kernel Driver Interface
+(all of your questions answered and then some)
+
+Greg Kroah-Hartman <greg@kroah.com>
+
+This is being written to try to explain why Linux does not have a binary
+kernel interface, nor does it have a stable kernel interface.  Please
+realize that this article describes the _in kernel_ interfaces, not the
+kernel to userspace interfaces.  The kernel to userspace interface is
+the one that application programs use, the syscall interface.  That
+interface is _very_ stable over time, and will not break.  I have old
+programs that were built on a pre 0.9something kernel that still works
+just fine on the latest 2.6 kernel release.  This interface is the one
+that users and application programmers can count on being stable.
+
+
+Executive Summary
+-----------------
+You think you want a stable kernel interface, but you really do not, and
+you don't even know it.  What you want is a stable running driver, and
+you get that only if your driver is in the main kernel tree.  You also
+get lots of other good benefits if your driver is in the main kernel
+tree, all of which has made Linux into such a strong, stable, and mature
+operating system which is the reason you are using it in the first
+place.
+
+
+Intro
+-----
+
+It's only the odd person who wants to write a kernel driver that needs
+to worry about the in-kernel interfaces changing.  For the majority of
+the world, they neither see this interface, nor do they care about it at
+all.
+
+First off, I'm not going to address _any_ legal issues about closed
+source, hidden source, binary blobs, source wrappers, or any other term
+that describes kernel drivers that do not have their source code
+released under the GPL.  Please consult a lawyer if you have any legal
+questions, I'm a programmer and hence, I'm just going to be describing
+the technical issues here (not to make light of the legal issues, they
+are real, and you do need to be aware of them at all times.)
+
+So, there are two main topics here, binary kernel interfaces and stable
+kernel source interfaces.  They both depend on each other, but we will
+discuss the binary stuff first to get it out of the way.
+
+
+Binary Kernel Interface
+-----------------------
+Assuming that we had a stable kernel source interface for the kernel, a
+binary interface would naturally happen too, right?  Wrong.  Please
+consider the following facts about the Linux kernel:
+  - Depending on the version of the C compiler you use, different kernel
+    data structures will contain different alignment of structures, and
+    possibly include different functions in different ways (putting
+    functions inline or not.)  The individual function organization
+    isn't that important, but the different data structure padding is
+    very important.
+  - Depending on what kernel build options you select, a wide range of
+    different things can be assumed by the kernel:
+      - different structures can contain different fields
+      - Some functions may not be implemented at all, (i.e. some locks
+       compile away to nothing for non-SMP builds.)
+      - Parameter passing of variables from function to function can be
+       done in different ways (the CONFIG_REGPARM option controls
+       this.)
+      - Memory within the kernel can be aligned in different ways,
+       depending on the build options.
+  - Linux runs on a wide range of different processor architectures.
+    There is no way that binary drivers from one architecture will run
+    on another architecture properly.
+
+Now a number of these issues can be addressed by simply compiling your
+module for the exact specific kernel configuration, using the same exact
+C compiler that the kernel was built with.  This is sufficient if you
+want to provide a module for a specific release version of a specific
+Linux distribution.  But multiply that single build by the number of
+different Linux distributions and the number of different supported
+releases of the Linux distribution and you quickly have a nightmare of
+different build options on different releases.  Also realize that each
+Linux distribution release contains a number of different kernels, all
+tuned to different hardware types (different processor types and
+different options), so for even a single release you will need to create
+multiple versions of your module.
+
+Trust me, you will go insane over time if you try to support this kind
+of release, I learned this the hard way a long time ago...
+
+
+Stable Kernel Source Interfaces
+-------------------------------
+
+This is a much more "volatile" topic if you talk to people who try to
+keep a Linux kernel driver that is not in the main kernel tree up to
+date over time.
+
+Linux kernel development is continuous and at a rapid pace, never
+stopping to slow down.  As such, the kernel developers find bugs in
+current interfaces, or figure out a better way to do things.  If they do
+that, they then fix the current interfaces to work better.  When they do
+so, function names may change, structures may grow or shrink, and
+function parameters may be reworked.  If this happens, all of the
+instances of where this interface is used within the kernel are fixed up
+at the same time, ensuring that everything continues to work properly.
+
+As a specific examples of this, the in-kernel USB interfaces have
+undergone at least three different reworks over the lifetime of this
+subsystem.  These reworks were done to address a number of different
+issues:
+  - A change from a synchronous model of data streams to an asynchronous
+    one.  This reduced the complexity of a number of drivers and
+    increased the throughput of all USB drivers such that we are now
+    running almost all USB devices at their maximum speed possible.
+  - A change was made in the way data packets were allocated from the
+    USB core by USB drivers so that all drivers now needed to provide
+    more information to the USB core to fix a number of documented
+    deadlocks.
+
+This is in stark contrast to a number of closed source operating systems
+which have had to maintain their older USB interfaces over time.  This
+provides the ability for new developers to accidentally use the old
+interfaces and do things in improper ways, causing the stability of the
+operating system to suffer.
+
+In both of these instances, all developers agreed that these were
+important changes that needed to be made, and they were made, with
+relatively little pain.  If Linux had to ensure that it preserve a
+stable source interface, a new interface would have been created, and
+the older, broken one would have had to be maintained over time, leading
+to extra work for the USB developers.  Since all Linux USB developers do
+their work on their own time, asking programmers to do extra work for no
+gain, for free, is not a possibility.
+
+Security issues are also a very important for Linux.  When a
+security issue is found, it is fixed in a very short amount of time.  A
+number of times this has caused internal kernel interfaces to be
+reworked to prevent the security problem from occurring.  When this
+happens, all drivers that use the interfaces were also fixed at the
+same time, ensuring that the security problem was fixed and could not
+come back at some future time accidentally.  If the internal interfaces
+were not allowed to change, fixing this kind of security problem and
+insuring that it could not happen again would not be possible.
+
+Kernel interfaces are cleaned up over time.  If there is no one using a
+current interface, it is deleted.  This ensures that the kernel remains
+as small as possible, and that all potential interfaces are tested as
+well as they can be (unused interfaces are pretty much impossible to
+test for validity.)
+
+
+What to do
+----------
+
+So, if you have a Linux kernel driver that is not in the main kernel
+tree, what are you, a developer, supposed to do?  Releasing a binary
+driver for every different kernel version for every distribution is a
+nightmare, and trying to keep up with an ever changing kernel interface
+is also a rough job.
+
+Simple, get your kernel driver into the main kernel tree (remember we
+are talking about GPL released drivers here, if your code doesn't fall
+under this category, good luck, you are on your own here, you leech
+<insert link to leech comment from Andrew and Linus here>.)  If your
+driver is in the tree, and a kernel interface changes, it will be fixed
+up by the person who did the kernel change in the first place.  This
+ensures that your driver is always buildable, and works over time, with
+very little effort on your part.
+
+The very good side affects of having your driver in the main kernel tree
+are:
+  - The quality of the driver will rise as the maintenance costs (to the
+    original developer) will decrease.
+  - Other developers will add features to your driver.
+  - Other people will find and fix bugs in your driver.
+  - Other people will find tuning opportunities in your driver.
+  - Other people will update the driver for you when external interface
+    changes require it.
+  - The driver automatically gets shipped in all Linux distributions
+    without having to ask the distros to add it.
+    
+As Linux supports a larger number of different devices "out of the box"
+than any other operating system, and it supports these devices on more
+different processor architectures than any other operating system, this
+proven type of development model must be doing something right :)
+
+
+
+------
+
+Thanks to Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
+Robert Love, and Nishanth Aravamudan for their review and comments on
+early drafts of this paper.
diff --git a/Documentation/time_interpolators.txt b/Documentation/time_interpolators.txt
new file mode 100644 (file)
index 0000000..d9fefd5
--- /dev/null
@@ -0,0 +1,40 @@
+Time Interpolators
+------------------
+
+Time interpolators are a base of time calculation between timer ticks and
+allow an accurate determination of time down to the accuracy of the time
+source in nanoseconds.
+
+The architecture specific code typically provides gettimeofday and
+settimeofday under Linux. The time interpolator provides both if an arch
+defines CONFIG_TIME_INTERPOLATION. The arch still must set up timer tick
+operations and call the necessary functions to advance the clock.
+With the time interpolator a standardized interface exists for time
+interpolation between ticks which also allows the determination
+of time in a hardware independent way. The provided logic is highly scalable
+and has been tested in SMP situations of up to 512 CPUs.
+
+If CONFIG_TIME_INTERPOLATION is defined then the architecture specific code
+(or the device drivers - like HPET) must register time interpolators.
+These are typically defined in the following way:
+
+static struct time_interpolator my_interpolator;
+
+void time_init(void)
+{
+       ....
+       /* Initialization of the timer *.
+       my_interpolator.frequency = MY_FREQUENCY;
+       my_interpolator.source = TIME_SOURCE_MMIO32;
+       my_interpolator.address = &my_timer;
+       my_interpolator.shift = 32;             /* increase accuracy of scaling */
+       my_interpolator.drift = -1;             /* Unknown */
+       my_interpolator.jitter = 0;             /* A stable time source */
+       register_time_interpolator(&my_interpolator);
+       ....
+}
+
+For more details see include/linux/timex.h.
+
+Christoph Lameter <christoph@lameter.com>, September 8, 2004
+
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
new file mode 100644 (file)
index 0000000..a496056
--- /dev/null
@@ -0,0 +1,194 @@
+
+                       The Lockronomicon
+
+Your guide to the ancient and twisted locking policies of the tty layer and
+the warped logic behind them. Beware all ye who read on.
+
+FIXME: still need to work out the full set of BKL assumptions and document
+them so they can eventually be killed off.
+
+
+Line Discipline
+---------------
+
+Line disciplines are registered with tty_register_ldisc() passing the
+discipline number and the ldisc structure. At the point of registration the 
+discipline must be ready to use and it is possible it will get used before
+the call returns success. If the call returns an error then it won't get
+called. Do not re-use ldisc numbers as they are part of the userspace ABI
+and writing over an existing ldisc will cause demons to eat your computer.
+After the return the ldisc data has been copied so you may free your own 
+copy of the structure. You must not re-register over the top of the line
+discipline even with the same data or your computer again will be eaten by
+demons.
+
+In order to remove a line discipline call tty_register_ldisc passing NULL.
+In ancient times this always worked. In modern times the function will
+return -EBUSY if the ldisc is currently in use. Since the ldisc referencing
+code manages the module counts this should not usually be a concern.
+
+Heed this warning: the reference count field of the registered copies of the
+tty_ldisc structure in the ldisc table counts the number of lines using this
+discipline. The reference count of the tty_ldisc structure within a tty 
+counts the number of active users of the ldisc at this instant. In effect it
+counts the number of threads of execution within an ldisc method (plus those
+about to enter and exit although this detail matters not).
+
+Line Discipline Methods
+-----------------------
+
+TTY side interfaces:
+
+close()                -       This is called on a terminal when the line
+                       discipline is being unplugged. At the point of
+                       execution no further users will enter the
+                       ldisc code for this tty. Can sleep.
+
+open()         -       Called when the line discipline is attached to
+                       the terminal. No other call into the line
+                       discipline for this tty will occur until it
+                       completes successfully. Can sleep.
+
+write()                -       A process is writing data from user space
+                       through the line discipline. Multiple write calls
+                       are serialized by the tty layer for the ldisc. May
+                       sleep.
+
+flush_buffer() -       May be called at any point between open and close.
+
+chars_in_buffer() -    Report the number of bytes in the buffer.
+
+set_termios()  -       Called on termios structure changes. The caller
+                       passes the old termios data and the current data
+                       is in the tty. Called under the termios semaphore so
+                       allowed to sleep. Serialized against itself only.
+
+read()         -       Move data from the line discipline to the user.
+                       Multiple read calls may occur in parallel and the
+                       ldisc must deal with serialization issues. May 
+                       sleep.
+
+poll()         -       Check the status for the poll/select calls. Multiple
+                       poll calls may occur in parallel. May sleep.
+
+ioctl()                -       Called when an ioctl is handed to the tty layer
+                       that might be for the ldisc. Multiple ioctl calls
+                       may occur in parallel. May sleep. 
+
+Driver Side Interfaces:
+
+receive_buf()  -       Hand buffers of bytes from the driver to the ldisc
+                       for processing. Semantics currently rather
+                       mysterious 8(
+
+receive_room() -       Can be called by the driver layer at any time when
+                       the ldisc is opened. The ldisc must be able to
+                       handle the reported amount of data at that instant.
+                       Synchronization between active receive_buf and
+                       receive_room calls is down to the driver not the
+                       ldisc. Must not sleep.
+
+write_wakeup() -       May be called at any point between open and close.
+                       The TTY_DO_WRITE_WAKEUP flag indicates if a call
+                       is needed but always races versus calls. Thus the
+                       ldisc must be careful about setting order and to
+                       handle unexpected calls. Must not sleep.
+
+
+Locking
+
+Callers to the line discipline functions from the tty layer are required to
+take line discipline locks. The same is true of calls from the driver side
+but not yet enforced.
+
+Three calls are now provided
+
+       ldisc = tty_ldisc_ref(tty);
+
+takes a handle to the line discipline in the tty and returns it. If no ldisc
+is currently attached or the ldisc is being closed and re-opened at this
+point then NULL is returned. While this handle is held the ldisc will not
+change or go away.
+
+       tty_ldisc_deref(ldisc)
+
+Returns the ldisc reference and allows the ldisc to be closed. Returning the
+reference takes away your right to call the ldisc functions until you take
+a new reference.
+
+       ldisc = tty_ldisc_ref_wait(tty);
+
+Performs the same function as tty_ldisc_ref except that it will wait for an
+ldisc change to complete and then return a reference to the new ldisc. 
+
+While these functions are slightly slower than the old code they should have
+minimal impact as most receive logic uses the flip buffers and they only
+need to take a reference when they push bits up through the driver.
+
+A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc 
+functions are called with the ldisc unavailable. Thus tty_ldisc_ref will
+fail in this situation if used within these functions. Ldisc and driver
+code calling its own functions must be careful in this case. 
+
+
+Driver Interface
+----------------
+
+open()         -       Called when a device is opened. May sleep
+
+close()                -       Called when a device is closed. At the point of
+                       return from this call the driver must make no 
+                       further ldisc calls of any kind. May sleep
+
+write()                -       Called to write bytes to the device. May not
+                       sleep. May occur in parallel in special cases. 
+                       Because this includes panic paths drivers generally
+                       shouldn't try and do clever locking here.
+
+put_char()     -       Stuff a single character onto the queue. The
+                       driver is guaranteed following up calls to
+                       flush_chars.
+
+flush_chars()  -       Ask the kernel to write put_char queue
+
+write_room()   -       Return the number of characters tht can be stuffed
+                       into the port buffers without overflow (or less).
+                       The ldisc is responsible for being intelligent
+                       about multi-threading of write_room/write calls
+
+ioctl()                -       Called when an ioctl may be for the driver
+
+set_termios()  -       Called on termios change, serialized against
+                       itself by a semaphore. May sleep.
+
+set_ldisc()    -       Notifier for discipline change. At the point this 
+                       is done the discipline is not yet usable. Can now
+                       sleep (I think)
+
+throttle()     -       Called by the ldisc to ask the driver to do flow
+                       control.  Serialization including with unthrottle
+                       is the job of the ldisc layer.
+
+unthrottle()   -       Called by the ldisc to ask the driver to stop flow
+                       control.
+
+stop()         -       Ldisc notifier to the driver to stop output. As with
+                       throttle the serializations with start() are down
+                       to the ldisc layer.
+
+start()                -       Ldisc notifier to the driver to start output.
+
+hangup()       -       Ask the tty driver to cause a hangup initiated
+                       from the host side. [Can sleep ??]
+
+break_ctl()    -       Send RS232 break. Can sleep. Can get called in
+                       parallel, driver must serialize (for now), and
+                       with write calls.
+
+wait_until_sent() -    Wait for characters to exit the hardware queue
+                       of the driver. Can sleep
+
+send_xchar()     -     Send XON/XOFF and if possible jump the queue with
+                       it in order to get fast flow control responses.
+                       Cannot sleep ??
+
diff --git a/Documentation/usb/gadget_serial.txt b/Documentation/usb/gadget_serial.txt
new file mode 100644 (file)
index 0000000..a938c3d
--- /dev/null
@@ -0,0 +1,332 @@
+
+                 Linux Gadget Serial Driver v2.0
+                           11/20/2004
+
+
+License and Disclaimer
+----------------------
+This 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.
+
+This document and the the gadget serial driver itself are
+Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
+
+If you have questions, problems, or suggestions for this driver
+please contact Al Borchers at alborchers@steinerpoint.com.
+
+
+Prerequisites
+-------------
+Versions of the gadget serial driver are available for the
+2.4 Linux kernels, but this document assumes you are using
+version 2.0 or later of the gadget serial driver in a 2.6
+Linux kernel.
+
+This document assumes that you are familiar with Linux and
+Windows and know how to configure and build Linux kernels, run
+standard utilities, use minicom and HyperTerminal, and work with
+USB and serial devices.  It also assumes you configure the Linux
+gadget and usb drivers as modules.
+
+
+Overview
+--------
+The gadget serial driver is a Linux USB gadget driver, a USB device
+side driver.  It runs on a Linux system that has USB device side
+hardware; for example, a PDA, an embedded Linux system, or a PC
+with a USB development card.
+
+The gadget serial driver talks over USB to either a CDC ACM driver
+or a generic USB serial driver running on a host PC.
+
+   Host
+   --------------------------------------
+  | Host-Side   CDC ACM       USB Host   |
+  | Operating |   or        | Controller |   USB
+  | System    | Generic USB | Driver     |--------
+  | (Linux or | Serial      | and        |        |
+  | Windows)    Driver        USB Stack  |        |
+   --------------------------------------         |
+                                                  |
+                                                  |
+                                                  |
+   Gadget                                         |
+   --------------------------------------         |
+  | Gadget                   USB Periph. |        |
+  | Device-Side |  Gadget  | Controller  |        |
+  | Linux       |  Serial  | Driver      |--------
+  | Operating   |  Driver  | and         |
+  | System                   USB Stack   |
+   --------------------------------------
+
+On the device-side Linux system, the gadget serial driver looks
+like a serial device.
+
+On the host-side system, the gadget serial device looks like a
+CDC ACM compliant class device or a simple vendor specific device
+with bulk in and bulk out endpoints, and it is treated similarly
+to other serial devices.
+
+The host side driver can potentially be any ACM compliant driver
+or any driver that can talk to a device with a simple bulk in/out
+interface.  Gadget serial has been tested with the Linux ACM driver,
+the Windows usbser.sys ACM driver, and the Linux USB generic serial
+driver.
+
+With the gadget serial driver and the host side ACM or generic
+serial driver running, you should be able to communicate between
+the host and the gadget side systems as if they were connected by a
+serial cable.
+
+The gadget serial driver only provides simple unreliable data
+communication.  It does not yet handle flow control or many other
+features of normal serial devices.
+
+
+Installing the Gadget Serial Driver
+-----------------------------------
+To use the gadget serial driver you must configure the Linux gadget
+side kernel for "Support for USB Gadgets", for a "USB Peripheral
+Controller" (for example, net2280), and for the "Serial Gadget"
+driver.  All this are listed under "USB Gadget Support" when
+configuring the kernel.  Then rebuild and install the kernel or
+modules.
+
+The gadget serial driver uses major number 127, for now.  So you
+will need to create a device node for it, like this:
+
+  mknod /dev/ttygserial c 127 0
+
+You only need to do this once.
+
+Then you must load the gadget serial driver.  To load it as an
+ACM device, do this:
+
+  modprobe g_serial use_acm=1
+
+To load it as a vendor specific bulk in/out device, do this:
+
+  modprobe g_serial
+
+This will also automatically load the underlying gadget peripheral
+controller driver.  This must be done each time you reboot the gadget
+side Linux system.  You can add this to the start up scripts, if
+desired.
+
+If gadget serial is loaded as an ACM device you will want to use
+either the Windows or Linux ACM driver on the host side.  If gadget
+serial is loaded as a bulk in/out device, you will want to use the
+Linux generic serial driver on the host side.  Follow the appropriate
+instructions below to install the host side driver.
+
+
+Installing the Windows Host ACM Driver
+--------------------------------------
+To use the Windows ACM driver you must have the files "gserial.inf"
+and "usbser.sys" together in a folder on the Windows machine.
+
+The "gserial.inf" file is given here.
+
+-------------------- CUT HERE --------------------
+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Provider=%LINUX%
+DriverVer=08/17/2004,0.0.2.0
+; Copyright (C) 2004 Al Borchers (alborchers@steinerpoint.com)
+
+[Manufacturer]
+%LINUX%=GSerialDeviceList
+
+[GSerialDeviceList]
+%GSERIAL%=GSerialInstall, USB\VID_0525&PID_A4A7
+
+[DestinationDirs]
+DefaultDestDir=10,System32\Drivers
+
+[GSerialInstall]
+CopyFiles=GSerialCopyFiles
+AddReg=GSerialAddReg
+
+[GSerialCopyFiles]
+usbser.sys
+
+[GSerialAddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,usbser.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[GSerialInstall.Services]
+AddService = usbser,0x0002,GSerialService
+
+[GSerialService]
+DisplayName = %GSERIAL_DISPLAY_NAME%
+ServiceType = 1                  ; SERVICE_KERNEL_DRIVER
+StartType = 3                    ; SERVICE_DEMAND_START
+ErrorControl = 1                 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %10%\System32\Drivers\usbser.sys
+LoadOrderGroup = Base
+
+[Strings]
+LINUX = "Linux"
+GSERIAL = "Gadget Serial"
+GSERIAL_DISPLAY_NAME = "USB Gadget Serial Driver"
+-------------------- CUT HERE --------------------
+
+The "usbser.sys" file comes with various versions of Windows.
+For example, it can be found on Windows XP typically in
+
+  C:\WINDOWS\Driver Cache\i386\driver.cab
+
+Or it can be found on the Windows 98SE CD in the "win98" folder
+in the "DRIVER11.CAB" through "DRIVER20.CAB" cab files.  You will
+need the DOS "expand" program, the Cygwin "cabextract" program, or
+a similar program to unpack these cab files and extract "usbser.sys".
+
+For example, to extract "usbser.sys" into the current directory
+on Windows XP, open a DOS window and run a command like
+
+  expand C:\WINDOWS\Driver~1\i386\driver.cab -F:usbser.sys .
+
+(Thanks to Nishant Kamat for pointing out this DOS command.)
+
+When the gadget serial driver is loaded and the USB device connected
+to the Windows host with a USB cable, Windows should recognize the
+gadget serial device and ask for a driver.  Tell Windows to find the
+driver in the folder that contains "gserial.inf" and "usbser.sys".
+
+For example, on Windows XP, when the gadget serial device is first
+plugged in, the "Found New Hardware Wizard" starts up.  Select
+"Install from a list or specific location (Advanced)", then on
+the next screen select "Include this location in the search" and
+enter the path or browse to the folder containing "gserial.inf" and
+"usbser.sys".  Windows will complain that the Gadget Serial driver
+has not passed Windows Logo testing, but select "Continue anyway"
+and finish the driver installation.
+
+On Windows XP, in the "Device Manager" (under "Control Panel",
+"System", "Hardware") expand the "Ports (COM & LPT)" entry and you
+should see "Gadget Serial" listed as the driver for one of the COM
+ports.
+
+To uninstall the Windows XP driver for "Gadget Serial", right click
+on the "Gadget Serial" entry in the "Device Manager" and select
+"Uninstall".
+
+
+Installing the Linux Host ACM Driver
+------------------------------------
+To use the Linux ACM driver you must configure the Linux host side
+kernel for "Support for Host-side USB" and for "USB Modem (CDC ACM)
+support".
+
+Once the gadget serial driver is loaded and the USB device connected
+to the Linux host with a USB cable, the host system should recognize
+the gadget serial device.  For example, the command
+
+  cat /proc/bus/usb/devices
+
+should show something like this:
+
+T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  5 Spd=480 MxCh= 0
+D:  Ver= 2.00 Cls=02(comm.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+P:  Vendor=0525 ProdID=a4a7 Rev= 2.01
+S:  Manufacturer=Linux 2.6.8.1 with net2280
+S:  Product=Gadget Serial
+S:  SerialNumber=0
+C:* #Ifs= 2 Cfg#= 2 Atr=c0 MxPwr=  2mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+E:  Ad=83(I) Atr=03(Int.) MxPS=   8 Ivl=32ms
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+If the host side Linux system is configured properly, the ACM driver
+should be loaded automatically.  The command "lsmod" should show the
+"acm" module is loaded.
+
+
+Installing the Linux Host Generic USB Serial Driver
+---------------------------------------------------
+To use the Linux generic USB serial driver you must configure the
+Linux host side kernel for "Support for Host-side USB", for "USB
+Serial Converter support", and for the "USB Generic Serial Driver".
+
+Once the gadget serial driver is loaded and the USB device connected
+to the Linux host with a USB cable, the host system should recognize
+the gadget serial device.  For example, the command
+
+  cat /proc/bus/usb/devices
+
+should show something like this:
+
+T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  6 Spd=480 MxCh= 0
+D:  Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
+P:  Vendor=0525 ProdID=a4a6 Rev= 2.01
+S:  Manufacturer=Linux 2.6.8.1 with net2280
+S:  Product=Gadget Serial
+S:  SerialNumber=0
+C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  2mA
+I:  If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial
+E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+You must explicitly load the usbserial driver with parameters to
+configure it to recognize the gadget serial device, like this:
+
+  modprobe usbserial vendor=0x0525 product=0xA4A6
+
+If everything is working, usbserial will print a message in the
+system log saying something like "Gadget Serial converter now
+attached to ttyUSB0".
+
+
+Testing with Minicom or HyperTerminal
+-------------------------------------
+Once the gadget serial driver and the host driver are both installed,
+and a USB cable connects the gadget device to the host, you should
+be able to communicate over USB between the gadget and host systems.
+You can use minicom or HyperTerminal to try this out.
+
+On the gadget side run "minicom -s" to configure a new minicom
+session.  Under "Serial port setup" set "/dev/ttygserial" as the
+"Serial Device".  Set baud rate, data bits, parity, and stop bits,
+to 9600, 8, none, and 1--these settings mostly do not matter.
+Under "Modem and dialing" erase all the modem and dialing strings.
+
+On a Linux host running the ACM driver, configure minicom similarly
+but use "/dev/ttyACM0" as the "Serial Device".  (If you have other
+ACM devices connected, change the device name appropriately.)
+
+On a Linux host running the USB generic serial driver, configure
+minicom similarly, but use "/dev/ttyUSB0" as the "Serial Device".
+(If you have other USB serial devices connected, change the device
+name appropriately.)
+
+On a Windows host configure a new HyperTerminal session to use the
+COM port assigned to Gadget Serial.  The "Port Settings" will be
+set automatically when HyperTerminal connects to the gadget serial
+device, so you can leave them set to the default values--these
+settings mostly do not matter.
+
+With minicom configured and running on the gadget side and with
+minicom or HyperTerminal configured and running on the host side,
+you should be able to send data back and forth between the gadget
+side and host side systems.  Anything you type on the terminal
+window on the gadget side should appear in the terminal window on
+the host side and vice versa.
+
+
diff --git a/arch/alpha/Kconfig.debug b/arch/alpha/Kconfig.debug
new file mode 100644 (file)
index 0000000..36d0106
--- /dev/null
@@ -0,0 +1,59 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+       bool
+       depends on ALPHA_GENERIC || ALPHA_SRM
+       default y
+
+config DEBUG_RWLOCK
+       bool "Read-write spinlock debugging"
+       depends on DEBUG_KERNEL
+       help
+         If you say Y here then read-write lock processing will count how many
+         times it has tried to get the lock and issue an error message after
+         too many attempts.  If you suspect a rwlock problem or a kernel
+         hacker asks for this option then say Y.  Otherwise say N.
+
+config DEBUG_SEMAPHORE
+       bool "Semaphore debugging"
+       depends on DEBUG_KERNEL
+       help
+         If you say Y here then semaphore processing will issue lots of
+         verbose debugging messages.  If you suspect a semaphore problem or a
+         kernel hacker asks for this option then say Y.  Otherwise say N.
+
+config ALPHA_LEGACY_START_ADDRESS
+       bool "Legacy kernel start address"
+       depends on ALPHA_GENERIC
+       default n
+       ---help---
+         The 2.4 kernel changed the kernel start address from 0x310000
+         to 0x810000 to make room for the Wildfire's larger SRM console.
+         Recent consoles on Titan and Marvel machines also require the
+         extra room.
+
+         If you're using aboot 0.7 or later, the bootloader will examine the
+         ELF headers to determine where to transfer control. Unfortunately,
+         most older bootloaders -- APB or MILO -- hardcoded the kernel start
+         address rather than examining the ELF headers, and the result is a
+         hard lockup.
+
+         Say Y if you have a broken bootloader.  Say N if you do not, or if
+         you wish to run on Wildfire, Titan, or Marvel.
+
+config ALPHA_LEGACY_START_ADDRESS
+       bool
+       depends on !ALPHA_GENERIC && !ALPHA_TITAN && !ALPHA_MARVEL && !ALPHA_WILDFIRE
+       default y
+
+config MATHEMU
+       tristate "Kernel FP software completion" if DEBUG_KERNEL && !SMP
+       default y if !DEBUG_KERNEL || SMP
+       help
+         This option is required for IEEE compliant floating point arithmetic
+         on the Alpha. The only time you would ever not say Y is to say M in
+         order to debug the code. Say Y unless you know what you are doing.
+
+endmenu
diff --git a/arch/alpha/kernel/io.c b/arch/alpha/kernel/io.c
new file mode 100644 (file)
index 0000000..19c5875
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * Alpha IO and memory functions.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+/* Out-of-line versions of the i/o routines that redirect into the 
+   platform-specific version.  Note that "platform-specific" may mean
+   "generic", which bumps through the machine vector.  */
+
+unsigned int
+ioread8(void __iomem *addr)
+{
+       unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
+       mb();
+       return ret;
+}
+
+unsigned int ioread16(void __iomem *addr)
+{
+       unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
+       mb();
+       return ret;
+}
+
+unsigned int ioread32(void __iomem *addr)
+{
+       unsigned int ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
+       mb();
+       return ret;
+}
+
+void iowrite8(u8 b, void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,iowrite8)(b, addr);
+       mb();
+}
+
+void iowrite16(u16 b, void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,iowrite16)(b, addr);
+       mb();
+}
+
+void iowrite32(u32 b, void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,iowrite32)(b, addr);
+       mb();
+}
+
+EXPORT_SYMBOL(ioread8);
+EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread32);
+EXPORT_SYMBOL(iowrite8);
+EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite32);
+
+u8 inb(unsigned long port)
+{
+       return ioread8(ioport_map(port, 1));
+}
+
+u16 inw(unsigned long port)
+{
+       return ioread16(ioport_map(port, 2));
+}
+
+u32 inl(unsigned long port)
+{
+       return ioread32(ioport_map(port, 4));
+}
+
+void outb(u8 b, unsigned long port)
+{
+       iowrite8(b, ioport_map(port, 1));
+}
+
+void outw(u16 b, unsigned long port)
+{
+       iowrite16(b, ioport_map(port, 2));
+}
+
+void outl(u32 b, unsigned long port)
+{
+       iowrite32(b, ioport_map(port, 4));
+}
+
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+
+u8 __raw_readb(const volatile void __iomem *addr)
+{
+       return IO_CONCAT(__IO_PREFIX,readb)(addr);
+}
+
+u16 __raw_readw(const volatile void __iomem *addr)
+{
+       return IO_CONCAT(__IO_PREFIX,readw)(addr);
+}
+
+u32 __raw_readl(const volatile void __iomem *addr)
+{
+       return IO_CONCAT(__IO_PREFIX,readl)(addr);
+}
+
+u64 __raw_readq(const volatile void __iomem *addr)
+{
+       return IO_CONCAT(__IO_PREFIX,readq)(addr);
+}
+
+void __raw_writeb(u8 b, volatile void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,writeb)(b, addr);
+}
+
+void __raw_writew(u16 b, volatile void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,writew)(b, addr);
+}
+
+void __raw_writel(u32 b, volatile void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,writel)(b, addr);
+}
+
+void __raw_writeq(u64 b, volatile void __iomem *addr)
+{
+       IO_CONCAT(__IO_PREFIX,writeq)(b, addr);
+}
+
+EXPORT_SYMBOL(__raw_readb); 
+EXPORT_SYMBOL(__raw_readw); 
+EXPORT_SYMBOL(__raw_readl); 
+EXPORT_SYMBOL(__raw_readq); 
+EXPORT_SYMBOL(__raw_writeb); 
+EXPORT_SYMBOL(__raw_writew); 
+EXPORT_SYMBOL(__raw_writel); 
+EXPORT_SYMBOL(__raw_writeq); 
+
+u8 readb(const volatile void __iomem *addr)
+{
+       u8 ret = __raw_readb(addr);
+       mb();
+       return ret;
+}
+
+u16 readw(const volatile void __iomem *addr)
+{
+       u16 ret = __raw_readw(addr);
+       mb();
+       return ret;
+}
+
+u32 readl(const volatile void __iomem *addr)
+{
+       u32 ret = __raw_readl(addr);
+       mb();
+       return ret;
+}
+
+u64 readq(const volatile void __iomem *addr)
+{
+       u64 ret = __raw_readq(addr);
+       mb();
+       return ret;
+}
+
+void writeb(u8 b, volatile void __iomem *addr)
+{
+       __raw_writeb(b, addr);
+       mb();
+}
+
+void writew(u16 b, volatile void __iomem *addr)
+{
+       __raw_writew(b, addr);
+       mb();
+}
+
+void writel(u32 b, volatile void __iomem *addr)
+{
+       __raw_writel(b, addr);
+       mb();
+}
+
+void writeq(u64 b, volatile void __iomem *addr)
+{
+       __raw_writeq(b, addr);
+       mb();
+}
+
+EXPORT_SYMBOL(readb);
+EXPORT_SYMBOL(readw);
+EXPORT_SYMBOL(readl);
+EXPORT_SYMBOL(readq);
+EXPORT_SYMBOL(writeb);
+EXPORT_SYMBOL(writew);
+EXPORT_SYMBOL(writel);
+EXPORT_SYMBOL(writeq);
+
+
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at SRC.
+ */
+void ioread8_rep(void __iomem *port, void *dst, unsigned long count)
+{
+       while ((unsigned long)dst & 0x3) {
+               if (!count)
+                       return;
+               count--;
+               *(unsigned char *)dst = ioread8(port);
+               dst += 1;
+       }
+
+       while (count >= 4) {
+               unsigned int w;
+               count -= 4;
+               w = ioread8(port);
+               w |= ioread8(port) << 8;
+               w |= ioread8(port) << 16;
+               w |= ioread8(port) << 24;
+               *(unsigned int *)dst = w;
+               dst += 4;
+       }
+
+       while (count) {
+               --count;
+               *(unsigned char *)dst = ioread8(port);
+               dst += 1;
+       }
+}
+
+void insb(unsigned long port, void *dst, unsigned long count)
+{
+       ioread8_rep(ioport_map(port, 1), dst, count);
+}
+
+EXPORT_SYMBOL(ioread8_rep);
+EXPORT_SYMBOL(insb);
+
+/*
+ * Read COUNT 16-bit words from port PORT into memory starting at
+ * SRC.  SRC must be at least short aligned.  This is used by the
+ * IDE driver to read disk sectors.  Performance is important, but
+ * the interfaces seems to be slow: just using the inlined version
+ * of the inw() breaks things.
+ */
+void ioread16_rep(void __iomem *port, void *dst, unsigned long count)
+{
+       if (unlikely((unsigned long)dst & 0x3)) {
+               if (!count)
+                       return;
+               BUG_ON((unsigned long)dst & 0x1);
+               count--;
+               *(unsigned short *)dst = ioread16(port);
+               dst += 2;
+       }
+
+       while (count >= 2) {
+               unsigned int w;
+               count -= 2;
+               w = ioread16(port);
+               w |= ioread16(port) << 16;
+               *(unsigned int *)dst = w;
+               dst += 4;
+       }
+
+       if (count) {
+               *(unsigned short*)dst = ioread16(port);
+       }
+}
+
+void insw(unsigned long port, void *dst, unsigned long count)
+{
+       ioread16_rep(ioport_map(port, 2), dst, count);
+}
+
+EXPORT_SYMBOL(ioread16_rep);
+EXPORT_SYMBOL(insw);
+
+
+/*
+ * Read COUNT 32-bit words from port PORT into memory starting at
+ * SRC. Now works with any alignment in SRC. Performance is important,
+ * but the interfaces seems to be slow: just using the inlined version
+ * of the inl() breaks things.
+ */
+void ioread32_rep(void __iomem *port, void *dst, unsigned long count)
+{
+       if (unlikely((unsigned long)dst & 0x3)) {
+               while (count--) {
+                       struct S { int x __attribute__((packed)); };
+                       ((struct S *)dst)->x = ioread32(port);
+                       dst += 4;
+               }
+       } else {
+               /* Buffer 32-bit aligned.  */
+               while (count--) {
+                       *(unsigned int *)dst = ioread32(port);
+                       dst += 4;
+               }
+       }
+}
+
+void insl(unsigned long port, void *dst, unsigned long count)
+{
+       ioread32_rep(ioport_map(port, 4), dst, count);
+}
+
+EXPORT_SYMBOL(ioread32_rep);
+EXPORT_SYMBOL(insl);
+
+
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+void iowrite8_rep(void __iomem *port, const void *xsrc, unsigned long count)
+{
+       const unsigned char *src = xsrc;
+       while (count--)
+               iowrite8(*src++, port);
+}
+
+void outsb(unsigned long port, const void *src, unsigned long count)
+{
+       iowrite8_rep(ioport_map(port, 1), src, count);
+}
+
+EXPORT_SYMBOL(iowrite8_rep);
+EXPORT_SYMBOL(outsb);
+
+
+/*
+ * Like insw but in the opposite direction.  This is used by the IDE
+ * driver to write disk sectors.  Performance is important, but the
+ * interfaces seems to be slow: just using the inlined version of the
+ * outw() breaks things.
+ */
+void iowrite16_rep(void __iomem *port, const void *src, unsigned long count)
+{
+       if (unlikely((unsigned long)src & 0x3)) {
+               if (!count)
+                       return;
+               BUG_ON((unsigned long)src & 0x1);
+               iowrite16(*(unsigned short *)src, port);
+               src += 2;
+               --count;
+       }
+
+       while (count >= 2) {
+               unsigned int w;
+               count -= 2;
+               w = *(unsigned int *)src;
+               src += 4;
+               iowrite16(w >>  0, port);
+               iowrite16(w >> 16, port);
+       }
+
+       if (count) {
+               iowrite16(*(unsigned short *)src, port);
+       }
+}
+
+void outsw(unsigned long port, const void *src, unsigned long count)
+{
+       iowrite16_rep(ioport_map(port, 2), src, count);
+}
+
+EXPORT_SYMBOL(iowrite16_rep);
+EXPORT_SYMBOL(outsw);
+
+
+/*
+ * Like insl but in the opposite direction.  This is used by the IDE
+ * driver to write disk sectors.  Works with any alignment in SRC.
+ * Performance is important, but the interfaces seems to be slow:
+ * just using the inlined version of the outl() breaks things.
+ */
+void iowrite32_rep(void __iomem *port, const void *src, unsigned long count)
+{
+       if (unlikely((unsigned long)src & 0x3)) {
+               while (count--) {
+                       struct S { int x __attribute__((packed)); };
+                       iowrite32(((struct S *)src)->x, port);
+                       src += 4;
+               }
+       } else {
+               /* Buffer 32-bit aligned.  */
+               while (count--) {
+                       iowrite32(*(unsigned int *)src, port);
+                       src += 4;
+               }
+       }
+}
+
+void outsl(unsigned long port, const void *src, unsigned long count)
+{
+       iowrite32_rep(ioport_map(port, 4), src, count);
+}
+
+EXPORT_SYMBOL(iowrite32_rep);
+EXPORT_SYMBOL(outsl);
+
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void memcpy_fromio(void *to, const volatile void __iomem *from, long count)
+{
+       /* Optimize co-aligned transfers.  Everything else gets handled
+          a byte at a time. */
+
+       if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
+               count -= 8;
+               do {
+                       *(u64 *)to = __raw_readq(from);
+                       count -= 8;
+                       to += 8;
+                       from += 8;
+               } while (count >= 0);
+               count += 8;
+       }
+
+       if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
+               count -= 4;
+               do {
+                       *(u32 *)to = __raw_readl(from);
+                       count -= 4;
+                       to += 4;
+                       from += 4;
+               } while (count >= 0);
+               count += 4;
+       }
+
+       if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
+               count -= 2;
+               do {
+                       *(u16 *)to = __raw_readw(from);
+                       count -= 2;
+                       to += 2;
+                       from += 2;
+               } while (count >= 0);
+               count += 2;
+       }
+
+       while (count > 0) {
+               *(u8 *) to = __raw_readb(from);
+               count--;
+               to++;
+               from++;
+       }
+       mb();
+}
+
+EXPORT_SYMBOL(memcpy_fromio);
+
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void memcpy_toio(volatile void __iomem *to, const void *from, long count)
+{
+       /* Optimize co-aligned transfers.  Everything else gets handled
+          a byte at a time. */
+       /* FIXME -- align FROM.  */
+
+       if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
+               count -= 8;
+               do {
+                       __raw_writeq(*(const u64 *)from, to);
+                       count -= 8;
+                       to += 8;
+                       from += 8;
+               } while (count >= 0);
+               count += 8;
+       }
+
+       if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
+               count -= 4;
+               do {
+                       __raw_writel(*(const u32 *)from, to);
+                       count -= 4;
+                       to += 4;
+                       from += 4;
+               } while (count >= 0);
+               count += 4;
+       }
+
+       if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
+               count -= 2;
+               do {
+                       __raw_writew(*(const u16 *)from, to);
+                       count -= 2;
+                       to += 2;
+                       from += 2;
+               } while (count >= 0);
+               count += 2;
+       }
+
+       while (count > 0) {
+               __raw_writeb(*(const u8 *) from, to);
+               count--;
+               to++;
+               from++;
+       }
+       mb();
+}
+
+EXPORT_SYMBOL(memcpy_toio);
+
+
+/*
+ * "memset" on IO memory space.
+ */
+void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
+{
+       /* Handle any initial odd byte */
+       if (count > 0 && ((u64)to & 1)) {
+               __raw_writeb(c, to);
+               to++;
+               count--;
+       }
+
+       /* Handle any initial odd halfword */
+       if (count >= 2 && ((u64)to & 2)) {
+               __raw_writew(c, to);
+               to += 2;
+               count -= 2;
+       }
+
+       /* Handle any initial odd word */
+       if (count >= 4 && ((u64)to & 4)) {
+               __raw_writel(c, to);
+               to += 4;
+               count -= 4;
+       }
+
+       /* Handle all full-sized quadwords: we're aligned
+          (or have a small count) */
+       count -= 8;
+       if (count >= 0) {
+               do {
+                       __raw_writeq(c, to);
+                       to += 8;
+                       count -= 8;
+               } while (count >= 0);
+       }
+       count += 8;
+
+       /* The tail is word-aligned if we still have count >= 4 */
+       if (count >= 4) {
+               __raw_writel(c, to);
+               to += 4;
+               count -= 4;
+       }
+
+       /* The tail is half-word aligned if we have count >= 2 */
+       if (count >= 2) {
+               __raw_writew(c, to);
+               to += 2;
+               count -= 2;
+       }
+
+       /* And finally, one last byte.. */
+       if (count) {
+               __raw_writeb(c, to);
+       }
+       mb();
+}
+
+EXPORT_SYMBOL(_memset_c_io);
+
+/* A version of memcpy used by the vga console routines to move data around
+   arbitrarily between screen and main memory.  */
+
+void
+scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
+{
+       const u16 __iomem *ios = (const u16 __iomem *) s;
+       u16 __iomem *iod = (u16 __iomem *) d;
+       int s_isio = __is_ioaddr(s);
+       int d_isio = __is_ioaddr(d);
+
+       if (s_isio) {
+               if (d_isio) {
+                       /* FIXME: Should handle unaligned ops and
+                          operation widening.  */
+
+                       count /= 2;
+                       while (count--) {
+                               u16 tmp = __raw_readw(ios++);
+                               __raw_writew(tmp, iod++);
+                       }
+               }
+               else
+                       memcpy_fromio(d, ios, count);
+       } else {
+               if (d_isio)
+                       memcpy_toio(iod, s, count);
+               else
+                       memcpy(d, s, count);
+       }
+}
+
+EXPORT_SYMBOL(scr_memcpyw);
+
+void __iomem *ioport_map(unsigned long port, unsigned int size)
+{
+       return IO_CONCAT(__IO_PREFIX,ioportmap) (port);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+}
+
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
new file mode 100644 (file)
index 0000000..266f46c
--- /dev/null
@@ -0,0 +1,115 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+# RMK wants arm kernels compiled with frame pointers so hardwire this to y.
+# If you know what you are doing and are willing to live without stack
+# traces, you can get a slightly smaller kernel by setting this option to
+# n, but then RMK will have to kill you ;).
+config FRAME_POINTER
+       bool
+       default y
+       help
+         If you say N here, the resulting kernel will be slightly smaller and
+         faster. However, when a problem occurs with the kernel, the
+         information that is reported is severely limited. Most people
+         should say Y here.
+
+config DEBUG_USER
+       bool "Verbose user fault messages"
+       help
+         When a user program crashes due to an exception, the kernel can
+         print a brief message explaining what the problem was. This is
+         sometimes helpful for debugging but serves no purpose on a
+         production system. Most people should say N here.
+
+         In addition, you need to pass user_debug=N on the kernel command
+         line to enable this feature.  N consists of the sum of:
+
+             1 - undefined instruction events
+             2 - system calls
+             4 - invalid data aborts
+             8 - SIGSEGV faults
+            16 - SIGBUS faults
+
+config DEBUG_WAITQ
+       bool "Wait queue debugging"
+       depends on DEBUG_KERNEL
+
+config DEBUG_ERRORS
+       bool "Verbose kernel error messages"
+       depends on DEBUG_KERNEL
+       help
+         This option controls verbose debugging information which can be
+         printed when the kernel detects an internal error. This debugging
+         information is useful to kernel hackers when tracking down problems,
+         but mostly meaningless to other people. It's safe to say Y unless
+         you are concerned with the code size or don't want to see these
+         messages.
+
+config DEBUG_INFO
+       bool "Include GDB debugging information in kernel binary"
+       help
+         Say Y here to include source-level debugging information in the
+         `vmlinux' binary image. This is handy if you want to use gdb or
+         addr2line to debug the kernel. It has no impact on the in-memory
+         footprint of the running kernel but it can increase the amount of
+         time and disk space needed for compilation of the kernel. If in
+         doubt say N.
+
+# These options are only for real kernel hackers who want to get their hands dirty.
+config DEBUG_LL
+       bool "Kernel low-level debugging functions"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here to include definitions of printascii, printchar, printhex
+         in the kernel.  This is helpful if you are debugging code that
+         executes before the console is initialized.
+
+config DEBUG_ICEDCC
+       bool "Kernel low-level debugging via EmbeddedICE DCC channel"
+       depends on DEBUG_LL
+       help
+         Say Y here if you want the debug print routines to direct their
+         output to the EmbeddedICE macrocell's DCC channel using
+         co-processor 14. This is known to work on the ARM9 style ICE
+         channel.
+
+         It does include a timeout to ensure that the system does not
+         totally freeze when there is nothing connected to read.
+
+config DEBUG_DC21285_PORT
+       bool "Kernel low-level debugging messages via footbridge serial port"
+       depends on DEBUG_LL && FOOTBRIDGE
+       help
+         Say Y here if you want the debug print routines to direct their
+         output to the serial port in the DC21285 (Footbridge). Saying N
+         will cause the debug messages to appear on the first 16550
+         serial port.
+
+config DEBUG_CLPS711X_UART2
+       bool "Kernel low-level debugging messages via UART2"
+       depends on DEBUG_LL && ARCH_CLPS711X
+       help
+         Say Y here if you want the debug print routines to direct their
+         output to the second serial port on these devices.  Saying N will
+         cause the debug messages to appear on the first serial port.
+
+config DEBUG_S3C2410_PORT
+       depends on DEBUG_LL && ARCH_S3C2410
+       bool "Kernel low-level debugging messages via S3C2410 UART"
+       help
+         Say Y here if you want debug print routines to go to one of the
+         S3C2410 internal UARTs. The chosen UART must have been configured
+         before it is used.
+
+config DEBUG_S3C2410_UART
+       depends on DEBUG_LL && ARCH_S3C2410
+       int "S3C2410 UART to use for low-level debug"
+       default "0"
+       help
+         Choice for UART for kernel low-level using S3C2410 UARTS,
+         should be between zero and two. The port must have been
+         initalised by the boot-loader before use.
+
+endmenu
diff --git a/arch/arm/boot/compressed/big-endian.S b/arch/arm/boot/compressed/big-endian.S
new file mode 100644 (file)
index 0000000..25ab26f
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *  linux/arch/arm/boot/compressed/big-endian.S
+ *
+ *  Switch CPU into big endian mode.
+ *  Author: Nicolas Pitre
+ */
+
+       .section ".start", #alloc, #execinstr
+
+       mrc     p15, 0, r0, c1, c0, 0   @ read control reg
+       orr     r0, r0, #(1 << 7)       @ enable big endian mode
+       mcr     p15, 0, r0, c1, c0, 0   @ write control reg
+
diff --git a/arch/arm/common/icst307.c b/arch/arm/common/icst307.c
new file mode 100644 (file)
index 0000000..bafe8b1
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  linux/arch/arm/common/icst307.c
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Support functions for calculating clocks/divisors for the ICST307
+ *  clock generators.  See http://www.icst.com/ for more information
+ *  on these devices.
+ *
+ *  This is an almost identical implementation to the ICST525 clock generator.
+ *  The s2div and idx2s files are different
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <asm/hardware/icst307.h>
+
+/*
+ * Divisors for each OD setting.
+ */
+static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 };
+
+unsigned long icst307_khz(const struct icst307_params *p, struct icst307_vco vco)
+{
+       return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]);
+}
+
+EXPORT_SYMBOL(icst307_khz);
+
+/*
+ * Ascending divisor S values.
+ */
+static unsigned char idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 };
+
+struct icst307_vco
+icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq)
+{
+       struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max };
+       unsigned long f;
+       unsigned int i = 0, rd, best = (unsigned int)-1;
+
+       /*
+        * First, find the PLL output divisor such
+        * that the PLL output is within spec.
+        */
+       do {
+               f = freq * s2div[idx2s[i]];
+
+               /*
+                * f must be between 6MHz and 200MHz (3.3 or 5V)
+                */
+               if (f > 6000 && f <= p->vco_max)
+                       break;
+       } while (i < ARRAY_SIZE(idx2s));
+
+       if (i > ARRAY_SIZE(idx2s))
+               return vco;
+
+       vco.s = idx2s[i];
+
+       /*
+        * Now find the closest divisor combination
+        * which gives a PLL output of 'f'.
+        */
+       for (rd = p->rd_min; rd <= p->rd_max; rd++) {
+               unsigned long fref_div, f_pll;
+               unsigned int vd;
+               int f_diff;
+
+               fref_div = (2 * p->ref) / rd;
+
+               vd = (f + fref_div / 2) / fref_div;
+               if (vd < p->vd_min || vd > p->vd_max)
+                       continue;
+
+               f_pll = fref_div * vd;
+               f_diff = f_pll - f;
+               if (f_diff < 0)
+                       f_diff = -f_diff;
+
+               if ((unsigned)f_diff < best) {
+                       vco.v = vd - 8;
+                       vco.r = rd - 2;
+                       if (f_diff == 0)
+                               break;
+                       best = f_diff;
+               }
+       }
+
+       return vco;
+}
+
+EXPORT_SYMBOL(icst307_khz_to_vco);
+
+struct icst307_vco
+icst307_ps_to_vco(const struct icst307_params *p, unsigned long period)
+{
+       struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max };
+       unsigned long f, ps;
+       unsigned int i = 0, rd, best = (unsigned int)-1;
+
+       ps = 1000000000UL / p->vco_max;
+
+       /*
+        * First, find the PLL output divisor such
+        * that the PLL output is within spec.
+        */
+       do {
+               f = period / s2div[idx2s[i]];
+
+               /*
+                * f must be between 6MHz and 200MHz (3.3 or 5V)
+                */
+               if (f >= ps && f < 1000000000UL / 6000 + 1)
+                       break;
+       } while (i < ARRAY_SIZE(idx2s));
+
+       if (i > ARRAY_SIZE(idx2s))
+               return vco;
+
+       vco.s = idx2s[i];
+
+       ps = 500000000UL / p->ref;
+
+       /*
+        * Now find the closest divisor combination
+        * which gives a PLL output of 'f'.
+        */
+       for (rd = p->rd_min; rd <= p->rd_max; rd++) {
+               unsigned long f_in_div, f_pll;
+               unsigned int vd;
+               int f_diff;
+
+               f_in_div = ps * rd;
+
+               vd = (f_in_div + f / 2) / f;
+               if (vd < p->vd_min || vd > p->vd_max)
+                       continue;
+
+               f_pll = (f_in_div + vd / 2) / vd;
+               f_diff = f_pll - f;
+               if (f_diff < 0)
+                       f_diff = -f_diff;
+
+               if ((unsigned)f_diff < best) {
+                       vco.v = vd - 8;
+                       vco.r = rd - 2;
+                       if (f_diff == 0)
+                               break;
+                       best = f_diff;
+               }
+       }
+
+       return vco;
+}
+
+EXPORT_SYMBOL(icst307_ps_to_vco);
diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c
new file mode 100644 (file)
index 0000000..dc170b3
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ *  linux/arch/arm/common/rtctime.c
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions Ltd.
+ *  Based on sa1100-rtc.c, Nils Faerber, CIH, Nicolas Pitre.
+ *  Based on rtc.c by Paul Gortmaker
+ *
+ * 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/kernel.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+
+#include <asm/rtc.h>
+#include <asm/semaphore.h>
+
+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
+static struct fasync_struct *rtc_async_queue;
+
+/*
+ * rtc_lock protects rtc_irq_data
+ */
+static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long rtc_irq_data;
+
+/*
+ * rtc_sem protects rtc_inuse and rtc_ops
+ */
+static DECLARE_MUTEX(rtc_sem);
+static unsigned long rtc_inuse;
+static struct rtc_ops *rtc_ops;
+
+#define rtc_epoch 1900UL
+
+static const unsigned char days_in_month[] = {
+       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+static int month_days(unsigned int month, unsigned int year)
+{
+       return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+}
+
+/*
+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
+ */
+void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+{
+       int days, month, year;
+
+       days = time / 86400;
+       time -= days * 86400;
+
+       tm->tm_wday = (days + 4) % 7;
+
+       year = 1970 + days / 365;
+       days -= (year - 1970) * 365
+               + LEAPS_THRU_END_OF(year - 1)
+               - LEAPS_THRU_END_OF(1970 - 1);
+       if (days < 0) {
+               year -= 1;
+               days += 365 + LEAP_YEAR(year);
+       }
+       tm->tm_year = year - 1900;
+       tm->tm_yday = days + 1;
+
+       for (month = 0; month < 11; month++) {
+               int newdays;
+
+               newdays = days - month_days(month, year);
+               if (newdays < 0)
+                       break;
+               days = newdays;
+       }
+       tm->tm_mon = month;
+       tm->tm_mday = days + 1;
+
+       tm->tm_hour = time / 3600;
+       time -= tm->tm_hour * 3600;
+       tm->tm_min = time / 60;
+       tm->tm_sec = time - tm->tm_min * 60;
+}
+EXPORT_SYMBOL(rtc_time_to_tm);
+
+/*
+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+ */
+int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+{
+       unsigned int yrs = tm->tm_year + 1900;
+
+       *time = 0;
+
+       if (yrs < 1970 ||
+           tm->tm_mon >= 12 ||
+           tm->tm_mday < 1 ||
+           tm->tm_mday > month_days(tm->tm_mon, yrs) ||
+           tm->tm_hour >= 24 ||
+           tm->tm_min >= 60 ||
+           tm->tm_sec >= 60)
+               return -EINVAL;
+
+       *time = mktime(yrs, tm->tm_mon + 1, tm->tm_mday,
+                      tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+EXPORT_SYMBOL(rtc_tm_to_time);
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ *
+ * FIXME: for now, we just copy the alarm time because we're lazy (and
+ * is therefore buggy - setting a 10am alarm at 8pm will not result in
+ * the alarm triggering.)
+ */
+void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
+{
+       next->tm_year = now->tm_year;
+       next->tm_mon = now->tm_mon;
+       next->tm_mday = now->tm_mday;
+       next->tm_hour = alrm->tm_hour;
+       next->tm_min = alrm->tm_min;
+       next->tm_sec = alrm->tm_sec;
+}
+
+static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
+{
+       memset(tm, 0, sizeof(struct rtc_time));
+       ops->read_time(tm);
+}
+
+static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
+{
+       return ops->set_time(tm);
+}
+
+static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+{
+       int ret = -EINVAL;
+       if (ops->read_alarm) {
+               memset(alrm, 0, sizeof(struct rtc_wkalrm));
+               ops->read_alarm(alrm);
+               ret = 0;
+       }
+       return ret;
+}
+
+static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+{
+       int ret = -EINVAL;
+       if (ops->set_alarm)
+               ret = ops->set_alarm(alrm);
+       return ret;
+}
+
+void rtc_update(unsigned long num, unsigned long events)
+{
+       spin_lock(&rtc_lock);
+       rtc_irq_data = (rtc_irq_data + (num << 8)) | events;
+       spin_unlock(&rtc_lock);
+
+       wake_up_interruptible(&rtc_wait);
+       kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL(rtc_update);
+
+
+static ssize_t
+rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long data;
+       ssize_t ret;
+
+       if (count < sizeof(unsigned long))
+               return -EINVAL;
+
+       add_wait_queue(&rtc_wait, &wait);
+       do {
+               __set_current_state(TASK_INTERRUPTIBLE);
+
+               spin_lock_irq(&rtc_lock);
+               data = rtc_irq_data;
+               rtc_irq_data = 0;
+               spin_unlock_irq(&rtc_lock);
+
+               if (data != 0) {
+                       ret = 0;
+                       break;
+               }
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       break;
+               }
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               schedule();
+       } while (1);
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&rtc_wait, &wait);
+
+       if (ret == 0) {
+               ret = put_user(data, (unsigned long __user *)buf);
+               if (ret == 0)
+                       ret = sizeof(unsigned long);
+       }
+       return ret;
+}
+
+static unsigned int rtc_poll(struct file *file, poll_table *wait)
+{
+       unsigned long data;
+
+       poll_wait(file, &rtc_wait, wait);
+
+       spin_lock_irq(&rtc_lock);
+       data = rtc_irq_data;
+       spin_unlock_irq(&rtc_lock);
+
+       return data != 0 ? POLLIN | POLLRDNORM : 0;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                    unsigned long arg)
+{
+       struct rtc_ops *ops = file->private_data;
+       struct rtc_time tm;
+       struct rtc_wkalrm alrm;
+       void __user *uarg = (void __user *)arg;
+       int ret = -EINVAL;
+
+       switch (cmd) {
+       case RTC_ALM_READ:
+               ret = rtc_read_alarm(ops, &alrm);
+               if (ret)
+                       break;
+               ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
+               if (ret)
+                       ret = -EFAULT;
+               break;
+
+       case RTC_ALM_SET:
+               ret = copy_from_user(&alrm.time, uarg, sizeof(tm));
+               if (ret) {
+                       ret = -EFAULT;
+                       break;
+               }
+               alrm.enabled = 0;
+               alrm.pending = 0;
+               alrm.time.tm_mday = -1;
+               alrm.time.tm_mon = -1;
+               alrm.time.tm_year = -1;
+               alrm.time.tm_wday = -1;
+               alrm.time.tm_yday = -1;
+               alrm.time.tm_isdst = -1;
+               ret = rtc_set_alarm(ops, &alrm);
+               break;
+
+       case RTC_RD_TIME:
+               rtc_read_time(ops, &tm);
+               ret = copy_to_user(uarg, &tm, sizeof(tm));
+               if (ret)
+                       ret = -EFAULT;
+               break;
+
+       case RTC_SET_TIME:
+               if (!capable(CAP_SYS_TIME)) {
+                       ret = -EACCES;
+                       break;
+               }
+               ret = copy_from_user(&tm, uarg, sizeof(tm));
+               if (ret) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = rtc_set_time(ops, &tm);
+               break;
+
+       case RTC_EPOCH_SET:
+#ifndef rtc_epoch
+               /*
+                * There were no RTC clocks before 1900.
+                */
+               if (arg < 1900) {
+                       ret = -EINVAL;
+                       break;
+               }
+               if (!capable(CAP_SYS_TIME)) {
+                       ret = -EACCES;
+                       break;
+               }
+               rtc_epoch = arg;
+               ret = 0;
+#endif
+               break;
+
+       case RTC_EPOCH_READ:
+               ret = put_user(rtc_epoch, (unsigned long __user *)uarg);
+               break;
+
+       case RTC_WKALM_SET:
+               ret = copy_from_user(&alrm, uarg, sizeof(alrm));
+               if (ret) {
+                       ret = -EFAULT;
+                       break;
+               }
+               ret = rtc_set_alarm(ops, &alrm);
+               break;
+
+       case RTC_WKALM_RD:
+               ret = rtc_read_alarm(ops, &alrm);
+               if (ret)
+                       break;
+               ret = copy_to_user(uarg, &alrm, sizeof(alrm));
+               if (ret)
+                       ret = -EFAULT;
+               break;
+
+       default:
+               if (ops->ioctl)
+                       ret = ops->ioctl(cmd, arg);
+               break;
+       }
+       return ret;
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       down(&rtc_sem);
+
+       if (rtc_inuse) {
+               ret = -EBUSY;
+       } else if (!rtc_ops || !try_module_get(rtc_ops->owner)) {
+               ret = -ENODEV;
+       } else {
+               file->private_data = rtc_ops;
+
+               ret = rtc_ops->open ? rtc_ops->open() : 0;
+               if (ret == 0) {
+                       spin_lock_irq(&rtc_lock);
+                       rtc_irq_data = 0;
+                       spin_unlock_irq(&rtc_lock);
+
+                       rtc_inuse = 1;
+               }
+       }
+       up(&rtc_sem);
+
+       return ret;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+       struct rtc_ops *ops = file->private_data;
+
+       if (ops->release)
+               ops->release();
+
+       spin_lock_irq(&rtc_lock);
+       rtc_irq_data = 0;
+       spin_unlock_irq(&rtc_lock);
+
+       module_put(rtc_ops->owner);
+       rtc_inuse = 0;
+
+       return 0;
+}
+
+static int rtc_fasync(int fd, struct file *file, int on)
+{
+       return fasync_helper(fd, file, on, &rtc_async_queue);
+}
+
+static struct file_operations rtc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = rtc_read,
+       .poll           = rtc_poll,
+       .ioctl          = rtc_ioctl,
+       .open           = rtc_open,
+       .release        = rtc_release,
+       .fasync         = rtc_fasync,
+};
+
+static struct miscdevice rtc_miscdev = {
+       .minor          = RTC_MINOR,
+       .name           = "rtc",
+       .fops           = &rtc_fops,
+};
+
+
+static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       struct rtc_ops *ops = data;
+       struct rtc_wkalrm alrm;
+       struct rtc_time tm;
+       char *p = page;
+       int len;
+
+       rtc_read_time(ops, &tm);
+
+       p += sprintf(p,
+               "rtc_time\t: %02d:%02d:%02d\n"
+               "rtc_date\t: %04d-%02d-%02d\n"
+               "rtc_epoch\t: %04lu\n",
+               tm.tm_hour, tm.tm_min, tm.tm_sec,
+               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+               rtc_epoch);
+
+       if (rtc_read_alarm(ops, &alrm) == 0) {
+               p += sprintf(p, "alrm_time\t: ");
+               if ((unsigned int)alrm.time.tm_hour <= 24)
+                       p += sprintf(p, "%02d:", alrm.time.tm_hour);
+               else
+                       p += sprintf(p, "**:");
+               if ((unsigned int)alrm.time.tm_min <= 59)
+                       p += sprintf(p, "%02d:", alrm.time.tm_min);
+               else
+                       p += sprintf(p, "**:");
+               if ((unsigned int)alrm.time.tm_sec <= 59)
+                       p += sprintf(p, "%02d\n", alrm.time.tm_sec);
+               else
+                       p += sprintf(p, "**\n");
+
+               p += sprintf(p, "alrm_date\t: ");
+               if ((unsigned int)alrm.time.tm_year <= 200)
+                       p += sprintf(p, "%04d-", alrm.time.tm_year + 1900);
+               else
+                       p += sprintf(p, "****-");
+               if ((unsigned int)alrm.time.tm_mon <= 11)
+                       p += sprintf(p, "%02d-", alrm.time.tm_mon + 1);
+               else
+                       p += sprintf(p, "**-");
+               if ((unsigned int)alrm.time.tm_mday <= 31)
+                       p += sprintf(p, "%02d\n", alrm.time.tm_mday);
+               else
+                       p += sprintf(p, "**\n");
+               p += sprintf(p, "alrm_wakeup\t: %s\n",
+                            alrm.enabled ? "yes" : "no");
+               p += sprintf(p, "alrm_pending\t: %s\n",
+                            alrm.pending ? "yes" : "no");
+       }
+
+       if (ops->proc)
+               p += ops->proc(p);
+
+       len = (p - page) - off;
+       if (len < 0)
+               len = 0;
+       *eof = len <= count;
+       *start = page + off;
+
+       return len;
+}
+
+int register_rtc(struct rtc_ops *ops)
+{
+       int ret = -EBUSY;
+
+       down(&rtc_sem);
+       if (rtc_ops == NULL) {
+               rtc_ops = ops;
+
+               ret = misc_register(&rtc_miscdev);
+               if (ret == 0)
+                       create_proc_read_entry("driver/rtc", 0, NULL,
+                                              rtc_read_proc, ops);
+       }
+       up(&rtc_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL(register_rtc);
+
+void unregister_rtc(struct rtc_ops *rtc)
+{
+       down(&rtc_sem);
+       if (rtc == rtc_ops) {
+               remove_proc_entry("driver/rtc", NULL);
+               misc_deregister(&rtc_miscdev);
+               rtc_ops = NULL;
+       }
+       up(&rtc_sem);
+}
+EXPORT_SYMBOL(unregister_rtc);
diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig
new file mode 100644 (file)
index 0000000..2f09ba9
--- /dev/null
@@ -0,0 +1,795 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+CONFIG_ARCH_IXP2000=y
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP2400/2800 Implementation Options
+#
+
+#
+# IXP2400/2800 Platforms
+#
+CONFIG_ARCH_ENP2611=y
+# CONFIG_ARCH_IXDP2400 is not set
+# CONFIG_ARCH_IXDP2800 is not set
+# CONFIG_ARCH_IXDP2401 is not set
+# CONFIG_ARCH_IXDP2801 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP2000=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=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=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=y
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+
+#
+# X.25/LAPB support is disabled
+#
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=y
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP2000_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_BDI2000_XSCALE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/ep80219_defconfig b/arch/arm/configs/ep80219_defconfig
new file mode 100644 (file)
index 0000000..fc4dbc2
--- /dev/null
@@ -0,0 +1,849 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_IOP3XX=y
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# IOP3xx Implementation Options
+#
+
+#
+# IOP3xx Platform Types
+#
+# CONFIG_ARCH_IQ80321 is not set
+CONFIG_ARCH_IQ31244=y
+# CONFIG_ARCH_IQ80331 is not set
+CONFIG_ARCH_EP80219=y
+CONFIG_ARCH_IOP321=y
+# CONFIG_ARCH_IOP331 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200 mem=128M@0xa0000000"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+CONFIG_E100_NAPI=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# 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_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC 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_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# 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_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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=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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+CONFIG_I2C_IOP3XX=y
+# CONFIG_I2C_ISA 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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/h7201_defconfig b/arch/arm/configs/h7201_defconfig
new file mode 100644 (file)
index 0000000..e18dad4
--- /dev/null
@@ -0,0 +1,511 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc1
+# Thu Sep  2 11:04:11 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+CONFIG_ARCH_H720X=y
+
+#
+# h720x Implementations
+#
+CONFIG_ARCH_H7201=y
+# CONFIG_ARCH_H7202 is not set
+CONFIG_CPU_H7201=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM720T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_TLB_V4WT=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE=""
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=0
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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=y
+# CONFIG_SERIO_CT82C710 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# 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_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_SYSFS=y
+# CONFIG_DEVFS_FS 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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/h7202_defconfig b/arch/arm/configs/h7202_defconfig
new file mode 100644 (file)
index 0000000..ba3f639
--- /dev/null
@@ -0,0 +1,652 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc1
+# Thu Sep 30 10:30:42 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+CONFIG_ARCH_H720X=y
+
+#
+# h720x Implementations
+#
+# CONFIG_ARCH_H7201 is not set
+CONFIG_ARCH_H7202=y
+# CONFIG_ARCH_FU7202 is not set
+CONFIG_CPU_H7202=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM720T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_TLB_V4WT=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_NWFPE_XP=y
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,19200"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+CONFIG_MTD_H720X=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD 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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_SMC91X is not set
+# CONFIG_CS89x0 is not set
+CONFIG_CIRRUS=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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=y
+# CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_H7202=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_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_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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 is not set
+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
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+CONFIG_USB_GADGET_H7202=y
+CONFIG_USB_H7202=m
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ETH is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_G_MULTISER=m
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/iq31244_defconfig b/arch/arm/configs/iq31244_defconfig
new file mode 100644 (file)
index 0000000..64ebb89
--- /dev/null
@@ -0,0 +1,818 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_IOP3XX=y
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# IOP3xx Implementation Options
+#
+
+#
+# IOP3xx Platform Types
+#
+# CONFIG_ARCH_IQ80321 is not set
+CONFIG_ARCH_IQ31244=y
+# CONFIG_ARCH_IQ80331 is not set
+# CONFIG_ARCH_EP80219 is not set
+CONFIG_ARCH_IOP321=y
+# CONFIG_ARCH_IOP331 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200 mem=256M@0xa0000000"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+CONFIG_E1000_NAPI=y
+# 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 is not set
+
+#
+# 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_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC 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_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# 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_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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=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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+CONFIG_I2C_IOP3XX=y
+# CONFIG_I2C_ISA 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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/iq80331_defconfig b/arch/arm/configs/iq80331_defconfig
new file mode 100644 (file)
index 0000000..9adbf9b
--- /dev/null
@@ -0,0 +1,753 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_IOP3XX=y
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# IOP3xx Implementation Options
+#
+
+#
+# IOP3xx Platform Types
+#
+# CONFIG_ARCH_IQ80321 is not set
+# CONFIG_ARCH_IQ31244 is not set
+CONFIG_ARCH_IQ80331=y
+# CONFIG_ARCH_EP80219 is not set
+CONFIG_ARCH_IOP331=y
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200 mem=128M@0x00000000"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+CONFIG_E1000_NAPI=y
+# 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 is not set
+
+#
+# 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_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC 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_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# 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_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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=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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# 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=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig
new file mode 100644 (file)
index 0000000..2f028ed
--- /dev/null
@@ -0,0 +1,796 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+CONFIG_ARCH_IXP2000=y
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP2400/2800 Implementation Options
+#
+
+#
+# IXP2400/2800 Platforms
+#
+# CONFIG_ARCH_ENP2611 is not set
+CONFIG_ARCH_IXDP2400=y
+# CONFIG_ARCH_IXDP2800 is not set
+CONFIG_ARCH_IXDP2X00=y
+# CONFIG_ARCH_IXDP2401 is not set
+# CONFIG_ARCH_IXDP2801 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP2000=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=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=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=y
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+
+#
+# X.25/LAPB support is disabled
+#
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=y
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP2000_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_BDI2000_XSCALE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig
new file mode 100644 (file)
index 0000000..7af19ae
--- /dev/null
@@ -0,0 +1,797 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+CONFIG_ARCH_IXP2000=y
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP2400/2800 Implementation Options
+#
+
+#
+# IXP2400/2800 Platforms
+#
+# CONFIG_ARCH_ENP2611 is not set
+# CONFIG_ARCH_IXDP2400 is not set
+# CONFIG_ARCH_IXDP2800 is not set
+CONFIG_ARCH_IXDP2401=y
+# CONFIG_ARCH_IXDP2801 is not set
+CONFIG_ARCH_IXDP2X01=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP2000=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=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=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_CS89x0=y
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=y
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+
+#
+# X.25/LAPB support is disabled
+#
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=y
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP2000_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_BDI2000_XSCALE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig
new file mode 100644 (file)
index 0000000..ea4b05a
--- /dev/null
@@ -0,0 +1,796 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+CONFIG_ARCH_IXP2000=y
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP2400/2800 Implementation Options
+#
+
+#
+# IXP2400/2800 Platforms
+#
+# CONFIG_ARCH_ENP2611 is not set
+# CONFIG_ARCH_IXDP2400 is not set
+CONFIG_ARCH_IXDP2800=y
+CONFIG_ARCH_IXDP2X00=y
+# CONFIG_ARCH_IXDP2401 is not set
+# CONFIG_ARCH_IXDP2801 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP2000=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=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=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=y
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+
+#
+# X.25/LAPB support is disabled
+#
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=y
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP2000_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_BDI2000_XSCALE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig
new file mode 100644 (file)
index 0000000..f0b0b1c
--- /dev/null
@@ -0,0 +1,797 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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_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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+CONFIG_ARCH_IXP2000=y
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP2400/2800 Implementation Options
+#
+
+#
+# IXP2400/2800 Platforms
+#
+# CONFIG_ARCH_ENP2611 is not set
+# CONFIG_ARCH_IXDP2400 is not set
+# CONFIG_ARCH_IXDP2800 is not set
+# CONFIG_ARCH_IXDP2401 is not set
+CONFIG_ARCH_IXDP2801=y
+CONFIG_ARCH_IXDP2X01=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware ixdp2x01_clock=50000000"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP2000=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=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=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_CS89x0=y
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=y
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+
+#
+# X.25/LAPB support is disabled
+#
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=y
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# 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
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP2000_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+CONFIG_I2C_SENSOR=y
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_BDI2000_XSCALE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/mx1ads_defconfig b/arch/arm/configs/mx1ads_defconfig
new file mode 100644 (file)
index 0000000..89da10c
--- /dev/null
@@ -0,0 +1,652 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_IOSCHED_NOOP is not set
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_ARCH_IMX=y
+
+#
+# IMX Implementations
+#
+CONFIG_ARCH_MX1ADS=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+
+#
+# General setup
+#
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_CPU_FREQ is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_NWFPE_XP=y
+CONFIG_FPE_FASTFPE=y
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+CONFIG_PREEMPT=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttySMX0,57600n8 ip=bootp root=/dev/nfs"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_MX1ADS=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# 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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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=y
+# CONFIG_SMC91X is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# 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
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+CONFIG_RTC=m
+# 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_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB 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_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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_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_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+# 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_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
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/simpad_defconfig b/arch/arm/configs/simpad_defconfig
new file mode 100644 (file)
index 0000000..10effbc
--- /dev/null
@@ -0,0 +1,896 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc2
+# Thu Sep 16 15:42:43 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="oe1"
+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=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+CONFIG_SA1100_SIMPAD=y
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
+# CONFIG_SA1100_SSP is not set
+# CONFIG_SA1100_USB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_SA1100=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+
+#
+# General setup
+#
+CONFIG_DISCONTIGMEM=y
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_CPU_FREQ is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=m
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+CONFIG_APM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mtdparts=sa1100:512k(boot),1m(kernel),-(root) console=ttySA0 root=1f02 noinitrd mem=64M jffs2_orphaned_inodes=delete rootfstype=jffs2"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=8192
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+CONFIG_IRPORT_SIR=m
+
+#
+# Old Serial dongle support
+#
+# CONFIG_DONGLE_OLD is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+CONFIG_SA1100_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_HIDP is not set
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+# CONFIG_BT_HCIVHCI 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=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# 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 is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_AIRO_CS=m
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=m
+# CONFIG_PCMCIA_NMCLAN is not set
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_PCMCIA_AXNET is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=600
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=800
+CONFIG_INPUT_TSDEV_SCREEN_Y=600
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_CT82C710=m
+
+#
+# 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_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+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_NVRAM is not set
+# CONFIG_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
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+# CONFIG_REISERFS_FS_XATTR 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_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_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_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 is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=m
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+# 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 is not set
+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=m
+# CONFIG_SMB_NLS_DEFAULT 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
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_SA1100 is not set
+CONFIG_FB_MQ200=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S
new file mode 100644 (file)
index 0000000..8f74e24
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ *  linux/arch/arm/kernel/iwmmxt.S
+ *
+ *  XScale iWMMXt (Concan) context switching and handling
+ *
+ *  Initial code:
+ *  Copyright (c) 2003, Intel Corporation
+ *
+ *  Full lazy switching support, optimizations and more, by Nicolas Pitre
+*   Copyright (c) 2003-2004, MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/constants.h>
+
+#define MMX_WR0                        (0x00)
+#define MMX_WR1                        (0x08)
+#define MMX_WR2                        (0x10)
+#define MMX_WR3                        (0x18)
+#define MMX_WR4                        (0x20)
+#define MMX_WR5                        (0x28)
+#define MMX_WR6                        (0x30)
+#define MMX_WR7                        (0x38)
+#define MMX_WR8                        (0x40)
+#define MMX_WR9                        (0x48)
+#define MMX_WR10               (0x50)
+#define MMX_WR11               (0x58)
+#define MMX_WR12               (0x60)
+#define MMX_WR13               (0x68)
+#define MMX_WR14               (0x70)
+#define MMX_WR15               (0x78)
+#define MMX_WCSSF              (0x80)
+#define MMX_WCASF              (0x84)
+#define MMX_WCGR0              (0x88)
+#define MMX_WCGR1              (0x8C)
+#define MMX_WCGR2              (0x90)
+#define MMX_WCGR3              (0x94)
+
+#define MMX_SIZE               (0x98)
+
+       .text
+
+/*
+ * Lazy switching of Concan coprocessor context
+ *
+ * r10 = struct thread_info pointer
+ * r9  = ret_from_exception
+ * lr  = undefined instr exit
+ *
+ * called from prefetch exception handler with interrupts disabled
+ */
+
+ENTRY(iwmmxt_task_enable)
+
+       mrc     p15, 0, r2, c15, c1, 0
+       tst     r2, #0x3                        @ CP0 and CP1 accessible?
+       movne   pc, lr                          @ if so no business here
+       orr     r2, r2, #0x3                    @ enable access to CP0 and CP1
+       mcr     p15, 0, r2, c15, c1, 0
+
+       ldr     r3, =concan_owner
+       add     r0, r10, #TI_IWMMXT_STATE       @ get task Concan save area
+       ldr     r2, [sp, #60]                   @ current task pc value
+       ldr     r1, [r3]                        @ get current Concan owner
+       str     r0, [r3]                        @ this task now owns Concan regs
+       sub     r2, r2, #4                      @ adjust pc back
+       str     r2, [sp, #60]
+
+       mrc     p15, 0, r2, c2, c0, 0
+       mov     r2, r2                          @ cpwait
+
+       teq     r1, #0                          @ test for last ownership
+       mov     lr, r9                          @ normal exit from exception
+       beq     concan_load                     @ no owner, skip save
+
+concan_save:
+
+       tmrc    r2, wCon
+
+       @ CUP? wCx
+       tst     r2, #0x1
+       beq     1f
+
+concan_dump:
+
+       wstrw   wCSSF, [r1, #MMX_WCSSF]
+       wstrw   wCASF, [r1, #MMX_WCASF]
+       wstrw   wCGR0, [r1, #MMX_WCGR0]
+       wstrw   wCGR1, [r1, #MMX_WCGR1]
+       wstrw   wCGR2, [r1, #MMX_WCGR2]
+       wstrw   wCGR3, [r1, #MMX_WCGR3]
+
+1:     @ MUP? wRn
+       tst     r2, #0x2
+       beq     2f
+
+       wstrd   wR0,  [r1, #MMX_WR0]
+       wstrd   wR1,  [r1, #MMX_WR1]
+       wstrd   wR2,  [r1, #MMX_WR2]
+       wstrd   wR3,  [r1, #MMX_WR3]
+       wstrd   wR4,  [r1, #MMX_WR4]
+       wstrd   wR5,  [r1, #MMX_WR5]
+       wstrd   wR6,  [r1, #MMX_WR6]
+       wstrd   wR7,  [r1, #MMX_WR7]
+       wstrd   wR8,  [r1, #MMX_WR8]
+       wstrd   wR9,  [r1, #MMX_WR9]
+       wstrd   wR10, [r1, #MMX_WR10]
+       wstrd   wR11, [r1, #MMX_WR11]
+       wstrd   wR12, [r1, #MMX_WR12]
+       wstrd   wR13, [r1, #MMX_WR13]
+       wstrd   wR14, [r1, #MMX_WR14]
+       wstrd   wR15, [r1, #MMX_WR15]
+
+2:     teq     r0, #0                          @ anything to load?
+       moveq   pc, lr
+
+concan_load:
+
+       @ Load wRn
+       wldrd   wR0,  [r0, #MMX_WR0]
+       wldrd   wR1,  [r0, #MMX_WR1]
+       wldrd   wR2,  [r0, #MMX_WR2]
+       wldrd   wR3,  [r0, #MMX_WR3]
+       wldrd   wR4,  [r0, #MMX_WR4]
+       wldrd   wR5,  [r0, #MMX_WR5]
+       wldrd   wR6,  [r0, #MMX_WR6]
+       wldrd   wR7,  [r0, #MMX_WR7]
+       wldrd   wR8,  [r0, #MMX_WR8]
+       wldrd   wR9,  [r0, #MMX_WR9]
+       wldrd   wR10, [r0, #MMX_WR10]
+       wldrd   wR11, [r0, #MMX_WR11]
+       wldrd   wR12, [r0, #MMX_WR12]
+       wldrd   wR13, [r0, #MMX_WR13]
+       wldrd   wR14, [r0, #MMX_WR14]
+       wldrd   wR15, [r0, #MMX_WR15]
+
+       @ Load wCx
+       wldrw   wCSSF, [r0, #MMX_WCSSF]
+       wldrw   wCASF, [r0, #MMX_WCASF]
+       wldrw   wCGR0, [r0, #MMX_WCGR0]
+       wldrw   wCGR1, [r0, #MMX_WCGR1]
+       wldrw   wCGR2, [r0, #MMX_WCGR2]
+       wldrw   wCGR3, [r0, #MMX_WCGR3]
+
+       @ clear CUP/MUP (only if r1 != 0)
+       teq     r1, #0
+       mov     r2, #0
+       moveq   pc, lr
+       tmcr    wCon, r2
+       mov     pc, lr
+
+/*
+ * Back up Concan regs to save area and disable access to them
+ * (mainly for gdb or sleep mode usage)
+ *
+ * r0 = struct thread_info pointer of target task or NULL for any
+ */
+
+ENTRY(iwmmxt_task_disable)
+
+       stmfd   sp!, {r4, lr}
+
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =concan_owner
+       add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
+       ldr     r1, [r3]                        @ get current Concan owner
+       teq     r1, #0                          @ any current owner?
+       beq     1f                              @ no: quit
+       teq     r0, #0                          @ any owner?
+       teqne   r1, r2                          @ or specified one?
+       bne     1f                              @ no: quit
+
+       mrc     p15, 0, r4, c15, c1, 0
+       orr     r4, r4, #0x3                    @ enable access to CP0 and CP1
+       mcr     p15, 0, r4, c15, c1, 0
+       mov     r0, #0                          @ nothing to load
+       str     r0, [r3]                        @ no more current owner
+       mrc     p15, 0, r2, c2, c0, 0
+       mov     r2, r2                          @ cpwait
+       bl      concan_save
+
+       bic     r4, r4, #0x3                    @ disable access to CP0 and CP1
+       mcr     p15, 0, r4, c15, c1, 0
+       mrc     p15, 0, r2, c2, c0, 0
+       mov     r2, r2                          @ cpwait
+
+1:     msr     cpsr_c, ip                      @ restore interrupt mode
+       ldmfd   sp!, {r4, pc}
+
+/*
+ * Copy Concan state to given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to store Concan state
+ *
+ * this is called mainly in the creation of signal stack frames
+ */
+
+ENTRY(iwmmxt_task_copy)
+
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =concan_owner
+       add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
+       ldr     r3, [r3]                        @ get current Concan owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ current Concan values are in the task save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r1
+       mov     r1, r2
+       mov     r2, #MMX_SIZE
+       b       memcpy
+
+1:     @ this task owns Concan regs -- grab a copy from there
+       mov     r0, #0                          @ nothing to load
+       mov     r2, #3                          @ save all regs
+       mov     r3, lr                          @ preserve return address
+       bl      concan_dump
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
+
+/*
+ * Restore Concan state from given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to get Concan state from
+ *
+ * this is used to restore Concan state when unwinding a signal stack frame
+ */
+
+ENTRY(iwmmxt_task_restore)
+
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =concan_owner
+       add     r2, r0, #TI_IWMMXT_STATE        @ get task Concan save area
+       ldr     r3, [r3]                        @ get current Concan owner
+       bic     r2, r2, #0x7                    @ 64-bit alignment
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ this task doesn't own Concan regs -- use its save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r2
+       mov     r2, #MMX_SIZE
+       b       memcpy
+
+1:     @ this task owns Concan regs -- load them directly
+       mov     r0, r1
+       mov     r1, #0                          @ don't clear CUP/MUP
+       mov     r3, lr                          @ preserve return address
+       bl      concan_load
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
+
+/*
+ * Concan handling on task switch
+ *
+ * r0 = previous task_struct pointer (must be preserved)
+ * r1 = previous thread_info pointer
+ * r2 = next thread_info.cpu_domain pointer (must be preserved)
+ *
+ * Called only from __switch_to with task preemption disabled.
+ * No need to care about preserving r4 and above.
+ */
+ENTRY(iwmmxt_task_switch)
+
+       mrc     p15, 0, r4, c15, c1, 0
+       tst     r4, #0x3                        @ CP0 and CP1 accessible?
+       bne     1f                              @ yes: block them for next task
+
+       ldr     r5, =concan_owner
+       add     r6, r2, #(TI_IWMMXT_STATE - TI_CPU_DOMAIN) @ get next task Concan save area
+       ldr     r5, [r5]                        @ get current Concan owner
+       teq     r5, r6                          @ next task owns it?
+       movne   pc, lr                          @ no: leave Concan disabled
+
+1:     eor     r4, r4, #3                      @ flip Concan access
+       mcr     p15, 0, r4, c15, c1, 0
+
+       mrc     p15, 0, r4, c2, c0, 0
+       sub     pc, lr, r4, lsr #32             @ cpwait and return
+
+/*
+ * Remove Concan ownership of given task
+ *
+ * r0 = struct thread_info pointer
+ */
+ENTRY(iwmmxt_task_release)
+
+       mrs     r2, cpsr
+       orr     ip, r2, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, ip
+       ldr     r3, =concan_owner
+       add     r0, r0, #TI_IWMMXT_STATE        @ get task Concan save area
+       ldr     r1, [r3]                        @ get current Concan owner
+       eors    r0, r0, r1                      @ if equal...
+       streq   r0, [r3]                        @ then clear ownership
+       msr     cpsr_c, r2                      @ restore interrupts
+       mov     pc, lr
+
+       .data
+concan_owner:
+       .word   0
+
diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl.S
new file mode 100644 (file)
index 0000000..75a9121
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  linux/arch/arm/lib/io-readsl.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(__raw_readsl)
+               teq     r2, #0          @ do we have to check for the zero len?
+               moveq   pc, lr
+               ands    ip, r1, #3
+               bne     3f
+
+               subs    r2, r2, #4
+               bmi     2f
+               stmfd   sp!, {r4, lr}
+1:             ldr     r3, [r0, #0]
+               ldr     r4, [r0, #0]
+               ldr     ip, [r0, #0]
+               ldr     lr, [r0, #0]
+               subs    r2, r2, #4
+               stmia   r1!, {r3, r4, ip, lr}
+               bpl     1b
+               ldmfd   sp!, {r4, lr}
+2:             movs    r2, r2, lsl #31
+               ldrcs   r3, [r0, #0]
+               ldrcs   ip, [r0, #0]
+               stmcsia r1!, {r3, ip}
+               ldrne   r3, [r0, #0]
+               strne   r3, [r1, #0]
+               mov     pc, lr
+
+3:             ldr     r3, [r0]
+               cmp     ip, #2
+               mov     ip, r3, get_byte_0
+               strb    ip, [r1], #1
+               bgt     6f
+               mov     ip, r3, get_byte_1
+               strb    ip, [r1], #1
+               beq     5f
+               mov     ip, r3, get_byte_2
+               strb    ip, [r1], #1
+
+4:             subs    r2, r2, #1
+               mov     ip, r3, pull #24
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, push #8
+               strne   ip, [r1], #4
+               bne     4b
+               b       8f
+
+5:             subs    r2, r2, #1
+               mov     ip, r3, pull #16
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, push #16
+               strne   ip, [r1], #4
+               bne     5b
+               b       7f
+
+6:             subs    r2, r2, #1
+               mov     ip, r3, pull #8
+               ldrne   r3, [r0]
+               orrne   ip, ip, r3, push #24
+               strne   ip, [r1], #4
+               bne     6b
+
+               mov     r3, ip, get_byte_2
+               strb    r3, [r1, #2]
+7:             mov     r3, ip, get_byte_1
+               strb    r3, [r1, #1]
+8:             mov     r3, ip, get_byte_0
+               strb    r3, [r1, #0]
+               mov     pc, lr
diff --git a/arch/arm/mach-clps711x/Makefile.boot b/arch/arm/mach-clps711x/Makefile.boot
new file mode 100644 (file)
index 0000000..d3d2933
--- /dev/null
@@ -0,0 +1,7 @@
+# The standard locations for stuff on CLPS711x type processors
+   zreladdr-y                          := 0xc0028000 
+params_phys-y                          := 0xc0000100
+# Should probably have some agreement on these...
+initrd_phys-$(CONFIG_ARCH_P720T)       := 0xc0400000
+initrd_phys-$(CONFIG_ARCH_CDB89712)    := 0x00700000
+
diff --git a/arch/arm/mach-clps711x/common.h b/arch/arm/mach-clps711x/common.h
new file mode 100644 (file)
index 0000000..2b8b801
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * linux/arch/arm/mach-clps711x/common.h
+ *
+ * Common bits.
+ */
+
+struct sys_timer;
+
+extern void clps711x_map_io(void);
+extern void clps711x_init_irq(void);
+extern struct sys_timer clps711x_timer;
diff --git a/arch/arm/mach-clps7500/Makefile.boot b/arch/arm/mach-clps7500/Makefile.boot
new file mode 100644 (file)
index 0000000..fe16506
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-y  := 0x10008000
+
diff --git a/arch/arm/mach-ebsa110/Makefile.boot b/arch/arm/mach-ebsa110/Makefile.boot
new file mode 100644 (file)
index 0000000..2321260
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000400
+initrd_phys-y  := 0x00800000
+
diff --git a/arch/arm/mach-epxa10db/Makefile.boot b/arch/arm/mach-epxa10db/Makefile.boot
new file mode 100644 (file)
index 0000000..28bec7d
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-y  := 0x00008000
+
diff --git a/arch/arm/mach-footbridge/Makefile.boot b/arch/arm/mach-footbridge/Makefile.boot
new file mode 100644 (file)
index 0000000..c7e75ac
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+initrd_phys-y  := 0x00800000
+
diff --git a/arch/arm/mach-footbridge/co285.c b/arch/arm/mach-footbridge/co285.c
new file mode 100644 (file)
index 0000000..e154191
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * linux/arch/arm/mach-footbridge/co285.c
+ *
+ * CO285 machine fixup
+ */
+#include <linux/init.h>
+
+#include <asm/hardware/dec21285.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+
+#include "common.h"
+
+static void __init
+fixup_coebsa285(struct machine_desc *desc, struct tag *tags,
+               char **cmdline, struct meminfo *mi)
+{
+       extern unsigned long boot_memory_end;
+       extern char boot_command_line[];
+
+       mi->nr_banks      = 1;
+       mi->bank[0].start = PHYS_OFFSET;
+       mi->bank[0].size  = boot_memory_end;
+       mi->bank[0].node  = 0;
+
+       *cmdline = boot_command_line;
+}
+
+MACHINE_START(CO285, "co-EBSA285")
+       MAINTAINER("Mark van Doesburg")
+       BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000)
+       FIXUP(fixup_coebsa285)
+       MAPIO(footbridge_map_io)
+       INITIRQ(footbridge_init_irq)
+       .timer          = &footbridge_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
new file mode 100644 (file)
index 0000000..eb8238c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *  linux/arch/arm/mach-footbridge/common.c
+ *
+ *  Copyright (C) 1998-2000 Russell King, Dave Gilbert.
+ *
+ * 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/types.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/setup.h>
+#include <asm/hardware/dec21285.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+
+#include "common.h"
+
+extern void __init isa_init_irq(unsigned int irq);
+
+unsigned int mem_fclk_21285 = 50000000;
+
+EXPORT_SYMBOL(mem_fclk_21285);
+
+static int __init parse_tag_memclk(const struct tag *tag)
+{
+       mem_fclk_21285 = tag->u.memclk.fmemclk;
+       return 0;
+}
+
+__tagtable(ATAG_MEMCLK, parse_tag_memclk);
+
+/*
+ * Footbridge IRQ translation table
+ *  Converts from our IRQ numbers into FootBridge masks
+ */
+static const int fb_irq_mask[] = {
+       IRQ_MASK_UART_RX,       /*  0 */
+       IRQ_MASK_UART_TX,       /*  1 */
+       IRQ_MASK_TIMER1,        /*  2 */
+       IRQ_MASK_TIMER2,        /*  3 */
+       IRQ_MASK_TIMER3,        /*  4 */
+       IRQ_MASK_IN0,           /*  5 */
+       IRQ_MASK_IN1,           /*  6 */
+       IRQ_MASK_IN2,           /*  7 */
+       IRQ_MASK_IN3,           /*  8 */
+       IRQ_MASK_DOORBELLHOST,  /*  9 */
+       IRQ_MASK_DMA1,          /* 10 */
+       IRQ_MASK_DMA2,          /* 11 */
+       IRQ_MASK_PCI,           /* 12 */
+       IRQ_MASK_SDRAMPARITY,   /* 13 */
+       IRQ_MASK_I2OINPOST,     /* 14 */
+       IRQ_MASK_PCI_ABORT,     /* 15 */
+       IRQ_MASK_PCI_SERR,      /* 16 */
+       IRQ_MASK_DISCARD_TIMER, /* 17 */
+       IRQ_MASK_PCI_DPERR,     /* 18 */
+       IRQ_MASK_PCI_PERR,      /* 19 */
+};
+
+static void fb_mask_irq(unsigned int irq)
+{
+       *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)];
+}
+
+static void fb_unmask_irq(unsigned int irq)
+{
+       *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)];
+}
+
+static struct irqchip fb_chip = {
+       .ack    = fb_mask_irq,
+       .mask   = fb_mask_irq,
+       .unmask = fb_unmask_irq,
+};
+
+static void __init __fb_init_irq(void)
+{
+       unsigned int irq;
+
+       /*
+        * setup DC21285 IRQs
+        */
+       *CSR_IRQ_DISABLE = -1;
+       *CSR_FIQ_DISABLE = -1;
+
+       for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) {
+               set_irq_chip(irq, &fb_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+       }
+}
+
+void __init footbridge_init_irq(void)
+{
+       __fb_init_irq();
+
+       if (!footbridge_cfn_mode())
+               return;
+
+       if (machine_is_ebsa285())
+               /* The following is dependent on which slot
+                * you plug the Southbridge card into.  We
+                * currently assume that you plug it into
+                * the right-hand most slot.
+                */
+               isa_init_irq(IRQ_PCI);
+
+       if (machine_is_cats())
+               isa_init_irq(IRQ_IN2);
+
+       if (machine_is_netwinder())
+               isa_init_irq(IRQ_IN3);
+}
+
+/*
+ * Common mapping for all systems.  Note that the outbound write flush is
+ * commented out since there is a "No Fix" problem with it.  Not mapping
+ * it means that we have extra bullet protection on our feet.
+ */
+static struct map_desc fb_common_io_desc[] __initdata = {
+ { ARMCSR_BASE,         DC21285_ARMCSR_BASE,       ARMCSR_SIZE,  MT_DEVICE },
+ { XBUS_BASE,    0x40000000,               XBUS_SIZE,    MT_DEVICE }
+};
+
+/*
+ * The mapping when the footbridge is in host mode.  We don't map any of
+ * this when we are in add-in mode.
+ */
+static struct map_desc ebsa285_host_io_desc[] __initdata = {
+#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST)
+ { PCIMEM_BASE,  DC21285_PCI_MEM,          PCIMEM_SIZE,  MT_DEVICE },
+ { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, MT_DEVICE },
+ { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, MT_DEVICE },
+ { PCIIACK_BASE, DC21285_PCI_IACK,         PCIIACK_SIZE, MT_DEVICE },
+ { PCIO_BASE,    DC21285_PCI_IO,           PCIO_SIZE,    MT_DEVICE }
+#endif
+};
+
+/*
+ * The CO-ebsa285 mapping.
+ */
+static struct map_desc co285_io_desc[] __initdata = {
+#ifdef CONFIG_ARCH_CO285
+ { PCIO_BASE,   DC21285_PCI_IO,            PCIO_SIZE,    MT_DEVICE },
+ { PCIMEM_BASE,         DC21285_PCI_MEM,           PCIMEM_SIZE,  MT_DEVICE }
+#endif
+};
+
+void __init footbridge_map_io(void)
+{
+       /*
+        * Set up the common mapping first; we need this to
+        * determine whether we're in host mode or not.
+        */
+       iotable_init(fb_common_io_desc, ARRAY_SIZE(fb_common_io_desc));
+
+       /*
+        * Now, work out what we've got to map in addition on this
+        * platform.
+        */
+       if (machine_is_co285())
+               iotable_init(co285_io_desc, ARRAY_SIZE(co285_io_desc));
+       if (footbridge_cfn_mode())
+               iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
+}
+
+#ifdef CONFIG_FOOTBRIDGE_ADDIN
+
+/*
+ * These two functions convert virtual addresses to PCI addresses and PCI
+ * addresses to virtual addresses.  Note that it is only legal to use these
+ * on memory obtained via get_zeroed_page or kmalloc.
+ */
+unsigned long __virt_to_bus(unsigned long res)
+{
+       WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory);
+
+       return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
+}
+EXPORT_SYMBOL(__virt_to_bus);
+
+unsigned long __bus_to_virt(unsigned long res)
+{
+       res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
+       res += PAGE_OFFSET;
+
+       WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory);
+
+       return res;
+}
+EXPORT_SYMBOL(__bus_to_virt);
+
+#endif
diff --git a/arch/arm/mach-footbridge/common.h b/arch/arm/mach-footbridge/common.h
new file mode 100644 (file)
index 0000000..580e31b
--- /dev/null
@@ -0,0 +1,9 @@
+
+extern struct sys_timer footbridge_timer;
+extern struct sys_timer isa_timer;
+
+extern void isa_rtc_init(void);
+
+extern void footbridge_map_io(void);
+extern void footbridge_init_irq(void);
+
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
new file mode 100644 (file)
index 0000000..580e1d4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  linux/arch/arm/mach-footbridge/dc21285-timer.c
+ *
+ *  Copyright (C) 1998 Russell King.
+ *  Copyright (C) 1998 Phil Blundell
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+
+#include <asm/hardware/dec21285.h>
+#include <asm/mach/time.h>
+
+#include "common.h"
+
+/*
+ * Footbridge timer 1 support.
+ */
+static unsigned long timer1_latch;
+
+static unsigned long timer1_gettimeoffset (void)
+{
+       unsigned long value = timer1_latch - *CSR_TIMER1_VALUE;
+
+       return ((tick_nsec / 1000) * value) / timer1_latch;
+}
+
+static irqreturn_t
+timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       write_seqlock(&xtime_lock);
+
+       *CSR_TIMER1_CLR = 0;
+
+       timer_tick(regs);
+
+       write_sequnlock(&xtime_lock);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction footbridge_timer_irq = {
+       .name           = "Timer1 timer tick",
+       .handler        = timer1_interrupt,
+       .flags          = SA_INTERRUPT,
+};
+
+/*
+ * Set up timer interrupt.
+ */
+static void __init footbridge_timer_init(void)
+{
+       isa_rtc_init();
+
+       timer1_latch = (mem_fclk_21285 + 8 * HZ) / (16 * HZ);
+
+       *CSR_TIMER1_CLR  = 0;
+       *CSR_TIMER1_LOAD = timer1_latch;
+       *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+
+       setup_irq(IRQ_TIMER1, &footbridge_timer_irq);
+}
+
+struct sys_timer footbridge_timer = {
+       .init           = footbridge_timer_init,
+       .offset         = timer1_gettimeoffset,
+};
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
new file mode 100644 (file)
index 0000000..d0931f5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * linux/arch/arm/mach-footbridge/ebsa285.c
+ *
+ * EBSA285 machine fixup
+ */
+#include <linux/init.h>
+
+#include <asm/hardware/dec21285.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+
+#include "common.h"
+
+MACHINE_START(EBSA285, "EBSA285")
+       MAINTAINER("Russell King")
+       BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+       BOOT_PARAMS(0x00000100)
+       VIDEO(0x000a0000, 0x000bffff)
+       MAPIO(footbridge_map_io)
+       INITIRQ(footbridge_init_irq)
+       .timer          = &footbridge_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
new file mode 100644 (file)
index 0000000..a4fefa0
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  linux/arch/arm/mach-footbridge/isa-timer.c
+ *
+ *  Copyright (C) 1998 Russell King.
+ *  Copyright (C) 1998 Phil Blundell
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/mach/time.h>
+
+#include "common.h"
+
+/*
+ * ISA timer tick support
+ */
+#define mSEC_10_from_14 ((14318180 + 100) / 200)
+
+static unsigned long isa_gettimeoffset(void)
+{
+       int count;
+
+       static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
+       static unsigned long jiffies_p = 0;
+
+       /*
+        * cache volatile jiffies temporarily; we have IRQs turned off. 
+        */
+       unsigned long jiffies_t;
+
+       /* timer count may underflow right here */
+       outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+       count = inb_p(0x40);    /* read the latched count */
+
+       /*
+        * We do this guaranteed double memory access instead of a _p 
+        * postfix in the previous port access. Wheee, hackady hack
+        */
+       jiffies_t = jiffies;
+
+       count |= inb_p(0x40) << 8;
+
+       /* Detect timer underflows.  If we haven't had a timer tick since 
+          the last time we were called, and time is apparently going
+          backwards, the counter must have wrapped during this routine. */
+       if ((jiffies_t == jiffies_p) && (count > count_p))
+               count -= (mSEC_10_from_14/6);
+       else
+               jiffies_p = jiffies_t;
+
+       count_p = count;
+
+       count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000);
+       count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
+
+       return count;
+}
+
+static irqreturn_t
+isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       write_seqlock(&xtime_lock);
+       timer_tick(regs);
+       write_sequnlock(&xtime_lock);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction isa_timer_irq = {
+       .name           = "ISA timer tick",
+       .handler        = isa_timer_interrupt,
+       .flags          = SA_INTERRUPT,
+};
+
+static void __init isa_timer_init(void)
+{
+       isa_rtc_init();
+
+       /* enable PIT timer */
+       /* set for periodic (4) and LSB/MSB write (0x30) */
+       outb(0x34, 0x43);
+       outb((mSEC_10_from_14/6) & 0xFF, 0x40);
+       outb((mSEC_10_from_14/6) >> 8, 0x40);
+
+       setup_irq(IRQ_ISA_TIMER, &isa_timer_irq);
+}
+
+struct sys_timer isa_timer = {
+       .init           = isa_timer_init,
+       .offset         = isa_gettimeoffset,
+};
diff --git a/arch/arm/mach-footbridge/isa.c b/arch/arm/mach-footbridge/isa.c
new file mode 100644 (file)
index 0000000..aa3a1fe
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  linux/arch/arm/mach-footbridge/isa.c
+ *
+ *  Copyright (C) 2004 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#include <asm/irq.h>
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .iobase         = 0x3f8,
+               .irq            = IRQ_ISA_UART,
+               .uartclk        = 1843200,
+               .regshift       = 0,
+               .iotype         = UPIO_PORT,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       {
+               .iobase         = 0x2f8,
+               .irq            = IRQ_ISA_UART2,
+               .uartclk        = 1843200,
+               .regshift       = 0,
+               .iotype         = UPIO_PORT,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       { },
+};
+
+static struct platform_device serial_device = {
+       .name                   = "serial8250",
+       .id                     = 0,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
+static int __init footbridge_isa_init(void)
+{
+       return platform_device_register(&serial_device);
+}
+
+arch_initcall(footbridge_isa_init);
diff --git a/arch/arm/mach-footbridge/personal.c b/arch/arm/mach-footbridge/personal.c
new file mode 100644 (file)
index 0000000..415086d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-footbridge/personal.c
+ *
+ * Personal server (Skiff) machine fixup
+ */
+#include <linux/init.h>
+
+#include <asm/hardware/dec21285.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+
+#include "common.h"
+
+MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
+       MAINTAINER("Jamey Hicks / George France")
+       BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(footbridge_map_io)
+       INITIRQ(footbridge_init_irq)
+       .timer          = &footbridge_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-h720x/Kconfig b/arch/arm/mach-h720x/Kconfig
new file mode 100644 (file)
index 0000000..44a303d
--- /dev/null
@@ -0,0 +1,27 @@
+menu "h720x Implementations"
+
+config ARCH_H7201
+       bool "gms30c7201"
+       depends on ARCH_H720X
+       select CPU_H7201
+       help
+         Say Y here if you are using the Hynix GMS30C7201 Reference Board
+
+config ARCH_H7202
+       bool "hms30c7202"
+       select CPU_H7202
+       depends on ARCH_H720X
+       help
+         Say Y here if you are using the Hynix HMS30C7202 Reference Board
+
+endmenu
+
+config CPU_H7201
+       bool
+       help
+         Select code specific to h7201 variants
+
+config CPU_H7202
+       bool
+       help
+         Select code specific to h7202 variants
diff --git a/arch/arm/mach-h720x/Makefile b/arch/arm/mach-h720x/Makefile
new file mode 100644 (file)
index 0000000..e4cf728
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := common.o
+obj-m :=
+obj-n :=
+obj-  :=
+
+# Specific board support
+
+obj-$(CONFIG_ARCH_H7201)               += h7201-eval.o
+obj-$(CONFIG_ARCH_H7202)               += h7202-eval.o
+obj-$(CONFIG_CPU_H7201)                += cpu-h7201.o
+obj-$(CONFIG_CPU_H7202)                += cpu-h7202.o
diff --git a/arch/arm/mach-h720x/Makefile.boot b/arch/arm/mach-h720x/Makefile.boot
new file mode 100644 (file)
index 0000000..5298401
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-$(CONFIG_ARCH_H720X)       := 0x40008000
+
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
new file mode 100644 (file)
index 0000000..96aa3af
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * linux/arch/arm/mach-h720x/common.c
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *               2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *               2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * common stuff for Hynix h720x processors
+ *
+ * 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/sched.h>
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/mach/dma.h>
+
+#if 0
+#define IRQDBG(args...) printk(args)
+#else
+#define IRQDBG(args...) do {} while(0)
+#endif
+
+void __init arch_dma_init(dma_t *dma)
+{
+}
+
+/*
+ * Return usecs since last timer reload
+ * (timercount * (usecs perjiffie)) / (ticks per jiffie)
+ */
+unsigned long h720x_gettimeoffset(void)
+{
+       return (CPU_REG (TIMER_VIRT, TM0_COUNT) * tick_usec) / LATCH;
+}
+
+/*
+ * mask Global irq's
+ */
+static void mask_global_irq (unsigned int irq )
+{
+       CPU_REG (IRQC_VIRT, IRQC_IER) &= ~(1 << irq);
+}
+
+/*
+ * unmask Global irq's
+ */
+static void unmask_global_irq (unsigned int irq )
+{
+       CPU_REG (IRQC_VIRT, IRQC_IER) |= (1 << irq);
+}
+
+
+/*
+ * ack GPIO irq's
+ * Ack only for edge triggered int's valid
+ */
+static void inline ack_gpio_irq(u32 irq)
+{
+       u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq));
+       u32 bit = IRQ_TO_BIT(irq);
+       if ( (CPU_REG (reg_base, GPIO_EDGE) & bit))
+               CPU_REG (reg_base, GPIO_CLR) = bit;
+}
+
+/*
+ * mask GPIO irq's
+ */
+static void inline mask_gpio_irq(u32 irq)
+{
+       u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq));
+       u32 bit = IRQ_TO_BIT(irq);
+       CPU_REG (reg_base, GPIO_MASK) &= ~bit;
+}
+
+/*
+ * unmask GPIO irq's
+ */
+static void inline unmask_gpio_irq(u32 irq)
+{
+       u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq));
+       u32 bit = IRQ_TO_BIT(irq);
+       CPU_REG (reg_base, GPIO_MASK) |= bit;
+}
+
+static void
+h720x_gpio_handler(unsigned int mask, unsigned int irq,
+                 struct irqdesc *desc, struct pt_regs *regs)
+{
+       IRQDBG("%s irq: %d\n",__FUNCTION__,irq);
+       desc = irq_desc + irq;
+       while (mask) {
+               if (mask & 1) {
+                       IRQDBG("handling irq %d\n", irq);
+                       desc->handle(irq, desc, regs);
+               }
+               irq++;
+               desc++;
+               mask >>= 1;
+       }
+}
+
+static void
+h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT);
+       irq = IRQ_CHAINED_GPIOA(0);
+       IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+       h720x_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+       mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT);
+       irq = IRQ_CHAINED_GPIOB(0);
+       IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+       h720x_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT);
+       irq = IRQ_CHAINED_GPIOC(0);
+       IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+       h720x_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT);
+       irq = IRQ_CHAINED_GPIOD(0);
+       IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+       h720x_gpio_handler(mask, irq, desc, regs);
+}
+
+#ifdef CONFIG_CPU_H7202
+static void
+h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT);
+       irq = IRQ_CHAINED_GPIOE(0);
+       IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
+       h720x_gpio_handler(mask, irq, desc, regs);
+}
+#endif
+
+static struct irqchip h720x_global_chip = {
+       .ack = mask_global_irq,
+       .mask = mask_global_irq,
+       .unmask = unmask_global_irq,
+};
+
+static struct irqchip h720x_gpio_chip = {
+       .ack = ack_gpio_irq,
+       .mask = mask_gpio_irq,
+       .unmask = unmask_gpio_irq,
+};
+
+/*
+ * Initialize IRQ's, mask all, enable multiplexed irq's
+ */
+void __init h720x_init_irq (void)
+{
+       int     irq;
+
+       /* Mask global irq's */
+       CPU_REG (IRQC_VIRT, IRQC_IER) = 0x0;
+
+       /* Mask all multiplexed irq's */
+       CPU_REG (GPIO_A_VIRT, GPIO_MASK) = 0x0;
+       CPU_REG (GPIO_B_VIRT, GPIO_MASK) = 0x0;
+       CPU_REG (GPIO_C_VIRT, GPIO_MASK) = 0x0;
+       CPU_REG (GPIO_D_VIRT, GPIO_MASK) = 0x0;
+
+       /* Initialize global IRQ's, fast path */
+       for (irq = 0; irq < NR_GLBL_IRQS; irq++) {
+               set_irq_chip(irq, &h720x_global_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+       }
+
+       /* Initialize multiplexed IRQ's, slow path */
+       for (irq = IRQ_CHAINED_GPIOA(0) ; irq <= IRQ_CHAINED_GPIOD(31); irq++) {
+               set_irq_chip(irq, &h720x_gpio_chip);
+               set_irq_handler(irq, do_edge_IRQ);
+               set_irq_flags(irq, IRQF_VALID );
+       }
+       set_irq_chained_handler(IRQ_GPIOA, h720x_gpioa_demux_handler);
+       set_irq_chained_handler(IRQ_GPIOB, h720x_gpiob_demux_handler);
+       set_irq_chained_handler(IRQ_GPIOC, h720x_gpioc_demux_handler);
+       set_irq_chained_handler(IRQ_GPIOD, h720x_gpiod_demux_handler);
+
+#ifdef CONFIG_CPU_H7202
+       for (irq = IRQ_CHAINED_GPIOE(0) ; irq <= IRQ_CHAINED_GPIOE(31); irq++) {
+               set_irq_chip(irq, &h720x_gpio_chip);
+               set_irq_handler(irq, do_edge_IRQ);
+               set_irq_flags(irq, IRQF_VALID );
+       }
+       set_irq_chained_handler(IRQ_GPIOE, h720x_gpioe_demux_handler);
+#endif
+
+       /* Enable multiplexed irq's */
+       CPU_REG (IRQC_VIRT, IRQC_IER) = IRQ_ENA_MUX;
+}
+
+static struct map_desc h720x_io_desc[] __initdata = {
+       { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
+};
+
+/* Initialize io tables */
+void __init h720x_map_io(void)
+{
+       iotable_init(h720x_io_desc,ARRAY_SIZE(h720x_io_desc));
+}
diff --git a/arch/arm/mach-h720x/common.h b/arch/arm/mach-h720x/common.h
new file mode 100644 (file)
index 0000000..d8798db
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * linux/arch/arm/mach-h720x/common.h
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *               2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *               2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * Architecture specific stuff for Hynix GMS30C7201 development board
+ *
+ * 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.
+ *
+ */
+
+extern unsigned long h720x_gettimeoffset(void);
+extern void __init h720x_init_irq (void);
+extern void __init h720x_map_io(void);
+
+#ifdef CONFIG_ARCH_H7202
+extern struct sys_timer h7202_timer;
+extern void __init init_hw_h7202(void);
+extern void __init h7202_init_irq (void);
+extern void __init h7202_init_time(void);
+#endif
+
+#ifdef CONFIG_ARCH_H7201
+extern struct sys_timer h7201_timer;
+#endif
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
new file mode 100644 (file)
index 0000000..30f4d61
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/arm/mach-h720x/cpu-h7201.c
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *               2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *               2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * processor specific stuff for the Hynix h7201
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/irqs.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+extern unsigned long h720x_gettimeoffset(void);
+extern void __init h720x_init_irq (void);
+
+/*
+ * Timer interrupt handler
+ */
+static irqreturn_t
+h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
+       timer_tick(regs);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction h7201_timer_irq = {
+       .name           = "h7201 Timer Tick",
+       .flags          = SA_INTERRUPT,
+       .handler        = h7201_timer_interrupt
+};
+
+/*
+ * Setup TIMER0 as system timer
+ */
+void __init h7201_init_time(void)
+{
+       gettimeoffset = h720x_gettimeoffset;
+
+       CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH;
+       CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET;
+       CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START;
+       CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) = ENABLE_TM0_INTR | TIMER_ENABLE_BIT;
+
+       setup_irq(IRQ_TIMER0, &h7201_timer_irq);
+}
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
new file mode 100644 (file)
index 0000000..ee7abcd
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * linux/arch/arm/mach-h720x/cpu-h7202.c
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *               2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *               2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * processor specific stuff for the Hynix h7201
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/irqs.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <linux/device.h>
+
+static struct resource h7202ps2_resources[] = {
+       [0] = {
+               .start  = 0x8002c000,
+               .end    = 0x8002c040,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_PS2,
+               .end    = IRQ_PS2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device h7202ps2_device = {
+       .name           = "h7202ps2",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(h7202ps2_resources),
+       .resource       = h7202ps2_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &h7202ps2_device,
+};
+
+extern unsigned long h720x_gettimeoffset(void);
+extern void __init h720x_init_irq (void);
+
+/* Although we have two interrupt lines for the timers, we only have one
+ * status register which clears all pending timer interrupts on reading. So
+ * we have to handle all timer interrupts in one place.
+ */
+static void
+h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
+
+       if ( mask & TSTAT_T0INT ) {
+               timer_tick(regs);
+               if( mask == TSTAT_T0INT )
+                       return;
+       }
+
+       mask >>= 1;
+       irq = IRQ_TIMER1;
+       desc = irq_desc + irq;
+       while (mask) {
+               if (mask & 1)
+                       desc->handle(irq, desc, regs);
+               irq++;
+               desc++;
+               mask >>= 1;
+       }
+}
+
+/*
+ * Timer interrupt handler
+ */
+static irqreturn_t
+h7202_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       h7202_timerx_demux_handler(0, NULL, regs);
+       return IRQ_HANDLED;
+}
+
+/*
+ * mask multiplexed timer irq's
+ */
+static void inline mask_timerx_irq (u32 irq)
+{
+       unsigned int bit;
+       bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1));
+       CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) &= ~bit;
+}
+
+/*
+ * unmask multiplexed timer irq's
+ */
+static void inline unmask_timerx_irq (u32 irq)
+{
+       unsigned int bit;
+       bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1));
+       CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) |= bit;
+}
+
+static struct irqchip h7202_timerx_chip = {
+       .ack = mask_timerx_irq,
+       .mask = mask_timerx_irq,
+       .unmask = unmask_timerx_irq,
+};
+
+static struct irqaction h7202_timer_irq = {
+       .name           = "h7202 Timer Tick",
+       .flags          = SA_INTERRUPT,
+       .handler        = h7202_timer_interrupt
+};
+
+/*
+ * Setup TIMER0 as system timer
+ */
+void __init h7202_init_time(void)
+{
+       gettimeoffset = h720x_gettimeoffset;
+
+       CPU_REG (TIMER_VIRT, TM0_PERIOD) = LATCH;
+       CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_RESET;
+       CPU_REG (TIMER_VIRT, TM0_CTRL) = TM_REPEAT | TM_START;
+       CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) = ENABLE_TM0_INTR | TIMER_ENABLE_BIT;
+
+       setup_irq(IRQ_TIMER0, &h7202_timer_irq);
+}
+
+void __init h7202_init_irq (void)
+{
+       int     irq;
+
+       CPU_REG (GPIO_E_VIRT, GPIO_MASK) = 0x0;
+
+       for (irq = IRQ_TIMER1;
+                         irq < IRQ_CHAINED_TIMERX(NR_TIMERX_IRQS); irq++) {
+               mask_timerx_irq(irq);
+               set_irq_chip(irq, &h7202_timerx_chip);
+               set_irq_handler(irq, do_edge_IRQ);
+               set_irq_flags(irq, IRQF_VALID );
+       }
+       set_irq_chained_handler(IRQ_TIMERX, h7202_timerx_demux_handler);
+
+       h720x_init_irq();
+}
+
+void __init init_hw_h7202(void)
+{
+       /* Enable clocks */
+       CPU_REG (PMU_BASE, PMU_PLL_CTRL) |= PLL_2_EN | PLL_1_EN | PLL_3_MUTE;
+
+       (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+}
diff --git a/arch/arm/mach-h720x/h7201-eval.c b/arch/arm/mach-h720x/h7201-eval.c
new file mode 100644 (file)
index 0000000..d2208c1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/arm/mach-h720x/h7201-eval.c
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *               2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *               2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * Architecture specific stuff for Hynix GMS30C7201 development board
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <asm/setup.h>
+#include <asm/types.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware.h>
+
+extern void h720x_init_irq (void);
+extern void h7201_init_time(void);
+extern void __init h720x_map_io(void);
+
+MACHINE_START(H7201, "Hynix GMS30C7201")
+       MAINTAINER("Robert Schwebel, Pengutronix")
+       BOOT_MEM(0x40000000, 0x80000000, 0xf0000000)
+       BOOT_PARAMS(0xc0001000)
+       MAPIO(h720x_map_io)
+       INITIRQ(h720x_init_irq)
+       INITTIME(h7201_init_time)
+MACHINE_END
diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c
new file mode 100644 (file)
index 0000000..9398731
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * linux/arch/arm/mach-h720x/h7202-eval.c
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *               2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *              2004 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * Architecture specific stuff for Hynix HMS30C7202 development board
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <asm/setup.h>
+#include <asm/types.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware.h>
+
+extern void __init init_hw_h7202(void);
+extern void __init h7202_init_irq (void);
+extern void __init h7202_init_time(void);
+extern void __init h720x_map_io(void);
+
+static struct resource cirrus_resources[] = {
+       [0] = {
+               .start  = ETH0_PHYS + 0x300,
+               .end    = ETH0_PHYS + 0x300 + 0x10,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_CHAINED_GPIOB(8),
+               .end    = IRQ_CHAINED_GPIOB(8),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cirrus_device = {
+       .name           = "cirrus-cs89x0",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(cirrus_resources),
+       .resource       = cirrus_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &cirrus_device,
+};
+
+/*
+ * Hardware init. This is called early in initcalls
+ * Place pin inits here. So you avoid adding ugly
+ * #ifdef stuff to common drivers.
+ * Use this only, if your bootloader is not able
+ * to initialize the pins proper.
+ */
+static void __init init_eval_h7202(void)
+{
+       init_hw_h7202();
+       (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       /* Enable interrupt on portb bit 8 (ethernet) */
+       CPU_REG (GPIO_B_VIRT, GPIO_POL) &= ~(1 << 8);
+       CPU_REG (GPIO_B_VIRT, GPIO_EN) |= (1 << 8);
+}
+
+MACHINE_START(H7202, "Hynix HMS30C7202")
+       MAINTAINER("Robert Schwebel, Pengutronix")
+       BOOT_MEM(0x40000000, 0x80000000, 0xf0000000)
+       BOOT_PARAMS(0x40000100)
+       MAPIO(h720x_map_io)
+       INITIRQ(h7202_init_irq)
+       INITTIME(h7202_init_time)
+       INIT_MACHINE(init_eval_h7202)
+MACHINE_END
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
new file mode 100644 (file)
index 0000000..ec85813
--- /dev/null
@@ -0,0 +1,10 @@
+menu "IMX Implementations"
+       depends on ARCH_IMX
+
+config ARCH_MX1ADS
+       bool "mx1ads"
+       depends on ARCH_IMX
+       help
+         Say Y here if you are using the Motorola MX1ADS board
+
+endmenu
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
new file mode 100644 (file)
index 0000000..0b27d79
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+# 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).
+
+# Object file lists.
+
+obj-y                  += irq.o time.o dma.o generic.o
+
+# Specific board support
+obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
+
+# Support for blinky lights
+led-y := leds.o
+
+obj-$(CONFIG_LEDS)     +=  $(led-y)
+led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
new file mode 100644 (file)
index 0000000..fd72ce5
--- /dev/null
@@ -0,0 +1,2 @@
+    zreladdr-$(CONFIG_ARCH_MX1ADS)     := 0x08008000
+
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
new file mode 100644 (file)
index 0000000..7387ccb
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  linux/arch/arm/mach-imx/dma.c
+ *
+ *  imx DMA registration and IRQ dispatching
+ *
+ *  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.
+ *
+ *  03/03/2004 Sascha Hauer <sascha@saschahauer.de>
+ *             initial version heavily inspired by
+ *             linux/arch/arm/mach-pxa/dma.c
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/dma.h>
+
+static struct dma_channel {
+       char *name;
+       void (*irq_handler) (int, void *, struct pt_regs *);
+       void (*err_handler) (int, void *, struct pt_regs *);
+       void *data;
+} dma_channels[11];
+
+/* set err_handler to NULL to have the standard info-only error handler */
+int
+imx_request_dma(char *name, imx_dma_prio prio,
+               void (*irq_handler) (int, void *, struct pt_regs *),
+               void (*err_handler) (int, void *, struct pt_regs *), void *data)
+{
+       unsigned long flags;
+       int i, found = 0;
+
+       /* basic sanity checks */
+       if (!name || !irq_handler)
+               return -EINVAL;
+
+       local_irq_save(flags);
+
+       /* try grabbing a DMA channel with the requested priority */
+       for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
+               if (!dma_channels[i].name) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               /* requested prio group is full, try hier priorities */
+               for (i = prio - 1; i >= 0; i--) {
+                       if (!dma_channels[i].name) {
+                               found = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (found) {
+               DIMR &= ~(1 << i);
+               dma_channels[i].name = name;
+               dma_channels[i].irq_handler = irq_handler;
+               dma_channels[i].err_handler = err_handler;
+               dma_channels[i].data = data;
+       } else {
+               printk(KERN_WARNING "No more available DMA channels for %s\n",
+                      name);
+               i = -ENODEV;
+       }
+
+       local_irq_restore(flags);
+       return i;
+}
+
+void
+imx_free_dma(int dma_ch)
+{
+       unsigned long flags;
+
+       if (!dma_channels[dma_ch].name) {
+               printk(KERN_CRIT
+                      "%s: trying to free channel %d which is already freed\n",
+                      __FUNCTION__, dma_ch);
+               return;
+       }
+
+       local_irq_save(flags);
+       DIMR &= ~(1 << dma_ch);
+       dma_channels[dma_ch].name = NULL;
+       local_irq_restore(flags);
+}
+
+static irqreturn_t
+dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int i;
+       struct dma_channel *channel;
+       unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
+
+       for (i = 0; i < 11; i++) {
+               channel = &dma_channels[i];
+
+               if ( (err_mask & 1<<i) && channel->name && channel->err_handler) {
+                       channel->err_handler(i, channel->data, regs);
+                       continue;
+               }
+
+               if (DBTOSR & (1 << i)) {
+                       printk(KERN_WARNING
+                              "Burst timeout on channel %d (%s)\n",
+                              i, channel->name);
+                       DBTOSR |= (1 << i);
+               }
+               if (DRTOSR & (1 << i)) {
+                       printk(KERN_WARNING
+                              "Request timeout on channel %d (%s)\n",
+                              i, channel->name);
+                       DRTOSR |= (1 << i);
+               }
+               if (DSESR & (1 << i)) {
+                       printk(KERN_WARNING
+                              "Transfer timeout on channel %d (%s)\n",
+                              i, channel->name);
+                       DSESR |= (1 << i);
+               }
+               if (DBOSR & (1 << i)) {
+                       printk(KERN_WARNING
+                              "Buffer overflow timeout on channel %d (%s)\n",
+                              i, channel->name);
+                       DBOSR |= (1 << i);
+               }
+               DISR |= (1 << i);
+       }
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int i, disr = DISR;
+
+       for (i = 0; i < 11; i++) {
+               if (disr & (1 << i)) {
+                       struct dma_channel *channel = &dma_channels[i];
+                       if (channel->name && channel->irq_handler) {
+                               channel->irq_handler(i, channel->data, regs);
+                       } else {
+                               /*
+                                * IRQ for an unregistered DMA channel:
+                                * let's clear the interrupts and disable it.
+                                */
+                               printk(KERN_WARNING
+                                      "spurious IRQ for DMA channel %d\n", i);
+                               DISR |= (1 << i);
+                       }
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static int __init
+imx_dma_init(void)
+{
+       int ret;
+
+       /* reset DMA module */
+       DCR = DCR_DRST;
+
+       ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
+       if (ret) {
+               printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
+               return ret;
+       }
+
+       ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
+       if (ret) {
+               printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");
+               free_irq(DMA_INT, NULL);
+       }
+
+       /* enable DMA module */
+       DCR = DCR_DEN;
+
+       /* clear all interrupts */
+       DISR = 0x3ff;
+
+       /* enable interrupts */
+       DIMR = 0;
+
+       return ret;
+}
+
+arch_initcall(imx_dma_init);
+
+EXPORT_SYMBOL(imx_request_dma);
+EXPORT_SYMBOL(imx_free_dma);
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
new file mode 100644 (file)
index 0000000..4954653
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ *  arch/arm/mach-imx/generic.c
+ *
+ *  author: Sascha Hauer
+ *  Created: april 20th, 2004
+ *  Copyright: Synertronixx GmbH
+ *
+ *  Common code for i.MX 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.
+ *
+ * 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/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/map.h>
+
+void imx_gpio_mode(int gpio_mode)
+{
+       unsigned int pin = gpio_mode & GPIO_PIN_MASK;
+       unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> 5;
+       unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> 10;
+       unsigned int tmp;
+
+       /* Pullup enable */
+       if(gpio_mode & GPIO_PUEN)
+               PUEN(port) |= (1<<pin);
+       else
+               PUEN(port) &= ~(1<<pin);
+
+       /* Data direction */
+       if(gpio_mode & GPIO_OUT)
+               DDIR(port) |= 1<<pin;
+       else
+               DDIR(port) &= ~(1<<pin);
+
+       /* Primary / alternate function */
+       if(gpio_mode & GPIO_AF)
+               GPR(port) |= (1<<pin);
+       else
+               GPR(port) &= ~(1<<pin);
+
+       /* use as gpio? */
+       if( ocr == 3 )
+               GIUS(port) |= (1<<pin);
+       else
+               GIUS(port) &= ~(1<<pin);
+
+       /* Output / input configuration */
+       /* FIXME: I'm not very sure about OCR and ICONF, someone
+        * should have a look over it
+        */
+       if(pin<16) {
+               tmp = OCR1(port);
+               tmp &= ~( 3<<(pin*2));
+               tmp |= (ocr << (pin*2));
+               OCR1(port) = tmp;
+
+               if( gpio_mode & GPIO_AOUT )
+                       ICONFA1(port) &= ~( 3<<(pin*2));
+               if( gpio_mode & GPIO_BOUT )
+                       ICONFB1(port) &= ~( 3<<(pin*2));
+       } else {
+               tmp = OCR2(port);
+               tmp &= ~( 3<<((pin-16)*2));
+               tmp |= (ocr << ((pin-16)*2));
+               OCR2(port) = tmp;
+
+               if( gpio_mode & GPIO_AOUT )
+                       ICONFA2(port) &= ~( 3<<((pin-16)*2));
+               if( gpio_mode & GPIO_BOUT )
+                       ICONFB2(port) &= ~( 3<<((pin-16)*2));
+       }
+}
+
+EXPORT_SYMBOL(imx_gpio_mode);
+
+/*
+ *  get the system pll clock in Hz
+ *
+ *                  mfi + mfn / (mfd +1)
+ *  f = 2 * f_ref * --------------------
+ *                        pd + 1
+ */
+static unsigned int imx_decode_pll(unsigned int pll)
+{
+       u32 mfi = (pll >> 10) & 0xf;
+       u32 mfn = pll & 0x3f;
+       u32 mfd = (pll >> 16) & 0x3f;
+       u32 pd =  (pll >> 26) & 0xf;
+       u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
+
+       mfi = mfi <= 5 ? 5 : mfi;
+
+       return (2 * (f_ref>>10) * ( (mfi<<10) + (mfn<<10) / (mfd+1) )) / (pd+1);
+}
+
+unsigned int imx_get_system_clk(void)
+{
+       return imx_decode_pll(SPCTL0);
+}
+EXPORT_SYMBOL(imx_get_system_clk);
+
+unsigned int imx_get_mcu_clk(void)
+{
+       return imx_decode_pll(MPCTL0);
+}
+EXPORT_SYMBOL(imx_get_mcu_clk);
+
+/*
+ *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
+ */
+unsigned int imx_get_perclk1(void)
+{
+       return imx_get_system_clk() / (((PCDR) & 0xf)+1);
+}
+EXPORT_SYMBOL(imx_get_perclk1);
+
+/*
+ *  get peripheral clock 2 ( LCD, SD, SPI[12] )
+ */
+unsigned int imx_get_perclk2(void)
+{
+       return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
+}
+EXPORT_SYMBOL(imx_get_perclk2);
+
+/*
+ *  get peripheral clock 3 ( SSI )
+ */
+unsigned int imx_get_perclk3(void)
+{
+       return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
+}
+EXPORT_SYMBOL(imx_get_perclk3);
+
+/*
+ *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
+ */
+unsigned int imx_get_hclk(void)
+{
+       return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
+}
+EXPORT_SYMBOL(imx_get_hclk);
+
+static struct resource imx_mmc_resources[] = {
+       [0] = {
+               .start  = 0x00214000,
+               .end    = 0x002140FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = (SDHC_INT),
+               .end    = (SDHC_INT),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device imx_mmc_device = {
+       .name           = "imx-mmc",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(imx_mmc_resources),
+       .resource       = imx_mmc_resources,
+};
+
+static struct resource imx_uart1_resources[] = {
+       [0] = {
+               .start  = 0x00206000,
+               .end    = 0x002060FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = (UART1_MINT_RX),
+               .end    = (UART1_MINT_RX),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = (UART1_MINT_TX),
+               .end    = (UART1_MINT_TX),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device imx_uart1_device = {
+       .name           = "imx-uart",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(imx_uart1_resources),
+       .resource       = imx_uart1_resources,
+};
+
+static struct resource imx_uart2_resources[] = {
+       [0] = {
+               .start  = 0x00207000,
+               .end    = 0x002070FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = (UART2_MINT_RX),
+               .end    = (UART2_MINT_RX),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = (UART2_MINT_TX),
+               .end    = (UART2_MINT_TX),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device imx_uart2_device = {
+       .name           = "imx-uart",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(imx_uart2_resources),
+       .resource       = imx_uart2_resources,
+};
+
+static struct resource imxfb_resources[] = {
+       [0] = {
+               .start  = 0x00205000,
+               .end    = 0x002050FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = LCDC_INT,
+               .end    = LCDC_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device imxfb_device = {
+       .name           = "imx-fb",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(imxfb_resources),
+       .resource       = imxfb_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &imx_mmc_device,
+       &imxfb_device,
+       &imx_uart1_device,
+       &imx_uart2_device,
+};
+
+static struct map_desc imx_io_desc[] __initdata = {
+       /* virtual     physical    length      type */
+       {IMX_IO_BASE, IMX_IO_PHYS, IMX_IO_SIZE, MT_DEVICE},
+};
+
+void __init
+imx_map_io(void)
+{
+       iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
+}
+
+static int __init imx_init(void)
+{
+       return platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+subsys_initcall(imx_init);
diff --git a/arch/arm/mach-imx/generic.h b/arch/arm/mach-imx/generic.h
new file mode 100644 (file)
index 0000000..31e1911
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ *  linux/arch/arm/mach-imx/generic.h
+ *
+ * Author:     Sascha Hauer <sascha@saschahauer.de>
+ * Copyright:  Synertronixx GmbH
+ *
+ * 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.
+ */
+
+extern void __init imx_map_io(void);
+extern void __init imx_init_irq(void);
+extern void __init imx_init_time(void);
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
new file mode 100644 (file)
index 0000000..0c27134
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ *  linux/arch/arm/mach-imx/irq.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  03/03/2004   Sascha Hauer <sascha@saschahauer.de>
+ *               Copied from the motorola bsp package and added gpio demux
+ *               interrupt handler
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+/*
+ *
+ * We simply use the ENABLE DISABLE registers inside of the IMX
+ * to turn on/off specific interrupts.  FIXME- We should
+ * also add support for the accelerated interrupt controller
+ * by putting offets to irq jump code in the appropriate
+ * places.
+ *
+ */
+
+#define INTENNUM_OFF              0x8
+#define INTDISNUM_OFF             0xC
+
+#define VA_AITC_BASE              IO_ADDRESS(IMX_AITC_BASE)
+#define IMX_AITC_INTDISNUM       (VA_AITC_BASE + INTDISNUM_OFF)
+#define IMX_AITC_INTENNUM        (VA_AITC_BASE + INTENNUM_OFF)
+
+#if 0
+#define DEBUG_IRQ(fmt...)      printk(fmt)
+#else
+#define DEBUG_IRQ(fmt...)      do { } while (0)
+#endif
+
+static void
+imx_mask_irq(unsigned int irq)
+{
+       __raw_writel(irq, IMX_AITC_INTDISNUM);
+}
+
+static void
+imx_unmask_irq(unsigned int irq)
+{
+       __raw_writel(irq, IMX_AITC_INTENNUM);
+}
+
+static int
+imx_gpio_irq_type(unsigned int _irq, unsigned int type)
+{
+       unsigned int irq_type = 0, irq, reg, bit;
+
+       irq = _irq - IRQ_GPIOA(0);
+       reg = irq >> 5;
+       bit = 1 << (irq % 32);
+
+       if (type == IRQT_PROBE) {
+               /* Don't mess with enabled GPIOs using preconfigured edges or
+                  GPIOs set to alternate function during probe */
+               /* TODO: support probe */
+//              if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
+//                  GPIO_bit(gpio))
+//                      return 0;
+//              if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
+//                      return 0;
+//              type = __IRQT_RISEDGE | __IRQT_FALEDGE;
+       }
+
+       GIUS(reg) |= bit;
+       DDIR(reg) &= ~(bit);
+
+       DEBUG_IRQ("setting type of irq %d to ", _irq);
+
+       if (type & __IRQT_RISEDGE) {
+               DEBUG_IRQ("rising edges\n");
+               irq_type = 0x0;
+       }
+       if (type & __IRQT_FALEDGE) {
+               DEBUG_IRQ("falling edges\n");
+               irq_type = 0x1;
+       }
+       if (type & __IRQT_LOWLVL) {
+               DEBUG_IRQ("low level\n");
+               irq_type = 0x3;
+       }
+       if (type & __IRQT_HIGHLVL) {
+               DEBUG_IRQ("high level\n");
+               irq_type = 0x2;
+       }
+
+       if (irq % 32 < 16) {
+               ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
+                   (irq_type << ((irq % 16) * 2));
+       } else {
+               ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
+                   (irq_type << ((irq % 16) * 2));
+       }
+
+       return 0;
+
+}
+
+static void
+imx_gpio_ack_irq(unsigned int irq)
+{
+       DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
+       ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
+}
+
+static void
+imx_gpio_mask_irq(unsigned int irq)
+{
+       DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
+       IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
+}
+
+static void
+imx_gpio_unmask_irq(unsigned int irq)
+{
+       DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
+       IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
+}
+
+static void
+imx_gpio_handler(unsigned int mask, unsigned int irq,
+                 struct irqdesc *desc, struct pt_regs *regs)
+{
+       desc = irq_desc + irq;
+       while (mask) {
+               if (mask & 1) {
+                       DEBUG_IRQ("handling irq %d\n", irq);
+                       desc->handle(irq, desc, regs);
+               }
+               irq++;
+               desc++;
+               mask >>= 1;
+       }
+}
+
+static void
+imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = ISR(0);
+       irq = IRQ_GPIOA(0);
+       imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = ISR(1);
+       irq = IRQ_GPIOB(0);
+       imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = ISR(2);
+       irq = IRQ_GPIOC(0);
+       imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static void
+imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
+                       struct pt_regs *regs)
+{
+       unsigned int mask, irq;
+
+       mask = ISR(3);
+       irq = IRQ_GPIOD(0);
+       imx_gpio_handler(mask, irq, desc, regs);
+}
+
+static struct irqchip imx_internal_chip = {
+       .ack = imx_mask_irq,
+       .mask = imx_mask_irq,
+       .unmask = imx_unmask_irq,
+};
+
+static struct irqchip imx_gpio_chip = {
+       .ack = imx_gpio_ack_irq,
+       .mask = imx_gpio_mask_irq,
+       .unmask = imx_gpio_unmask_irq,
+       .type = imx_gpio_irq_type,
+};
+
+void __init
+imx_init_irq(void)
+{
+       unsigned int irq;
+
+       DEBUG_IRQ("Initializing imx interrupts\n");
+
+       /* Mask all interrupts initially */
+       IMR(0) = 0;
+       IMR(1) = 0;
+       IMR(2) = 0;
+       IMR(3) = 0;
+
+       for (irq = 0; irq < IMX_IRQS; irq++) {
+               set_irq_chip(irq, &imx_internal_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
+               set_irq_chip(irq, &imx_gpio_chip);
+               set_irq_handler(irq, do_edge_IRQ);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
+       set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
+       set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
+       set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
+
+       /* Disable all interrupts initially. */
+       /* In IMX this is done in the bootloader. */
+}
diff --git a/arch/arm/mach-imx/leds-mx1ads.c b/arch/arm/mach-imx/leds-mx1ads.c
new file mode 100644 (file)
index 0000000..e6399b0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * linux/arch/arm/mach-imx/leds-mx1ads.c
+ *
+ * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * Original (leds-footbridge.c) by Russell King
+ *
+ * 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/init.h>
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include "leds.h"
+
+/*
+ * The MX1ADS Board has only one usable LED,
+ * so select only the timer led or the
+ * cpu usage led
+ */
+void
+mx1ads_leds_event(led_event_t ledevt)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       switch (ledevt) {
+#ifdef CONFIG_LEDS_CPU
+       case led_idle_start:
+               DR(0) &= ~(1<<2);
+               break;
+
+       case led_idle_end:
+               DR(0) |= 1<<2;
+               break;
+#endif
+
+#ifdef CONFIG_LEDS_TIMER
+       case led_timer:
+               DR(0) ^= 1<<2;
+#endif
+       default:
+               break;
+       }
+       local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
new file mode 100644 (file)
index 0000000..471c1db
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/arm/mach-imx/leds.h
+ *
+ * Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+
+#include "leds.h"
+
+static int __init
+leds_init(void)
+{
+       if (machine_is_mx1ads()) {
+               leds_event = mx1ads_leds_event;
+       }
+
+       return 0;
+}
+
+__initcall(leds_init);
diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
new file mode 100644 (file)
index 0000000..83fa21e
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * include/asm-arm/arch-imx/leds.h
+ *
+ * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * blinky lights for IMX-based systems
+ *
+ */
+extern void mx1ads_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
new file mode 100644 (file)
index 0000000..bd92b90
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-imx/mx1ads.c
+ *
+ * Initially based on:
+ *     linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
+ *     Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * 2004 (c) MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <linux/interrupt.h>
+#include "generic.h"
+#include <asm/serial.h>
+
+static struct resource mx1ads_resources[] = {
+       [0] = {
+               .start  = IMX_CS4_VIRT,
+               .end    = IMX_CS4_VIRT + 16,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 13,
+               .end    = 13,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mx1ads_device = {
+       .name           = "mx1ads",
+       .num_resources  = ARRAY_SIZE(mx1ads_resources),
+       .resource       = mx1ads_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &mx1ads_device,
+};
+
+static void __init
+mx1ads_init(void)
+{
+#ifdef CONFIG_LEDS
+       imx_gpio_mode(GPIO_PORTA | GPIO_OUT | GPIO_GPIO | 2);
+#endif
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static struct map_desc mx1ads_io_desc[] __initdata = {
+       /* virtual     physical    length      type */
+       {IMX_CS0_VIRT, IMX_CS0_PHYS, IMX_CS0_SIZE, MT_DEVICE},
+       {IMX_CS1_VIRT, IMX_CS1_PHYS, IMX_CS1_SIZE, MT_DEVICE},
+       {IMX_CS2_VIRT, IMX_CS2_PHYS, IMX_CS2_SIZE, MT_DEVICE},
+       {IMX_CS3_VIRT, IMX_CS3_PHYS, IMX_CS3_SIZE, MT_DEVICE},
+       {IMX_CS4_VIRT, IMX_CS4_PHYS, IMX_CS4_SIZE, MT_DEVICE},
+       {IMX_CS5_VIRT, IMX_CS5_PHYS, IMX_CS5_SIZE, MT_DEVICE},
+};
+
+static void __init
+mx1ads_map_io(void)
+{
+       imx_map_io();
+       iotable_init(mx1ads_io_desc, ARRAY_SIZE(mx1ads_io_desc));
+}
+
+MACHINE_START(MX1ADS, "Motorola MX1ADS")
+       MAINTAINER("Sascha Hauer, Pengutronix")
+       BOOT_MEM(0x08000000, 0x00200000, 0xe0200000)
+       BOOT_PARAMS(0x08000100)
+       MAPIO(mx1ads_map_io)
+       INITIRQ(imx_init_irq)
+       INITTIME(imx_init_time)
+       INIT_MACHINE(mx1ads_init)
+MACHINE_END
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
new file mode 100644 (file)
index 0000000..ac7cab9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  linux/arch/arm/mach-imx/time.c
+ *
+ *  Copyright (C) 2000-2001 Deep Blue Solutions
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/time.h>
+
+/* Use timer 1 as system timer */
+#define TIMER_BASE IMX_TIM1_BASE
+
+/*
+ * Returns number of us since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long
+imx_gettimeoffset(void)
+{
+       unsigned long ticks;
+
+       /*
+        * Get the current number of ticks.  Note that there is a race
+        * condition between us reading the timer and checking for
+        * an interrupt.  We get around this by ensuring that the
+        * counter has not reloaded between our two reads.
+        */
+       ticks = IMX_TCN(TIMER_BASE);
+
+       /*
+        * Interrupt pending?  If so, we've reloaded once already.
+        */
+       if (IMX_TSTAT(TIMER_BASE) & TSTAT_COMP)
+               ticks += LATCH;
+
+       /*
+        * Convert the ticks to usecs
+        */
+       return (1000000 / CLK32) * ticks;
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t
+imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       /* clear the interrupt */
+       if (IMX_TSTAT(TIMER_BASE))
+               IMX_TSTAT(TIMER_BASE) = 0;
+
+       timer_tick(regs);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction imx_timer_irq = {
+       .name           = "i.MX Timer Tick",
+       .flags          = SA_INTERRUPT,
+       .handler        = imx_timer_interrupt
+};
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+void __init
+imx_init_time(void)
+{
+       /*
+        * Initialise to a known state (all timers off, and timing reset)
+        */
+       IMX_TCTL(TIMER_BASE) = 0;
+       IMX_TPRER(TIMER_BASE) = 0;
+       IMX_TCMP(TIMER_BASE) = LATCH - 1;
+       IMX_TCTL(TIMER_BASE) = TCTL_CLK_32 | TCTL_IRQEN | TCTL_TEN;
+
+       /*
+        * Make irqs happen for the system timer
+        */
+       setup_irq(TIM1_INT, &imx_timer_irq);
+       gettimeoffset = imx_gettimeoffset;
+}
diff --git a/arch/arm/mach-integrator/Makefile.boot b/arch/arm/mach-integrator/Makefile.boot
new file mode 100644 (file)
index 0000000..c7e75ac
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+initrd_phys-y  := 0x00800000
+
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
new file mode 100644 (file)
index 0000000..609c49d
--- /dev/null
@@ -0,0 +1,2 @@
+extern void integrator_time_init(unsigned long, unsigned int);
+extern unsigned long integrator_gettimeoffset(void);
diff --git a/arch/arm/mach-iop3xx/Makefile.boot b/arch/arm/mach-iop3xx/Makefile.boot
new file mode 100644 (file)
index 0000000..6387aa2
--- /dev/null
@@ -0,0 +1,9 @@
+   zreladdr-y  := 0xa0008000
+params_phys-y  := 0xa0000100
+initrd_phys-y  := 0xa0800000
+ifeq ($(CONFIG_ARCH_IOP331),y)
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+initrd_phys-y  := 0x00800000
+endif
+
diff --git a/arch/arm/mach-iop3xx/common.c b/arch/arm/mach-iop3xx/common.c
new file mode 100644 (file)
index 0000000..c0bbe5a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * arch/arm/mach-iop3xx/common.c
+ *
+ * Common routines shared across all IOP3xx implementations
+ *
+ * Author: Deepak Saxena <dsaxena@mvista.com>
+ *
+ * Copyright 2003 (c) MontaVista, Software, Inc.
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <asm/hardware.h>
+
+/*
+ * Shared variables
+ */
+unsigned long iop3xx_pcibios_min_io = 0;
+unsigned long iop3xx_pcibios_min_mem = 0;
+
+#ifdef CONFIG_ARCH_EP80219
+#include <linux/kernel.h>
+/*
+ * Default power-off for EP80219
+ */
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+static inline void ep80219_send_to_pic(__u8 c) {
+}
+
+void ep80219_power_off(void)
+{
+       /*
+     * This function will send a SHUTDOWN_COMPLETE message to the PIC controller
+     * over I2C.  We are not using the i2c subsystem since we are going to power
+     * off and it may be removed
+     */
+
+       /* Send the Address byte w/ the start condition */
+       *IOP321_IDBR1 = 0x60;
+       *IOP321_ICR1 = 0xE9;
+    mdelay(1);
+
+       /* Send the START_MSG byte w/ no start or stop condition */
+       *IOP321_IDBR1 = 0x0F;
+       *IOP321_ICR1 = 0xE8;
+    mdelay(1);
+
+       /* Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or stop condition */
+       *IOP321_IDBR1 = 0x03;
+       *IOP321_ICR1 = 0xE8;
+    mdelay(1);
+
+       /* Send an ignored byte w/ stop condition */
+       *IOP321_IDBR1 = 0x00;
+       *IOP321_ICR1 = 0xEA;
+
+       while (1) ;
+}
+
+#include <linux/init.h>
+#include <linux/pm.h>
+
+static int __init ep80219_init(void)
+{
+       pm_power_off = ep80219_power_off;
+       return 0;
+}
+arch_initcall(ep80219_init);
+#endif
diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
new file mode 100644 (file)
index 0000000..e92f77f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * linux/arch/arm/mach-iop3xx/iop321-setup.c
+ *
+ * Author: Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#ifdef CONFIG_ARCH_IQ80321
+extern void iq80321_map_io(void);
+extern void iop321_init_irq(void);
+extern void iop321_init_time(void);
+#endif
+
+#ifdef CONFIG_ARCH_IQ31244
+extern void iq31244_map_io(void);
+extern void iop321_init_irq(void);
+extern void iop321_init_time(void);
+#endif
+
+static void __init
+fixup_iop321(struct machine_desc *desc, struct tag *tags,
+             char **cmdline, struct meminfo *mi)
+{
+}
+
+#if defined(CONFIG_ARCH_IQ80321)
+MACHINE_START(IQ80321, "Intel IQ80321")
+       MAINTAINER("Intel Corporation")
+       BOOT_MEM(PHYS_OFFSET, IQ80321_UART, 0xfe800000)
+       FIXUP(fixup_iop321)
+       MAPIO(iq80321_map_io)
+       INITIRQ(iop321_init_irq)
+       INITTIME(iop321_init_time)
+    BOOT_PARAMS(0xa0000100)
+MACHINE_END
+#elif defined(CONFIG_ARCH_IQ31244)
+    MACHINE_START(IQ31244, "Intel IQ31244")
+    MAINTAINER("Intel Corp.")
+    BOOT_MEM(PHYS_OFFSET, IQ31244_UART, IQ31244_UART)
+    MAPIO(iq31244_map_io)
+    INITIRQ(iop321_init_irq)
+       INITTIME(iop321_init_time)
+    BOOT_PARAMS(0xa0000100)
+MACHINE_END
+#else
+#error No machine descriptor defined for this IOP3XX implementation
+#endif
diff --git a/arch/arm/mach-iop3xx/iop331-irq.c b/arch/arm/mach-iop3xx/iop331-irq.c
new file mode 100644 (file)
index 0000000..f4d4321
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * linux/arch/arm/mach-iop3xx/iop331-irq.c
+ *
+ * Generic IOP331 IRQ handling functionality
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ * Copyright (C) 2003 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+
+#include <asm/mach-types.h>
+
+static u32 iop331_mask0 = 0;
+static u32 iop331_mask1 = 0;
+
+static inline void intctl_write0(u32 val)
+{
+    // INTCTL0
+       asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
+}
+
+static inline void intctl_write1(u32 val)
+{
+    // INTCTL1
+    asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val));
+}
+
+static inline void intstr_write0(u32 val)
+{
+    // INTSTR0
+       asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val));
+}
+
+static inline void intstr_write1(u32 val)
+{
+    // INTSTR1
+       asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val));
+}
+
+static void
+iop331_irq_mask1 (unsigned int irq)
+{
+        iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS));
+        intctl_write0(iop331_mask0);
+}
+
+static void
+iop331_irq_mask2 (unsigned int irq)
+{
+        iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32));
+        intctl_write1(iop331_mask1);
+}
+
+static void
+iop331_irq_unmask1(unsigned int irq)
+{
+        iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS));
+        intctl_write0(iop331_mask0);
+}
+
+static void
+iop331_irq_unmask2(unsigned int irq)
+{
+        iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32));
+        intctl_write1(iop331_mask1);
+}
+
+struct irqchip iop331_irqchip1 = {
+       .ack    = iop331_irq_mask1,
+       .mask   = iop331_irq_mask1,
+       .unmask = iop331_irq_unmask1,
+};
+
+struct irqchip iop331_irqchip2 = {
+       .ack    = iop331_irq_mask2,
+       .mask   = iop331_irq_mask2,
+       .unmask = iop331_irq_unmask2,
+};
+
+void __init iop331_init_irq(void)
+{
+       unsigned int i, tmp;
+
+       /* Enable access to coprocessor 6 for dealing with IRQs.
+        * From RMK:
+        * Basically, the Intel documentation here is poor.  It appears that
+        * you need to set the bit to be able to access the coprocessor from
+        * SVC mode.  Whether that allows access from user space or not is
+        * unclear.
+        */
+       asm volatile (
+               "mrc p15, 0, %0, c15, c1, 0\n\t"
+               "orr %0, %0, %1\n\t"
+               "mcr p15, 0, %0, c15, c1, 0\n\t"
+               /* The action is delayed, so we have to do this: */
+               "mrc p15, 0, %0, c15, c1, 0\n\t"
+               "mov %0, %0\n\t"
+               "sub pc, pc, #4"
+               : "=r" (tmp) : "i" (1 << 6) );
+
+       intctl_write0(0);               // disable all interrupts
+       intctl_write1(0);
+       intstr_write0(0);               // treat all as IRQ
+       intstr_write1(0);
+       if(machine_is_iq80331())        // all interrupts are inputs to chip
+               *IOP331_PCIIRSR = 0x0f;
+
+       for(i = IOP331_IRQ_OFS; i < NR_IOP331_IRQS; i++)
+       {
+               set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2);
+               set_irq_handler(i, do_level_IRQ);
+               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+       }
+}
+
diff --git a/arch/arm/mach-iop3xx/iop331-pci.c b/arch/arm/mach-iop3xx/iop331-pci.c
new file mode 100644 (file)
index 0000000..f6118dd
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * arch/arm/mach-iop3xx/iop331-pci.c
+ *
+ * PCI support for the Intel IOP331 chipset
+ *
+ * Author: Dave Jiang (dave.jiang@intel.com)
+ * Copyright (C) 2003 Intel Corp.
+ *
+ * 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/pci.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach/pci.h>
+
+#include <asm/arch/iop331.h>
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define  DBG(x...) printk(x)
+#else
+#define  DBG(x...) do { } while (0)
+#endif
+
+/*
+ * This routine builds either a type0 or type1 configuration command.  If the
+ * bus is on the 80331 then a type0 made, else a type1 is created.
+ */
+static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where)
+{
+       struct pci_sys_data *sys = bus->sysdata;
+       u32 addr;
+
+       if (sys->busnr == bus->number)
+               addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
+       else
+               addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
+
+       addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
+
+       return addr;
+}
+
+/*
+ * This routine checks the status of the last configuration cycle.  If an error
+ * was detected it returns a 1, else it returns a 0.  The errors being checked
+ * are parity, master abort, target abort (master and target).  These types of
+ * errors occure during a config cycle where there is no device, like during
+ * the discovery stage.
+ */
+static int iop331_pci_status(void)
+{
+       unsigned int status;
+       int ret = 0;
+
+       /*
+        * Check the status registers.
+        */
+       status = *IOP331_ATUSR;
+       if (status & 0xf900)
+       {
+               DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
+               *IOP331_ATUSR = status & 0xf900;
+               ret = 1;
+       }
+       status = *IOP331_ATUISR;
+       if (status & 0x679f)
+       {
+               DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
+               *IOP331_ATUISR = status & 0x679f;
+               ret = 1;
+       }
+       return ret;
+}
+
+/*
+ * Simply write the address register and read the configuration
+ * data.  Note that the 4 nop's ensure that we are able to handle
+ * a delayed abort (in theory.)
+ */
+static inline u32 iop331_read(unsigned long addr)
+{
+       u32 val;
+
+       __asm__ __volatile__(
+               "str    %1, [%2]\n\t"
+               "ldr    %0, [%3]\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               : "=r" (val)
+               : "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
+
+       return val;
+}
+
+/*
+ * The read routines must check the error status of the last configuration
+ * cycle.  If there was an error, the routine returns all hex f's.
+ */
+static int
+iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+               int size, u32 *value)
+{
+       unsigned long addr = iop331_cfg_address(bus, devfn, where);
+       u32 val = iop331_read(addr) >> ((where & 3) * 8);
+
+       if( iop331_pci_status() )
+               val = 0xffffffff;
+
+       *value = val;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+               int size, u32 value)
+{
+       unsigned long addr = iop331_cfg_address(bus, devfn, where);
+       u32 val;
+
+       if (size != 4) {
+               val = iop331_read(addr);
+               if (!iop331_pci_status() == 0)
+                       return PCIBIOS_SUCCESSFUL;
+
+               where = (where & 3) * 8;
+
+               if (size == 1)
+                       val &= ~(0xff << where);
+               else
+                       val &= ~(0xffff << where);
+
+               *IOP331_OCCDR = val | value << where;
+       } else {
+               asm volatile(
+                       "str    %1, [%2]\n\t"
+                       "str    %0, [%3]\n\t"
+                       "nop\n\t"
+                       "nop\n\t"
+                       "nop\n\t"
+                       "nop\n\t"
+                       :
+                       : "r" (value), "r" (addr),
+                         "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops iop331_ops = {
+       .read   = iop331_read_config,
+       .write  = iop331_write_config,
+};
+
+/*
+ * When a PCI device does not exist during config cycles, the XScale gets a
+ * bus error instead of returning 0xffffffff. This handler simply returns.
+ */
+int
+iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+       DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
+               addr, fsr, regs->ARM_pc, regs->ARM_lr);
+
+       /*
+        * If it was an imprecise abort, then we need to correct the
+        * return address to be _after_ the instruction.
+        */
+       if (fsr & (1 << 10))
+               regs->ARM_pc += 4;
+
+       return 0;
+}
+
+/*
+ * Scan an IOP331 PCI bus.  sys->bus defines which bus we scan.
+ */
+struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys)
+{
+       return pci_scan_bus(sys->busnr, &iop331_ops, sys);
+}
+
+void iop331_init(void)
+{
+       DBG("PCI:  Intel 80331 PCI init code.\n");
+       DBG("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD);
+       DBG("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n",
+                       *IOP331_OMWTVR0,
+                       *IOP331_OIOWTVR);
+       DBG("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR);
+       DBG("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0);
+       DBG("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR);
+       DBG("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2);
+       DBG("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3);
+
+       /* redboot changed, reset IABAR0 to something sane */
+       /* fixes master aborts in plugged in cards */
+       /* will clean up later and work nicely with redboot */
+       *IOP331_IABAR0 = 0x00000004;
+       hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort");
+}
+
diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c
new file mode 100644 (file)
index 0000000..681e1ce
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/mach-iop3xx/iop331-setup.c
+ *
+ * Author: Dave Jiang (dave.jiang@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.
+ *
+ */
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#define IOP331_UART_XTAL 33334000
+
+/*
+ * Standard IO mapping for all IOP331 based systems
+ */
+static struct map_desc iop331_std_desc[] __initdata = {
+ /* virtual     physical      length      type */
+
+ /* mem mapped registers */
+ { IOP331_VIRT_MEM_BASE,  IOP331_PHYS_MEM_BASE,   0x00002000,  MT_DEVICE },
+
+ /* PCI IO space */
+ { 0xfe000000,  0x90000000,   0x00020000,  MT_DEVICE }
+};
+
+static struct uart_port iop331_serial_ports[] = {
+       {
+               .membase        = (char*)(IQ80331_UART0_VIRT),
+               .mapbase        = (IQ80331_UART0_PHYS),
+               .irq            = IRQ_IOP331_UART0,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = IOP331_UART_XTAL,
+               .line           = 0,
+               .type           = PORT_XSCALE,
+               .fifosize       = 32
+       } , {
+               .membase        = (char*)(IQ80331_UART1_VIRT),
+               .mapbase        = (IQ80331_UART1_PHYS),
+               .irq            = IRQ_IOP331_UART1,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = IOP331_UART_XTAL,
+               .line           = 1,
+               .type           = PORT_XSCALE,
+               .fifosize       = 32
+       }
+};
+
+void __init iop331_map_io(void)
+{
+       iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc));
+       early_serial_setup(&iop331_serial_ports[0]);
+       early_serial_setup(&iop331_serial_ports[1]);
+}
+
+#ifdef CONFIG_ARCH_IQ80331
+extern void iop331_init_irq(void);
+extern void iop331_init_time(void);
+extern void iq80331_map_io(void);
+#endif
+
+#if defined(CONFIG_ARCH_IQ80331)
+MACHINE_START(IQ80331, "Intel IQ80331")
+    MAINTAINER("Intel Corp.")
+    BOOT_MEM(PHYS_OFFSET, 0xfefff000, 0xfffff000) // virtual, physical
+    //BOOT_MEM(PHYS_OFFSET, IQ80331_UART0_VIRT, IQ80331_UART0_PHYS)
+    MAPIO(iq80331_map_io)
+    INITIRQ(iop331_init_irq)
+    INITTIME(iop331_init_time)
+    BOOT_PARAMS(0x0100)
+MACHINE_END
+#else
+#error No machine descriptor defined for this IOP3XX implementation
+#endif
+
+
diff --git a/arch/arm/mach-iop3xx/iop331-time.c b/arch/arm/mach-iop3xx/iop331-time.c
new file mode 100644 (file)
index 0000000..c90a0c9
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * arch/arm/mach-iop3xx/iop331-time.c
+ *
+ * Timer code for IOP331 based systems
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ *
+ * Copyright 2003 Intel 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 <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#undef IOP331_TIME_SYNC
+
+static unsigned long iop331_latch;
+
+static inline unsigned long get_elapsed(void)
+{
+       return iop331_latch - *IOP331_TU_TCR0;
+}
+
+static unsigned long iop331_gettimeoffset(void)
+{
+       unsigned long elapsed, usec;
+       u32 tisr1, tisr2;
+
+       /*
+        * If an interrupt was pending before we read the timer,
+        * we've already wrapped.  Factor this into the time.
+        * If an interrupt was pending after we read the timer,
+        * it may have wrapped between checking the interrupt
+        * status and reading the timer.  Re-read the timer to
+        * be sure its value is after the wrap.
+        */
+
+       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
+       elapsed = get_elapsed();
+       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
+
+       if(tisr1 & 1)
+               elapsed += iop331_latch;
+       else if (tisr2 & 1)
+               elapsed = iop331_latch + get_elapsed();
+
+       /*
+        * Now convert them to usec.
+        */
+       usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / iop331_latch;
+
+       return usec;
+}
+
+static irqreturn_t
+iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       u32 tisr;
+#ifdef IOP331_TIME_SYNC
+       u32 passed;
+#define TM_THRESH (iop331_latch*2)
+#endif
+
+       asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
+
+       tisr |= 1;
+
+       asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
+
+#ifdef IOP331_TIME_SYNC
+       passed = 0xffffffff - *IOP331_TU_TCR1;
+
+       do
+       {
+               do_timer(regs);
+               if(passed < TM_THRESH)
+                       break;
+               if(passed > iop331_latch)
+                       passed -= iop331_latch;
+               else
+                       passed = 0;
+       } while(1);
+
+       asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff));
+#else
+       do_timer(regs);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction iop331_timer_irq = {
+       .name           = "IOP331 Timer Tick",
+       .handler        = iop331_timer_interrupt,
+       .flags          = SA_INTERRUPT
+};
+
+extern int setup_arm_irq(int, struct irqaction*);
+
+void __init iop331_init_time(void)
+{
+       u32 timer_ctl;
+
+       iop331_latch = (CLOCK_TICK_RATE + HZ / 2) / HZ;
+       gettimeoffset = iop331_gettimeoffset;
+       setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq);
+
+       timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD |
+                       IOP331_TMR_RATIO_1_1;
+
+       asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (iop331_latch));
+
+       asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
+
+#ifdef IOP331_TIME_SYNC
+        /* Setup second timer */
+        /* setup counter */
+        timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED |
+                        IOP331_TMR_RATIO_1_1;
+        asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff));
+        /* setup control */
+        asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl));
+#endif
+}
+
+
diff --git a/arch/arm/mach-iop3xx/iq31244-mm.c b/arch/arm/mach-iop3xx/iq31244-mm.c
new file mode 100644 (file)
index 0000000..b01042f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * linux/arch/arm/mach-iop3xx/mm.c
+ *
+ * Low level memory initialization for iq80321 platform
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ *
+ * This 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/mm.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+
+/*
+ * IQ80321 specific IO mappings
+ *
+ * We use RedBoot's setup for the onboard devices.
+ */
+static struct map_desc iq31244_io_desc[] __initdata = {
+ /* virtual     physical      length        type */
+
+ /* on-board devices */
+ { IQ31244_UART, IQ31244_UART,   0x00100000,   MT_DEVICE }
+};
+
+void __init iq31244_map_io(void)
+{
+       iop321_map_io();
+
+       iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc));
+}
diff --git a/arch/arm/mach-iop3xx/iq31244-pci.c b/arch/arm/mach-iop3xx/iq31244-pci.c
new file mode 100644 (file)
index 0000000..5eac93e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * arch/arm/mach-iop3xx/iq80321-pci.c
+ *
+ * PCI support for the Intel IQ80321 reference board
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ *
+ * 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/pci.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/pci.h>
+#include <asm/mach-types.h>
+
+/*
+ * The following macro is used to lookup irqs in a standard table
+ * format for those systems that do not already have PCI
+ * interrupts properly routed.  We assume 1 <= pin <= 4
+ */
+#define PCI_IRQ_TABLE_LOOKUP(minid,maxid)      \
+({ int _ctl_ = -1;                             \
+   unsigned int _idsel = idsel - minid;                \
+   if (_idsel <= maxid)                                \
+      _ctl_ = pci_irq_table[_idsel][pin-1];    \
+   _ctl_; })
+
+#define INTA   IRQ_IQ31244_INTA
+#define INTB   IRQ_IQ31244_INTB
+#define INTC   IRQ_IQ31244_INTC
+#define INTD   IRQ_IQ31244_INTD
+
+#define INTE   IRQ_IQ31244_I82546
+
+static inline int __init
+iq31244_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+{
+       static int pci_irq_table[][4] = {
+               /*
+                * PCI IDSEL/INTPIN->INTLINE
+                * A       B       C       D
+                */
+#ifdef CONFIG_ARCH_EP80219
+               {INTB, INTB, INTB, INTB}, /* CFlash */
+               {INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */
+               {INTD, INTD, INTD, INTD}, /* PCI-X Slot */
+               {INTC, INTC, INTC, INTC}, /* SATA   */
+#else
+               {INTB, INTB, INTB, INTB}, /* CFlash */
+               {INTC, INTC, INTC, INTC}, /* SATA   */
+               {INTD, INTD, INTD, INTD}, /* PCI-X Slot */
+               {INTE, INTE, INTE, INTE}, /* 82546 GigE */
+#endif // CONFIG_ARCH_EP80219
+       };
+
+       BUG_ON(pin < 1 || pin > 4);
+
+       return PCI_IRQ_TABLE_LOOKUP(0, 7);
+}
+
+static int iq31244_setup(int nr, struct pci_sys_data *sys)
+{
+       struct resource *res;
+
+       if(nr != 0)
+               return 0;
+
+       res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+       if (!res)
+               panic("PCI: unable to alloc resources");
+
+       memset(res, 0, sizeof(struct resource) * 2);
+
+       res[0].start = IQ31244_PCI_IO_BASE + 0x6e000000;
+       res[0].end   = IQ31244_PCI_IO_BASE + IQ31244_PCI_IO_SIZE - 1 + IQ31244_PCI_IO_OFFSET;
+       res[0].name  = "IQ31244 PCI I/O Space";
+       res[0].flags = IORESOURCE_IO;
+
+       res[1].start = IQ31244_PCI_MEM_BASE;
+       res[1].end   = IQ31244_PCI_MEM_BASE + IQ31244_PCI_MEM_SIZE;
+       res[1].name  = "IQ31244 PCI Memory Space";
+       res[1].flags = IORESOURCE_MEM;
+
+       request_resource(&ioport_resource, &res[0]);
+       request_resource(&iomem_resource, &res[1]);
+
+       sys->resource[0] = &res[0];
+       sys->resource[1] = &res[1];
+       sys->resource[2] = NULL;
+       sys->io_offset   = IQ31244_PCI_IO_OFFSET;
+       sys->mem_offset = IQ80321_PCI_MEM_BASE -
+               (*IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK);
+
+       iop3xx_pcibios_min_io = IQ31244_PCI_IO_BASE;
+       iop3xx_pcibios_min_mem = IQ31244_PCI_MEM_BASE;
+
+       return 1;
+}
+
+static void iq31244_preinit(void)
+{
+       iop321_init();
+       /* setting up the second translation window */
+       *IOP321_OMWTVR1 = IQ31244_PCI_MEM_BASE + 0x04000000;
+       *IOP321_OUMWTVR1 = 0x0;
+}
+
+static struct hw_pci iq31244_pci __initdata = {
+       .swizzle        = pci_std_swizzle,
+       .nr_controllers = 1,
+       .setup          = iq31244_setup,
+       .scan           = iop321_scan_bus,
+       .preinit        = iq31244_preinit,
+       .map_irq        = iq31244_map_irq
+};
+
+static int __init iq31244_pci_init(void)
+{
+       if (machine_is_iq31244())
+               pci_common_init(&iq31244_pci);
+       return 0;
+}
+
+subsys_initcall(iq31244_pci_init);
+
+
+
+
diff --git a/arch/arm/mach-iop3xx/iq80321-mm.c b/arch/arm/mach-iop3xx/iq80321-mm.c
new file mode 100644 (file)
index 0000000..1580c7e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * linux/arch/arm/mach-iop3xx/mm.c
+ *
+ * Low level memory initialization for iq80321 platform
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ *
+ * This 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/mm.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+
+/*
+ * IQ80321 specific IO mappings
+ *
+ * We use RedBoot's setup for the onboard devices.
+ */
+static struct map_desc iq80321_io_desc[] __initdata = {
+ /* virtual     physical      length        type */
+
+ /* on-board devices */
+ { IQ80321_UART, IQ80321_UART,   0x00100000,   MT_DEVICE }
+};
+
+void __init iq80321_map_io(void)
+{
+       iop321_map_io();
+
+       iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc));
+}
diff --git a/arch/arm/mach-iop3xx/iq80331-mm.c b/arch/arm/mach-iop3xx/iq80331-mm.c
new file mode 100644 (file)
index 0000000..ee8c333
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/mach-iop3xx/mm.c
+ *
+ * Low level memory initialization for iq80331 platform
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ * Copyright (C) 2003 Intel 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 <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+
+/*
+ * IQ80331 specific IO mappings
+ *
+ * We use RedBoot's setup for the onboard devices.
+ */
+
+void __init iq80331_map_io(void)
+{
+       iop331_map_io();
+}
diff --git a/arch/arm/mach-iop3xx/iq80331-pci.c b/arch/arm/mach-iop3xx/iq80331-pci.c
new file mode 100644 (file)
index 0000000..1eff557
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * arch/arm/mach-iop3xx/iq80331-pci.c
+ *
+ * PCI support for the Intel IQ80331 reference board
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ * Copyright (C) 2003 Intel Corp.
+ *
+ * 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/pci.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/pci.h>
+#include <asm/mach-types.h>
+
+/*
+ * The following macro is used to lookup irqs in a standard table
+ * format for those systems that do not already have PCI
+ * interrupts properly routed.  We assume 1 <= pin <= 4
+ */
+#define PCI_IRQ_TABLE_LOOKUP(minid,maxid)      \
+({ int _ctl_ = -1;                             \
+   unsigned int _idsel = idsel - minid;                \
+   if (_idsel <= maxid)                                \
+      _ctl_ = pci_irq_table[_idsel][pin-1];    \
+   _ctl_; })
+
+#define INTA   IRQ_IQ80331_INTA
+#define INTB   IRQ_IQ80331_INTB
+#define INTC   IRQ_IQ80331_INTC
+#define INTD   IRQ_IQ80331_INTD
+
+//#define INTE IRQ_IQ80331_I82544
+
+static inline int __init
+iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+{
+       static int pci_irq_table[][4] = {
+               /*
+                * PCI IDSEL/INTPIN->INTLINE
+                * A       B       C       D
+                */
+               {INTB, INTC, INTD, INTA}, /* PCI-X Slot */
+               {INTC, INTC, INTC, INTC}, /* GigE  */
+       };
+
+       BUG_ON(pin < 1 || pin > 4);
+
+       return PCI_IRQ_TABLE_LOOKUP(1, 7);
+}
+
+static int iq80331_setup(int nr, struct pci_sys_data *sys)
+{
+       struct resource *res;
+
+       if(nr != 0)
+               return 0;
+
+       res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+       if (!res)
+               panic("PCI: unable to alloc resources");
+
+       memset(res, 0, sizeof(struct resource) * 2);
+
+       res[0].start = IQ80331_PCI_IO_BASE + 0x6e000000;
+       res[0].end   = IQ80331_PCI_IO_BASE + IQ80331_PCI_IO_SIZE - 1 + IQ80331_PCI_IO_OFFSET;
+       res[0].name  = "IQ80331 PCI I/O Space";
+       res[0].flags = IORESOURCE_IO;
+
+       res[1].start = IQ80331_PCI_MEM_BASE;
+       res[1].end   = IQ80331_PCI_MEM_BASE + IQ80331_PCI_MEM_SIZE;
+       res[1].name  = "IQ80331 PCI Memory Space";
+       res[1].flags = IORESOURCE_MEM;
+
+       request_resource(&ioport_resource, &res[0]);
+       request_resource(&iomem_resource, &res[1]);
+
+       /*
+        * Since the IQ80331 is a slave card on a PCI backplane,
+        * it uses BAR1 to reserve a portion of PCI memory space for
+        * use with the private devices on the secondary bus
+        * (GigE and PCI-X slot). We read BAR1 and configure
+        * our outbound translation windows to target that
+        * address range and assign all devices in that
+        * address range. W/O this, certain BIOSes will fail
+        * to boot as the IQ80331 claims addresses that are
+        * in use by other devices.
+        *
+        * Note that the same cannot be done  with I/O space,
+        * so hopefully the host will stick to the lower 64K for
+        * PCI I/O and leave us alone.
+        */
+       sys->mem_offset = IQ80331_PCI_MEM_BASE -
+               (*IOP331_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK);
+
+       sys->resource[0] = &res[0];
+       sys->resource[1] = &res[1];
+       sys->resource[2] = NULL;
+       sys->io_offset   = IQ80331_PCI_IO_OFFSET;
+
+       iop3xx_pcibios_min_io = IQ80331_PCI_IO_BASE;
+       iop3xx_pcibios_min_mem = IQ80331_PCI_MEM_BASE;
+
+       return 1;
+}
+
+static void iq80331_preinit(void)
+{
+       iop331_init();
+}
+
+static struct hw_pci iq80331_pci __initdata = {
+       .swizzle        = pci_std_swizzle,
+       .nr_controllers = 1,
+       .setup          = iq80331_setup,
+       .scan           = iop331_scan_bus,
+       .preinit        = iq80331_preinit,
+       .map_irq        = iq80331_map_irq
+};
+
+static int __init iq80331_pci_init(void)
+{
+       if (machine_is_iq80331())
+               pci_common_init(&iq80331_pci);
+       return 0;
+}
+
+subsys_initcall(iq80331_pci_init);
+
+
+
+
diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig
new file mode 100644 (file)
index 0000000..a22d220
--- /dev/null
@@ -0,0 +1,59 @@
+
+if ARCH_IXP2000
+
+config ARCH_SUPPORTS_BIG_ENDIAN
+       bool
+       default y
+
+menu "Intel IXP2400/2800 Implementation Options"
+
+comment "IXP2400/2800 Platforms"
+
+config ARCH_ENP2611
+       bool "Support Radisys ENP-2611"
+       help
+         Say 'Y' here if you want your kernel to support the Radisys
+         ENP2611 PCI network processing card. For more information on
+         this card, see Documentation/arm/ENP2611.
+
+config ARCH_IXDP2400
+       bool "Support Intel IXDP2400"
+       help
+         Say 'Y' here if you want your kernel to support the Intel
+         IXDP2400 reference platform. For more information on
+         this platform, see Documentation/arm/IXP2000.
+
+config ARCH_IXDP2800
+       bool "Support Intel IXDP2800"
+       help
+         Say 'Y' here if you want your kernel to support the Intel
+         IXDP2800 reference platform. For more information on
+         this platform, see Documentation/arm/IXP2000.
+
+config ARCH_IXDP2X00
+       bool
+       depends on ARCH_IXDP2400 || ARCH_IXDP2800
+       default y       
+
+config ARCH_IXDP2401
+       bool "Support Intel IXDP2401"
+       help
+         Say 'Y' here if you want your kernel to support the Intel
+         IXDP2401 reference platform. For more information on
+         this platform, see Documentation/arm/IXP2000.
+
+config ARCH_IXDP2801
+       bool "Support Intel IXDP2801"
+       help
+         Say 'Y' here if you want your kernel to support the Intel
+         IXDP2801 reference platform. For more information on
+         this platform, see Documentation/arm/IXP2000.
+
+config ARCH_IXDP2X01
+       bool
+       depends on ARCH_IXDP2401 || ARCH_IXDP2801
+       default y       
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile
new file mode 100644 (file)
index 0000000..1e6139d
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux kernel.
+#
+obj-y                  := core.o pci.o
+obj-m                  :=
+obj-n                  :=
+obj-                   :=
+
+obj-$(CONFIG_ARCH_ENP2611)     += enp2611.o
+obj-$(CONFIG_ARCH_IXDP2400)    += ixdp2400.o
+obj-$(CONFIG_ARCH_IXDP2800)    += ixdp2800.o
+obj-$(CONFIG_ARCH_IXDP2X00)    += ixdp2x00.o
+obj-$(CONFIG_ARCH_IXDP2X01)    += ixdp2x01.o
+
diff --git a/arch/arm/mach-ixp2000/Makefile.boot b/arch/arm/mach-ixp2000/Makefile.boot
new file mode 100644 (file)
index 0000000..d84c580
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
new file mode 100644 (file)
index 0000000..2d66337
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * arch/arm/mach-ixp2000/common.c
+ *
+ * Common routines used by all IXP2400/2800 based platforms.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (C) MontaVista Software, Inc. 
+ *
+ * Based on work Copyright (C) 2002-2003 Intel Corporation
+ * 
+ * This file is licensed under  the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/bitops.h>
+#include <linux/serial_core.h>
+#include <linux/mm.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+static spinlock_t ixp2000_slowport_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long ixp2000_slowport_irq_flags;
+
+/*************************************************************************
+ * Slowport access routines
+ *************************************************************************/
+void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
+{
+
+       spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
+
+       old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
+       old_cfg->WTC = *IXP2000_SLOWPORT_WTC2;
+       old_cfg->RTC = *IXP2000_SLOWPORT_RTC2;
+       old_cfg->PCR = *IXP2000_SLOWPORT_PCR;
+       old_cfg->ADC = *IXP2000_SLOWPORT_ADC;
+
+       ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR);
+       ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
+       ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
+       ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
+       ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
+}
+
+void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
+{
+       ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR);
+       ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
+       ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
+       ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
+       ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
+
+       spin_unlock_irqrestore(&ixp2000_slowport_lock, 
+                                       ixp2000_slowport_irq_flags);
+}
+
+/*************************************************************************
+ * Chip specific mappings shared by all IXP2000 systems
+ *************************************************************************/
+static struct map_desc ixp2000_small_io_desc[] __initdata = {
+       {
+               .virtual        = IXP2000_GLOBAL_REG_VIRT_BASE,
+               .physical       = IXP2000_GLOBAL_REG_PHYS_BASE,
+               .length         = IXP2000_GLOBAL_REG_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_GPIO_VIRT_BASE,
+               .physical       = IXP2000_GPIO_PHYS_BASE,
+               .length         = IXP2000_GPIO_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_TIMER_VIRT_BASE,
+               .physical       = IXP2000_TIMER_PHYS_BASE,
+               .length         = IXP2000_TIMER_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_UART_VIRT_BASE,
+               .physical       = IXP2000_UART_PHYS_BASE,
+               .length         = IXP2000_UART_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_SLOWPORT_CSR_VIRT_BASE,
+               .physical       = IXP2000_SLOWPORT_CSR_PHYS_BASE,
+               .length         = IXP2000_SLOWPORT_CSR_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_INTCTL_VIRT_BASE,
+               .physical       = IXP2000_INTCTL_PHYS_BASE,
+               .length         = IXP2000_INTCTL_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_PCI_CREG_VIRT_BASE,
+               .physical       = IXP2000_PCI_CREG_PHYS_BASE,
+               .length         = IXP2000_PCI_CREG_SIZE,
+               .type           = MT_DEVICE
+       }
+};
+
+static struct map_desc ixp2000_large_io_desc[] __initdata = {
+       {
+               .virtual        = IXP2000_PCI_CSR_VIRT_BASE,
+               .physical       = IXP2000_PCI_CSR_PHYS_BASE,
+               .length         = IXP2000_PCI_CSR_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_PCI_IO_VIRT_BASE,
+               .physical       = IXP2000_PCI_IO_PHYS_BASE,
+               .length         = IXP2000_PCI_IO_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_PCI_CFG0_VIRT_BASE,
+               .physical       = IXP2000_PCI_CFG0_PHYS_BASE,
+               .length         = IXP2000_PCI_CFG0_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = IXP2000_PCI_CFG1_VIRT_BASE,
+               .physical       = IXP2000_PCI_CFG1_PHYS_BASE,
+               .length         = IXP2000_PCI_CFG1_SIZE,
+               .type           = MT_DEVICE
+       }
+};
+
+static struct uart_port ixp2000_serial_port = {
+       .membase        = (char *)(IXP2000_UART_VIRT_BASE + 3),
+       .mapbase        = IXP2000_UART_PHYS_BASE + 3,
+       .irq            = IRQ_IXP2000_UART,
+       .flags          = UPF_SKIP_TEST,
+       .iotype         = UPIO_MEM,
+       .regshift       = 2,
+       .uartclk        = 50000000,
+       .line           = 0,
+       .type           = PORT_XSCALE,
+       .fifosize       = 16
+};
+
+void __init ixp2000_map_io(void)
+{
+       iotable_init(ixp2000_small_io_desc, ARRAY_SIZE(ixp2000_small_io_desc));
+       iotable_init(ixp2000_large_io_desc, ARRAY_SIZE(ixp2000_large_io_desc));
+       early_serial_setup(&ixp2000_serial_port);
+}
+
+/*************************************************************************
+ * Timer-tick functions for IXP2000
+ *************************************************************************/
+static unsigned ticks_per_jiffy;
+static unsigned ticks_per_usec;
+
+static unsigned long ixp2000_gettimeoffset (void)
+{
+       unsigned long elapsed;
+
+       /* Get ticks since last perfect jiffy */
+       elapsed = ticks_per_jiffy - *IXP2000_T1_CSR;
+
+       return elapsed / ticks_per_usec;
+}
+
+static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       /* clear timer 1 */
+       ixp2000_reg_write(IXP2000_T1_CLR, 1);
+       
+       timer_tick(regs);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction ixp2000_timer_irq = {
+       .name           = "IXP2000 Timer Tick",
+       .flags          = SA_INTERRUPT,
+       .handler        = ixp2000_timer_interrupt
+};
+
+void __init ixp2000_init_time(unsigned long tick_rate)
+{
+       gettimeoffset = ixp2000_gettimeoffset;
+
+       ixp2000_reg_write(IXP2000_T1_CLR, 0);
+       ixp2000_reg_write(IXP2000_T2_CLR, 0);
+
+       ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
+       ticks_per_usec = tick_rate / 1000000;
+
+       ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy);
+       ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
+
+       /* register for interrupt */
+       setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq);
+}
+
+/*************************************************************************
+ * GPIO helpers
+ *************************************************************************/
+static unsigned long GPIO_IRQ_rising_edge;
+static unsigned long GPIO_IRQ_falling_edge;
+static unsigned long GPIO_IRQ_level_low;
+static unsigned long GPIO_IRQ_level_high;
+
+void gpio_line_config(int line, int style)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       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));
+       }
+               
+       local_irq_restore(flags);
+}      
+
+
+/*************************************************************************
+ * IRQ handling IXP2000
+ *************************************************************************/
+static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{                               
+       int i;
+       unsigned long status = *IXP2000_GPIO_INST;
+                  
+       for (i = 0; i <= 7; i++) {
+               if (status & (1<<i)) {
+                       desc = irq_desc + i + IRQ_IXP2000_GPIO0;
+                       desc->handle(i + IRQ_IXP2000_GPIO0, desc, regs);
+               }
+       }
+}
+
+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_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
+}
+
+static void ixp2000_GPIO_irq_mask(unsigned int irq)
+{
+       ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+}
+
+static void ixp2000_GPIO_irq_unmask(unsigned int irq)
+{
+       ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+}
+
+static struct irqchip ixp2000_GPIO_irq_chip = {
+       .ack    = ixp2000_GPIO_irq_mask_ack,
+       .mask   = ixp2000_GPIO_irq_mask,
+       .unmask = ixp2000_GPIO_irq_unmask
+};
+
+static void ixp2000_pci_irq_mask(unsigned int irq)
+{
+       unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
+       if (irq == IRQ_IXP2000_PCIA)
+               ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
+       else if (irq == IRQ_IXP2000_PCIB)
+               ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
+}
+
+static void ixp2000_pci_irq_unmask(unsigned int irq)
+{
+       unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
+       if (irq == IRQ_IXP2000_PCIA)
+               ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26)));
+       else if (irq == IRQ_IXP2000_PCIB)
+               ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27)));
+}
+
+static struct irqchip ixp2000_pci_irq_chip = {
+       .ack    = ixp2000_pci_irq_mask,
+       .mask   = ixp2000_pci_irq_mask,
+       .unmask = ixp2000_pci_irq_unmask
+};
+
+/*
+ * Error interrupts. These are used extensively by the microengine drivers
+ */
+static void ixp2000_err_irq_handler(unsigned int irq, struct irqdesc *desc,  struct pt_regs *regs)
+{
+       int i;
+       unsigned long status = *IXP2000_IRQ_ERR_STATUS;
+
+
+       for (i = 0; i <= 12; i++) {
+               if (status & (1 << i)) {
+                       desc = irq_desc + IRQ_IXP2000_DRAM0_MIN_ERR + i;
+                       desc->handle(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc, regs);
+               }
+       }
+}
+
+static void ixp2000_err_irq_mask(unsigned int irq)
+{
+       ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_CLR,
+                       (1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
+}
+
+static void ixp2000_err_irq_unmask(unsigned int irq)
+{
+       ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_SET,
+                       (1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
+}
+
+static struct irqchip ixp2000_err_irq_chip = {
+       .ack    = ixp2000_err_irq_mask,
+       .mask   = ixp2000_err_irq_mask,
+       .unmask = ixp2000_err_irq_unmask
+};
+
+static void ixp2000_irq_mask(unsigned int irq)
+{
+       ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq));
+}
+
+static void ixp2000_irq_unmask(unsigned int irq)
+{
+       ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET,  (1 << irq));
+}
+
+static struct irqchip ixp2000_irq_chip = {
+       .ack    = ixp2000_irq_mask,
+       .mask   = ixp2000_irq_mask,
+       .unmask = ixp2000_irq_unmask
+};
+
+void __init ixp2000_init_irq(void)
+{
+       int irq;
+
+       /*
+        * Mask all sources
+        */
+       ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff);
+       ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff);
+
+       /* clear all GPIO edge/level detects */
+       ixp2000_reg_write(IXP2000_GPIO_REDR, 0);
+       ixp2000_reg_write(IXP2000_GPIO_FEDR, 0);
+       ixp2000_reg_write(IXP2000_GPIO_LSHR, 0);
+       ixp2000_reg_write(IXP2000_GPIO_LSLR, 0);
+       ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
+
+       /* clear PCI interrupt sources */
+       ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
+
+       /*
+        * Certain bits in the IRQ status register of the 
+        * IXP2000 are reserved. Instead of trying to map
+        * things non 1:1 from bit position to IRQ number,
+        * we mark the reserved IRQs as invalid. This makes
+        * our mask/unmask code much simpler.
+        */
+       for (irq = IRQ_IXP2000_SWI; irq <= IRQ_IXP2000_THDB3; irq++) {
+               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();
+        */
+       for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
+               set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, 0);
+       }
+       set_irq_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler);
+
+       /*
+        * Enable PCI irq
+        */
+       *(IXP2000_IRQ_ENABLE_SET) = (1 << IRQ_IXP2000_PCI);
+       for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) {
+               set_irq_chip(irq, &ixp2000_pci_irq_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       for (irq = IRQ_IXP2000_DRAM0_MIN_ERR; irq <= IRQ_IXP2000_SP_INT; irq++) {
+               set_irq_chip(irq, &ixp2000_err_irq_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID);
+       }       
+       set_irq_chained_handler(IRQ_IXP2000_ERRSUM, ixp2000_err_irq_handler);
+}
+
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
new file mode 100644 (file)
index 0000000..a6e30d0
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * arch/arm/mach-ixp2000/enp2611.c
+ *
+ * Radisys ENP-2611 support.
+ *
+ * Created 2004 by Lennert Buytenhek from the ixdp2x01 code.  The
+ * original version carries the following notices:
+ *
+ * Original Author: Andrzej Mialwoski <andrzej.mialwoski@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002-2003 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+/*************************************************************************
+ * ENP-2611 timer tick configuration
+ *************************************************************************/
+static void __init enp2611_init_time(void)
+{
+       ixp2000_init_time(50 * 1000 * 1000);
+}
+
+
+/*************************************************************************
+ * ENP-2611 PCI
+ *************************************************************************/
+static int enp2611_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       sys->mem_offset = 0xe0000000;
+       ixp2000_pci_setup(nr, sys);
+       return 1;
+}
+
+static void __init enp2611_pci_preinit(void)
+{
+       ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
+       ixp2000_pci_preinit();
+}
+
+static inline int enp2611_pci_valid_device(struct pci_bus *bus,
+                                               unsigned int devfn)
+{
+       /* The 82559 ethernet controller appears at both PCI:1:0:0 and
+        * PCI:1:2:0, so let's pretend the second one isn't there.
+        */
+       if (bus->number == 0x01 && devfn == 0x10)
+               return 0;
+
+       return 1;
+}
+
+static int enp2611_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                                       int where, int size, u32 *value)
+{
+       if (enp2611_pci_valid_device(bus, devfn))
+               return ixp2000_pci_read_config(bus, devfn, where, size, value);
+
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int enp2611_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+                                       int where, int size, u32 value)
+{
+       if (enp2611_pci_valid_device(bus, devfn))
+               return ixp2000_pci_write_config(bus, devfn, where, size, value);
+
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static struct pci_ops enp2611_pci_ops = {
+       .read   = enp2611_pci_read_config,
+       .write  = enp2611_pci_write_config
+};
+
+static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
+                                               struct pci_sys_data *sys)
+{
+       return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
+}
+
+static int __init enp2611_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int irq;
+
+       if (dev->bus->number == 0x00 && PCI_SLOT(dev->devfn) == 0x01) {
+               /* 21555 non-transparent bridge.  */
+               irq = IRQ_IXP2000_PCIB;
+       } else if (dev->bus->number == 0x01 && PCI_SLOT(dev->devfn) == 0x00) {
+               /* 82559 ethernet.  */
+               irq = IRQ_IXP2000_PCIA;
+       } else {
+               printk(KERN_INFO "enp2611_pci_map_irq for unknown device\n");
+               irq = IRQ_IXP2000_PCI;
+       }
+
+       printk(KERN_INFO "Assigned IRQ %d to PCI:%d:%d:%d\n", irq,
+               dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
+       return irq;
+}
+
+struct hw_pci enp2611_pci __initdata = {
+       .nr_controllers = 1,
+       .setup          = enp2611_pci_setup,
+       .preinit        = enp2611_pci_preinit,
+       .scan           = enp2611_pci_scan_bus,
+       .map_irq        = enp2611_pci_map_irq,
+};
+
+int __init enp2611_pci_init(void)
+{
+       pci_common_init(&enp2611_pci);
+       return 0;
+}
+
+subsys_initcall(enp2611_pci_init);
+
+
+/*************************************************************************
+ * ENP-2611 Machine Intialization
+ *************************************************************************/
+static struct flash_platform_data enp2611_flash_platform_data = {
+       .map_name       = "cfi_probe",
+       .width          = 1,
+};
+
+static struct ixp2000_flash_data enp2611_flash_data = {
+       .platform_data  = &enp2611_flash_platform_data,
+       .nr_banks       = 1
+};
+
+static struct resource enp2611_flash_resource = {
+       .start          = 0xc4000000,
+       .end            = 0xc4000000 + 0x00ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device enp2611_flash = {
+       .name           = "IXP2000-Flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &enp2611_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &enp2611_flash_resource,
+};
+
+static struct platform_device *enp2611_devices[] __initdata = {
+       &enp2611_flash
+};
+
+static void __init enp2611_init_machine(void)
+{
+       platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices));
+}
+
+
+#ifdef CONFIG_ARCH_ENP2611
+MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
+       MAINTAINER("Lennert Buytenhek <buytenh@wantstofly.org>")
+       BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(ixp2000_map_io)
+       INITIRQ(ixp2000_init_irq)
+       INITTIME(enp2611_init_time)
+       INIT_MACHINE(enp2611_init_machine)
+MACHINE_END
+#endif
+
+
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
new file mode 100644 (file)
index 0000000..39ef558
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * arch/arm/mach-ixp2000/ixdp2400.c
+ *
+ * IXDP2400 platform support
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+/*************************************************************************
+ * IXDP2400 timer tick
+ *************************************************************************/
+static void __init ixdp2400_init_time(void)
+{
+       int numerator, denominator;
+       int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8};
+
+       numerator = (*(IXDP2400_CPLD_SYS_CLK_M) & 0xFF) *2;
+       denominator = denom_array[(*(IXDP2400_CPLD_SYS_CLK_N) & 0x7)];
+
+       ixp2000_init_time(((3125000 * numerator) / (denominator)) / 2);
+}
+
+/*************************************************************************
+ * IXDP2400 PCI
+ *************************************************************************/
+void __init ixdp2400_pci_preinit(void)
+{
+       ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
+       ixp2000_pci_preinit();
+}
+
+int ixdp2400_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       sys->mem_offset = 0xe0000000;
+
+       ixp2000_pci_setup(nr, sys);
+
+       return 1;
+}
+
+static int __init ixdp2400_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (ixdp2x00_master_npu()) {
+
+               /*
+                * Root bus devices.  Slave NPU is only one with interrupt.
+                * Everything else, we just return -1 b/c nothing else
+                * on the root bus has interrupts.
+                */
+               if(!dev->bus->self) {
+                       if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
+                               return IRQ_IXDP2400_INGRESS_NPU;
+
+                       return -1;
+               }
+
+               /*
+                * Bridge behind the PMC slot.
+                * NOTE: Only INTA from the PMC slot is routed. VERY BAD.
+                */
+               if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
+                       dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
+                       !dev->bus->parent->self->bus->parent)
+                                 return IRQ_IXDP2400_PMC;
+
+               /*
+                * Device behind the first bridge
+                */
+               if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
+                       switch(dev->devfn) {
+                               case IXDP2400_MASTER_ENET_DEVFN:        
+                                       return IRQ_IXDP2400_ENET;       
+                       
+                               case IXDP2400_MEDIA_DEVFN:
+                                       return IRQ_IXDP2400_MEDIA_PCI;
+
+                               case IXDP2400_SWITCH_FABRIC_DEVFN:
+                                       return IRQ_IXDP2400_SF_PCI;
+
+                               case IXDP2X00_PMC_DEVFN:
+                                       return IRQ_IXDP2400_PMC;
+                       }
+               }
+
+               return -1;
+       } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
+}
+
+
+static void ixdp2400_pci_postinit(void)
+{
+       struct pci_dev *dev;
+
+       if (ixdp2x00_master_npu()) {
+               dev = pci_find_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
+               pci_remove_bus_device(dev);
+       } else {
+               dev = pci_find_slot(1, IXDP2400_MASTER_ENET_DEVFN);
+               pci_remove_bus_device(dev);
+
+               ixdp2x00_slave_pci_postinit();
+       }
+}
+
+static struct hw_pci ixdp2400_pci __initdata = {
+       .nr_controllers = 1,
+       .setup          = ixdp2400_pci_setup,
+       .preinit        = ixdp2400_pci_preinit,
+       .postinit       = ixdp2400_pci_postinit,
+       .scan           = ixp2000_pci_scan_bus,
+       .map_irq        = ixdp2400_pci_map_irq,
+};
+
+int __init ixdp2400_pci_init(void)
+{
+       if (machine_is_ixdp2400())
+               pci_common_init(&ixdp2400_pci);
+
+       return 0;
+}
+
+subsys_initcall(ixdp2400_pci_init);
+
+void ixdp2400_init_irq(void)
+{
+       ixdp2x00_init_irq(IXDP2400_CPLD_INT_STAT, IXDP2400_CPLD_INT_MASK, IXDP2400_NR_IRQS);
+}
+
+MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
+       MAINTAINER("MontaVista Software, Inc.")
+       BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(ixdp2x00_map_io)
+       INITIRQ(ixdp2400_init_irq)
+       INITTIME(ixdp2400_init_time)
+       INIT_MACHINE(ixdp2x00_init_machine)
+MACHINE_END
+
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
new file mode 100644 (file)
index 0000000..285eaf0
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * arch/arm/mach-ixp2000/ixdp2800.c
+ *
+ * IXDP2800 platform support
+ *
+ * Original Author: Jeffrey Daly <jeffrey.daly@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#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
+ *************************************************************************/
+
+static void __init ixdp2800_init_time(void)
+{
+       ixp2000_init_time(50000000);
+}
+
+/*************************************************************************
+ * IXDP2800 PCI
+ *************************************************************************/
+void __init ixdp2800_pci_preinit(void)
+{
+       printk("ixdp2x00_pci_preinit called\n");
+
+       *IXP2000_PCI_ADDR_EXT =  0x0000e000;
+
+       *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
+       *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
+
+       ixp2000_pci_preinit();
+}
+
+int ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       sys->mem_offset = 0x00000000;
+
+       ixp2000_pci_setup(nr, sys);
+
+       return 1;
+}
+
+static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (ixdp2x00_master_npu()) {
+
+               /*
+                * Root bus devices.  Slave NPU is only one with interrupt.
+                * Everything else, we just return -1 which is invalid.
+                */
+               if(!dev->bus->self) {
+                       if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
+                               return IRQ_IXDP2800_INGRESS_NPU;
+
+                       return -1;
+               }
+
+               /*
+                * Bridge behind the PMC slot.
+                */
+               if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
+                       dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
+                       !dev->bus->parent->self->bus->parent)
+                                 return IRQ_IXDP2800_PMC;
+
+               /*
+                * Device behind the first bridge
+                */
+               if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
+                       switch(PCI_SLOT(dev->devfn)) {
+                               case IXDP2X00_PMC_DEVFN:
+                                       return IRQ_IXDP2800_PMC;        
+                       
+                               case IXDP2800_MASTER_ENET_DEVFN:
+                                       return IRQ_IXDP2800_EGRESS_ENET;
+
+                               case IXDP2800_SWITCH_FABRIC_DEVFN:
+                                       return IRQ_IXDP2800_FABRIC;
+                       }
+               }
+
+               return -1;
+       } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
+}
+
+static void ixdp2800_pci_postinit(void)
+{
+       struct pci_dev *dev;
+
+       if (ixdp2x00_master_npu()) {
+               dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
+               pci_remove_bus_device(dev);
+       } else {
+               dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
+               pci_remove_bus_device(dev);
+
+               ixdp2x00_slave_pci_postinit();
+       }
+}
+
+struct hw_pci ixdp2800_pci __initdata = {
+       .nr_controllers = 1,
+       .setup          = ixdp2800_pci_setup,
+       .preinit        = ixdp2800_pci_preinit,
+       .postinit       = ixdp2800_pci_postinit,
+       .scan           = ixp2000_pci_scan_bus,
+       .map_irq        = ixdp2800_pci_map_irq,
+};
+
+int __init ixdp2800_pci_init(void)
+{
+       if (machine_is_ixdp2800())
+               pci_common_init(&ixdp2800_pci);
+
+       return 0;
+}
+
+subsys_initcall(ixdp2800_pci_init);
+
+void ixdp2800_init_irq(void)
+{
+       ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2800_NR_IRQS);
+}
+
+MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
+       MAINTAINER("MontaVista Software, Inc.")
+       BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(ixdp2x00_map_io)
+       INITIRQ(ixdp2800_init_irq)
+       INITTIME(ixdp2800_init_time)
+       INIT_MACHINE(ixdp2x00_init_machine)
+MACHINE_END
+
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
new file mode 100644 (file)
index 0000000..cda60b7
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * arch/arm/mach-ixp2000/ixdp2x00.c
+ *
+ * Code common to IXDP2400 and IXDP2800 platforms.
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+/*************************************************************************
+ * IXDP2x00 IRQ Initialization
+ *************************************************************************/
+static volatile unsigned long *board_irq_mask;
+static volatile unsigned long *board_irq_stat;
+static unsigned long board_irq_count;
+
+#ifdef CONFIG_ARCH_IXDP2400
+/*
+ * Slowport configuration for accessing CPLD registers on IXDP2x00
+ */
+static struct slowport_cfg slowport_cpld_cfg = {
+       .CCR =  SLOWPORT_CCR_DIV_2,
+       .WTC = 0x00000070,
+       .RTC = 0x00000070,
+       .PCR = SLOWPORT_MODE_FLASH,
+       .ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8
+};
+#endif
+
+static void ixdp2x00_irq_mask(unsigned int irq)
+{
+       unsigned long dummy;
+       static struct slowport_cfg old_cfg;
+
+       /*
+        * This is ugly in common code but really don't know
+        * of a better way to handle it. :(
+        */
+#ifdef CONFIG_ARCH_IXDP2400
+       if (machine_is_ixdp2400())
+               ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
+#endif
+
+       dummy = *board_irq_mask;
+       dummy |=  IXP2000_BOARD_IRQ_MASK(irq);
+       ixp2000_reg_write(board_irq_mask, dummy);
+
+#ifdef CONFIG_ARCH_IXDP2400
+       if (machine_is_ixdp2400())
+               ixp2000_release_slowport(&old_cfg);
+#endif
+}
+
+static void ixdp2x00_irq_unmask(unsigned int irq)
+{
+       unsigned long dummy;
+       static struct slowport_cfg old_cfg;
+
+#ifdef CONFGI_ARCH_IXDP2400
+       if (machine_is_ixdp2400())
+               ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
+#endif
+
+       dummy = *board_irq_mask;
+       dummy &=  ~IXP2000_BOARD_IRQ_MASK(irq);
+       ixp2000_reg_write(board_irq_mask, dummy);
+
+       if (machine_is_ixdp2400()) 
+               ixp2000_release_slowport(&old_cfg);
+}
+
+static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+        volatile u32 ex_interrupt = 0;
+       static struct slowport_cfg old_cfg;
+       int i;
+
+       desc->chip->mask(irq);
+
+#ifdef CONFIG_ARCH_IXDP2400
+       if (machine_is_ixdp2400())
+               ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
+#endif
+        ex_interrupt = *board_irq_stat & 0xff;
+       if (machine_is_ixdp2400())
+               ixp2000_release_slowport(&old_cfg);
+
+       if(!ex_interrupt) {
+               printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n");
+               return;
+       }
+
+       for(i = 0; i < board_irq_count; i++) {
+               if(ex_interrupt & (1 << i))  {
+                       struct irqdesc *cpld_desc;
+                       int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
+                       cpld_desc = irq_desc + cpld_irq;
+                       cpld_desc->handle(cpld_irq, cpld_desc, regs);
+               }
+       }
+
+       desc->chip->unmask(irq);
+}
+
+static struct irqchip ixdp2x00_cpld_irq_chip = {
+       .ack    = ixdp2x00_irq_mask,
+       .mask   = ixdp2x00_irq_mask,
+       .unmask = ixdp2x00_irq_unmask
+};
+
+void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs)
+{
+       unsigned int irq;
+
+       ixp2000_init_irq();
+       
+       if (!ixdp2x00_master_npu())
+               return;
+
+       board_irq_stat = stat_reg;
+       board_irq_mask = mask_reg;
+       board_irq_count = nr_irqs;
+
+       *board_irq_mask = 0xffffffff;
+
+       for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) {
+               set_irq_chip(irq, &ixdp2x00_cpld_irq_chip);
+               set_irq_handler(irq, do_level_IRQ);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       /* Hook into PCI interrupt */
+       set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x00_irq_handler);
+}
+
+/*************************************************************************
+ * IXDP2x00 memory map
+ *************************************************************************/
+static struct map_desc ixdp2x00_io_desc __initdata = {
+       .virtual        = IXDP2X00_VIRT_CPLD_BASE, 
+       .physical       = IXDP2X00_PHYS_CPLD_BASE,
+       .length         = IXDP2X00_CPLD_SIZE,
+       .type           = MT_DEVICE
+};
+
+void __init ixdp2x00_map_io(void)
+{
+       ixp2000_map_io();       
+
+       iotable_init(&ixdp2x00_io_desc, 1);
+}
+
+/*************************************************************************
+ * IXDP2x00-common PCI init
+ *
+ * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board 
+ * contains two NPUs (ingress and egress) connected over PCI,  both running 
+ * instances  of the kernel. So far so good. Peers on the PCI bus running 
+ * Linux is a common design in telecom systems. The problem is that instead 
+ * of all the devices being controlled by a single host, different
+ * devices are controlles by different NPUs on the same bus, leading to
+ * multiple hosts on the bus.i The exact bus layout looks like:
+ *
+ *                   Bus 0
+ *    Master NPU <-------------------+-------------------> Slave NPU
+ *                                   |
+ *                                   |
+ *                                  P2P 
+ *                                   |
+ *
+ *                  Bus 1            |
+ *               <--+------+---------+---------+------+-->
+ *                  |      |         |         |      |
+ *                  |      |         |         |      |
+ *             ... Dev    PMC       Media     Eth0   Eth1 ...
+ *
+ * The master controlls all but Eth1, which is controlled by the
+ * slave. What this measn is that the both the master and the slave
+ * have to scan the bus, but only one of them can enumerate the bus.
+ * In addition, after the bus is scaned, each kernel must remove
+ * the device(s) it does not control from the PCI dev list otherwise
+ * a driver on each NPU will try to manage it and we will have horrible
+ * conflicts. Oh..and the slave NPU needs to see the master NPU
+ * for Intel's drivers to work properly. Closed source drivers...
+ *
+ * The way we deal with this is fairly simple but ugly:
+ *
+ * 1) Let master scan and enumerate the bus completely.
+ * 2) Master deletes Eth1 from device list.
+ * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave)
+ *    from device list.
+ * 4) Find HW designers and LART them.
+ *
+ * The boards also do not do normal PCI IRQ routing, or any sort of 
+ * sensical  swizzling, so we just need to check where on the  bus a
+ * device sits and figure out to which CPLD pin the interrupt is routed.
+ * See ixdp2[48]00.c files.
+ *
+ *************************************************************************/
+void ixdp2x00_slave_pci_postinit(void)
+{
+       struct pci_dev *dev;
+
+       /*
+        * Remove PMC device is there is one
+        */
+       if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN)))
+               pci_remove_bus_device(dev);
+
+       dev = pci_find_slot(0, IXDP2X00_21555_DEVFN);
+       pci_remove_bus_device(dev);
+}
+
+/**************************************************************************
+ * IXDP2x00 Machine Setup
+ *************************************************************************/
+static struct flash_platform_data ixdp2x00_platform_data = {
+       .map_name       = "cfi_probe",
+       .width          = 1,
+};
+
+static struct ixp2000_flash_data ixdp2x00_flash_data = {
+       .platform_data  = &ixdp2x00_platform_data,
+       .nr_banks       = 1
+};
+
+static struct resource ixdp2x00_flash_resource = {
+       .start          = 0xc4000000,
+       .end            = 0xc4000000 + 0x00ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp2x00_flash = {
+       .name           = "IXP2000-Flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &ixdp2x00_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &ixdp2x00_flash_resource,
+};
+
+static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = {
+       .sda_pin        = IXDP2X00_GPIO_SDA,
+       .scl_pin        = IXDP2X00_GPIO_SCL,
+};
+
+static struct platform_device ixdp2x00_i2c_controller = {
+       .name           = "IXP2000-I2C",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &ixdp2x00_i2c_gpio_pins,
+       },
+       .num_resources  = 0
+};
+
+static struct platform_device *ixdp2x00_devices[] __initdata = {
+       &ixdp2x00_flash,
+       &ixdp2x00_i2c_controller
+};
+
+void __init ixdp2x00_init_machine(void)
+{
+       gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1);
+       gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
+
+       platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
+}
+
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
new file mode 100644 (file)
index 0000000..176114a
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * arch/arm/mach-ixp2000/ixdp2x01.c
+ *
+ * Code common to Intel IXDP2401 and IXDP2801 platforms
+ *
+ * Original Author: Andrzej Mialwoski <andrzej.mialwoski@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002-2003 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+/*************************************************************************
+ * IXDP2x01 IRQ Handling
+ *************************************************************************/
+static void ixdp2x01_irq_mask(unsigned int irq)
+{
+       *IXDP2X01_INT_MASK_SET_REG = IXP2000_BOARD_IRQ_MASK(irq);
+}
+
+static void ixdp2x01_irq_unmask(unsigned int irq)
+{
+       *IXDP2X01_INT_MASK_CLR_REG = IXP2000_BOARD_IRQ_MASK(irq);
+}
+
+static u32 valid_irq_mask;
+
+static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+       u32 ex_interrupt;
+       int i;
+
+       desc->chip->mask(irq);
+
+       ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask;
+
+       if (!ex_interrupt) {
+               printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n");
+               return;
+       }
+
+       for (i = 0; i < IXP2000_BOARD_IRQS; i++) {
+               if (ex_interrupt & (1 << i)) {
+                       struct irqdesc *cpld_desc;
+                       int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
+                       cpld_desc = irq_desc + cpld_irq;
+                       cpld_desc->handle(cpld_irq, cpld_desc, regs);
+               }
+       }
+
+       desc->chip->unmask(irq);
+}
+
+static struct irqchip ixdp2x01_irq_chip = {
+       .mask   = ixdp2x01_irq_mask,
+       .ack    = ixdp2x01_irq_mask,
+       .unmask = ixdp2x01_irq_unmask
+};
+
+/*
+ * We only do anything if we are the master NPU on the board.
+ * The slave NPU only has the ethernet chip going directly to
+ * the PCIB interrupt input.
+ */
+void __init ixdp2x01_init_irq(void)
+{
+       int irq = 0;
+
+       /* initialize chip specific interrupts */
+       ixp2000_init_irq();
+
+       if (machine_is_ixdp2401())
+               valid_irq_mask = IXDP2401_VALID_IRQ_MASK;
+       else
+               valid_irq_mask = IXDP2801_VALID_IRQ_MASK;
+
+       /* Mask all interrupts from CPLD, disable simulation */
+       *IXDP2X01_INT_MASK_SET_REG = 0xffffffff;
+       *IXDP2X01_INT_SIM_REG = 0;
+
+       for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
+               if (irq & valid_irq_mask) {
+                       set_irq_chip(irq, &ixdp2x01_irq_chip);
+                       set_irq_handler(irq, do_level_IRQ);
+                       set_irq_flags(irq, IRQF_VALID);
+               } else {
+                       set_irq_flags(irq, 0);
+               }
+       }
+
+       /* Hook into PCI interrupts */
+       set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler);
+}
+
+
+/*************************************************************************
+ * IXDP2x01 memory map and serial ports
+ *************************************************************************/
+static struct map_desc ixdp2x01_io_desc __initdata = {
+       .virtual        = IXDP2X01_VIRT_CPLD_BASE, 
+       .physical       = IXDP2X01_PHYS_CPLD_BASE,
+       .length         = IXDP2X01_CPLD_REGION_SIZE,
+       .type           = MT_DEVICE
+};
+
+static struct uart_port ixdp2x01_serial_ports[2] = {
+       {
+               .membase        = (char *)(IXDP2X01_UART1_VIRT_BASE),
+               .mapbase        = (unsigned long)IXDP2X01_UART1_PHYS_BASE,
+               .irq            = IRQ_IXDP2X01_UART1,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+               .uartclk        = IXDP2X01_UART_CLK,
+               .line           = 1,
+               .type           = PORT_16550A,
+               .fifosize       = 16
+       }, {
+               .membase        = (char *)(IXDP2X01_UART2_VIRT_BASE),
+               .mapbase        = (unsigned long)IXDP2X01_UART2_PHYS_BASE,
+               .irq            = IRQ_IXDP2X01_UART2,
+               .flags          = UPF_SKIP_TEST,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+               .uartclk        = IXDP2X01_UART_CLK,
+               .line           = 2,
+               .type           = PORT_16550A,
+               .fifosize       = 16
+       }, 
+};
+
+static void __init ixdp2x01_map_io(void)
+{
+       ixp2000_map_io();       
+
+       iotable_init(&ixdp2x01_io_desc, 1);
+
+       early_serial_setup(&ixdp2x01_serial_ports[0]);
+       early_serial_setup(&ixdp2x01_serial_ports[1]);
+}
+
+
+/*************************************************************************
+ * IXDP2x01 timer tick configuration
+ *************************************************************************/
+static unsigned int ixdp2x01_clock;
+
+static int __init ixdp2x01_clock_setup(char *str)
+{
+       ixdp2x01_clock = simple_strtoul(str, NULL, 10);
+
+       return 1;
+}
+
+__setup("ixdp2x01_clock=", ixdp2x01_clock_setup);
+
+static void __init ixdp2x01_init_time(void)
+{
+       if (!ixdp2x01_clock)
+               ixdp2x01_clock = 50000000;
+
+       ixp2000_init_time(ixdp2x01_clock);
+}
+
+/*************************************************************************
+ * IXDP2x01 PCI
+ *************************************************************************/
+void __init ixdp2x01_pci_preinit(void)
+{
+       ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000);
+       ixp2000_pci_preinit();
+}
+
+#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
+
+static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       u8 bus = dev->bus->number;
+       u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
+       struct pci_bus *tmp_bus = dev->bus;
+
+       /* Primary bus, no interrupts here */
+       if (bus == 0) {
+               return -1;
+       }
+
+       /* Lookup first leaf in bus tree */
+       while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) {
+               tmp_bus = tmp_bus->parent;
+       }
+
+       /* Select between known bridges */
+       switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
+       /* Device is located after first MB bridge */
+       case 0x0008:
+               if (tmp_bus == dev->bus) {
+                       /* Device is located directy after first MB bridge */
+                       switch (devpin) {
+                       case DEVPIN(1, 1):      /* Onboard 82546 ch 0 */
+                               if (machine_is_ixdp2401())
+                                       return IRQ_IXDP2401_INTA_82546;
+                               return -1;
+                       case DEVPIN(1, 2):      /* Onboard 82546 ch 1 */
+                               if (machine_is_ixdp2401())
+                                       return IRQ_IXDP2401_INTB_82546;
+                               return -1;
+                       case DEVPIN(0, 1):      /* PMC INTA# */
+                               return IRQ_IXDP2X01_SPCI_PMC_INTA;
+                       case DEVPIN(0, 2):      /* PMC INTB# */
+                               return IRQ_IXDP2X01_SPCI_PMC_INTB;
+                       case DEVPIN(0, 3):      /* PMC INTC# */
+                               return IRQ_IXDP2X01_SPCI_PMC_INTC;
+                       case DEVPIN(0, 4):      /* PMC INTD# */
+                               return IRQ_IXDP2X01_SPCI_PMC_INTD;
+                       }
+               }
+               break;
+       case 0x0010:
+               if (tmp_bus == dev->bus) {
+                       /* Device is located directy after second MB bridge */
+                       /* Secondary bus of second bridge */
+                       switch (devpin) {
+                       case DEVPIN(0, 1):      /* DB#0 */
+                               return IRQ_IXDP2X01_SPCI_DB_0;
+                       case DEVPIN(1, 1):      /* DB#1 */
+                               return IRQ_IXDP2X01_SPCI_DB_1;
+                       }
+               } else {
+                       /* Device is located indirectly after second MB bridge */
+                       /* Not supported now */
+               }
+               break;
+       }
+
+       return -1;
+}
+
+
+static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       sys->mem_offset = 0xe0000000;
+
+       if (machine_is_ixdp2801())
+               sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16);
+
+       return ixp2000_pci_setup(nr, sys);
+}
+
+struct hw_pci ixdp2x01_pci __initdata = {
+       .nr_controllers = 1,
+       .setup          = ixdp2x01_pci_setup,
+       .preinit        = ixdp2x01_pci_preinit,
+       .scan           = ixp2000_pci_scan_bus,
+       .map_irq        = ixdp2x01_pci_map_irq,
+};
+
+int __init ixdp2x01_pci_init(void)
+{
+
+       pci_common_init(&ixdp2x01_pci);
+       return 0;
+}
+
+subsys_initcall(ixdp2x01_pci_init);
+
+/*************************************************************************
+ * IXDP2x01 Machine Intialization
+ *************************************************************************/
+static struct flash_platform_data ixdp2x01_flash_platform_data = {
+       .map_name       = "cfi_probe",
+       .width          = 1,
+};
+
+static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
+{
+       *IXDP2X01_CPLD_FLASH_REG = 
+               ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN);
+       return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
+}
+
+static struct ixp2000_flash_data ixdp2x01_flash_data = {
+       .platform_data  = &ixdp2x01_flash_platform_data,
+       .bank_setup     = ixdp2x01_flash_bank_setup
+};
+
+static struct resource ixdp2x01_flash_resource = {
+       .start          = 0xc4000000,
+       .end            = 0xc4000000 + 0x01ffffff,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp2x01_flash = {
+       .name           = "IXP2000-Flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &ixdp2x01_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &ixdp2x01_flash_resource,
+};
+
+static struct platform_device *ixdp2x01_devices[] __initdata = {
+       &ixdp2x01_flash
+};
+
+static void __init ixdp2x01_init_machine(void)
+{
+       *IXDP2X01_CPLD_FLASH_REG = 
+               (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN);
+       
+       ixdp2x01_flash_data.nr_banks =
+               ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
+
+       platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
+}
+
+
+#ifdef CONFIG_ARCH_IXDP2401
+MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
+       MAINTAINER("MontaVista Software, Inc.")
+       BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(ixdp2x01_map_io)
+       INITIRQ(ixdp2x01_init_irq)
+       INITTIME(ixdp2x01_init_time)
+       INIT_MACHINE(ixdp2x01_init_machine)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_IXDP2801
+MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
+       MAINTAINER("MontaVista Software, Inc.")
+       BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(ixdp2x01_map_io)
+       INITIRQ(ixdp2x01_init_irq)
+       INITTIME(ixdp2x01_init_time)
+       INIT_MACHINE(ixdp2x01_init_machine)
+MACHINE_END
+#endif
+
+
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
new file mode 100644 (file)
index 0000000..d08cebe
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * arch/arm/mach-ixp2000/pci.c
+ *
+ * PCI routines for IXDP2400/IXDP2800 boards
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintained by: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/pci.h>
+
+static int pci_master_aborts = 0;
+
+static int clear_master_aborts(void);
+
+static u32 *
+ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
+{
+       u32 *paddress;
+
+       if (PCI_SLOT(devfn) > 7)
+               return 0;
+
+       /* Must be dword aligned */
+       where &= ~3;
+
+       /*
+        * For top bus, generate type 0, else type 1
+        */
+       if (!bus_nr) {
+               /* only bits[23:16] are used for IDSEL */
+               paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE
+                                   | (1 << (PCI_SLOT(devfn) + 16))
+                                   | (PCI_FUNC(devfn) << 8) | where);
+       } else {
+               paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE 
+                                   | (bus_nr << 16)
+                                   | (PCI_SLOT(devfn) << 11)
+                                   | (PCI_FUNC(devfn) << 8) | where);
+       }
+
+       return paddress;
+}
+
+/*
+ * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
+ * 0 and 3 are not valid indexes...
+ */
+static u32 bytemask[] = {
+       /*0*/   0,
+       /*1*/   0xff,
+       /*2*/   0xffff,
+       /*3*/   0,
+       /*4*/   0xffffffff,
+};
+
+
+int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+                               int size, u32 *value)
+{
+       u32 n;
+       u32 *addr;
+
+       n = where % 4;
+
+       addr = ixp2000_pci_config_addr(bus->number, devfn, where);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       pci_master_aborts = 0;
+       *value = (*addr >> (8*n)) & bytemask[size];
+       if (pci_master_aborts) {
+               pci_master_aborts = 0;
+               *value = 0xffffffff;
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * We don't do error checks by callling clear_master_aborts() b/c the
+ * assumption is that the caller did a read first to make sure a device
+ * exists.
+ */
+int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+                               int size, u32 value)
+{
+       u32 mask;
+       u32 *addr;
+       u32 temp;
+
+       mask = ~(bytemask[size] << ((where % 0x4) * 8));
+       addr = ixp2000_pci_config_addr(bus->number, devfn, where);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       temp = (u32) (value) << ((where % 0x4) * 8);
+       *addr = (*addr & mask) | temp;
+
+       clear_master_aborts();
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+static struct pci_ops ixp2000_pci_ops = {
+       .read   = ixp2000_pci_read_config,
+       .write  = ixp2000_pci_write_config
+};
+
+struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
+{
+       return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
+}
+
+
+int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+
+       volatile u32 temp;
+
+       pci_master_aborts = 1;
+
+       cli();
+       temp = *(IXP2000_PCI_CONTROL);
+       if (temp & ((1 << 8) | (1 << 5))) {
+               *(IXP2000_PCI_CONTROL) = temp;
+       }
+
+       temp = *(IXP2000_PCI_CMDSTAT);
+       if (temp & (1 << 29)) {
+               while (temp & (1 << 29)) {      
+                       *(IXP2000_PCI_CMDSTAT) = temp;
+                       temp = *(IXP2000_PCI_CMDSTAT);
+               }
+       }
+       sti();
+
+       /*
+        * If it was an imprecise abort, then we need to correct the
+        * return address to be _after_ the instruction.
+        */
+       if (fsr & (1 << 10))
+               regs->ARM_pc += 4;
+
+       return 0;
+}
+
+int
+clear_master_aborts(void)
+{
+       volatile u32 temp;
+
+       cli();
+       temp = *(IXP2000_PCI_CONTROL);
+       if (temp & ((1 << 8) | (1 << 5))) {     
+               *(IXP2000_PCI_CONTROL) = temp;
+       }
+
+       temp = *(IXP2000_PCI_CMDSTAT);
+       if (temp & (1 << 29)) {
+               while (temp & (1 << 29)) {
+                       *(IXP2000_PCI_CMDSTAT) = temp;
+                       temp = *(IXP2000_PCI_CMDSTAT);
+               }
+       }
+       sti();
+
+       return 0;
+}
+
+void __init
+ixp2000_pci_preinit(void)
+{
+       hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
+                               "PCI config cycle to non-existent device");
+}
+
+
+/*
+ * IXP2000 systems often have large resource requirements, so we just
+ * use our own resource space.
+ */
+static struct resource ixp2000_pci_mem_space = {
+       .start  = 0x00000000,
+       .end    = 0xffffffff,
+       .flags  = IORESOURCE_MEM,
+       .name   = "PCI Mem Space"
+};
+
+static struct resource ixp2000_pci_io_space = {
+       .start  = 0x00000000,
+       .end    = 0xffffffff,
+       .flags  = IORESOURCE_IO,
+       .name   = "PCI I/O Space"
+};
+
+int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       if (nr >= 1)
+               return 0;
+
+       sys->resource[0] = &ixp2000_pci_io_space;
+       sys->resource[1] = &ixp2000_pci_mem_space;
+       sys->resource[2] = NULL;
+
+       return 1;
+}
+
diff --git a/arch/arm/mach-ixp4xx/Makefile.boot b/arch/arm/mach-ixp4xx/Makefile.boot
new file mode 100644 (file)
index 0000000..d84c580
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+
diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
new file mode 100644 (file)
index 0000000..0f90433
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * arch/arch/mach-ixp4xx/ixdpg425-pci.c
+ *
+ * PCI setup routines for Intel IXDPG425 Platform
+ *
+ * Copyright (C) 2004 MontaVista Softwrae, Inc.
+ *
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * 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/pci.h>
+#include <linux/init.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/pci.h>
+
+extern void ixp4xx_pci_preinit(void);
+extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
+extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
+
+void __init ixdpg425_pci_preinit(void)
+{
+       gpio_line_config(6, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+       gpio_line_config(7, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
+
+       gpio_line_isr_clear(6);
+       gpio_line_isr_clear(7);
+
+       ixp4xx_pci_preinit();
+}
+
+static int __init ixdpg425_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       if (slot == 12 || slot == 13)
+               return IRQ_IXP4XX_GPIO7;
+       else if (slot == 14)
+               return IRQ_IXP4XX_GPIO6;
+       else return -1;
+}
+
+struct hw_pci ixdpg425_pci __initdata = {
+       .nr_controllers = 1,
+       .preinit =        ixdpg425_pci_preinit,
+       .swizzle =        pci_std_swizzle,
+       .setup =          ixp4xx_setup,
+       .scan =           ixp4xx_scan_bus,
+       .map_irq =        ixdpg425_map_irq,
+};
+
+int __init ixdpg425_pci_init(void)
+{
+       if (machine_is_ixdpg425())
+               pci_common_init(&ixdpg425_pci);
+       return 0;
+}
+
+subsys_initcall(ixdpg425_pci_init);
diff --git a/arch/arm/mach-l7200/Makefile.boot b/arch/arm/mach-l7200/Makefile.boot
new file mode 100644 (file)
index 0000000..6c72ecb
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-y  := 0xf0008000
+
diff --git a/arch/arm/mach-lh7a40x/Makefile.boot b/arch/arm/mach-lh7a40x/Makefile.boot
new file mode 100644 (file)
index 0000000..af941be
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0xc0008000
+params_phys-y  := 0xc0000100
+initrd_phys-y  := 0xc4000000
+
diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h
new file mode 100644 (file)
index 0000000..05564ec
--- /dev/null
@@ -0,0 +1,14 @@
+/* arch/arm/mach-lh7a40x/common.h
+ *
+ *  Copyright (C) 2004 Marc Singer
+ *
+ *  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.
+ *
+ */
+
+extern struct sys_timer lh7a40x_timer;
+
+extern void lh7a400_init_irq (void);
+extern void lh7a404_init_irq (void);
diff --git a/arch/arm/mach-omap/Makefile.boot b/arch/arm/mach-omap/Makefile.boot
new file mode 100644 (file)
index 0000000..fee1a6a
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y          := 0x10008000
+params_phys-y          := 0x10000100
+initrd_phys-y          := 0x10800000
+
diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c
new file mode 100644 (file)
index 0000000..1441089
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * linux/arch/arm/mach-omap/board-h2.c
+ *
+ * Board specific inits for OMAP-1610 H2
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ *
+ * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
+ * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com>
+ *
+ * H2 specific changes and cleanup
+ * Copyright (C) 2004 Nokia Corporation by Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/clocks.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern void __init omap_init_time(void);
+
+static struct map_desc h2_io_desc[] __initdata = {
+{ OMAP1610_ETHR_BASE, OMAP1610_ETHR_START, OMAP1610_ETHR_SIZE,MT_DEVICE },
+{ OMAP1610_NOR_FLASH_BASE, OMAP1610_NOR_FLASH_START, OMAP1610_NOR_FLASH_SIZE,
+       MT_DEVICE },
+};
+
+static struct resource h2_smc91x_resources[] = {
+       [0] = {
+               .start  = OMAP1610_ETHR_START,          /* Physical */
+               .end    = OMAP1610_ETHR_START + SZ_4K,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0,                            /* Really GPIO 0 */
+               .end    = 0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device h2_smc91x_device = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(h2_smc91x_resources),
+       .resource       = h2_smc91x_resources,
+};
+
+static struct platform_device *h2_devices[] __initdata = {
+       &h2_smc91x_device,
+};
+
+void h2_init_irq(void)
+{
+       omap_init_irq();
+}
+
+static struct omap_usb_config h2_usb_config __initdata = {
+       /* usb1 has a Mini-AB port and external isp1301 transceiver */
+       .otg            = 2,
+
+#ifdef CONFIG_USB_GADGET_OMAP
+       .hmc_mode       = 19,   // 0:host(off) 1:dev|otg 2:disabled
+       // .hmc_mode    = 21,   // 0:host(off) 1:dev(loopback) 2:host(loopback)
+#elif  defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+       /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
+       .hmc_mode       = 20,   // 1:dev|otg(off) 1:host 2:disabled
+#endif
+
+       .pins[1]        = 3,
+};
+
+static struct omap_board_config_kernel h2_config[] = {
+       { OMAP_TAG_USB,           &h2_usb_config },
+};
+
+static void __init h2_init(void)
+{
+       platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
+       omap_board_config = h2_config;
+       omap_board_config_size = ARRAY_SIZE(h2_config);
+}
+
+static void __init h2_map_io(void)
+{
+       omap_map_io();
+       iotable_init(h2_io_desc, ARRAY_SIZE(h2_io_desc));
+}
+
+MACHINE_START(OMAP_H2, "TI-H2")
+       MAINTAINER("Imre Deak <imre.deak@nokia.com>")
+       BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+       BOOT_PARAMS(0x10000100)
+       MAPIO(h2_map_io)
+       INITIRQ(h2_init_irq)
+       INIT_MACHINE(h2_init)
+       INITTIME(omap_init_time)
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c
new file mode 100644 (file)
index 0000000..d573b0c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * linux/arch/arm/mach-omap/board-h3.c
+ *
+ * This file contains OMAP1710 H3 specific code.
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/hardware.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach-types.h>
+#include "common.h"
+
+extern void __init omap_init_time(void);
+
+void h3_init_irq(void)
+{
+       omap_init_irq();
+}
+
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .start  = OMAP1710_ETHR_START,          /* Physical */
+               .end    = OMAP1710_ETHR_START + OMAP1710_ETHR_SIZE,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0,
+               .end    = 0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+        &smc91x_device,
+};
+
+static void __init h3_init(void)
+{
+       (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static struct map_desc h3_io_desc[] __initdata = {
+{ OMAP1710_ETHR_BASE,  OMAP1710_ETHR_START,  OMAP1710_ETHR_SIZE,  MT_DEVICE },
+{ OMAP_NOR_FLASH_BASE, OMAP_NOR_FLASH_START, OMAP_NOR_FLASH_SIZE, MT_DEVICE },
+};
+
+static void __init h3_map_io(void)
+{
+       omap_map_io();
+       iotable_init(h3_io_desc, ARRAY_SIZE(h3_io_desc));
+}
+
+MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
+       MAINTAINER("Texas Instruments, Inc.")
+       BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+       BOOT_PARAMS(0x10000100)
+       MAPIO(h3_map_io)
+       INITIRQ(h3_init_irq)
+       INIT_MACHINE(h3_init)
+       INITTIME(omap_init_time)
+MACHINE_END
diff --git a/arch/arm/mach-omap/clock.c b/arch/arm/mach-omap/clock.c
new file mode 100644 (file)
index 0000000..39d8503
--- /dev/null
@@ -0,0 +1,955 @@
+/*
+ *  linux/arch/arm/mach-omap/clock.c
+ *
+ *  Copyright (C) 2004 Nokia corporation
+ *  Written by 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <asm/semaphore.h>
+#include <asm/hardware/clock.h>
+#include <asm/arch/board.h>
+
+#include "clock.h"
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+static spinlock_t clockfw_lock = SPIN_LOCK_UNLOCKED;
+static void propagate_rate(struct clk *  clk);
+/* MPU virtual clock functions */
+static int select_table_rate(unsigned long rate);
+static long round_to_table_rate(unsigned long rate);
+void clk_setdpll(__u16, __u16);
+
+struct mpu_rate rate_table[] = {
+       /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
+        * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
+        */
+#if defined(CONFIG_OMAP_ARM_216MHZ) && defined(CONFIG_ARCH_OMAP16XX)
+       { 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_195MHZ) && defined(CONFIG_ARCH_OMAP730)
+       { 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_192MHZ) && defined(CONFIG_ARCH_OMAP16XX)
+       { 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
+       { 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
+       {  96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
+       {  48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
+       {  24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730)
+       { 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_168MHZ)
+       { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_120MHZ)
+       { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
+#endif
+#if defined(CONFIG_OMAP_ARM_96MHZ)
+       {  96000000, 12000000,  96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_60MHZ)
+       {  60000000, 12000000,  60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_30MHZ)
+       {  30000000, 12000000,  60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */
+#endif
+       { 0, 0, 0, 0, 0 },
+};
+
+
+static void ckctl_recalc(struct clk *  clk)
+{
+       int dsor;
+
+       /* Calculate divisor encoded as 2-bit exponent */
+       dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+       if (unlikely(clk->rate == clk->parent->rate / dsor))
+               return; /* No change, quick exit */
+       clk->rate = clk->parent->rate / dsor;
+
+       if (unlikely(clk->flags & RATE_PROPAGATES))
+               propagate_rate(clk);
+}
+
+
+static void followparent_recalc(struct clk *  clk)
+{
+       clk->rate = clk->parent->rate;
+}
+
+
+static void watchdog_recalc(struct clk *  clk)
+{
+       clk->rate = clk->parent->rate / 14;
+}
+
+
+static struct clk ck_ref = {
+       .name           = "ck_ref",
+       .rate           = 12000000,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         ALWAYS_ENABLED,
+};
+
+static struct clk ck_dpll1 = {
+       .name           = "ck_dpll1",
+       .parent         = &ck_ref,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_PROPAGATES | ALWAYS_ENABLED,
+};
+
+static struct clk ck_dpll1out = {
+       .name           = "ck_dpll1out",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_CKOUT_ARM,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk arm_ck = {
+       .name           = "arm_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .rate_offset    = CKCTL_ARMDIV_OFFSET,
+       .recalc         = &ckctl_recalc,
+};
+
+static struct clk armper_ck = {
+       .name           = "armper_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_PERCK,
+       .rate_offset    = CKCTL_PERDIV_OFFSET,
+       .recalc         = &ckctl_recalc,
+};
+
+static struct clk arm_gpio_ck = {
+       .name           = "arm_gpio_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_GPIOCK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk armxor_ck = {
+       .name           = "armxor_ck",
+       .parent         = &ck_ref,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_XORPCK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk armtim_ck = {
+       .name           = "armtim_ck",
+       .parent         = &ck_ref,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_TIMCK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk armwdt_ck = {
+       .name           = "armwdt_ck",
+       .parent         = &ck_ref,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_WDTCK,
+       .recalc         = &watchdog_recalc,
+};
+
+static struct clk arminth_ck1610 = {
+       .name           = "arminth_ck",
+       .parent         = &arm_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .recalc         = &followparent_recalc,
+       /* Note: On 1610/1710 frequency can be divided by 2 by programming
+        * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+        *
+        * 1510 version is in TC clocks.
+        */
+};
+
+static struct clk dsp_ck = {
+       .name           = "dsp_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL,
+       .enable_reg     = ARM_CKCTL,
+       .enable_bit     = EN_DSPCK,
+       .rate_offset    = CKCTL_DSPDIV_OFFSET,
+       .recalc         = &ckctl_recalc,
+};
+
+static struct clk dspmmu_ck = {
+       .name           = "dspmmu_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL | ALWAYS_ENABLED,
+       .rate_offset    = CKCTL_DSPMMUDIV_OFFSET,
+       .recalc         = &ckctl_recalc,
+};
+
+static struct clk tc_ck = {
+       .name           = "tc_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .rate_offset    = CKCTL_TCDIV_OFFSET,
+       .recalc         = &ckctl_recalc,
+};
+
+static struct clk arminth_ck1510 = {
+       .name           = "arminth_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP1510,
+       .recalc         = &followparent_recalc,
+       /* Note: On 1510 frequency follows TC_CK
+        *
+        * 1610/1710 version is in MPU clocks.
+        */
+};
+
+static struct clk tipb_ck = {
+       .name           = "tibp_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP1510,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk l3_ocpi_ck = {
+       .name           = "l3_ocpi_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT3,
+       .enable_bit     = EN_OCPI_CK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk tc1_ck = {
+       .name           = "tc1_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT3,
+       .enable_bit     = EN_TC1_CK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk tc2_ck = {
+       .name           = "tc2_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT3,
+       .enable_bit     = EN_TC2_CK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dma_ck = {
+       .name           = "dma_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dma_lcdfree_ck = {
+       .name           = "dma_lcdfree_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk api_ck = {
+       .name           = "api_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_APICK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk lb_ck = {
+       .name           = "lb_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP1510,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_LBCK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk rhea1_ck = {
+       .name           = "rhea1_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk rhea2_ck = {
+       .name           = "rhea2_ck",
+       .parent         = &tc_ck,
+       .flags          = CLOCK_IN_OMAP16XX,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk lcd_ck = {
+       .name           = "lcd_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL,
+       .enable_reg     = ARM_IDLECT2,
+       .enable_bit     = EN_LCDCK,
+       .rate_offset    = CKCTL_LCDDIV_OFFSET,
+       .recalc         = &ckctl_recalc,
+};
+
+static struct clk uart1_ck = {
+       .name           = "uart1_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 29,
+       /* (Only on 1510)
+        * The "enable bit" actually chooses between 48MHz and 12MHz.
+        */
+};
+
+static struct clk uart2_ck = {
+       .name           = "uart2_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 30,
+       /* (1510/1610/1710)
+        * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
+        */
+};
+
+static struct clk uart3_ck = {
+       .name           = "uart3_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 31,
+       /* (Only on 1510)
+        * The "enable bit" actually chooses between 48MHz and 12MHz.
+        */
+};
+
+static struct clk usb_ck1610 = {
+       .name           = "usb_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = ULPD_CLOCK_CTRL,
+       .enable_bit     = USB_MCLK_EN,
+};
+
+static struct clk usb_ck1510 = {
+       .name           = "usb_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP1510 | RATE_FIXED,
+};
+
+static struct clk usb_hhc_ck = {
+       .name           = "usb_hhc_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = USB_HOST_HHC_UHOST_EN,
+};
+
+/* To be done --
+static struct clk mclk = {
+       .name           = "mclk",
+};
+
+static struct clk bclk = {
+       .name           = "bclk",
+};
+-- to be done */
+
+static struct clk mmc1_ck = {
+       .name           = "mmc1_ck",
+       /* Functional clock is direct from ULPD, interface clock is ARMPER */
+       .parent         = &armper_ck,
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 23,
+};
+
+static struct clk mmc2_ck = {
+       .name           = "mmc2_ck",
+       /* Functional clock is direct from ULPD, interface clock is ARMPER */
+       .parent         = &armper_ck,
+       .rate           = 48000000,
+       .flags          = CLOCK_IN_OMAP16XX |
+                         RATE_FIXED | ENABLE_REG_32BIT,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 20,
+};
+
+static struct clk virtual_ck_mpu = {
+       .name           = "mpu",
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         VIRTUAL_CLOCK | ALWAYS_ENABLED,
+       .parent         = &arm_ck, /* Is smarter alias for */
+       .recalc         = &followparent_recalc,
+       .set_rate       = &select_table_rate,
+       .round_rate     = &round_to_table_rate,
+};
+
+
+static struct clk *  onchip_clks[] = {
+       /* non-ULPD clocks */
+       &ck_ref,
+       &ck_dpll1,
+       /* CK_GEN1 clocks */
+       &ck_dpll1out,
+       &arm_ck,
+       &armper_ck,
+       &arm_gpio_ck,
+       &armxor_ck,
+       &armtim_ck,
+       &armwdt_ck,
+       &arminth_ck1510,
+       &arminth_ck1610,
+       /* CK_GEN2 clocks */
+       &dsp_ck,
+       &dspmmu_ck,
+       /* CK_GEN3 clocks */
+       &tc_ck,
+       &tipb_ck,
+       &l3_ocpi_ck,
+       &tc1_ck,
+       &tc2_ck,
+       &dma_ck,
+       &dma_lcdfree_ck,
+       &api_ck,
+       &lb_ck,
+       &rhea1_ck,
+       &rhea2_ck,
+       &lcd_ck,
+       /* ULPD clocks */
+       &uart1_ck,
+       &uart2_ck,
+       &uart3_ck,
+       &usb_ck1510,
+       &usb_ck1610,
+       &usb_hhc_ck,
+       /* To be done --
+       &mclk,
+       &bclk,
+       -- to be done */
+       &mmc1_ck,
+       &mmc2_ck,
+       /* Virtual clocks */
+       &virtual_ck_mpu,
+};
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+       down(&clocks_sem);
+       list_for_each_entry(p, &clocks, node) {
+               if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+                       clk = p;
+                       break;
+               }
+       }
+       up(&clocks_sem);
+
+       return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+
+void clk_put(struct clk *clk)
+{
+       if (clk && !IS_ERR(clk))
+               module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+
+int __clk_enable(struct clk *clk)
+{
+       __u16 regval16;
+       __u32 regval32;
+
+       if (clk->flags & ALWAYS_ENABLED)
+               return 0;
+
+       if (unlikely(clk->enable_reg == 0)) {
+               printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+                      clk->name);
+               return 0;
+       }
+
+       if (clk->flags & ENABLE_REG_32BIT) {
+               regval32 = omap_readl(clk->enable_reg);
+               regval32 |= (1 << clk->enable_bit);
+               omap_writel(regval32, clk->enable_reg);
+       } else {
+               regval16 = omap_readw(clk->enable_reg);
+               regval16 |= (1 << clk->enable_bit);
+               omap_writew(regval16, clk->enable_reg);
+       }
+
+       return 0;
+}
+
+
+void __clk_disable(struct clk *clk)
+{
+       __u16 regval16;
+       __u32 regval32;
+
+       if (clk->enable_reg == 0)
+               return;
+
+       if (clk->flags & ENABLE_REG_32BIT) {
+               regval32 = omap_readl(clk->enable_reg);
+               regval32 &= ~(1 << clk->enable_bit);
+               omap_writel(regval32, clk->enable_reg);
+       } else {
+               regval16 = omap_readw(clk->enable_reg);
+               regval16 &= ~(1 << clk->enable_bit);
+               omap_writew(regval16, clk->enable_reg);
+       }
+}
+
+
+void __clk_unuse(struct clk *clk)
+{
+       if (clk->usecount > 0 && !(--clk->usecount)) {
+               __clk_disable(clk);
+               if (likely(clk->parent))
+                       __clk_unuse(clk->parent);
+       }
+}
+
+
+int __clk_use(struct clk *clk)
+{
+       int ret = 0;
+       if (clk->usecount++ == 0) {
+               if (likely(clk->parent))
+                       ret = __clk_use(clk->parent);
+
+               if (unlikely(ret != 0)) {
+                       clk->usecount--;
+                       return ret;
+               }
+
+               ret = __clk_enable(clk);
+
+               if (unlikely(ret != 0) && clk->parent) {
+                       __clk_unuse(clk->parent);
+                       clk->usecount--;
+               }
+       }
+
+       return ret;
+}
+
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       ret = __clk_enable(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       __clk_disable(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+
+int clk_use(struct clk *clk)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       ret = __clk_use(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(clk_use);
+
+
+void clk_unuse(struct clk *clk)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       __clk_unuse(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_unuse);
+
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+
+static __u16 verify_ckctl_value(__u16 newval)
+{
+       /* This function checks for following limitations set
+        * by the hardware (all conditions must be true):
+        * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
+        * ARM_CK >= TC_CK
+        * DSP_CK >= TC_CK
+        * DSPMMU_CK >= TC_CK
+        *
+        * In addition following rules are enforced:
+        * LCD_CK <= TC_CK
+        * ARMPER_CK <= TC_CK
+        *
+        * However, maximum frequencies are not checked for!
+        */
+       __u8 per_exp;
+       __u8 lcd_exp;
+       __u8 arm_exp;
+       __u8 dsp_exp;
+       __u8 tc_exp;
+       __u8 dspmmu_exp;
+
+       per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
+       lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
+       arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
+       dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
+       tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
+       dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
+
+       if (dspmmu_exp < dsp_exp)
+               dspmmu_exp = dsp_exp;
+       if (dspmmu_exp > dsp_exp+1)
+               dspmmu_exp = dsp_exp+1;
+       if (tc_exp < arm_exp)
+               tc_exp = arm_exp;
+       if (tc_exp < dspmmu_exp)
+               tc_exp = dspmmu_exp;
+       if (tc_exp > lcd_exp)
+               lcd_exp = tc_exp;
+       if (tc_exp > per_exp)
+               per_exp = tc_exp;
+
+       newval &= 0xf000;
+       newval |= per_exp << CKCTL_PERDIV_OFFSET;
+       newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
+       newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
+       newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
+       newval |= tc_exp << CKCTL_TCDIV_OFFSET;
+       newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
+
+       return newval;
+}
+
+
+static int calc_dsor_exp(struct clk *clk, unsigned long rate)
+{
+       /* Note: If target frequency is too low, this function will return 4,
+        * which is invalid value. Caller must check for this value and act
+        * accordingly.
+        *
+        * Note: This function does not check for following limitations set
+        * by the hardware (all conditions must be true):
+        * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
+        * ARM_CK >= TC_CK
+        * DSP_CK >= TC_CK
+        * DSPMMU_CK >= TC_CK
+        */
+       unsigned long realrate;
+       struct clk *  parent;
+       unsigned  dsor_exp;
+
+       if (unlikely(!(clk->flags & RATE_CKCTL)))
+               return -EINVAL;
+
+       parent = clk->parent;
+       if (unlikely(parent == 0))
+               return -EIO;
+
+       realrate = parent->rate;
+       for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
+               if (realrate <= rate)
+                       break;
+
+               realrate /= 2;
+       }
+
+       return dsor_exp;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       int dsor_exp;
+
+       if (clk->flags & RATE_FIXED)
+               return clk->rate;
+
+       if (clk->flags & RATE_CKCTL) {
+               dsor_exp = calc_dsor_exp(clk, rate);
+               if (dsor_exp < 0)
+                       return dsor_exp;
+               if (dsor_exp > 3)
+                       dsor_exp = 3;
+               return clk->parent->rate / (1 << dsor_exp);
+       }
+
+       if(clk->round_rate != 0)
+               return clk->round_rate(rate);
+
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+
+static void propagate_rate(struct clk *  clk)
+{
+       struct clk **  clkp;
+
+       for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
+               if (likely((*clkp)->parent != clk)) continue;
+               if (likely((*clkp)->recalc))
+                       (*clkp)->recalc(*clkp);
+       }
+}
+
+
+static int select_table_rate(unsigned long rate)
+{
+       /* Find the highest supported frequency <= rate and switch to it */
+       struct mpu_rate *  ptr;
+
+       for (ptr = rate_table; ptr->rate; ptr++) {
+               if (ptr->xtal != ck_ref.rate)
+                       continue;
+
+               /* DPLL1 cannot be reprogrammed without risking system crash */
+               if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate)
+                       continue;
+
+               /* Can check only after xtal frequency check */
+               if (ptr->rate <= rate)
+                       break;
+       }
+
+       if (!ptr->rate)
+               return -EINVAL;
+
+       if (unlikely(ck_dpll1.rate == 0)) {
+               omap_writew(ptr->dpllctl_val, DPLL_CTL);
+               ck_dpll1.rate = ptr->pll_rate;
+       }
+       omap_writew(ptr->ckctl_val, ARM_CKCTL);
+       propagate_rate(&ck_dpll1);
+       return 0;
+}
+
+
+static long round_to_table_rate(unsigned long rate)
+{
+       /* Find the highest supported frequency <= rate */
+       struct mpu_rate *  ptr;
+       long  highest_rate;
+
+       highest_rate = -EINVAL;
+
+       for (ptr = rate_table; ptr->rate; ptr++) {
+               if (ptr->xtal != ck_ref.rate)
+                       continue;
+
+               highest_rate = ptr->rate;
+
+               /* Can check only after xtal frequency check */
+               if (ptr->rate <= rate)
+                       break;
+       }
+
+       return highest_rate;
+}
+
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int  ret = -EINVAL;
+       int  dsor_exp;
+       __u16  regval;
+       unsigned long  flags;
+
+       if (clk->flags & RATE_CKCTL) {
+               dsor_exp = calc_dsor_exp(clk, rate);
+               if (dsor_exp > 3)
+                       dsor_exp = -EINVAL;
+               if (dsor_exp < 0)
+                       return dsor_exp;
+
+               spin_lock_irqsave(&clockfw_lock, flags);
+               regval = omap_readw(ARM_CKCTL);
+               regval &= ~(3 << clk->rate_offset);
+               regval |= dsor_exp << clk->rate_offset;
+               regval = verify_ckctl_value(regval);
+               omap_writew(regval, ARM_CKCTL);
+               clk->rate = clk->parent->rate / (1 << dsor_exp);
+               spin_unlock_irqrestore(&clockfw_lock, flags);
+               ret = 0;
+       } else if(clk->set_rate != 0) {
+               spin_lock_irqsave(&clockfw_lock, flags);
+               ret = clk->set_rate(rate);
+               spin_unlock_irqrestore(&clockfw_lock, flags);
+       }
+
+       if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+               propagate_rate(clk);
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+
+int clk_register(struct clk *clk)
+{
+       down(&clocks_sem);
+       list_add(&clk->node, &clocks);
+       up(&clocks_sem);
+       return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+       down(&clocks_sem);
+       list_del(&clk->node);
+       up(&clocks_sem);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+
+
+int __init clk_init(void)
+{
+       struct clk **  clkp;
+       const struct omap_clock_config *info;
+       int crystal_type = 0; /* Default 12 MHz */
+
+       for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
+               if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
+                       clk_register(*clkp);
+                       continue;
+               }
+
+               if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) {
+                       clk_register(*clkp);
+                       continue;
+               }
+       }
+
+       info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
+       if (info != NULL) {
+               if (!cpu_is_omap1510())
+                       crystal_type = info->system_clock_type;
+       }
+
+#if defined(CONFIG_ARCH_OMAP730)
+       ck_ref.rate = 13000000;
+#elif defined(CONFIG_ARCH_OMAP16XX)
+       if (crystal_type == 2)
+               ck_ref.rate = 19200000;
+#endif
+
+       /* We want to be in syncronous scalable mode */
+       omap_writew(0x1000, ARM_SYSST);
+
+       /* Find the highest supported frequency and enable it */
+       if (select_table_rate(~0)) {
+               printk(KERN_ERR "System frequencies not set. Check your config.\n");
+               /* Guess sane values (60MHz) */
+               omap_writew(0x2290, DPLL_CTL);
+               omap_writew(0x1005, ARM_CKCTL);
+               ck_dpll1.rate = 60000000;
+               propagate_rate(&ck_dpll1);
+               printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
+                      ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
+       }
+
+       /* Cache rates for clocks connected to ck_ref (not dpll1) */
+       propagate_rate(&ck_ref);
+
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+       /* Select slicer output as OMAP input clock */
+       omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
+#endif
+
+       /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
+       omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
+
+       /* Put DSP/MPUI into reset until needed */
+       omap_writew(0, ARM_RSTCT1);
+       omap_writew(1, ARM_RSTCT2);
+       omap_writew(0x400, ARM_IDLECT1);
+
+       /*
+        * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8)
+        * of the ARM_IDLECT2 register must be set to zero. The power-on
+        * default value of this bit is one.
+        */
+       omap_writew(0x0000, ARM_IDLECT2);       /* Turn LCD clock off also */
+
+       /*
+        * Only enable those clocks we will need, let the drivers
+        * enable other clocks as necessary
+        */
+       clk_use(&armper_ck);
+       clk_use(&armxor_ck);
+       clk_use(&armtim_ck);
+
+       if (cpu_is_omap1510())
+               clk_enable(&arm_gpio_ck);
+
+       return 0;
+}
diff --git a/arch/arm/mach-omap/clock.h b/arch/arm/mach-omap/clock.h
new file mode 100644 (file)
index 0000000..f3037bc
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  linux/arch/arm/mach-omap/clock.h
+ *
+ *  Copyright (C) 2004 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_OMAP_CLOCK_H
+#define __ARCH_ARM_OMAP_CLOCK_H
+
+struct module;
+
+struct clk {
+       struct list_head        node;
+       struct module           *owner;
+       const char              *name;
+       struct clk              *parent;
+       unsigned long           rate;
+       __s8                    usecount;
+       __u8                    flags;
+       __u32                   enable_reg;
+       __u8                    enable_bit;
+       __u8                    rate_offset;
+       void                    (*recalc)(struct clk *);
+       int                     (*set_rate)(unsigned long);
+       long                    (*round_rate)(unsigned long);
+};
+
+
+struct mpu_rate {
+       unsigned long           rate;
+       unsigned long           xtal;
+       unsigned long           pll_rate;
+       __u16                   ckctl_val;
+       __u16                   dpllctl_val;
+};
+
+
+/* Clock flags */
+#define RATE_CKCTL             1
+#define RATE_FIXED             2
+#define RATE_PROPAGATES                4
+#define VIRTUAL_CLOCK          8
+#define ALWAYS_ENABLED         16
+#define ENABLE_REG_32BIT       32
+#define CLOCK_IN_OMAP16XX      64
+#define CLOCK_IN_OMAP1510      128
+
+/* ARM_CKCTL bit shifts */
+#define CKCTL_PERDIV_OFFSET    0
+#define CKCTL_LCDDIV_OFFSET    2
+#define CKCTL_ARMDIV_OFFSET    4
+#define CKCTL_DSPDIV_OFFSET    6
+#define CKCTL_TCDIV_OFFSET     8
+#define CKCTL_DSPMMUDIV_OFFSET 10
+/*#define ARM_TIMXO            12*/
+#define EN_DSPCK               13
+/*#define ARM_INTHCK_SEL       14*/ /* Divide-by-2 for mpu inth_ck */
+
+/* ARM_IDLECT1 bit shifts */
+/*#define IDLWDT_ARM   0*/
+/*#define IDLXORP_ARM  1*/
+/*#define IDLPER_ARM   2*/
+/*#define IDLLCD_ARM   3*/
+/*#define IDLLB_ARM    4*/
+/*#define IDLHSAB_ARM  5*/
+/*#define IDLIF_ARM    6*/
+/*#define IDLDPLL_ARM  7*/
+/*#define IDLAPI_ARM   8*/
+/*#define IDLTIM_ARM   9*/
+/*#define SETARM_IDLE  11*/
+
+/* ARM_IDLECT2 bit shifts */
+#define EN_WDTCK       0
+#define EN_XORPCK      1
+#define EN_PERCK       2
+#define EN_LCDCK       3
+#define EN_LBCK                4 /* Not on 1610/1710 */
+/*#define EN_HSABCK    5*/
+#define EN_APICK       6
+#define EN_TIMCK       7
+#define DMACK_REQ      8
+#define EN_GPIOCK      9 /* Not on 1610/1710 */
+/*#define EN_LBFREECK  10*/
+#define EN_CKOUT_ARM   11
+
+/* ARM_IDLECT3 bit shifts */
+#define EN_OCPI_CK     0
+#define EN_TC1_CK      2
+#define EN_TC2_CK      4
+
+/* Various register defines for clock controls scattered around OMAP chip */
+#define USB_MCLK_EN            4       /* In ULPD_CLKC_CTRL */
+#define USB_HOST_HHC_UHOST_EN  9       /* In MOD_CONF_CTRL_0 */
+
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
+int clk_init(void);
+
+#endif
diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c
new file mode 100644 (file)
index 0000000..8ff27af
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * linux/arch/arm/mach-omap/leds-h2p2-debug.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include <asm/arch/fpga.h>
+
+#include "leds.h"
+
+void h2p2_dbg_leds_event(led_event_t evt)
+{
+       unsigned long flags;
+       static unsigned long hw_led_state = 0;
+
+       local_irq_save(flags);
+
+       switch (evt) {
+       case led_start:
+               hw_led_state |= H2P2_DBG_FPGA_LED_STARTSTOP;
+               break;
+
+       case led_stop:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_STARTSTOP;
+               break;
+
+       case led_claim:
+               hw_led_state |= H2P2_DBG_FPGA_LED_CLAIMRELEASE;
+               break;
+
+       case led_release:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_CLAIMRELEASE;
+               break;
+
+#ifdef CONFIG_LEDS_TIMER
+       case led_timer:
+               /*
+                * Toggle Timer LED
+                */
+               if (hw_led_state & H2P2_DBG_FPGA_LED_TIMER)
+                       hw_led_state &= ~H2P2_DBG_FPGA_LED_TIMER;
+               else
+                       hw_led_state |= H2P2_DBG_FPGA_LED_TIMER;
+               break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+       case led_idle_start:
+               hw_led_state |= H2P2_DBG_FPGA_LED_IDLE;
+               break;
+
+       case led_idle_end:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_IDLE;
+               break;
+#endif
+
+       case led_halted:
+               if (hw_led_state & H2P2_DBG_FPGA_LED_HALTED)
+                       hw_led_state &= ~H2P2_DBG_FPGA_LED_HALTED;
+               else
+                       hw_led_state |= H2P2_DBG_FPGA_LED_HALTED;
+               break;
+
+       case led_green_on:
+               break;
+
+       case led_green_off:
+               break;
+
+       case led_amber_on:
+               break;
+
+       case led_amber_off:
+               break;
+
+       case led_red_on:
+               break;
+
+       case led_red_off:
+               break;
+
+       default:
+               break;
+       }
+
+
+       /*
+        *  Actually burn the LEDs
+        */
+       __raw_writew(~hw_led_state & 0xffff, H2P2_DBG_FPGA_LEDS);
+
+       local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-omap/mcbsp.c b/arch/arm/mach-omap/mcbsp.c
new file mode 100644 (file)
index 0000000..d334395
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * linux/arch/arm/omap/mcbsp.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.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.
+ *
+ * Multichannel mode not supported.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mcbsp.h>
+
+#ifdef CONFIG_MCBSP_DEBUG
+#define DBG(x...)      printk(x)
+#else
+#define DBG(x...)      do { } while (0)
+#endif
+
+struct omap_mcbsp {
+       u32                          io_base;
+       u8                           id;
+       u8                           free;
+       omap_mcbsp_word_length       rx_word_length;
+       omap_mcbsp_word_length       tx_word_length;
+
+       /* IRQ based TX/RX */
+       int                          rx_irq;
+       int                          tx_irq;
+
+       /* DMA stuff */
+       u8                           dma_rx_sync;
+       short                        dma_rx_lch;
+       u8                           dma_tx_sync;
+       short                        dma_tx_lch;
+
+       /* Completion queues */
+       struct completion            tx_irq_completion;
+       struct completion            rx_irq_completion;
+       struct completion            tx_dma_completion;
+       struct completion            rx_dma_completion;
+
+       spinlock_t                   lock;
+};
+
+static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+
+
+static void omap_mcbsp_dump_reg(u8 id)
+{
+       DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);
+       DBG("DRR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
+       DBG("DRR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
+       DBG("DXR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
+       DBG("DXR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
+       DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
+       DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
+       DBG("RCR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
+       DBG("RCR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
+       DBG("XCR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
+       DBG("XCR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
+       DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
+       DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
+       DBG("PCR0:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
+       DBG("***********************\n");
+}
+
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
+
+       DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+
+       complete(&mcbsp_tx->tx_irq_completion);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
+
+       DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+
+       complete(&mcbsp_rx->rx_irq_completion);
+       return IRQ_HANDLED;
+}
+
+
+static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
+
+       DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
+
+       /* We can free the channels */
+       omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
+       mcbsp_dma_tx->dma_tx_lch = -1;
+
+       complete(&mcbsp_dma_tx->tx_dma_completion);
+}
+
+static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
+
+       DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
+
+       /* We can free the channels */
+       omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
+       mcbsp_dma_rx->dma_rx_lch = -1;
+
+       complete(&mcbsp_dma_rx->rx_dma_completion);
+}
+
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+
+void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config)
+{
+       u32 io_base = mcbsp[id].io_base;
+
+       DBG("OMAP-McBSP: McBSP%d  io_base: 0x%8x\n", id+1, io_base);
+
+       /* We write the given config */
+       OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
+       OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1);
+       OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2);
+       OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1);
+       OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2);
+       OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1);
+       OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2);
+       OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1);
+       OMAP_MCBSP_WRITE(io_base, SRGR2, config->mcr2);
+       OMAP_MCBSP_WRITE(io_base, SRGR1, config->mcr1);
+       OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
+}
+
+
+
+static int omap_mcbsp_check(unsigned int id)
+{
+       if (cpu_is_omap730()) {
+               if (id > OMAP_MAX_MCBSP_COUNT - 1) {
+                      printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+                      return -1;
+               }
+               return 0;
+       }
+
+       if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+               if (id > OMAP_MAX_MCBSP_COUNT) {
+                       printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+                       return -1;
+               }
+               return 0;
+       }
+
+       return -1;
+}
+
+#define DSP_RSTCT2              0xe1008014
+
+static void omap_mcbsp_dsp_request(void)
+{
+       if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+               omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
+                           ARM_RSTCT1);
+               omap_writew((omap_readw(ARM_CKCTL) | 1 << EN_DSPCK),
+                           ARM_CKCTL);
+               omap_writew((omap_readw(ARM_IDLECT2) | (1 << EN_APICK)),
+                           ARM_IDLECT2);
+
+               /* enable 12MHz clock to mcbsp 1 & 3 */
+               __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
+                            DSP_IDLECT2);
+               __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
+                            DSP_RSTCT2);
+       }
+}
+
+static void omap_mcbsp_dsp_free(void)
+{
+       /* Useless for now */
+}
+
+
+int omap_mcbsp_request(unsigned int id)
+{
+       int err;
+
+       if (omap_mcbsp_check(id) < 0)
+               return -EINVAL;
+
+       /*
+        * On 1510, 1610 and 1710, McBSP1 and McBSP3
+        * are DSP public peripherals.
+        */
+       if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+               omap_mcbsp_dsp_request();
+
+       spin_lock(&mcbsp[id].lock);
+       if (!mcbsp[id].free) {
+               printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+               spin_unlock(&mcbsp[id].lock);
+               return -1;
+       }
+
+       mcbsp[id].free = 0;
+       spin_unlock(&mcbsp[id].lock);
+
+       /* We need to get IRQs here */
+       err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
+                         "McBSP",
+                         (void *) (&mcbsp[id]));
+       if (err != 0) {
+               printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
+                      mcbsp[id].tx_irq, mcbsp[id].id);
+               return err;
+       }
+
+       init_completion(&(mcbsp[id].tx_irq_completion));
+
+
+       err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
+                         "McBSP",
+                         (void *) (&mcbsp[id]));
+       if (err != 0) {
+               printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
+                      mcbsp[id].rx_irq, mcbsp[id].id);
+               free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+               return err;
+       }
+
+       init_completion(&(mcbsp[id].rx_irq_completion));
+       return 0;
+
+}
+
+void omap_mcbsp_free(unsigned int id)
+{
+       if (omap_mcbsp_check(id) < 0)
+               return;
+
+       if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+               omap_mcbsp_dsp_free();
+
+       spin_lock(&mcbsp[id].lock);
+       if (mcbsp[id].free) {
+               printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);
+               spin_unlock(&mcbsp[id].lock);
+               return;
+       }
+
+       mcbsp[id].free = 1;
+       spin_unlock(&mcbsp[id].lock);
+
+       /* Free IRQs */
+       free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
+       free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+}
+
+/*
+ * Here we start the McBSP, by enabling the sample
+ * generator, both transmitter and receivers,
+ * and the frame sync.
+ */
+void omap_mcbsp_start(unsigned int id)
+{
+       u32 io_base;
+       u16 w;
+
+       if (omap_mcbsp_check(id) < 0)
+               return;
+
+       io_base = mcbsp[id].io_base;
+
+       mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
+       mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
+
+       /* Start the sample generator */
+       w = OMAP_MCBSP_READ(io_base, SPCR2);
+       OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+
+       /* Enable transmitter and receiver */
+       w = OMAP_MCBSP_READ(io_base, SPCR2);
+       OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+
+       w = OMAP_MCBSP_READ(io_base, SPCR1);
+       OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+
+       udelay(100);
+
+       /* Start frame sync */
+       w = OMAP_MCBSP_READ(io_base, SPCR2);
+       OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+
+       /* Dump McBSP Regs */
+       omap_mcbsp_dump_reg(id);
+
+}
+
+void omap_mcbsp_stop(unsigned int id)
+{
+       u32 io_base;
+       u16 w;
+
+       if (omap_mcbsp_check(id) < 0)
+               return;
+
+       io_base = mcbsp[id].io_base;
+
+        /* Reset transmitter */
+       w = OMAP_MCBSP_READ(io_base, SPCR2);
+       OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+
+       /* Reset receiver */
+       w = OMAP_MCBSP_READ(io_base, SPCR1);
+       OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+
+       /* Reset the sample rate generator */
+       w = OMAP_MCBSP_READ(io_base, SPCR2);
+       OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+}
+
+
+/*
+ * IRQ based word transmission.
+ */
+void omap_mcbsp_xmit_word(unsigned int id, u32 word)
+{
+       u32 io_base;
+       omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length;
+
+       if (omap_mcbsp_check(id) < 0)
+               return;
+
+       io_base = mcbsp[id].io_base;
+
+       wait_for_completion(&(mcbsp[id].tx_irq_completion));
+
+       if (word_length > OMAP_MCBSP_WORD_16)
+               OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
+       OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
+}
+
+u32 omap_mcbsp_recv_word(unsigned int id)
+{
+       u32 io_base;
+       u16 word_lsb, word_msb = 0;
+       omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length;
+
+       if (omap_mcbsp_check(id) < 0)
+               return -EINVAL;
+
+       io_base = mcbsp[id].io_base;
+
+       wait_for_completion(&(mcbsp[id].rx_irq_completion));
+
+       if (word_length > OMAP_MCBSP_WORD_16)
+               word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+       word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+       return (word_lsb | (word_msb << 16));
+}
+
+
+/*
+ * Simple DMA based buffer rx/tx routines.
+ * Nothing fancy, just a single buffer tx/rx through DMA.
+ * The DMA resources are released once the transfer is done.
+ * For anything fancier, you should use your own customized DMA
+ * routines and callbacks.
+ */
+int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+{
+       int dma_tx_ch;
+
+       if (omap_mcbsp_check(id) < 0)
+               return -EINVAL;
+
+       if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,
+                            &mcbsp[id],
+                            &dma_tx_ch)) {
+               printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);
+               return -EAGAIN;
+       }
+       mcbsp[id].dma_tx_lch = dma_tx_ch;
+
+       DBG("TX DMA on channel %d\n", dma_tx_ch);
+
+       init_completion(&(mcbsp[id].tx_dma_completion));
+
+       omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
+                                    OMAP_DMA_DATA_TYPE_S16,
+                                    length >> 1, 1,
+                                    OMAP_DMA_SYNC_ELEMENT);
+
+       omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
+                                OMAP_DMA_PORT_TIPB,
+                                OMAP_DMA_AMODE_CONSTANT,
+                                mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
+
+       omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
+                               OMAP_DMA_PORT_EMIFF,
+                               OMAP_DMA_AMODE_POST_INC,
+                               buffer);
+
+       omap_start_dma(mcbsp[id].dma_tx_lch);
+       wait_for_completion(&(mcbsp[id].tx_dma_completion));
+       return 0;
+}
+
+
+int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+{
+       int dma_rx_ch;
+
+       if (omap_mcbsp_check(id) < 0)
+               return -EINVAL;
+
+       if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,
+                            &mcbsp[id],
+                            &dma_rx_ch)) {
+               printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);
+               return -EAGAIN;
+       }
+       mcbsp[id].dma_rx_lch = dma_rx_ch;
+
+       DBG("RX DMA on channel %d\n", dma_rx_ch);
+
+       init_completion(&(mcbsp[id].rx_dma_completion));
+
+       omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
+                                    OMAP_DMA_DATA_TYPE_S16,
+                                    length >> 1, 1,
+                                    OMAP_DMA_SYNC_ELEMENT);
+
+       omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
+                               OMAP_DMA_PORT_TIPB,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
+
+       omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
+                                OMAP_DMA_PORT_EMIFF,
+                                OMAP_DMA_AMODE_POST_INC,
+                                buffer);
+
+       omap_start_dma(mcbsp[id].dma_rx_lch);
+       wait_for_completion(&(mcbsp[id].rx_dma_completion));
+       return 0;
+}
+
+
+/*
+ * SPI wrapper.
+ * Since SPI setup is much simpler than the generic McBSP one,
+ * this wrapper just need an omap_mcbsp_spi_cfg structure as an input.
+ * Once this is done, you can call omap_mcbsp_start().
+ */
+void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg)
+{
+       struct omap_mcbsp_reg_cfg mcbsp_cfg;
+
+       if (omap_mcbsp_check(id) < 0)
+               return;
+
+       memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
+
+       /* SPI has only one frame */
+       mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));
+       mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));
+
+        /* Clock stop mode */
+       if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)
+               mcbsp_cfg.spcr1 |= (1 << 12);
+       else
+               mcbsp_cfg.spcr1 |= (3 << 11);
+
+       /* Set clock parities */
+       if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING)
+               mcbsp_cfg.pcr0 |= CLKRP;
+       else
+               mcbsp_cfg.pcr0 &= ~CLKRP;
+
+       if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING)
+               mcbsp_cfg.pcr0 &= ~CLKXP;
+       else
+               mcbsp_cfg.pcr0 |= CLKXP;
+
+       /* Set SCLKME to 0 and CLKSM to 1 */
+       mcbsp_cfg.pcr0 &= ~SCLKME;
+       mcbsp_cfg.srgr2 |= CLKSM;
+
+       /* Set FSXP */
+       if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH)
+               mcbsp_cfg.pcr0 &= ~FSXP;
+       else
+               mcbsp_cfg.pcr0 |= FSXP;
+
+       if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {
+               mcbsp_cfg.pcr0 |= CLKXM;
+               mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);
+               mcbsp_cfg.pcr0 |= FSXM;
+               mcbsp_cfg.srgr2 &= ~FSGM;
+               mcbsp_cfg.xcr2 |= XDATDLY(1);
+               mcbsp_cfg.rcr2 |= RDATDLY(1);
+       }
+       else {
+               mcbsp_cfg.pcr0 &= ~CLKXM;
+               mcbsp_cfg.srgr1 |= CLKGDV(1);
+               mcbsp_cfg.pcr0 &= ~FSXM;
+               mcbsp_cfg.xcr2 &= ~XDATDLY(3);
+               mcbsp_cfg.rcr2 &= ~RDATDLY(3);
+       }
+
+       mcbsp_cfg.xcr2 &= ~XPHASE;
+       mcbsp_cfg.rcr2 &= ~RPHASE;
+
+       omap_mcbsp_config(id, &mcbsp_cfg);
+}
+
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+struct omap_mcbsp_info {
+       u32 virt_base;
+       u8 dma_rx_sync, dma_tx_sync;
+       u16 rx_irq, tx_irq;
+};
+
+#ifdef CONFIG_ARCH_OMAP730
+static const struct omap_mcbsp_info mcbsp_730[] = {
+       [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE),
+               .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+               .rx_irq = INT_730_McBSP1RX,
+               .tx_irq = INT_730_McBSP1TX },
+       [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE),
+               .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+               .rx_irq = INT_730_McBSP2RX,
+               .tx_irq = INT_730_McBSP2TX },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static const struct omap_mcbsp_info mcbsp_1510[] = {
+       [0] = { .virt_base = OMAP1510_MCBSP1_BASE,
+               .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+               .rx_irq = INT_McBSP1RX,
+               .tx_irq = INT_McBSP1TX },
+       [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE),
+               .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
+               .rx_irq = INT_1510_SPI_RX,
+               .tx_irq = INT_1510_SPI_TX },
+       [2] = { .virt_base = OMAP1510_MCBSP3_BASE,
+               .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+               .rx_irq = INT_McBSP3RX,
+               .tx_irq = INT_McBSP3TX },
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+static const struct omap_mcbsp_info mcbsp_1610[] = {
+       [0] = { .virt_base = OMAP1610_MCBSP1_BASE,
+               .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+               .rx_irq = INT_McBSP1RX,
+               .tx_irq = INT_McBSP1TX },
+       [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE),
+               .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
+               .rx_irq = INT_1610_McBSP2_RX,
+               .tx_irq = INT_1610_McBSP2_TX },
+       [2] = { .virt_base = OMAP1610_MCBSP3_BASE,
+               .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+               .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+               .rx_irq = INT_McBSP3RX,
+               .tx_irq = INT_McBSP3TX },
+};
+#endif
+
+static int __init omap_mcbsp_init(void)
+{
+       int mcbsp_count = 0, i;
+       static const struct omap_mcbsp_info *mcbsp_info;
+
+       printk("Initializing OMAP McBSP system\n");
+#ifdef CONFIG_ARCH_OMAP730
+       if (cpu_is_omap730()) {
+               mcbsp_info = mcbsp_730;
+               mcbsp_count = ARRAY_SIZE(mcbsp_730);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+       if (cpu_is_omap1510()) {
+               mcbsp_info = mcbsp_1510;
+               mcbsp_count = ARRAY_SIZE(mcbsp_1510);
+       }
+#endif
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+       if (cpu_is_omap1610() || cpu_is_omap1710()) {
+               mcbsp_info = mcbsp_1610;
+               mcbsp_count = ARRAY_SIZE(mcbsp_1610);
+       }
+#endif
+       for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
+               if (i >= mcbsp_count) {
+                       mcbsp[i].io_base = 0;
+                       mcbsp[i].free = 0;
+                        continue;
+               }
+               mcbsp[i].id = i + 1;
+               mcbsp[i].free = 1;
+               mcbsp[i].dma_tx_lch = -1;
+               mcbsp[i].dma_rx_lch = -1;
+
+               mcbsp[i].io_base = mcbsp_info[i].virt_base;
+               mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
+               mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
+               mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
+               mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;
+               spin_lock_init(&mcbsp[i].lock);
+       }
+
+       return 0;
+}
+
+
+arch_initcall(omap_mcbsp_init);
+
+EXPORT_SYMBOL(omap_mcbsp_config);
+EXPORT_SYMBOL(omap_mcbsp_request);
+EXPORT_SYMBOL(omap_mcbsp_free);
+EXPORT_SYMBOL(omap_mcbsp_start);
+EXPORT_SYMBOL(omap_mcbsp_stop);
+EXPORT_SYMBOL(omap_mcbsp_xmit_word);
+EXPORT_SYMBOL(omap_mcbsp_recv_word);
+EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
+EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
+EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/mach-omap/pm.c
new file mode 100644 (file)
index 0000000..095322c
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * linux/arch/arm/mach-omap/pm.c
+ *
+ * OMAP Power Management Routines
+ *
+ * Original code for the SA11x0:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Modified for the PXA250 by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Modified for the OMAP1510 by David Singleton:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS 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 AUTHOR 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.
+ *
+ * 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/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/omap16xx.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tps65010.h>
+
+#include "clock.h"
+
+static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
+static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
+static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+
+/*
+ * Let's power down on idle, but only if we are really
+ * idle, because once we start down the path of
+ * going idle we continue to do idle even if we get
+ * a clock tick interrupt . .
+ */
+void omap_pm_idle(void)
+{
+       int (*func_ptr)(void) = 0;
+       unsigned int mask32 = 0;
+
+       /*
+        * If the DSP is being used let's just idle the CPU, the overhead
+        * to wake up from Big Sleep is big, milliseconds versus micro
+        * seconds for wait for interrupt.
+        */
+
+       local_irq_disable();
+       local_fiq_disable();
+       if (need_resched()) {
+               local_fiq_enable();
+               local_irq_enable();
+               return;
+       }
+       mask32 = omap_readl(ARM_SYSST);
+       local_fiq_enable();
+       local_irq_enable();
+       if ((mask32 & DSP_IDLE) == 0) {
+               __asm__ volatile ("mcr  p15, 0, r0, c7, c0, 4");
+       } else {
+
+               if (cpu_is_omap1510()) {
+                       func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND);
+               } else if (cpu_is_omap1610() || cpu_is_omap1710()) {
+                       func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND);
+               } else if (cpu_is_omap5912()) {
+                       func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND);
+               }
+
+               func_ptr();
+       }
+}
+
+/*
+ * Configuration of the wakeup event is board specific. For the
+ * moment we put it into this helper function. Later it may move
+ * to board specific files.
+ */
+static void omap_pm_wakeup_setup(void)
+{
+       /*
+        * Enable ARM XOR clock and release peripheral from reset by
+        * writing 1 to PER_EN bit in ARM_RSTCT2, this is required
+        * for UART configuration to use UART2 to wake up.
+        */
+
+       omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2);
+       omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2);
+       omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL);
+
+       /*
+        * Turn off all interrupts except L1-2nd level cascade,
+        * and the L2 wakeup interrupts: keypad and UART2.
+        */
+
+       omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR);
+
+       if (cpu_is_omap1510()) {
+               omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD),  OMAP_IH2_MIR);
+       }
+
+       if (cpu_is_omap16xx()) {
+               omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR);
+
+               omap_writel(~0x0, OMAP_IH2_1_MIR);
+               omap_writel(~0x0, OMAP_IH2_2_MIR);
+               omap_writel(~0x0, OMAP_IH2_3_MIR);
+       }
+
+       /*  New IRQ agreement */
+       omap_writel(1, OMAP_IH1_CONTROL);
+
+       /* external PULL to down, bit 22 = 0 */
+       omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2);
+}
+
+void omap_pm_suspend(void)
+{
+       unsigned int mask32 = 0;
+       unsigned long arg0 = 0, arg1 = 0;
+       int (*func_ptr)(unsigned short, unsigned short) = 0;
+       unsigned short save_dsp_idlect2;
+
+       printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev);
+
+       if (machine_is_omap_osk()) {
+               /* Stop LED1 (D9) blink */
+               tps65010_set_led(LED1, OFF);
+       }
+
+       /*
+        * Step 1: turn off interrupts
+        */
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       /*
+        * Step 2: save registers
+        *
+        * The omap is a strange/beautiful device. The caches, memory
+        * and register state are preserved across power saves.
+        * We have to save and restore very little register state to
+        * idle the omap.
+         *
+        * Save interrupt, MPUI, ARM and UPLD control registers.
+        */
+
+       if (cpu_is_omap1510()) {
+               MPUI1510_SAVE(OMAP_IH1_MIR);
+               MPUI1510_SAVE(OMAP_IH2_MIR);
+               MPUI1510_SAVE(MPUI_CTRL);
+               MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+               MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+               MPUI1510_SAVE(EMIFS_CONFIG);
+               MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+       } else if (cpu_is_omap16xx()) {
+               MPUI1610_SAVE(OMAP_IH1_MIR);
+               MPUI1610_SAVE(OMAP_IH2_0_MIR);
+               MPUI1610_SAVE(OMAP_IH2_1_MIR);
+               MPUI1610_SAVE(OMAP_IH2_2_MIR);
+               MPUI1610_SAVE(OMAP_IH2_3_MIR);
+               MPUI1610_SAVE(MPUI_CTRL);
+               MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+               MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+               MPUI1610_SAVE(EMIFS_CONFIG);
+               MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+       }
+
+       ARM_SAVE(ARM_CKCTL);
+       ARM_SAVE(ARM_IDLECT1);
+       ARM_SAVE(ARM_IDLECT2);
+       ARM_SAVE(ARM_EWUPCT);
+       ARM_SAVE(ARM_RSTCT1);
+       ARM_SAVE(ARM_RSTCT2);
+       ARM_SAVE(ARM_SYSST);
+       ULPD_SAVE(ULPD_CLOCK_CTRL);
+       ULPD_SAVE(ULPD_STATUS_REQ);
+
+       /*
+        * Step 3: LOW_PWR signal enabling
+        *
+        * Allow the LOW_PWR signal to be visible on MPUIO5 ball.
+        */
+       if (cpu_is_omap1510()) {
+               /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
+               omap_writew(omap_readw(ULPD_POWER_CTRL) |
+                           OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+       } else if (cpu_is_omap16xx()) {
+               /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
+               omap_writew(omap_readw(ULPD_POWER_CTRL) |
+                           OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+       }
+
+       /* configure LOW_PWR pin */
+       omap_cfg_reg(T20_1610_LOW_PWR);
+
+       /*
+        * Step 4: OMAP DSP Shutdown
+        */
+
+       /* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
+       omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
+                   ARM_RSTCT1);
+
+       /* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
+        omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
+
+       /* Set EN_DSPCK = 0, stop DSP block clock */
+       omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
+
+       /* Stop any DSP domain clocks */
+       omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
+       save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
+       __raw_writew(0, DSP_IDLECT2);
+
+       /*
+        * Step 5: Wakeup Event Setup
+        */
+
+       omap_pm_wakeup_setup();
+
+       /*
+        * Step 6a: ARM and Traffic controller shutdown
+        *
+        * Step 6 starts here with clock and watchdog disable
+        */
+
+       /* stop clocks */
+       mask32 = omap_readl(ARM_IDLECT2);
+       mask32 &= ~(1<<EN_WDTCK);  /* bit 0 -> 0 (WDT clock) */
+       mask32 |=  (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */
+       mask32 &= ~(1<<EN_PERCK);  /* bit 2 -> 0 (MPUPER_CK clock) */
+       mask32 &= ~(1<<EN_LCDCK);  /* bit 3 -> 0 (LCDC clock) */
+       mask32 &= ~(1<<EN_LBCK);   /* bit 4 -> 0 (local bus clock) */
+       mask32 |=  (1<<EN_APICK);  /* bit 6 -> 1 (MPUI clock) */
+       mask32 &= ~(1<<EN_TIMCK);  /* bit 7 -> 0 (MPU timer clock) */
+       mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */
+       mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */
+       omap_writel(mask32, ARM_IDLECT2);
+
+       /* disable ARM watchdog */
+       omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
+       omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
+
+       /*
+        * Step 6b: ARM and Traffic controller shutdown
+        *
+        * Step 6 continues here. Prepare jump to power management
+        * assembly code in internal SRAM.
+        *
+        * Since the omap_cpu_suspend routine has been copied to
+        * SRAM, we'll do an indirect procedure call to it and pass the
+        * contents of arm_idlect1 and arm_idlect2 so it can restore
+        * them when it wakes up and it will return.
+        */
+
+       arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
+       arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
+
+       if (cpu_is_omap1510()) {
+               func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND);
+       } else if (cpu_is_omap1610() || cpu_is_omap1710()) {
+               func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND);
+       } else if (cpu_is_omap5912()) {
+               func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND);
+       }
+
+       /*
+        * Step 6c: ARM and Traffic controller shutdown
+        *
+        * Jump to assembly code. The processor will stay there
+        * until wake up.
+        */
+
+        func_ptr(arg0, arg1);
+
+       /*
+        * If we are here, processor is woken up!
+        */
+
+       if (cpu_is_omap1510()) {
+               /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
+               omap_writew(omap_readw(ULPD_POWER_CTRL) &
+                           ~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+       } else if (cpu_is_omap16xx()) {
+               /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
+               omap_writew(omap_readw(ULPD_POWER_CTRL) &
+                           ~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+       }
+
+
+       /* Restore DSP clocks */
+       omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
+       __raw_writew(save_dsp_idlect2, DSP_IDLECT2);
+       ARM_RESTORE(ARM_IDLECT2);
+
+       /*
+        * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
+        */
+
+       ARM_RESTORE(ARM_CKCTL);
+       ARM_RESTORE(ARM_EWUPCT);
+       ARM_RESTORE(ARM_RSTCT1);
+       ARM_RESTORE(ARM_RSTCT2);
+       ARM_RESTORE(ARM_SYSST);
+       ULPD_RESTORE(ULPD_CLOCK_CTRL);
+       ULPD_RESTORE(ULPD_STATUS_REQ);
+
+       if (cpu_is_omap1510()) {
+               MPUI1510_RESTORE(MPUI_CTRL);
+               MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
+               MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
+               MPUI1510_RESTORE(EMIFS_CONFIG);
+               MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
+               MPUI1510_RESTORE(OMAP_IH1_MIR);
+               MPUI1510_RESTORE(OMAP_IH2_MIR);
+       } else if (cpu_is_omap16xx()) {
+               MPUI1610_RESTORE(MPUI_CTRL);
+               MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
+               MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
+               MPUI1610_RESTORE(EMIFS_CONFIG);
+               MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
+
+               MPUI1610_RESTORE(OMAP_IH1_MIR);
+               MPUI1610_RESTORE(OMAP_IH2_0_MIR);
+               MPUI1610_RESTORE(OMAP_IH2_1_MIR);
+               MPUI1610_RESTORE(OMAP_IH2_2_MIR);
+               MPUI1610_RESTORE(OMAP_IH2_3_MIR);
+       }
+
+       /*
+        * Reenable interrupts
+        */
+
+       local_irq_enable();
+       local_fiq_enable();
+
+       printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
+
+       if (machine_is_omap_osk()) {
+               /* Let LED1 (D9) blink again */
+               tps65010_set_led(LED1, BLINK);
+       }
+}
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+static int g_read_completed;
+
+/*
+ * Read system PM registers for debugging
+ */
+static int omap_pm_read_proc(
+       char *page_buffer,
+       char **my_first_byte,
+       off_t virtual_start,
+       int length,
+       int *eof,
+       void *data)
+{
+       int my_buffer_offset = 0;
+       char * const my_base = page_buffer;
+
+       ARM_SAVE(ARM_CKCTL);
+       ARM_SAVE(ARM_IDLECT1);
+       ARM_SAVE(ARM_IDLECT2);
+       ARM_SAVE(ARM_EWUPCT);
+       ARM_SAVE(ARM_RSTCT1);
+       ARM_SAVE(ARM_RSTCT2);
+       ARM_SAVE(ARM_SYSST);
+
+       ULPD_SAVE(ULPD_IT_STATUS);
+       ULPD_SAVE(ULPD_CLOCK_CTRL);
+       ULPD_SAVE(ULPD_SOFT_REQ);
+       ULPD_SAVE(ULPD_STATUS_REQ);
+       ULPD_SAVE(ULPD_DPLL_CTRL);
+       ULPD_SAVE(ULPD_POWER_CTRL);
+
+       if (cpu_is_omap1510()) {
+               MPUI1510_SAVE(MPUI_CTRL);
+               MPUI1510_SAVE(MPUI_DSP_STATUS);
+               MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+               MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+               MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+               MPUI1510_SAVE(EMIFS_CONFIG);
+       } else if (cpu_is_omap16xx()) {
+               MPUI1610_SAVE(MPUI_CTRL);
+               MPUI1610_SAVE(MPUI_DSP_STATUS);
+               MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+               MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+               MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+               MPUI1610_SAVE(EMIFS_CONFIG);
+       }
+
+       if (virtual_start == 0) {
+               g_read_completed = 0;
+
+               my_buffer_offset += sprintf(my_base + my_buffer_offset,
+                  "ARM_CKCTL_REG:            0x%-8x     \n"
+                  "ARM_IDLECT1_REG:          0x%-8x     \n"
+                  "ARM_IDLECT2_REG:          0x%-8x     \n"
+                  "ARM_EWUPCT_REG:           0x%-8x     \n"
+                  "ARM_RSTCT1_REG:           0x%-8x     \n"
+                  "ARM_RSTCT2_REG:           0x%-8x     \n"
+                  "ARM_SYSST_REG:            0x%-8x     \n"
+                  "ULPD_IT_STATUS_REG:       0x%-4x     \n"
+                  "ULPD_CLOCK_CTRL_REG:      0x%-4x     \n"
+                  "ULPD_SOFT_REQ_REG:        0x%-4x     \n"
+                  "ULPD_DPLL_CTRL_REG:       0x%-4x     \n"
+                  "ULPD_STATUS_REQ_REG:      0x%-4x     \n"
+                  "ULPD_POWER_CTRL_REG:      0x%-4x     \n",
+                  ARM_SHOW(ARM_CKCTL),
+                  ARM_SHOW(ARM_IDLECT1),
+                  ARM_SHOW(ARM_IDLECT2),
+                  ARM_SHOW(ARM_EWUPCT),
+                  ARM_SHOW(ARM_RSTCT1),
+                  ARM_SHOW(ARM_RSTCT2),
+                  ARM_SHOW(ARM_SYSST),
+                  ULPD_SHOW(ULPD_IT_STATUS),
+                  ULPD_SHOW(ULPD_CLOCK_CTRL),
+                  ULPD_SHOW(ULPD_SOFT_REQ),
+                  ULPD_SHOW(ULPD_DPLL_CTRL),
+                  ULPD_SHOW(ULPD_STATUS_REQ),
+                  ULPD_SHOW(ULPD_POWER_CTRL));
+
+               if (cpu_is_omap1510()) {
+                       my_buffer_offset += sprintf(my_base + my_buffer_offset,
+                          "MPUI1510_CTRL_REG             0x%-8x \n"
+                          "MPUI1510_DSP_STATUS_REG:      0x%-8x \n"
+                          "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+                          "MPUI1510_DSP_API_CONFIG_REG:  0x%-8x \n"
+                          "MPUI1510_SDRAM_CONFIG_REG:    0x%-8x \n"
+                          "MPUI1510_EMIFS_CONFIG_REG:    0x%-8x \n",
+                          MPUI1510_SHOW(MPUI_CTRL),
+                          MPUI1510_SHOW(MPUI_DSP_STATUS),
+                          MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
+                          MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
+                          MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
+                          MPUI1510_SHOW(EMIFS_CONFIG));
+               } else if (cpu_is_omap16xx()) {
+                       my_buffer_offset += sprintf(my_base + my_buffer_offset,
+                          "MPUI1610_CTRL_REG             0x%-8x \n"
+                          "MPUI1610_DSP_STATUS_REG:      0x%-8x \n"
+                          "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+                          "MPUI1610_DSP_API_CONFIG_REG:  0x%-8x \n"
+                          "MPUI1610_SDRAM_CONFIG_REG:    0x%-8x \n"
+                          "MPUI1610_EMIFS_CONFIG_REG:    0x%-8x \n",
+                          MPUI1610_SHOW(MPUI_CTRL),
+                          MPUI1610_SHOW(MPUI_DSP_STATUS),
+                          MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
+                          MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
+                          MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
+                          MPUI1610_SHOW(EMIFS_CONFIG));
+               }
+
+               g_read_completed++;
+       } else if (g_read_completed >= 1) {
+                *eof = 1;
+                return 0;
+       }
+       g_read_completed++;
+
+       *my_first_byte = page_buffer;
+       return  my_buffer_offset;
+}
+
+static void omap_pm_init_proc(void)
+{
+       struct proc_dir_entry *entry;
+
+       entry = create_proc_read_entry("driver/omap_pm",
+                                      S_IWUSR | S_IRUGO, NULL,
+                                      omap_pm_read_proc, 0);
+}
+
+#endif /* DEBUG && CONFIG_PROC_FS */
+
+/*
+ *     omap_pm_prepare - Do preliminary suspend work.
+ *     @state:         suspend state we're entering.
+ *
+ */
+//#include <asm/arch/hardware.h>
+
+static int omap_pm_prepare(u32 state)
+{
+       int error = 0;
+
+       switch (state)
+       {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               break;
+
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+
+       default:
+               return -EINVAL;
+       }
+
+       return error;
+}
+
+
+/*
+ *     omap_pm_enter - Actually enter a sleep state.
+ *     @state:         State we're entering.
+ *
+ */
+
+static int omap_pm_enter(u32 state)
+{
+       switch (state)
+       {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               omap_pm_suspend();
+               break;
+
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+/**
+ *     omap_pm_finish - Finish up suspend sequence.
+ *     @state:         State we're coming out of.
+ *
+ *     This is called after we wake back up (or if entering the sleep state
+ *     failed).
+ */
+
+static int omap_pm_finish(u32 state)
+{
+       return 0;
+}
+
+
+struct pm_ops omap_pm_ops ={
+       .pm_disk_mode = 0,
+        .prepare        = omap_pm_prepare,
+        .enter          = omap_pm_enter,
+        .finish         = omap_pm_finish,
+};
+
+static int __init omap_pm_init(void)
+{
+       printk("Power Management for TI OMAP.\n");
+       pm_idle = omap_pm_idle;
+       /*
+        * We copy the assembler sleep/wakeup routines to SRAM.
+        * These routines need to be in SRAM as that's the only
+        * memory the MPU can see when it wakes up.
+        */
+
+#ifdef CONFIG_ARCH_OMAP1510
+       if (cpu_is_omap1510()) {
+               memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND,
+                      omap1510_idle_loop_suspend,
+                      omap1510_idle_loop_suspend_sz);
+               memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend,
+                      omap1510_cpu_suspend_sz);
+       } else
+#endif
+       if (cpu_is_omap1610() || cpu_is_omap1710()) {
+               memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND,
+                      omap1610_idle_loop_suspend,
+                      omap1610_idle_loop_suspend_sz);
+               memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend,
+                      omap1610_cpu_suspend_sz);
+       } else if (cpu_is_omap5912()) {
+               memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND,
+                      omap1610_idle_loop_suspend,
+                      omap1610_idle_loop_suspend_sz);
+               memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend,
+                      omap1610_cpu_suspend_sz);
+       }
+
+       pm_set_ops(&omap_pm_ops);
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+       omap_pm_init_proc();
+#endif
+
+       return 0;
+}
+__initcall(omap_pm_init);
+
diff --git a/arch/arm/mach-omap/sleep.S b/arch/arm/mach-omap/sleep.S
new file mode 100644 (file)
index 0000000..4d426d1
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * linux/arch/arm/mach-omap/sleep.S
+ *
+ * Low-level OMAP1510/1610 sleep/wakeUp support
+ *
+ * Initial SA1110 code:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Adapted for PXA by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS 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 AUTHOR 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.
+ *
+ * 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/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/pm.h>
+
+               .text
+
+/*
+ * Forces OMAP into idle state
+ *
+ * omapXXXX_idle_loop_suspend()
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *      wakes up it continues execution at the point it went to sleep.
+ *
+ * Note: Because of slightly different configuration values we have
+ *       processor specific functions here.
+ */
+
+#ifdef CONFIG_ARCH_OMAP1510
+ENTRY(omap1510_idle_loop_suspend)
+
+       stmfd   sp!, {r0 - r12, lr}             @ save registers on stack
+
+       @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+       mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+       @ turn off clock domains
+       @ get ARM_IDLECT2 into r2
+       ldrh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       mov     r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
+       orr     r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+       strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+       @ request ARM idle
+       @ get ARM_IDLECT1 into r1
+       ldrh    r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+       orr     r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff
+       strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       mov     r5, #IDLE_WAIT_CYCLES & 0xff
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1510:        subs    r5, r5, #1
+       bne     l_1510
+/*
+ * Let's wait for the next clock tick to wake us up.
+ */
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c0, 4           @ wait for interrupt
+/*
+ * omap1510_idle_loop_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+
+       @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
+       @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
+       strh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       strh    r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
+
+ENTRY(omap1510_idle_loop_suspend_sz)
+       .word   . - omap1510_idle_loop_suspend
+#endif /* CONFIG_ARCH_OMAP1510 */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+ENTRY(omap1610_idle_loop_suspend)
+
+       stmfd   sp!, {r0 - r12, lr}             @ save registers on stack
+
+       @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+       mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+       @ turn off clock domains
+       @ get ARM_IDLECT2 into r2
+       ldrh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       mov     r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
+       orr     r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
+       strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+       @ request ARM idle
+       @ get ARM_IDLECT1 into r1
+       ldrh    r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+       orr     r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff
+       strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       mov     r5, #IDLE_WAIT_CYCLES & 0xff
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1610:        subs    r5, r5, #1
+       bne     l_1610
+/*
+ * Let's wait for the next clock tick to wake us up.
+ */
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c0, 4           @ wait for interrupt
+/*
+ * omap1610_idle_loop_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+
+       @ restore ARM_IDLECT1 and ARM_IDLECT2 and return
+       @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
+       strh    r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       strh    r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
+
+ENTRY(omap1610_idle_loop_suspend_sz)
+       .word   . - omap1610_idle_loop_suspend
+#endif /* CONFIG_ARCH_OMAP16XX */
+
+/*
+ * Forces OMAP into deep sleep state
+ *
+ * omapXXXX_cpu_suspend()
+ *
+ * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
+ * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
+ * in register r1.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *      wakes up it continues execution at the point it went to sleep.
+ *
+ * Note: Because of errata work arounds we have processor specific functions
+ *       here. They are mostly the same, but slightly different.
+ *
+ */
+
+#ifdef CONFIG_ARCH_OMAP1510
+ENTRY(omap1510_cpu_suspend)
+
+       @ save registers on stack
+       stmfd   sp!, {r0 - r12, lr}
+
+       @ load base address of Traffic Controller
+       mov     r4, #TCMIF_ASM_BASE & 0xff000000
+       orr     r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
+       orr     r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+
+       @ work around errata of OMAP1510 PDE bit for TC shut down
+       @ clear PDE bit
+       ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+       bic     r5, r5, #PDE_BIT & 0xff
+       str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+       @ set PWD_EN bit
+       and     r5, r5, #PWD_EN_BIT & 0xff
+       str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+       @ prepare to put SDRAM into self-refresh manually
+       ldr     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+       orr     r5, r5, #SELF_REFRESH_MODE & 0xff000000
+       orr     r5, r5, #SELF_REFRESH_MODE & 0x000000ff
+       str     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+       @ prepare to put EMIFS to Sleep
+       ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+       orr     r5, r5, #IDLE_EMIFS_REQUEST & 0xff
+       str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+       @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+       mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+       @ turn off clock domains
+       mov     r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
+       orr     r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+       strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+       @ request ARM idle
+       mov     r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
+       orr     r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
+       strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       mov     r5, #IDLE_WAIT_CYCLES & 0xff
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1510_2:
+       subs    r5, r5, #1
+       bne     l_1510_2
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+       mov     r2, #0
+       mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
+/*
+ * omap1510_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+       strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       @ restore regs and return
+       ldmfd   sp!, {r0 - r12, pc}
+
+ENTRY(omap1510_cpu_suspend_sz)
+       .word   . - omap1510_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP1510 */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+ENTRY(omap1610_cpu_suspend)
+
+       @ save registers on stack
+       stmfd   sp!, {r0 - r12, lr}
+
+       @ load base address of Traffic Controller
+       mov     r4, #TCMIF_ASM_BASE & 0xff000000
+       orr     r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
+       orr     r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+
+       @ prepare to put SDRAM into self-refresh manually
+       ldr     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+       orr     r5, r5, #SELF_REFRESH_MODE & 0xff000000
+       orr     r5, r5, #SELF_REFRESH_MODE & 0x000000ff
+       str     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+       @ prepare to put EMIFS to Sleep
+       ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+       orr     r5, r5, #IDLE_EMIFS_REQUEST & 0xff
+       str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+       @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+       mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+       orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+       @ turn off clock domains
+       mov     r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
+       orr     r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
+       strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+       @ work around errata of OMAP1610/5912. Enable (!) peripheral
+       @ clock to let the chip go into deep sleep
+       ldrh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       orr     r5,r5, #EN_PERCK_BIT & 0xff
+       strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+       @ request ARM idle
+       mov     r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
+       orr     r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
+       strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       mov     r5, #IDLE_WAIT_CYCLES & 0xff
+       orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1610_2:
+       subs    r5, r5, #1
+       bne     l_1610_2
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+       mov     r2, #0
+       mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
+/*
+ * omap1610_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+       strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+       strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+       @ restore regs and return
+       ldmfd   sp!, {r0 - r12, pc}
+
+ENTRY(omap1610_cpu_suspend_sz)
+       .word   . - omap1610_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP16XX */
diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c
new file mode 100644 (file)
index 0000000..f3451d2
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * arch/arm/mach-omap/usb.c -- platform level USB initialization
+ *
+ * Copyright (C) 2004 Texas Instruments, 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.
+ *
+ * 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
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/usb_otg.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+
+/* These routines should handle the standard chip-specific modes
+ * for usb0/1/2 ports, covering basic mux and transceiver setup.
+ * Call omap_usb_init() once, from INIT_MACHINE().
+ *
+ * Some board-*.c files will need to set up additional mux options,
+ * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
+ */
+
+/* TESTED ON:
+ *  - 1611B H2 (with usb1 mini-AB)
+ *  - 1510 Innovator with built-in transceiver (custom cable feeding 5V VBUS)
+ *  - 1710 custom development board using alternate pin group
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP_OTG
+
+static struct otg_transceiver *xceiv;
+
+/**
+ * otg_get_transceiver - find the (single) OTG transceiver driver
+ *
+ * Returns the transceiver driver, after getting a refcount to it; or
+ * null if there is no such transceiver.  The caller is responsible for
+ * releasing that count.
+ */
+struct otg_transceiver *otg_get_transceiver(void)
+{
+       if (xceiv)
+               get_device(xceiv->dev);
+       return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+       if (xceiv && x)
+               return -EBUSY;
+       xceiv = x;
+       return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
+{
+       u32     syscon1 = 0;
+
+       if (nwires == 0) {
+               USB_TRANSCEIVER_CTRL_REG &= ~(1 << 3);
+               return 0;
+       }
+
+       /*
+        * VP and VM are needed for all active usb0 configurations.
+        * USB0_VP and USB0_VM are always set on 1510, there's no muxing
+        * available for them.
+        */
+       if (nwires >= 2 && !cpu_is_omap1510()) {
+               omap_cfg_reg(AA9_USB0_VP);
+               omap_cfg_reg(R9_USB0_VM);
+       }
+
+       /* internal transceiver */
+       if (nwires == 2) {
+               if (cpu_is_omap1510()) {
+                       /* This works for OHCI on 1510-Innovator, nothing to mux */
+                       return 0;
+               }
+
+#if 0
+               /* NOTE:  host OR device mode for now, no OTG */
+               USB_TRANSCEIVER_CTRL_REG &= ~(3 << 4);
+               if (is_device) {
+                       omap_cfg_reg(W4_USB_PUEN);
+                       omap_cfg_reg(R18_1510_USB_GPIO0);
+                       // omap_cfg_reg(USB0_VBUS);
+                       // omap_cfg_reg(USB0_PUEN);
+                       // USB_TRANSCEIVER_CTRL_REG.CONF_USB0_PORT_R = 7
+                       // when USB0_PUEN is needed
+               } else /* host mode needs D+ and D- pulldowns */
+                       USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
+               return 3 << 16;
+#else
+               /* FIXME: 1610 needs to return the right value here */
+               printk(KERN_ERR "usb0 internal transceiver, nyet\n");
+               return 0;
+#endif
+       }
+
+       /* alternate pin config, external transceiver */
+       omap_cfg_reg(V6_USB0_TXD);
+       omap_cfg_reg(W9_USB0_TXEN);
+       omap_cfg_reg(W5_USB0_SE0);
+
+#ifdef CONFIG_ARCH_OMAP_USB_SPEED
+       /* FIXME: there's good chance that pin V9 is used for MMC2 port cmddir */
+       omap_cfg_reg(V9_USB0_SPEED);
+       // omap_cfg_reg(V9_USB0_SUSP);
+#endif
+
+       if (nwires != 3)
+               omap_cfg_reg(Y5_USB0_RCV);
+
+       switch (nwires) {
+       case 3:
+               syscon1 = 2;
+               break;
+       case 4:
+               syscon1 = 1;
+               break;
+       case 6:
+               syscon1 = 3;
+               /* REVISIT: Is CONF_USB2_UNI_R only needed when nwires = 6? */
+               USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+               break;
+       default:
+               printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+                       0, nwires);
+       }
+       return syscon1 << 16;
+}
+
+static u32 __init omap_usb1_init(unsigned nwires)
+{
+       u32     syscon1 = 0;
+
+       if (nwires != 6)
+               USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+       if (nwires == 0)
+               return 0;
+
+       /* external transceiver */
+       omap_cfg_reg(USB1_TXD);
+       omap_cfg_reg(USB1_TXEN);
+       if (cpu_is_omap1510()) {
+               omap_cfg_reg(USB1_SEO);
+               omap_cfg_reg(USB1_SPEED);
+               // SUSP
+       } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) {
+               omap_cfg_reg(W13_1610_USB1_SE0);
+               omap_cfg_reg(R13_1610_USB1_SPEED);
+               // SUSP
+       } else {
+               pr_debug("usb unrecognized\n");
+       }
+       if (nwires != 3)
+               omap_cfg_reg(USB1_RCV);
+
+       switch (nwires) {
+       case 3:
+               syscon1 = 2;
+               break;
+       case 4:
+               syscon1 = 1;
+               break;
+       case 6:
+               syscon1 = 3;
+               omap_cfg_reg(USB1_VP);
+               omap_cfg_reg(USB1_VM);
+               USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
+               break;
+       default:
+               printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+                       1, nwires);
+       }
+       return syscon1 << 20;
+}
+
+static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
+{
+       u32     syscon1 = 0;
+
+       if (alt_pingroup)
+               return 0;
+       if (nwires != 6)
+               USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
+       if (nwires == 0)
+               return 0;
+
+       /* external transceiver */
+       if (cpu_is_omap1510()) {
+               omap_cfg_reg(USB2_TXD);
+               omap_cfg_reg(USB2_TXEN);
+               omap_cfg_reg(USB2_SEO);
+               if (nwires != 3)
+                       omap_cfg_reg(USB2_RCV);
+       } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) {
+               omap_cfg_reg(V6_USB2_TXD);
+               omap_cfg_reg(W9_USB2_TXEN);
+               omap_cfg_reg(W5_USB2_SE0);
+               if (nwires != 3)
+                       omap_cfg_reg(Y5_USB2_RCV);
+       } else {
+               pr_debug("usb unrecognized\n");
+       }
+       // omap_cfg_reg(USB2_SUSP);
+       // FIXME omap_cfg_reg(USB2_SPEED);
+
+       switch (nwires) {
+       case 3:
+               syscon1 = 2;
+               break;
+       case 4:
+               syscon1 = 1;
+               break;
+       case 6:
+               syscon1 = 3;
+               if (cpu_is_omap1510()) {
+                       omap_cfg_reg(USB2_VP);
+                       omap_cfg_reg(USB2_VM);
+               } else {
+                       omap_cfg_reg(AA9_USB2_VP);
+                       omap_cfg_reg(R9_USB2_VM);
+               }
+               USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+               break;
+       default:
+               printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+                       2, nwires);
+       }
+       return syscon1 << 24;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if    defined(CONFIG_USB_GADGET_OMAP) || \
+       defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \
+       (defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG))
+static void usb_release(struct device *dev)
+{
+       /* normally not freed */
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_OMAP
+
+static struct resource udc_resources[] = {
+       /* order is significant! */
+       {               /* registers */
+               .start          = IO_ADDRESS(UDC_BASE),
+               .end            = IO_ADDRESS(UDC_BASE + 0xff),
+               .flags          = IORESOURCE_MEM,
+       }, {            /* general IRQ */
+               .start          = IH2_BASE + 20,
+               .flags          = IORESOURCE_IRQ,
+       }, {            /* PIO IRQ */
+               .start          = IH2_BASE + 30,
+               .flags          = IORESOURCE_IRQ,
+       }, {            /* SOF IRQ */
+               .start          = IH2_BASE + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device udc_device = {
+       .name           = "omap_udc",
+       .id             = -1,
+       .dev = {
+               .release                = usb_release,
+               .dma_mask               = &udc_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(udc_resources),
+       .resource       = udc_resources,
+};
+
+#endif
+
+#if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct resource ohci_resources[] = {
+       {
+               .start  = IO_ADDRESS(OMAP_OHCI_BASE),
+               .end    = IO_ADDRESS(OMAP_OHCI_BASE + 4096),
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = INT_USB_HHC_1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ohci_device = {
+       .name                   = "ohci",
+       .id                     = -1,
+       .dev = {
+               .release                = usb_release,
+               .dma_mask               = &ohci_dmamask,
+               .coherent_dma_mask      = 0x0fffffff,
+       },
+       .num_resources  = ARRAY_SIZE(ohci_resources),
+       .resource               = ohci_resources,
+};
+
+#endif
+
+#if    defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)
+
+static struct resource otg_resources[] = {
+       /* order is significant! */
+       {
+               .start          = IO_ADDRESS(OTG_BASE),
+               .end            = IO_ADDRESS(OTG_BASE + 0xff),
+               .flags          = IORESOURCE_MEM,
+       }, {
+               .start          = IH2_BASE + 8,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device otg_device = {
+       .name           = "omap_otg",
+       .id             = -1,
+       .dev = {
+               .release                = usb_release,
+       },
+       .num_resources  = ARRAY_SIZE(otg_resources),
+       .resource       = otg_resources,
+};
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+// FIXME correct answer depends on hmc_mode,
+// as does any nonzero value for config->otg port number
+#define        is_usb0_device(config)  0
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP_OTG
+
+void __init
+omap_otg_init(struct omap_usb_config *config)
+{
+       u32             syscon = OTG_SYSCON_1_REG & 0xffff;
+       int             status;
+       int             alt_pingroup = 0;
+
+       /* NOTE:  no bus or clock setup (yet?) */
+
+       syscon = OTG_SYSCON_1_REG & 0xffff;
+       if (!(syscon & OTG_RESET_DONE))
+               pr_debug("USB resets not complete?\n");
+
+       // OTG_IRQ_EN_REG = 0;
+
+       /* pin muxing and transceiver pinouts */
+       if (config->pins[0] > 2)        /* alt pingroup 2 */
+               alt_pingroup = 1;
+       syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config));
+       syscon |= omap_usb1_init(config->pins[1]);
+       syscon |= omap_usb2_init(config->pins[2], alt_pingroup);
+       pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
+       OTG_SYSCON_1_REG = syscon;
+
+       syscon = config->hmc_mode;
+       syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
+       if (config->otg || config->register_host)
+               syscon |= UHOST_EN;
+#ifdef CONFIG_USB_OTG
+       if (config->otg)
+               syscon |= OTG_EN;
+#endif
+       pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
+       OTG_SYSCON_2_REG = syscon;
+
+       printk("USB: hmc %d", config->hmc_mode);
+       if (alt_pingroup)
+               printk(", usb2 alt %d wires", config->pins[2]);
+       else if (config->pins[0])
+               printk(", usb0 %d wires%s", config->pins[2],
+                       is_usb0_device(config) ? " (dev)" : "");
+       if (config->pins[1])
+               printk(", usb1 %d wires", config->pins[1]);
+       if (!alt_pingroup && config->pins[2])
+               printk(", usb2 %d wires", config->pins[2]);
+       if (config->otg)
+               printk(", Mini-AB on usb%d", config->otg - 1);
+       printk("\n");
+
+       /* don't clock unused USB controllers  */
+       syscon = OTG_SYSCON_1_REG;
+       syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
+
+#ifdef CONFIG_USB_GADGET_OMAP
+       if (config->otg || config->register_dev) {
+               syscon &= ~DEV_IDLE_EN;
+               udc_device.dev.platform_data = config;
+               status = platform_device_register(&udc_device);
+               if (status)
+                       pr_debug("can't register UDC device, %d\n", status);
+       }
+#endif
+
+#if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+       if (config->otg || config->register_host) {
+               syscon &= ~HST_IDLE_EN;
+               ohci_device.dev.platform_data = config;
+               status = platform_device_register(&ohci_device);
+               if (status)
+                       pr_debug("can't register OHCI device, %d\n", status);
+       }
+#endif
+
+#ifdef CONFIG_USB_OTG
+       if (config->otg) {
+               syscon &= ~OTG_IDLE_EN;
+               if (cpu_is_omap730())
+                       otg_resources[1].start = INT_730_USB_OTG;
+               status = platform_device_register(&otg_device);
+               // ...
+       }
+#endif
+       pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
+       OTG_SYSCON_1_REG = syscon;
+
+       status = 0;
+}
+
+#else
+static inline void omap_otg_init(struct omap_usb_config *config) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP1510
+
+static void __init omap_1510_usb_init(struct omap_usb_config *config)
+{
+       int status;
+       unsigned int val;
+
+       omap_usb0_init(config->pins[0], is_usb0_device(config));
+       omap_usb1_init(config->pins[1]);
+       omap_usb2_init(config->pins[2], 0);
+
+       val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1);
+       val |= (config->hmc_mode << 1);
+       omap_writel(val, MOD_CONF_CTRL_0);
+
+       // FIXME this has a UDC controller too
+
+#if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+       if (config->otg || config->register_host) {
+               ohci_device.dev.platform_data = config;
+               status = platform_device_register(&ohci_device);
+               if (status)
+                       pr_debug("can't register OHCI device, %d\n", status);
+       }
+       // FIXME completely untested ...
+#endif
+
+}
+
+#else
+static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static struct omap_usb_config platform_data;
+
+static int __init
+omap_usb_init(void)
+{
+       const struct omap_usb_config *config;
+
+       config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config);
+       if (config == NULL) {
+               printk(KERN_ERR "USB: No board-specific platform config found\n");
+               return -ENODEV;
+       }
+       platform_data = *config;
+
+       if (cpu_is_omap730()
+                       || cpu_is_omap1610()
+                       || cpu_is_omap1710()
+                       || cpu_is_omap5912())
+               omap_otg_init(&platform_data);
+       else if (cpu_is_omap1510())
+               omap_1510_usb_init(&platform_data);
+       else {
+               printk(KERN_ERR "USB: No init for your chip yet\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+subsys_initcall(omap_usb_init);
diff --git a/arch/arm/mach-pxa/Makefile.boot b/arch/arm/mach-pxa/Makefile.boot
new file mode 100644 (file)
index 0000000..1ead671
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-y  := 0xa0008000
+
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
new file mode 100644 (file)
index 0000000..50132a7
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ *  linux/arch/arm/mach-pxa/ssp.c
+ *
+ *  based on linux/arch/arm/mach-sa1100/ssp.c by Russell King
+ *
+ *  Copyright (C) 2003 Russell King.
+ *  Copyright (C) 2003 Wolfson Microelectronics PLC
+ *
+ * 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.
+ *
+ *  PXA2xx SSP driver.  This provides the generic core for simple
+ *  IO-based SSP applications and allows easy port setup for DMA access.
+ *
+ *  Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ *
+ *  Revision history:
+ *   22nd Aug 2003 Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/arch/ssp.h>
+#include <asm/arch/pxa-regs.h>
+
+static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct ssp_dev *dev = (struct ssp_dev*) dev_id;
+       unsigned int status = SSSR_P(dev->port);
+
+       SSSR_P(dev->port) = status; /* clear status bits */
+
+       if (status & SSSR_ROR)
+               printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
+
+       if (status & SSSR_TUR)
+               printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port);
+
+       if (status & SSSR_BCE)
+               printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * ssp_write_word - write a word to the SSP port
+ * @data: 32-bit, MSB justified data to write.
+ *
+ * Wait for a free entry in the SSP transmit FIFO, and write a data
+ * word to the SSP port.
+ *
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ *   %-ETIMEDOUT       timeout occurred (for future)
+ *   0                 success
+ */
+int ssp_write_word(struct ssp_dev *dev, u32 data)
+{
+       while (!(SSSR_P(dev->port) & SSSR_TNF))
+               cpu_relax();
+
+       SSDR_P(dev->port) = data;
+
+       return 0;
+}
+
+/**
+ * ssp_read_word - read a word from the SSP port
+ *
+ * Wait for a data word in the SSP receive FIFO, and return the
+ * received data.  Data is LSB justified.
+ *
+ * Note: Currently, if data is not expected to be received, this
+ * function will wait for ever.
+ *
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ *   %-ETIMEDOUT       timeout occurred (for future)
+ *   32-bit data       success
+ */
+int ssp_read_word(struct ssp_dev *dev)
+{
+       while (!(SSSR_P(dev->port) & SSSR_RNE))
+               cpu_relax();
+
+       return SSDR_P(dev->port);
+}
+
+/**
+ * ssp_flush - flush the transmit and receive FIFOs
+ *
+ * Wait for the SSP to idle, and ensure that the receive FIFO
+ * is empty.
+ *
+ * The caller is expected to perform the necessary locking.
+ */
+void ssp_flush(struct ssp_dev *dev)
+{
+       do {
+               while (SSSR_P(dev->port) & SSSR_RNE) {
+                       (void) SSDR_P(dev->port);
+               }
+       } while (SSSR_P(dev->port) & SSSR_BSY);
+}
+
+/**
+ * ssp_enable - enable the SSP port
+ *
+ * Turn on the SSP port.
+ */
+void ssp_enable(struct ssp_dev *dev)
+{
+       SSCR0_P(dev->port) |= SSCR0_SSE;
+}
+
+/**
+ * ssp_disable - shut down the SSP port
+ *
+ * Turn off the SSP port, optionally powering it down.
+ */
+void ssp_disable(struct ssp_dev *dev)
+{
+       SSCR0_P(dev->port) &= ~SSCR0_SSE;
+}
+
+/**
+ * ssp_save_state - save the SSP configuration
+ * @ssp: pointer to structure to save SSP configuration
+ *
+ * Save the configured SSP state for suspend.
+ */
+void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
+{
+       ssp->cr0 = SSCR0_P(dev->port);
+       ssp->cr1 = SSCR1_P(dev->port);
+       ssp->to = SSTO_P(dev->port);
+       ssp->psp = SSPSP_P(dev->port);
+
+       SSCR0_P(dev->port) &= ~SSCR0_SSE;
+}
+
+/**
+ * ssp_restore_state - restore a previously saved SSP configuration
+ * @ssp: pointer to configuration saved by ssp_save_state
+ *
+ * Restore the SSP configuration saved previously by ssp_save_state.
+ */
+void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
+{
+       SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE;
+
+       SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE;
+       SSCR1_P(dev->port) = ssp->cr1;
+       SSTO_P(dev->port) = ssp->to;
+       SSPSP_P(dev->port) = ssp->psp;
+
+       SSCR0_P(dev->port) = ssp->cr0;
+}
+
+/**
+ * ssp_init - setup the SSP port
+ *
+ * initialise and claim resources for the SSP port.
+ *
+ * Returns:
+ *   %-ENODEV  if the SSP port is unavailable
+ *   %-EBUSY   if the resources are already in use
+ *   %0                on success
+ */
+int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
+                                               u32 speed)
+{
+       int ret, irq;
+
+       if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+               return -EBUSY;
+       }
+
+       switch (port) {
+               case 1:
+                       irq = IRQ_SSP;
+                       break;
+#if defined (CONFIG_PXA27x)
+               case 2:
+                       irq = IRQ_SSP2;
+                       break;
+               case 3:
+                       irq = IRQ_SSP3;
+                       break;
+#else
+               case 2:
+                       irq = IRQ_NSSP;
+                       break;
+               case 3:
+                       irq = IRQ_ASSP;
+                       break;
+#endif
+               default:
+                       return -ENODEV;
+       }
+
+       dev->port = port;
+       dev->mode = mode;
+       dev->flags = flags;
+       dev->psp_flags = psp_flags;
+       dev->speed = speed;
+
+       /* set up port type, speed, port settings */
+       SSCR0_P(dev->port) = (dev->speed | dev->mode);
+       SSCR1_P(dev->port) = dev->flags;
+       SSPSP_P(dev->port) = dev->psp_flags;
+
+       ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
+       if (ret)
+               goto out_region;
+
+       /* turn on SSP port clock */
+       switch (dev->port) {
+#if defined (CONFIG_PXA27x)
+               case 1:
+                       pxa_set_cken(CKEN23_SSP1, 1);
+                       break;
+               case 2:
+                       pxa_set_cken(CKEN3_SSP2, 1);
+                       break;
+               case 3:
+                       pxa_set_cken(CKEN4_SSP3, 1);
+                       break;
+#else
+               case 1:
+                       pxa_set_cken(CKEN3_SSP, 1);
+                       break;
+               case 2:
+                       pxa_set_cken(CKEN9_NSSP, 1);
+                       break;
+               case 3:
+                       pxa_set_cken(CKEN10_ASSP, 1);
+                       break;
+#endif
+       }
+
+       return 0;
+
+out_region:
+       release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+       return ret;
+}
+
+/**
+ * ssp_exit - undo the effects of ssp_init
+ *
+ * release and free resources for the SSP port.
+ */
+void ssp_exit(struct ssp_dev *dev)
+{
+       int irq;
+
+       SSCR0_P(dev->port) &= ~SSCR0_SSE;
+
+       /* find irq, save power and turn off SSP port clock */
+       switch (dev->port) {
+#if defined (CONFIG_PXA27x)
+               case 1:
+                       irq = IRQ_SSP;
+                       pxa_set_cken(CKEN23_SSP1, 0);
+                       break;
+               case 2:
+                       irq = IRQ_SSP2;
+                       pxa_set_cken(CKEN3_SSP2, 0);
+                       break;
+               case 3:
+                       irq = IRQ_SSP3;
+                       pxa_set_cken(CKEN4_SSP3, 0);
+                       break;
+#else
+               case 1:
+                       irq = IRQ_SSP;
+                       pxa_set_cken(CKEN3_SSP, 0);
+                       break;
+               case 2:
+                       irq = IRQ_NSSP;
+                       pxa_set_cken(CKEN9_NSSP, 0);
+                       break;
+               case 3:
+                       irq = IRQ_ASSP;
+                       pxa_set_cken(CKEN10_ASSP, 0);
+                       break;
+#endif
+               default:
+                       printk(KERN_WARNING "SSP: tried to close invalid port\n");
+                       return;
+       }
+
+       free_irq(irq, dev);
+       release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+}
+
+EXPORT_SYMBOL(ssp_write_word);
+EXPORT_SYMBOL(ssp_read_word);
+EXPORT_SYMBOL(ssp_flush);
+EXPORT_SYMBOL(ssp_enable);
+EXPORT_SYMBOL(ssp_disable);
+EXPORT_SYMBOL(ssp_save_state);
+EXPORT_SYMBOL(ssp_restore_state);
+EXPORT_SYMBOL(ssp_init);
+EXPORT_SYMBOL(ssp_exit);
diff --git a/arch/arm/mach-rpc/Makefile.boot b/arch/arm/mach-rpc/Makefile.boot
new file mode 100644 (file)
index 0000000..9c9e768
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x10008000
+params_phys-y  := 0x10000100
+initrd_phys-y  := 0x18000000
+
diff --git a/arch/arm/mach-s3c2410/Makefile.boot b/arch/arm/mach-s3c2410/Makefile.boot
new file mode 100644 (file)
index 0000000..7dab2a0
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y  := 0x30008000
+params_phys-y  := 0x30000100
+
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
new file mode 100644 (file)
index 0000000..a12ade7
--- /dev/null
@@ -0,0 +1,310 @@
+/* linux/arch/arm/mach-s3c2410/clock.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Clock control support
+ *
+ * Based on, and code from linux/arch/arm/mach-versatile/clock.c
+ **
+ **  Copyright (C) 2004 ARM Limited.
+ **  Written by Deep Blue Solutions Limited.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/hardware/clock.h>
+#include <asm/arch/regs-clock.h>
+
+#include "clock.h"
+
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+
+
+/* old functions */
+
+void s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
+{
+       unsigned long clkcon;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       clkcon = __raw_readl(S3C2410_CLKCON);
+       clkcon &= ~clocks;
+
+       if (enable)
+               clkcon |= clocks;
+
+       __raw_writel(clkcon, S3C2410_CLKCON);
+
+       local_irq_restore(flags);
+}
+
+
+/* Clock API calls */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       struct clk *p;
+       struct clk *clk = ERR_PTR(-ENOENT);
+
+       down(&clocks_sem);
+       list_for_each_entry(p, &clocks, list) {
+               if (strcmp(id, p->name) == 0 &&
+                   try_module_get(p->owner)) {
+                       clk = p;
+                       break;
+               }
+       }
+       up(&clocks_sem);
+
+       return clk;
+}
+
+void clk_put(struct clk *clk)
+{
+       module_put(clk->owner);
+}
+
+int clk_enable(struct clk *clk)
+{
+       if (clk->ctrlbit != 0)
+               s3c2410_clk_enable(clk->ctrlbit, 1);
+
+       return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+       s3c2410_clk_enable(clk->ctrlbit, 0);
+}
+
+
+int clk_use(struct clk *clk)
+{
+       atomic_inc(&clk->used);
+       return 0;
+}
+
+
+void clk_unuse(struct clk *clk)
+{
+       atomic_dec(&clk->used);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (clk->parent != NULL)
+               return clk->parent->rate;
+
+       return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       return rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       return -EINVAL;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+       return clk->parent;
+}
+
+EXPORT_SYMBOL(clk_get);
+EXPORT_SYMBOL(clk_put);
+EXPORT_SYMBOL(clk_enable);
+EXPORT_SYMBOL(clk_disable);
+EXPORT_SYMBOL(clk_use);
+EXPORT_SYMBOL(clk_unuse);
+EXPORT_SYMBOL(clk_get_rate);
+EXPORT_SYMBOL(clk_round_rate);
+EXPORT_SYMBOL(clk_set_rate);
+EXPORT_SYMBOL(clk_get_parent);
+
+/* base clocks */
+
+static struct clk clk_f = {
+       .name          = "fclk",
+       .rate          = 0,
+       .parent        = NULL,
+       .ctrlbit       = 0
+};
+
+static struct clk clk_h = {
+       .name          = "hclk",
+       .rate          = 0,
+       .parent        = NULL,
+       .ctrlbit       = 0
+};
+
+static struct clk clk_p = {
+       .name          = "pclk",
+       .rate          = 0,
+       .parent        = NULL,
+       .ctrlbit       = 0
+};
+
+/* clock definitions */
+
+static struct clk init_clocks[] = {
+       { .name    = "nand",
+         .parent  = &clk_h,
+         .ctrlbit = S3C2410_CLKCON_NAND
+       },
+       { .name    = "lcd",
+         .parent  = &clk_h,
+         .ctrlbit = S3C2410_CLKCON_LCDC
+       },
+       { .name    = "usb-host",
+         .parent  = &clk_h,
+         .ctrlbit =   S3C2410_CLKCON_USBH
+       },
+       { .name    = "usb-device",
+         .parent  = &clk_h,
+         .ctrlbit = S3C2410_CLKCON_USBD
+       },
+       { .name    = "timers",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_PWMT
+       },
+       { .name    = "sdi",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_SDI
+       },
+       { .name    = "uart0",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_UART0
+       },
+       { .name    = "uart1",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_UART1
+       },
+       { .name    = "uart2",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_UART2
+       },
+       { .name    = "gpio",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_GPIO
+       },
+       { .name    = "rtc",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_RTC
+       },
+       { .name    = "adc",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_ADC
+       },
+       { .name    = "i2c",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_IIC
+       },
+       { .name    = "iis",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_IIS
+       },
+       { .name    = "spi",
+         .parent  = &clk_p,
+         .ctrlbit = S3C2410_CLKCON_SPI
+       },
+       { .name    = "watchdog",
+         .parent  = &clk_p,
+         .ctrlbit = 0
+       }
+};
+
+/* initialise the clock system */
+
+int s3c2410_register_clock(struct clk *clk)
+{
+       clk->owner = THIS_MODULE;
+       atomic_set(&clk->used, 0);
+
+       /* add to the list of available clocks */
+
+       down(&clocks_sem);
+       list_add(&clk->list, &clocks);
+       up(&clocks_sem);
+
+       return 0;
+}
+
+/* initalise all the clocks */
+
+static int __init s3c2410_init_clocks(void)
+{
+       struct clk *clkp = init_clocks;
+       int ptr;
+       int ret;
+
+       printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n");
+
+       /* initialise the main system clocks */
+
+       clk_h.rate = s3c2410_hclk;
+       clk_p.rate = s3c2410_pclk;
+       clk_f.rate = s3c2410_fclk;
+
+       /* set the enabled clocks to a minimal (known) state */
+       __raw_writel(S3C2410_CLKCON_PWMT | S3C2410_CLKCON_UART0 | S3C2410_CLKCON_UART1 | S3C2410_CLKCON_UART2 | S3C2410_CLKCON_GPIO | S3C2410_CLKCON_RTC, S3C2410_CLKCON);
+
+       /* register our clocks */
+
+       if (s3c2410_register_clock(&clk_f) < 0)
+               printk(KERN_ERR "failed to register cpu fclk\n");
+
+       if (s3c2410_register_clock(&clk_h) < 0)
+               printk(KERN_ERR "failed to register cpu hclk\n");
+
+       if (s3c2410_register_clock(&clk_p) < 0)
+               printk(KERN_ERR "failed to register cpu pclk\n");
+
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+               ret = s3c2410_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       return 0;
+}
+
+arch_initcall(s3c2410_init_clocks);
+
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
new file mode 100644 (file)
index 0000000..4c7b94e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * linux/arch/arm/mach-s3c2410/clock.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Written by Ben Dooks, <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct clk {
+       struct list_head      list;
+       struct module        *owner;
+       struct clk           *parent;
+       const char           *name;
+       atomic_t              used;
+       unsigned long         rate;
+       unsigned long         ctrlbit;
+};
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
new file mode 100644 (file)
index 0000000..42eec79
--- /dev/null
@@ -0,0 +1,152 @@
+/* linux/arch/arm/mach-s3c2410/cpu.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX CPU 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/regs-gpio.h>
+
+#include "cpu.h"
+#include "s3c2410.h"
+#include "s3c2440.h"
+
+struct cpu_table {
+       unsigned long   idcode;
+       unsigned long   idmask;
+       void            (*map_io)(struct map_desc *mach_desc, int size);
+       int             (*init)(void);
+       const char      *name;
+};
+
+/* table of supported CPUs */
+
+static const char name_s3c2410[]  = "S3C2410";
+static const char name_s3c2440[]  = "S3C2440";
+static const char name_s3c2410a[] = "S3C2410A";
+static const char name_s3c2440a[] = "S3C2440A";
+
+static struct cpu_table cpu_ids[] __initdata = {
+       {
+               .idcode = 0x32410000,
+               .idmask = 0xffffffff,
+               .map_io = s3c2410_map_io,
+               .init   = s3c2410_init,
+               .name   = name_s3c2410
+       },
+       {
+               .idcode = 0x3241002,
+               .idmask = 0xffffffff,
+               .map_io = s3c2410_map_io,
+               .init   = s3c2410_init,
+               .name   = name_s3c2410a
+       },
+       {
+               .idcode = 0x32440000,
+               .idmask = 0xffffffff,
+               .map_io = s3c2440_map_io,
+               .init   = s3c2440_init,
+               .name   = name_s3c2440
+       },
+       {
+               .idcode = 0x32440001,
+               .idmask = 0xffffffff,
+               .map_io = s3c2440_map_io,
+               .init   = s3c2440_init,
+               .name   = name_s3c2440a
+       }
+};
+
+/* minimal IO mapping */
+
+static struct map_desc s3c_iodesc[] __initdata = {
+       IODESC_ENT(GPIO),
+       IODESC_ENT(IRQ),
+       IODESC_ENT(MEMCTRL),
+       IODESC_ENT(UART)
+};
+
+
+static struct cpu_table *
+s3c_lookup_cpu(unsigned long idcode)
+{
+       struct cpu_table *tab;
+       int count;
+
+       tab = cpu_ids;
+       for (count = 0; count < ARRAY_SIZE(cpu_ids); count++) {
+               if ((idcode & tab->idmask) == tab->idcode)
+                       return tab;
+       }
+
+       return NULL;
+}
+
+static struct cpu_table *cpu;
+
+void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
+{
+       unsigned long idcode;
+
+       /* initialise the io descriptors we need for initialisation */
+       iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
+
+       idcode = __raw_readl(S3C2410_GSTATUS1);
+       cpu = s3c_lookup_cpu(idcode);
+
+       if (cpu == NULL) {
+               printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
+               panic("Unknown S3C24XX CPU");
+       }
+
+       if (cpu->map_io == NULL || cpu->init == NULL) {
+               printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
+               panic("Unsupported S3C24XX CPU");
+       }
+
+       printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
+
+       (cpu->map_io)(mach_desc, size);
+}
+
+static int __init s3c_arch_init(void)
+{
+       // do the correct init for cpu
+
+       if (cpu == NULL)
+               panic("s3c_arch_init: NULL cpu\n");
+
+       return (cpu->init)();
+}
+
+arch_initcall(s3c_arch_init);
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
new file mode 100644 (file)
index 0000000..b0053d7
--- /dev/null
@@ -0,0 +1,41 @@
+/* arch/arm/mach-s3c2410/cpu.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for S3C24XX CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ *     24-Aug-2004 BJD  Start of generic S3C24XX support
+*/
+
+#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE }
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
+
+#ifdef CONFIG_CPU_S3C2410
+extern  int s3c2410_init(void);
+extern void s3c2410_map_io(struct map_desc *mach_desc, int size);
+#else
+#define s3c2410_map_io NULL
+#define s3c2410_init NULL
+#endif
+
+#ifdef CONFIG_CPU_S3C2440
+extern  int s3c2440_init(void);
+extern void s3c2440_map_io(struct map_desc *mach_desc, int size);
+#else
+#define s3c2440_map_io NULL
+#define s3c2440_init NULL
+#endif
+
+extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
+
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
new file mode 100644 (file)
index 0000000..7cf560c
--- /dev/null
@@ -0,0 +1,442 @@
+/* linux/arch/arm/mach-s3c2410/devs.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Base S3C2410 platform device definitions
+ *
+ * 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.
+ *
+ * Modifications:
+ *     29-Aug-2004 BJD  Added timers 0 through 3
+ *     29-Aug-2004 BJD  Changed index of devices we only have one of to -1
+ *     21-Aug-2004 BJD  Added IRQ_TICK to RTC resources
+ *     18-Aug-2004 BJD  Created initial version
+*/
+
+#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/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "devs.h"
+
+/* USB Host Controller */
+
+static struct resource s3c_usb_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_USBHOST,
+               .end   = S3C2410_PA_USBHOST + S3C2410_SZ_USBHOST,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_USBH,
+               .end   = IRQ_USBH,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 s3c_device_usb_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_usb = {
+       .name             = "s3c2410-ohci",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_usb_resource),
+       .resource         = s3c_usb_resource,
+       .dev              = {
+               .dma_mask = &s3c_device_usb_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c_device_usb);
+
+/* LCD Controller */
+
+static struct resource s3c_lcd_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_LCD,
+               .end   = S3C2410_PA_LCD + S3C2410_SZ_LCD,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_LCD,
+               .end   = IRQ_LCD,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_lcd = {
+       .name             = "s3c2410-lcd",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_lcd_resource),
+       .resource         = s3c_lcd_resource,
+       .dev              = {
+               .dma_mask = &s3c_device_lcd_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c_device_lcd);
+
+/* NAND Controller */
+
+static struct resource s3c_nand_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_NAND,
+               .end   = S3C2410_PA_NAND + S3C2410_SZ_NAND,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+struct platform_device s3c_device_nand = {
+       .name             = "s3c2410-nand",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_nand_resource),
+       .resource         = s3c_nand_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_nand);
+
+/* USB Device (Gadget)*/
+
+static struct resource s3c_usbgadget_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_USBDEV,
+               .end   = S3C2410_PA_USBDEV + S3C2410_SZ_USBDEV,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_USBD,
+               .end   = IRQ_USBD,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_usbgadget = {
+       .name             = "s3c2410-usbgadget",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_usbgadget_resource),
+       .resource         = s3c_usbgadget_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_usbgadget);
+
+/* Watchdog */
+
+static struct resource s3c_wdt_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_WATCHDOG,
+               .end   = S3C2410_PA_WATCHDOG + S3C2410_SZ_WATCHDOG,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_WDT,
+               .end   = IRQ_WDT,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_wdt = {
+       .name             = "s3c2410-wdt",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_wdt_resource),
+       .resource         = s3c_wdt_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_wdt);
+
+/* I2C */
+
+static struct resource s3c_i2c_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_IIC,
+               .end   = S3C2410_PA_IIC + S3C2410_SZ_IIC,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_IIC,
+               .end   = IRQ_IIC,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_i2c = {
+       .name             = "s3c2410-i2c",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_i2c_resource),
+       .resource         = s3c_i2c_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_i2c);
+
+/* IIS */
+
+static struct resource s3c_iis_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_IIS,
+               .end   = S3C2410_PA_IIS + S3C2410_SZ_IIS,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+static u64 s3c_device_iis_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_iis = {
+       .name             = "s3c2410-iis",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_iis_resource),
+       .resource         = s3c_iis_resource,
+       .dev              = {
+               .dma_mask = &s3c_device_iis_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c_device_iis);
+
+/* RTC */
+
+static struct resource s3c_rtc_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_RTC,
+               .end   = S3C2410_PA_RTC + 0xff,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_RTC,
+               .end   = IRQ_RTC,
+               .flags = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start = IRQ_TICK,
+               .end   = IRQ_TICK,
+               .flags = IORESOURCE_IRQ
+       }
+};
+
+struct platform_device s3c_device_rtc = {
+       .name             = "s3c2410-rtc",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_rtc_resource),
+       .resource         = s3c_rtc_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_rtc);
+
+/* ADC */
+
+static struct resource s3c_adc_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_ADC,
+               .end   = S3C2410_PA_ADC + S3C2410_SZ_ADC,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TC,
+               .end   = IRQ_ADC,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_adc = {
+       .name             = "s3c2410-adc",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_adc_resource),
+       .resource         = s3c_adc_resource,
+};
+
+/* SDI */
+
+static struct resource s3c_sdi_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_SDI,
+               .end   = S3C2410_PA_SDI + S3C2410_SZ_SDI,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_SDI,
+               .end   = IRQ_SDI,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_sdi = {
+       .name             = "s3c2410-sdi",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_sdi_resource),
+       .resource         = s3c_sdi_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_sdi);
+
+/* SPI (0) */
+
+static struct resource s3c_spi0_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_SPI,
+               .end   = S3C2410_PA_SPI + 0x1f,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_spi0 = {
+       .name             = "s3c2410-spi",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s3c_spi0_resource),
+       .resource         = s3c_spi0_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_spi0);
+
+/* SPI (1) */
+
+static struct resource s3c_spi1_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_SPI + 0x20,
+               .end   = S3C2410_PA_SPI + 0x20 + 0x1f,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_spi1 = {
+       .name             = "s3c2410-spi",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s3c_spi1_resource),
+       .resource         = s3c_spi1_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_spi1);
+
+/* pwm timer blocks */
+
+static struct resource s3c_timer0_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_TIMER + 0x0C,
+               .end   = S3C2410_PA_TIMER + 0x0C + 0xB,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TIMER0,
+               .end   = IRQ_TIMER0,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_timer0 = {
+       .name             = "s3c2410-timer",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s3c_timer0_resource),
+       .resource         = s3c_timer0_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_timer0);
+
+/* timer 1 */
+
+static struct resource s3c_timer1_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_TIMER + 0x18,
+               .end   = S3C2410_PA_TIMER + 0x23,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TIMER1,
+               .end   = IRQ_TIMER1,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_timer1 = {
+       .name             = "s3c2410-timer",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s3c_timer1_resource),
+       .resource         = s3c_timer1_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_timer1);
+
+/* timer 2 */
+
+static struct resource s3c_timer2_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_TIMER + 0x24,
+               .end   = S3C2410_PA_TIMER + 0x2F,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TIMER2,
+               .end   = IRQ_TIMER2,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_timer2 = {
+       .name             = "s3c2410-timer",
+       .id               = 2,
+       .num_resources    = ARRAY_SIZE(s3c_timer2_resource),
+       .resource         = s3c_timer2_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_timer2);
+
+/* timer 3 */
+
+static struct resource s3c_timer3_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_TIMER + 0x30,
+               .end   = S3C2410_PA_TIMER + 0x3B,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_TIMER3,
+               .end   = IRQ_TIMER3,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+struct platform_device s3c_device_timer3 = {
+       .name             = "s3c2410-timer",
+       .id               = 3,
+       .num_resources    = ARRAY_SIZE(s3c_timer3_resource),
+       .resource         = s3c_timer3_resource,
+};
+
+EXPORT_SYMBOL(s3c_device_timer3);
diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h
new file mode 100644 (file)
index 0000000..08a4416
--- /dev/null
@@ -0,0 +1,36 @@
+/* arch/arm/mach-s3c2410/devs.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2410 standard platform devices
+ *
+ * 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.
+ *
+ * Modifications:
+ *      18-Aug-2004 BJD  Created initial version
+ *     27-Aug-2004 BJD  Added timers 0 through 3
+*/
+
+extern struct platform_device s3c_device_usb;
+extern struct platform_device s3c_device_lcd;
+extern struct platform_device s3c_device_wdt;
+extern struct platform_device s3c_device_i2c;
+extern struct platform_device s3c_device_iis;
+extern struct platform_device s3c_device_rtc;
+extern struct platform_device s3c_device_adc;
+extern struct platform_device s3c_device_sdi;
+
+extern struct platform_device s3c_device_spi0;
+extern struct platform_device s3c_device_spi1;
+
+extern struct platform_device s3c_device_nand;
+
+extern struct platform_device s3c_device_timer0;
+extern struct platform_device s3c_device_timer1;
+extern struct platform_device s3c_device_timer2;
+extern struct platform_device s3c_device_timer3;
+
+extern struct platform_device s3c_device_usbgadget;
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
new file mode 100644 (file)
index 0000000..819e5af
--- /dev/null
@@ -0,0 +1,1085 @@
+/* linux/arch/arm/mach-bast/dma.c
+ *
+ * (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 DMA core
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * 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:
+ *  08-Aug-2004 BJD  Apply rmk's suggestions
+ *  21-Jul-2004 BJD  Ported to linux 2.6
+ *  12-Jul-2004 BJD  Finished re-write and change of API
+ *  06-Jul-2004 BJD  Rewrote dma code to try and cope with various problems
+ *  23-May-2003 BJD  Created file
+ *  19-Aug-2003 BJD  Cleanup, header fix, added URL
+ *
+ * This file is based on the Sangwook Lee/Samsung patches, re-written due
+ * to various ommisions from the code (such as flexible dma configuration)
+ * for use with the BAST system board.
+ *
+ * The re-write is pretty much complete, and should be good enough for any
+ * possible DMA function
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_S3C2410_DMA_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/mach/dma.h>
+#include <asm/arch/map.h>
+
+/* io map for dma */
+static void *dma_base;
+
+/* dma channel state information */
+s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
+
+/* debugging functions */
+
+#define BUF_MAGIC (0xcafebabe)
+
+#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
+
+#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
+
+#if 1
+#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
+#else
+static inline void
+dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val)
+{
+       pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
+       writel(val, dma_regaddr(chan, reg));
+}
+
+#endif
+
+#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
+
+/* captured register state for debug */
+
+struct s3c2410_dma_regstate {
+       unsigned long         dcsrc;
+       unsigned long         disrc;
+       unsigned long         dstat;
+       unsigned long         dcon;
+       unsigned long         dmsktrig;
+};
+
+#ifdef CONFIG_S3C2410_DMA_DEBUG
+
+/* dmadbg_showregs
+ *
+ * simple debug routine to print the current state of the dma registers
+*/
+
+static void
+dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
+{
+       regs->dcsrc    = dma_rdreg(chan, S3C2410_DMA_DCSRC);
+       regs->disrc    = dma_rdreg(chan, S3C2410_DMA_DISRC);
+       regs->dstat    = dma_rdreg(chan, S3C2410_DMA_DSTAT);
+       regs->dcon     = dma_rdreg(chan, S3C2410_DMA_DCON);
+       regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+}
+
+static void
+dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
+                struct s3c2410_dma_regstate *regs)
+{
+       printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
+              chan->number, fname, line,
+              regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
+              regs->dcon);
+}
+
+static void
+dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
+{
+       struct s3c2410_dma_regstate state;
+
+       dmadbg_capture(chan, &state);
+
+       printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
+              chan->number, fname, line, chan->load_state,
+              chan->curr, chan->next, chan->end);
+
+       dmadbg_showregs(fname, line, chan, &state);
+}
+
+#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
+#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
+#else
+#define dbg_showregs(chan) do { } while(0)
+#define dbg_showchan(chan) do { } while(0)
+#endif /* CONFIG_S3C2410_DMA_DEBUG */
+
+#define check_channel(chan) \
+  do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
+    printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
+    return -EINVAL; \
+  } } while(0)
+
+
+/* s3c2410_dma_stats_timeout
+ *
+ * Update DMA stats from timeout info
+*/
+
+static void
+s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val)
+{
+       if (stats == NULL)
+               return;
+
+       if (val > stats->timeout_longest)
+               stats->timeout_longest = val;
+       if (val < stats->timeout_shortest)
+               stats->timeout_shortest = val;
+
+       stats->timeout_avg += val;
+}
+
+/* s3c2410_dma_waitforload
+ *
+ * wait for the DMA engine to load a buffer, and update the state accordingly
+*/
+
+static int
+s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line)
+{
+       int timeout = chan->load_timeout;
+       int took;
+
+       if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
+               printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
+               return 0;
+       }
+
+       if (chan->stats != NULL)
+               chan->stats->loads++;
+
+       while (--timeout > 0) {
+               if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
+                       took = chan->load_timeout - timeout;
+
+                       s3c2410_dma_stats_timeout(chan->stats, took);
+
+                       switch (chan->load_state) {
+                       case S3C2410_DMALOAD_1LOADED:
+                               chan->load_state = S3C2410_DMALOAD_1RUNNING;
+                               break;
+
+                       default:
+                               printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
+                       }
+
+                       return 1;
+               }
+       }
+
+       if (chan->stats != NULL) {
+               chan->stats->timeout_failed++;
+       }
+
+       return 0;
+}
+
+
+
+/* s3c2410_dma_loadbuffer
+ *
+ * load a buffer, and update the channel state
+*/
+
+static inline int
+s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan,
+                      s3c2410_dma_buf_t *buf)
+{
+       unsigned long reload;
+
+       pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
+                buf, (unsigned long)buf->data, buf->size);
+
+       if (buf == NULL) {
+               dmawarn("buffer is NULL\n");
+               return -EINVAL;
+       }
+
+       /* check the state of the channel before we do anything */
+
+       if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+               dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
+       }
+
+       if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
+               dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
+       }
+
+       /* it would seem sensible if we are the last buffer to not bother
+        * with the auto-reload bit, so that the DMA engine will not try
+        * and load another transfer after this one has finished...
+        */
+       if (chan->load_state == S3C2410_DMALOAD_NONE) {
+               pr_debug("load_state is none, checking for noreload (next=%p)\n",
+                        buf->next);
+               reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
+       } else {
+               pr_debug("load_state is %d => autoreload\n", chan->load_state);
+               reload = S3C2410_DCON_AUTORELOAD;
+       }
+
+       writel(buf->data, chan->addr_reg);
+
+       dma_wrreg(chan, S3C2410_DMA_DCON,
+                 chan->dcon | reload | (buf->size/chan->xfer_unit));
+
+       chan->next = buf->next;
+
+       /* update the state of the channel */
+
+       switch (chan->load_state) {
+       case S3C2410_DMALOAD_NONE:
+               chan->load_state = S3C2410_DMALOAD_1LOADED;
+               break;
+
+       case S3C2410_DMALOAD_1RUNNING:
+               chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
+               break;
+
+       default:
+               dmawarn("dmaload: unknown state %d in loadbuffer\n",
+                       chan->load_state);
+               break;
+       }
+
+       return 0;
+}
+
+/* s3c2410_dma_call_op
+ *
+ * small routine to call the op routine with the given op if it has been
+ * registered
+*/
+
+static void
+s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op)
+{
+       if (chan->op_fn != NULL) {
+               (chan->op_fn)(chan, op);
+       }
+}
+
+/* s3c2410_dma_buffdone
+ *
+ * small wrapper to check if callback routine needs to be called, and
+ * if so, call it
+*/
+
+static inline void
+s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf,
+                    s3c2410_dma_buffresult_t result)
+{
+       pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
+                chan->callback_fn, buf, buf->id, buf->size, result);
+
+       if (chan->callback_fn != NULL) {
+               (chan->callback_fn)(chan, buf->id, buf->size, result);
+       }
+}
+
+/* s3c2410_dma_start
+ *
+ * start a dma channel going
+*/
+
+static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
+{
+       unsigned long tmp;
+       unsigned long flags;
+
+       pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
+
+       local_irq_save(flags);
+
+       if (chan->state == S3C2410_DMA_RUNNING) {
+               pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
+               local_irq_restore(flags);
+               return 0;
+       }
+
+       chan->state = S3C2410_DMA_RUNNING;
+
+       /* check wether there is anything to load, and if not, see
+        * if we can find anything to load
+        */
+
+       if (chan->load_state == S3C2410_DMALOAD_NONE) {
+               if (chan->next == NULL) {
+                       printk(KERN_ERR "dma%d: channel has nothing loaded\n",
+                              chan->number);
+                       chan->state = S3C2410_DMA_IDLE;
+                       local_irq_restore(flags);
+                       return -EINVAL;
+               }
+
+               s3c2410_dma_loadbuffer(chan, chan->next);
+       }
+
+       dbg_showchan(chan);
+
+       /* enable the channel */
+
+       if (!chan->irq_enabled) {
+               enable_irq(chan->irq);
+               chan->irq_enabled = 1;
+       }
+
+       /* start the channel going */
+
+       tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+       tmp &= ~S3C2410_DMASKTRIG_STOP;
+       tmp |= S3C2410_DMASKTRIG_ON;
+       dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+
+       pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
+
+#if 0
+       /* the dma buffer loads should take care of clearing the AUTO
+        * reloading feature */
+       tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+       tmp &= ~S3C2410_DCON_NORELOAD;
+       dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+#endif
+
+       s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
+
+       dbg_showchan(chan);
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+/* s3c2410_dma_canload
+ *
+ * work out if we can queue another buffer into the DMA engine
+*/
+
+static int
+s3c2410_dma_canload(s3c2410_dma_chan_t *chan)
+{
+       if (chan->load_state == S3C2410_DMALOAD_NONE ||
+           chan->load_state == S3C2410_DMALOAD_1RUNNING)
+               return 1;
+
+       return 0;
+}
+
+
+/* s3c2410_dma_enqueue
+ *
+ * queue an given buffer for dma transfer.
+ *
+ * id         the device driver's id information for this buffer
+ * data       the physical address of the buffer data
+ * size       the size of the buffer in bytes
+ *
+ * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
+ * is checked, and if set, the channel is started. If this flag isn't set,
+ * then an error will be returned.
+ *
+ * It is possible to queue more than one DMA buffer onto a channel at
+ * once, and the code will deal with the re-loading of the next buffer
+ * when necessary.
+*/
+
+int s3c2410_dma_enqueue(unsigned int channel, void *id,
+                       dma_addr_t data, int size)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+       s3c2410_dma_buf_t *buf;
+       unsigned long flags;
+
+       check_channel(channel);
+
+       pr_debug("%s: id=%p, data=%08x, size=%d\n",
+                __FUNCTION__, id, (unsigned int)data, size);
+
+       buf = (s3c2410_dma_buf_t *)kmalloc(sizeof(*buf), GFP_ATOMIC);
+       if (buf == NULL) {
+               pr_debug("%s: out of memory (%d alloc)\n",
+                        __FUNCTION__, sizeof(*buf));
+               return -ENOMEM;
+       }
+
+       pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
+
+       //dbg_showchan(chan);
+
+       buf->next  = NULL;
+       buf->data  = buf->ptr = data;
+       buf->size  = size;
+       buf->id    = id;
+       buf->magic = BUF_MAGIC;
+
+       local_irq_save(flags);
+
+       if (chan->curr == NULL) {
+               /* we've got nothing loaded... */
+               pr_debug("%s: buffer %p queued onto empty channel\n",
+                        __FUNCTION__, buf);
+
+               chan->curr = buf;
+               chan->end  = buf;
+               chan->next = NULL;
+       } else {
+               pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
+                        chan->number, __FUNCTION__, buf);
+
+               if (chan->end == NULL)
+                       pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
+                                chan->number, __FUNCTION__, chan);
+
+               chan->end->next = buf;
+               chan->end = buf;
+       }
+
+       /* if necessary, update the next buffer field */
+       if (chan->next == NULL)
+               chan->next = buf;
+
+       /* check to see if we can load a buffer */
+       if (chan->state == S3C2410_DMA_RUNNING) {
+               if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
+                       if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+                               printk(KERN_ERR "dma%d: loadbuffer:"
+                                      "timeout loading buffer\n",
+                                      chan->number);
+                               dbg_showchan(chan);
+                               local_irq_restore(flags);
+                               return -EINVAL;
+                       }
+               }
+
+               while (s3c2410_dma_canload(chan) && chan->next != NULL) {
+                       s3c2410_dma_loadbuffer(chan, chan->next);
+               }
+       } else if (chan->state == S3C2410_DMA_IDLE) {
+               if (chan->flags & S3C2410_DMAF_AUTOSTART) {
+                       s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
+               } else {
+                       printk(KERN_DEBUG "dma%d: cannot load onto stopped channel'n", chan->number);
+                       local_irq_restore(flags);
+                       return -EINVAL;
+               }
+       }
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+static inline void
+s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
+{
+       int magicok = (buf->magic == BUF_MAGIC);
+
+       buf->magic = -1;
+
+       if (magicok) {
+               kfree(buf);
+       } else {
+               printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
+       }
+}
+
+/* s3c2410_dma_lastxfer
+ *
+ * called when the system is out of buffers, to ensure that the channel
+ * is prepared for shutdown.
+*/
+
+static inline void
+s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
+{
+       pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
+                chan->number, chan->load_state);
+
+       switch (chan->load_state) {
+       case S3C2410_DMALOAD_NONE:
+               break;
+
+       case S3C2410_DMALOAD_1LOADED:
+               if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+                               /* flag error? */
+                       printk(KERN_ERR "dma%d: timeout waiting for load\n",
+                              chan->number);
+                       return;
+               }
+               break;
+
+       default:
+               pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
+                        chan->number, chan->load_state);
+               return;
+
+       }
+
+       /* hopefully this'll shut the damned thing up after the transfer... */
+       dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
+}
+
+
+#define dmadbg2(x...)
+
+static irqreturn_t
+s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
+{
+       s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw;
+       s3c2410_dma_buf_t  *buf;
+
+       buf = chan->curr;
+
+       dbg_showchan(chan);
+
+       /* modify the channel state */
+
+       switch (chan->load_state) {
+       case S3C2410_DMALOAD_1RUNNING:
+               /* TODO - if we are running only one buffer, we probably
+                * want to reload here, and then worry about the buffer
+                * callback */
+
+               chan->load_state = S3C2410_DMALOAD_NONE;
+               break;
+
+       case S3C2410_DMALOAD_1LOADED:
+               /* iirc, we should go back to NONE loaded here, we
+                * had a buffer, and it was never verified as being
+                * loaded.
+                */
+
+               chan->load_state = S3C2410_DMALOAD_NONE;
+               break;
+
+       case S3C2410_DMALOAD_1LOADED_1RUNNING:
+               /* we'll worry about checking to see if another buffer is
+                * ready after we've called back the owner. This should
+                * ensure we do not wait around too long for the DMA
+                * engine to start the next transfer
+                */
+
+               chan->load_state = S3C2410_DMALOAD_1LOADED;
+               break;
+
+       case S3C2410_DMALOAD_NONE:
+               printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
+                      chan->number);
+               break;
+
+       default:
+               printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
+                      chan->number, chan->load_state);
+               break;
+       }
+
+       if (buf != NULL) {
+               /* update the chain to make sure that if we load any more
+                * buffers when we call the callback function, things should
+                * work properly */
+
+               chan->curr = buf->next;
+               buf->next  = NULL;
+
+               if (buf->magic != BUF_MAGIC) {
+                       printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
+                              chan->number, __FUNCTION__, buf);
+                       return IRQ_HANDLED;
+               }
+
+               s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
+
+               /* free resouces */
+               s3c2410_dma_freebuf(buf);
+       } else {
+       }
+
+       if (chan->next != NULL) {
+               unsigned long flags;
+
+               switch (chan->load_state) {
+               case S3C2410_DMALOAD_1RUNNING:
+                       /* don't need to do anything for this state */
+                       break;
+
+               case S3C2410_DMALOAD_NONE:
+                       /* can load buffer immediately */
+                       break;
+
+               case S3C2410_DMALOAD_1LOADED:
+                       if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+                               /* flag error? */
+                               printk(KERN_ERR "dma%d: timeout waiting for load\n",
+                                      chan->number);
+                               return IRQ_HANDLED;
+                       }
+
+                       break;
+
+               default:
+                       printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
+                              chan->number, chan->load_state);
+                       return IRQ_HANDLED;
+               }
+
+               local_irq_save(flags);
+               s3c2410_dma_loadbuffer(chan, chan->next);
+               local_irq_restore(flags);
+       } else {
+               s3c2410_dma_lastxfer(chan);
+
+               /* see if we can stop this channel.. */
+               if (chan->load_state == S3C2410_DMALOAD_NONE) {
+                       pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
+                                chan->number, jiffies);
+                       s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+
+
+/* s3c2410_request_dma
+ *
+ * get control of an dma channel
+*/
+
+int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
+                       void *dev)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+       unsigned long flags;
+       int err;
+
+       pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
+                channel, client->name, dev);
+
+       check_channel(channel);
+
+       local_irq_save(flags);
+
+       dbg_showchan(chan);
+
+       if (chan->in_use) {
+               if (client != chan->client) {
+                       printk(KERN_ERR "dma%d: already in use\n", channel);
+                       local_irq_restore(flags);
+                       return -EBUSY;
+               } else {
+                       printk(KERN_ERR "dma%d: client already has channel\n", channel);
+               }
+       }
+
+       chan->client = client;
+       chan->in_use = 1;
+
+       if (!chan->irq_claimed) {
+               pr_debug("dma%d: %s : requesting irq %d\n",
+                        channel, __FUNCTION__, chan->irq);
+
+               err = request_irq(chan->irq, s3c2410_dma_irq, SA_INTERRUPT,
+                                 client->name, (void *)chan);
+
+               if (err) {
+                       chan->in_use = 0;
+                       local_irq_restore(flags);
+
+                       printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
+                              client->name, chan->irq, chan->number);
+                       return err;
+               }
+
+               chan->irq_claimed = 1;
+               chan->irq_enabled = 1;
+       }
+
+       local_irq_restore(flags);
+
+       /* need to setup */
+
+       pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
+
+       return 0;
+}
+
+/* s3c2410_dma_free
+ *
+ * release the given channel back to the system, will stop and flush
+ * any outstanding transfers, and ensure the channel is ready for the
+ * next claimant.
+ *
+ * Note, although a warning is currently printed if the freeing client
+ * info is not the same as the registrant's client info, the free is still
+ * allowed to go through.
+*/
+
+int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+       unsigned long flags;
+
+       check_channel(channel);
+
+       local_irq_save(flags);
+
+
+       if (chan->client != client) {
+               printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
+                      channel, chan->client, client);
+       }
+
+       /* sort out stopping and freeing the channel */
+
+       if (chan->state != S3C2410_DMA_IDLE) {
+               pr_debug("%s: need to stop dma channel %p\n",
+                      __FUNCTION__, chan);
+
+               /* possibly flush the channel */
+               s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
+       }
+
+       chan->client = NULL;
+       chan->in_use = 0;
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
+{
+       unsigned long tmp;
+       unsigned long flags;
+
+       pr_debug("%s:\n", __FUNCTION__);
+
+       dbg_showchan(chan);
+
+       local_irq_save(flags);
+
+       s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP);
+
+       tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+       tmp |= S3C2410_DMASKTRIG_STOP;
+       dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+
+#if 0
+       /* should also clear interrupts, according to WinCE BSP */
+       tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+       tmp |= S3C2410_DCON_NORELOAD;
+       dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+#endif
+
+       chan->state      = S3C2410_DMA_IDLE;
+       chan->load_state = S3C2410_DMALOAD_NONE;
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+/* s3c2410_dma_flush
+ *
+ * stop the channel, and remove all current and pending transfers
+*/
+
+static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
+{
+       s3c2410_dma_buf_t *buf, *next;
+       unsigned long flags;
+
+       pr_debug("%s:\n", __FUNCTION__);
+
+       local_irq_save(flags);
+
+       if (chan->state != S3C2410_DMA_IDLE) {
+               pr_debug("%s: stopping channel...\n", __FUNCTION__ );
+               s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
+       }
+
+       buf = chan->curr;
+       if (buf == NULL)
+               buf = chan->next;
+
+       chan->curr = chan->next = chan->end = NULL;
+
+       if (buf != NULL) {
+               for ( ; buf != NULL; buf = next) {
+                       next = buf->next;
+
+                       pr_debug("%s: free buffer %p, next %p\n",
+                              __FUNCTION__, buf, buf->next);
+
+                       s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
+                       s3c2410_dma_freebuf(buf);
+               }
+       }
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+
+int
+s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+
+       check_channel(channel);
+
+       switch (op) {
+       case S3C2410_DMAOP_START:
+               return s3c2410_dma_start(chan);
+
+       case S3C2410_DMAOP_STOP:
+               return s3c2410_dma_dostop(chan);
+
+       case S3C2410_DMAOP_PAUSE:
+               return -ENOENT;
+
+       case S3C2410_DMAOP_RESUME:
+               return -ENOENT;
+
+       case S3C2410_DMAOP_FLUSH:
+               return s3c2410_dma_flush(chan);
+
+       case S3C2410_DMAOP_TIMEOUT:
+               return 0;
+
+       }
+
+       return -ENOENT;      /* unknown, don't bother */
+}
+
+
+/* DMA configuration for each channel
+ *
+ * DISRCC -> source of the DMA (AHB,APB)
+ * DISRC  -> source address of the DMA
+ * DIDSTC -> destination of the DMA (AHB,APD)
+ * DIDST  -> destination address of the DMA
+*/
+
+/* s3c2410_dma_config
+ *
+ * xfersize:     size of unit in bytes (1,2,4)
+ * dcon:         base value of the DCONx register
+*/
+
+int s3c2410_dma_config(dmach_t channel,
+                      int xferunit,
+                      int dcon)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+
+       pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
+                __FUNCTION__, channel, xferunit, dcon);
+
+       check_channel(channel);
+
+       switch (xferunit) {
+       case 1:
+               dcon |= S3C2410_DCON_BYTE;
+               break;
+
+       case 2:
+               dcon |= S3C2410_DCON_HALFWORD;
+               break;
+
+       case 4:
+               dcon |= S3C2410_DCON_WORD;
+               break;
+
+       default:
+               pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
+               return -EINVAL;
+       }
+
+       dcon |= S3C2410_DCON_HWTRIG;
+       dcon |= S3C2410_DCON_INTREQ;
+
+       pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
+
+       chan->dcon = dcon;
+       chan->xfer_unit = xferunit;
+
+       return 0;
+}
+
+
+int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+
+       check_channel(channel);
+
+       pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
+
+       chan->flags = flags;
+
+       return 0;
+}
+
+/* do we need to protect the settings of the fields from
+ * irq?
+*/
+
+int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+
+       check_channel(channel);
+
+       pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
+
+       chan->op_fn = rtn;
+
+       return 0;
+}
+
+int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+
+       check_channel(channel);
+
+       pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
+
+       chan->callback_fn = rtn;
+
+       return 0;
+}
+
+/* s3c2410_dma_devconfig
+ *
+ * configure the dma source/destination hardware type and address
+ *
+ * source:    S3C2410_DMASRC_HW: source is hardware
+ *            S3C2410_DMASRC_MEM: source is memory
+ *
+ * hwcfg:     the value for xxxSTCn register,
+ *            bit 0: 0=increment pointer, 1=leave pointer
+ *            bit 1: 0=soucre is AHB, 1=soucre is APB
+ *
+ * devaddr:   physical address of the source
+*/
+
+int s3c2410_dma_devconfig(int channel,
+                         s3c2410_dmasrc_t source,
+                         int hwcfg,
+                         unsigned long devaddr)
+{
+       s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
+
+       check_channel(channel);
+
+       pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
+                __FUNCTION__, (int)source, hwcfg, devaddr);
+
+       chan->source = source;
+       chan->dev_addr = devaddr;
+
+       switch (source) {
+       case S3C2410_DMASRC_HW:
+               /* source is hardware */
+               pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
+                        __FUNCTION__, devaddr, hwcfg);
+               dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
+               dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);
+               dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
+
+               chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
+               return 0;
+
+       case S3C2410_DMASRC_MEM:
+               /* source is memory */
+               pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
+                         __FUNCTION__, devaddr, hwcfg);
+               dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
+               dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);
+               dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
+
+               chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
+               return 0;
+       }
+
+       printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
+       return -EINVAL;
+}
+
+/* initialisation code */
+
+static int __init s3c2410_init_dma(void)
+{
+       int channel;
+       s3c2410_dma_chan_t *cp;
+
+       printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
+
+       dma_base = ioremap(S3C2410_PA_DMA, 0x200);
+       if (dma_base == NULL) {
+               printk(KERN_ERR "dma failed to remap register block\n");
+               return -ENOMEM;
+       }
+
+       for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
+               cp = &s3c2410_chans[channel];
+
+               memset(cp, 0, sizeof(s3c2410_dma_chan_t));
+
+               /* dma channel irqs are in order.. */
+               cp->number = channel;
+               cp->irq    = channel + IRQ_DMA0;
+               cp->regs   = (unsigned long)dma_base + (channel*0x40);
+
+               /* point current stats somewhere */
+               cp->stats  = &cp->stats_store;
+               cp->stats_store.timeout_shortest = LONG_MAX;
+
+               /* basic channel configuration */
+
+               cp->load_timeout = 1<<18;
+
+               printk("DMA channel %d at %08lx, irq %d\n",
+                      cp->number, cp->regs, cp->irq);
+       }
+
+       return 0;
+}
+
+__initcall(s3c2410_init_dma);
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
new file mode 100644 (file)
index 0000000..c577c5f
--- /dev/null
@@ -0,0 +1,124 @@
+/* linux/arch/arm/mach-s3c2410/mach-rx3715.c
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.handhelds.org/projects/rx3715.html
+ *
+ * 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.
+ *
+ * Modifications:
+ *     16-Sep-2004 BJD Copied from mach-h1940.c
+ *     25-Oct-2004 BJD Updates for 2.6.10-rc1
+*/
+
+#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/tty.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "s3c2410.h"
+#include "s3c2440.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+#include "pm.h"
+
+static struct map_desc rx3715_iodesc[] __initdata = {
+       /* dump ISA space somewhere unused */
+
+       { S3C2410_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE },
+       { S3C2410_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE },
+};
+
+static struct s3c2410_uartcfg rx3715_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x00,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .uart_flags  = UPF_CONS_FLOW,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+       }
+};
+
+static struct platform_device *rx3715_devices[] __initdata = {
+       &s3c_device_usb,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c,
+       &s3c_device_iis,
+};
+
+static struct s3c24xx_board rx3715_board __initdata = {
+       .devices       = rx3715_devices,
+       .devices_count = ARRAY_SIZE(rx3715_devices)
+};
+
+void __init rx3715_map_io(void)
+{
+       s3c24xx_xtal = 16934000;
+
+       s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
+       s3c2440_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
+       s3c24xx_set_board(&rx3715_board);
+}
+
+void __init rx3715_init_irq(void)
+{
+       s3c2410_init_irq();
+}
+
+#ifdef CONFIG_PM
+static void __init rx3715_init_machine(void)
+{
+       s3c2410_pm_init();
+}
+#else
+#define rx3715_init_machine NULL
+#endif
+
+MACHINE_START(RX3715, "IPAQ-RX3715")
+     MAINTAINER("Ben Dooks <ben@fluff.org>")
+     BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART)
+     BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+     MAPIO(rx3715_map_io)
+     INITIRQ(rx3715_init_irq)
+     INIT_MACHINE(rx3715_init_machine)
+     .timer            = &s3c2410_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
new file mode 100644 (file)
index 0000000..ea7c25a
--- /dev/null
@@ -0,0 +1,667 @@
+/* linux/arch/arm/mach-s3c2410/pm.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Power Manager (Suspend-To-RAM) support
+ *
+ * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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
+ *
+ * Parts based on arch/arm/mach-pxa/pm.c
+ *
+ * Thanks to Dimitry Andric for debugging
+*/
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/crc32.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-irq.h>
+
+#include <asm/mach/time.h>
+
+#include "pm.h"
+
+/* for external use */
+
+unsigned long s3c_pm_flags;
+
+/* cache functions from arch/arm/mm/proc-arm920.S */
+
+extern void arm920_flush_kern_cache_all(void);
+
+#define PFX "s3c24xx-pm: "
+
+static struct sleep_save core_save[] = {
+       SAVE_ITEM(S3C2410_LOCKTIME),
+       SAVE_ITEM(S3C2410_CLKCON),
+
+       /* we restore the timings here, with the proviso that the board
+        * brings the system up in an slower, or equal frequency setting
+        * to the original system.
+        *
+        * if we cannot guarantee this, then things are going to go very
+        * wrong here, as we modify the refresh and both pll settings.
+        */
+
+       SAVE_ITEM(S3C2410_BWSCON),
+       SAVE_ITEM(S3C2410_BANKCON0),
+       SAVE_ITEM(S3C2410_BANKCON1),
+       SAVE_ITEM(S3C2410_BANKCON2),
+       SAVE_ITEM(S3C2410_BANKCON3),
+       SAVE_ITEM(S3C2410_BANKCON4),
+       SAVE_ITEM(S3C2410_BANKCON5),
+
+       SAVE_ITEM(S3C2410_CLKDIVN),
+       SAVE_ITEM(S3C2410_MPLLCON),
+       SAVE_ITEM(S3C2410_UPLLCON),
+       SAVE_ITEM(S3C2410_CLKSLOW),
+       SAVE_ITEM(S3C2410_REFRESH),
+};
+
+/* this lot should be really saved by the IRQ code */
+static struct sleep_save irq_save[] = {
+       SAVE_ITEM(S3C2410_EXTINT0),
+       SAVE_ITEM(S3C2410_EXTINT1),
+       SAVE_ITEM(S3C2410_EXTINT2),
+       SAVE_ITEM(S3C2410_EINFLT0),
+       SAVE_ITEM(S3C2410_EINFLT1),
+       SAVE_ITEM(S3C2410_EINFLT2),
+       SAVE_ITEM(S3C2410_EINFLT3),
+       SAVE_ITEM(S3C2410_EINTMASK),
+       SAVE_ITEM(S3C2410_INTMSK)
+};
+
+static struct sleep_save gpio_save[] = {
+       SAVE_ITEM(S3C2410_GPACON),
+       SAVE_ITEM(S3C2410_GPADAT),
+
+       SAVE_ITEM(S3C2410_GPBCON),
+       SAVE_ITEM(S3C2410_GPBDAT),
+       SAVE_ITEM(S3C2410_GPBUP),
+
+       SAVE_ITEM(S3C2410_GPCCON),
+       SAVE_ITEM(S3C2410_GPCDAT),
+       SAVE_ITEM(S3C2410_GPCUP),
+
+       SAVE_ITEM(S3C2410_GPDCON),
+       SAVE_ITEM(S3C2410_GPDDAT),
+       SAVE_ITEM(S3C2410_GPDUP),
+
+       SAVE_ITEM(S3C2410_GPECON),
+       SAVE_ITEM(S3C2410_GPEDAT),
+       SAVE_ITEM(S3C2410_GPEUP),
+
+       SAVE_ITEM(S3C2410_GPFCON),
+       SAVE_ITEM(S3C2410_GPFDAT),
+       SAVE_ITEM(S3C2410_GPFUP),
+
+       SAVE_ITEM(S3C2410_GPGCON),
+       SAVE_ITEM(S3C2410_GPGDAT),
+       SAVE_ITEM(S3C2410_GPGUP),
+
+       SAVE_ITEM(S3C2410_GPHCON),
+       SAVE_ITEM(S3C2410_GPHDAT),
+       SAVE_ITEM(S3C2410_GPHUP),
+
+       SAVE_ITEM(S3C2410_DCLKCON),
+};
+
+#ifdef CONFIG_S3C2410_PM_DEBUG
+
+#define SAVE_UART(va) \
+       SAVE_ITEM((va) + S3C2410_ULCON), \
+       SAVE_ITEM((va) + S3C2410_UCON), \
+       SAVE_ITEM((va) + S3C2410_UFCON), \
+       SAVE_ITEM((va) + S3C2410_UMCON), \
+       SAVE_ITEM((va) + S3C2410_UBRDIV)
+
+static struct sleep_save uart_save[] = {
+       SAVE_UART(S3C2410_VA_UART0),
+       SAVE_UART(S3C2410_VA_UART1),
+       SAVE_UART(S3C2410_VA_UART2),
+};
+
+/* debug
+ *
+ * we send the debug to printascii() to allow it to be seen if the
+ * system never wakes up from the sleep
+*/
+
+extern void printascii(const char *);
+
+static void pm_dbg(const char *fmt, ...)
+{
+       va_list va;
+       char buff[256];
+
+       va_start(va, fmt);
+       vsprintf(buff, fmt, va);
+       va_end(va);
+
+       printascii(buff);
+}
+
+static void s3c2410_pm_debug_init(void)
+{
+       unsigned long tmp = __raw_readl(S3C2410_CLKCON);
+
+       /* re-start uart clocks */
+       tmp |= S3C2410_CLKCON_UART0;
+       tmp |= S3C2410_CLKCON_UART1;
+       tmp |= S3C2410_CLKCON_UART2;
+
+       __raw_writel(tmp, S3C2410_CLKCON);
+       udelay(10);
+}
+
+#define DBG(fmt...) pm_dbg(fmt)
+#else
+#define DBG(fmt...) printk(KERN_DEBUG fmt)
+
+#define s3c2410_pm_debug_init() do { } while(0)
+
+static struct sleep_save uart_save[] = {};
+#endif
+
+#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
+
+/* suspend checking code...
+ *
+ * this next area does a set of crc checks over all the installed
+ * memory, so the system can verify if the resume was ok.
+ *
+ * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
+ * increasing it will mean that the area corrupted will be less easy to spot,
+ * and reducing the size will cause the CRC save area to grow
+*/
+
+#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
+
+static u32 crc_size;   /* size needed for the crc block */
+static u32 *crcs;      /* allocated over suspend/resume */
+
+typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
+
+/* s3c2410_pm_run_res
+ *
+ * go thorugh the given resource list, and look for system ram
+*/
+
+static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
+{
+       while (ptr != NULL) {
+               if (ptr->child != NULL)
+                       s3c2410_pm_run_res(ptr->child, fn, arg);
+
+               if ((ptr->flags & IORESOURCE_MEM) &&
+                   strcmp(ptr->name, "System RAM") == 0) {
+                       DBG("Found system RAM at %08lx..%08lx\n",
+                           ptr->start, ptr->end);
+                       arg = (fn)(ptr, arg);
+               }
+
+               ptr = ptr->sibling;
+       }
+}
+
+static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
+{
+       s3c2410_pm_run_res(&iomem_resource, fn, arg);
+}
+
+static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
+{
+       u32 size = (u32)(res->end - res->start)+1;
+
+       size += CHECK_CHUNKSIZE-1;
+       size /= CHECK_CHUNKSIZE;
+
+       DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
+
+       *val += size * sizeof(u32);
+       return val;
+}
+
+/* s3c2410_pm_prepare_check
+ *
+ * prepare the necessary information for creating the CRCs. This
+ * must be done before the final save, as it will require memory
+ * allocating, and thus touching bits of the kernel we do not
+ * know about.
+*/
+
+static void s3c2410_pm_check_prepare(void)
+{
+       crc_size = 0;
+
+       s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
+
+       DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
+
+       crcs = kmalloc(crc_size+4, GFP_KERNEL);
+       if (crcs == NULL)
+               printk(KERN_ERR "Cannot allocated CRC save area\n");
+}
+
+static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
+{
+       unsigned long addr, left;
+
+       for (addr = res->start; addr < res->end;
+            addr += CHECK_CHUNKSIZE) {
+               left = res->end - addr;
+
+               if (left > CHECK_CHUNKSIZE)
+                       left = CHECK_CHUNKSIZE;
+
+               *val = crc32_le(~0, phys_to_virt(addr), left);
+               val++;
+       }
+
+       return val;
+}
+
+/* s3c2410_pm_check_store
+ *
+ * compute the CRC values for the memory blocks before the final
+ * sleep.
+*/
+
+static void s3c2410_pm_check_store(void)
+{
+       if (crcs != NULL)
+               s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
+}
+
+/* in_region
+ *
+ * return TRUE if the area defined by ptr..ptr+size contatins the
+ * what..what+whatsz
+*/
+
+static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
+{
+       if ((what+whatsz) < ptr)
+               return 0;
+
+       if (what > (ptr+size))
+               return 0;
+
+       return 1;
+}
+
+static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
+{
+       void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
+       unsigned long addr;
+       unsigned long left;
+       void *ptr;
+       u32 calc;
+
+       for (addr = res->start; addr < res->end;
+            addr += CHECK_CHUNKSIZE) {
+               left = res->end - addr;
+
+               if (left > CHECK_CHUNKSIZE)
+                       left = CHECK_CHUNKSIZE;
+
+               ptr = phys_to_virt(addr);
+
+               if (in_region(ptr, left, crcs, crc_size)) {
+                       DBG("skipping %08lx, has crc block in\n", addr);
+                       goto skip_check;
+               }
+
+               if (in_region(ptr, left, save_at, 32*4 )) {
+                       DBG("skipping %08lx, has save block in\n", addr);
+                       goto skip_check;
+               }
+
+               /* calculate and check the checksum */
+
+               calc = crc32_le(~0, ptr, left);
+               if (calc != *val) {
+                       printk(KERN_ERR PFX "Restore CRC error at "
+                              "%08lx (%08x vs %08x)\n", addr, calc, *val);
+
+                       DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
+                           addr, calc, *val);
+               }
+
+       skip_check:
+               val++;
+       }
+
+       return val;
+}
+
+/* s3c2410_pm_check_restore
+ *
+ * check the CRCs after the restore event and free the memory used
+ * to hold them
+*/
+
+static void s3c2410_pm_check_restore(void)
+{
+       if (crcs != NULL) {
+               s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
+               kfree(crcs);
+               crcs = NULL;
+       }
+}
+
+#else
+
+#define s3c2410_pm_check_prepare() do { } while(0)
+#define s3c2410_pm_check_restore() do { } while(0)
+#define s3c2410_pm_check_store()   do { } while(0)
+#endif
+
+/* helper functions to save and restore register state */
+
+void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
+{
+       for (; count > 0; count--, ptr++) {
+               ptr->val = __raw_readl(ptr->reg);
+               DBG("saved %08lx value %08lx\n", ptr->reg, ptr->val);
+       }
+}
+
+/* s3c2410_pm_do_restore
+ *
+ * restore the system from the given list of saved registers
+ *
+ * Note, we do not use DBG() in here, as the system may not have
+ * restore the UARTs state yet
+*/
+
+void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
+{
+       for (; count > 0; count--, ptr++) {
+               printk(KERN_DEBUG "restore %08lx (restore %08lx, was %08x)\n",
+                      ptr->reg, ptr->val, __raw_readl(ptr->reg));
+
+               __raw_writel(ptr->val, ptr->reg);
+       }
+}
+
+/* s3c2410_pm_do_restore_core
+ *
+ * similar to s3c2410_pm_do_restore_core
+ *
+ * WARNING: Do not put any debug in here that may effect memory or use
+ * peripherals, as things may be changing!
+*/
+
+static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
+{
+       for (; count > 0; count--, ptr++) {
+               __raw_writel(ptr->val, ptr->reg);
+       }
+}
+
+/* s3c2410_pm_show_resume_irqs
+ *
+ * print any IRQs asserted at resume time (ie, we woke from)
+*/
+
+static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
+                                       unsigned long mask)
+{
+       int i;
+
+       which &= ~mask;
+
+       for (i = 0; i <= 31; i++) {
+               if ((which) & (1L<<i)) {
+                       DBG("IRQ %d asserted at resume\n", start+i);
+               }
+       }
+}
+
+/* s3c2410_pm_check_resume_pin
+ *
+ * check to see if the pin is configured correctly for sleep mode, and
+ * make any necessary adjustments if it is not
+*/
+
+static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
+{
+       unsigned long irqstate;
+       unsigned long pinstate;
+       int irq = s3c2410_gpio_getirq(pin);
+
+       if (irqoffs < 4)
+               irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
+       else
+               irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
+
+       pinstate = s3c2410_gpio_getcfg(pin);
+       pinstate >>= S3C2410_GPIO_OFFSET(pin)*2;
+
+       if (!irqstate) {
+               if (pinstate == 0x02)
+                       DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
+       } else {
+               if (pinstate == 0x02) {
+                       DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
+                       s3c2410_gpio_cfgpin(pin, 0x00);
+               }
+       }
+}
+
+/* s3c2410_pm_configure_extint
+ *
+ * configure all external interrupt pins
+*/
+
+static void s3c2410_pm_configure_extint(void)
+{
+       int pin;
+
+       /* for each of the external interrupts (EINT0..EINT15) we
+        * need to check wether it is an external interrupt source,
+        * and then configure it as an input if it is not
+       */
+
+       for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
+               s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
+       }
+
+       for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
+               s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
+       }
+}
+
+#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
+
+/* s3c2410_pm_enter
+ *
+ * central control for sleep/resume process
+*/
+
+static int s3c2410_pm_enter(suspend_state_t state)
+{
+       unsigned long regs_save[16];
+       unsigned long tmp;
+
+       /* ensure the debug is initialised (if enabled) */
+
+       s3c2410_pm_debug_init();
+
+       DBG("s3c2410_pm_enter(%d)\n", state);
+
+       if (state != PM_SUSPEND_MEM) {
+               printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
+               return -EINVAL;
+       }
+
+       /* check if we have anything to wake-up with... bad things seem
+        * to happen if you suspend with no wakeup (system will often
+        * require a full power-cycle)
+       */
+
+       if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
+           !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
+               printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
+               printk(KERN_ERR PFX "Aborting sleep\n");
+               return -EINVAL;
+       }
+
+       /* prepare check area if configured */
+
+       s3c2410_pm_check_prepare();
+
+       /* store the physical address of the register recovery block */
+
+       s3c2410_sleep_save_phys = virt_to_phys(regs_save);
+
+       DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
+
+       /* ensure at least GESTATUS3 has the resume address */
+
+       __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
+
+       DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
+       DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
+
+       /* save all necessary core registers not covered by the drivers */
+
+       s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
+       s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+       s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
+       s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
+
+       /* set the irq configuration for wake */
+
+       s3c2410_pm_configure_extint();
+
+       DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
+           s3c_irqwake_intmask, s3c_irqwake_eintmask);
+
+       __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
+       __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
+
+       /* ack any outstanding external interrupts before we go to sleep */
+
+       __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
+
+       /* flush cache back to ram */
+
+       arm920_flush_kern_cache_all();
+
+       s3c2410_pm_check_store();
+
+       // need to make some form of time-delta
+
+       /* send the cpu to sleep... */
+
+       __raw_writel(0x00, S3C2410_CLKCON);  /* turn off clocks over sleep */
+
+       s3c2410_cpu_suspend(regs_save);
+
+       /* unset the return-from-sleep flag, to ensure reset */
+
+       tmp = __raw_readl(S3C2410_GSTATUS2);
+       tmp &= S3C2410_GSTATUS2_OFFRESET;
+       __raw_writel(tmp, S3C2410_GSTATUS2);
+
+       /* restore the system state */
+
+       s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+       s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
+       s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+       s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
+
+       s3c2410_pm_debug_init();
+
+       /* check what irq (if any) restored the system */
+
+       DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
+           __raw_readl(S3C2410_SRCPND),
+           __raw_readl(S3C2410_EINTPEND));
+
+       s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
+                                   s3c_irqwake_intmask);
+
+       s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
+                                   s3c_irqwake_eintmask);
+
+       DBG("post sleep, preparing to return\n");
+
+       s3c2410_pm_check_restore();
+
+       /* ok, let's return from sleep */
+
+       DBG("S3C2410 PM Resume (post-restore)\n");
+       return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int s3c2410_pm_prepare(suspend_state_t state)
+{
+       return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static int s3c2410_pm_finish(suspend_state_t state)
+{
+       return 0;
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static struct pm_ops s3c2410_pm_ops = {
+       .pm_disk_mode   = PM_DISK_FIRMWARE,
+       .prepare        = s3c2410_pm_prepare,
+       .enter          = s3c2410_pm_enter,
+       .finish         = s3c2410_pm_finish,
+};
+
+/* s3c2410_pm_init
+ *
+ * Attach the power management functions. This should be called
+ * from the board specific initialisation if the board supports
+ * it.
+*/
+
+int __init s3c2410_pm_init(void)
+{
+       printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
+
+       pm_set_ops(&s3c2410_pm_ops);
+       return 0;
+}
diff --git a/arch/arm/mach-s3c2410/pm.h b/arch/arm/mach-s3c2410/pm.h
new file mode 100644 (file)
index 0000000..dcbe714
--- /dev/null
@@ -0,0 +1,59 @@
+/* linux/arch/arm/mach-s3c2410/pm.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Written by Ben Dooks, <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* s3c2410_pm_init
+ *
+ * called from board at initialisation time to setup the power
+ * management
+*/
+
+#ifdef CONFIG_PM
+
+extern __init int s3c2410_pm_init(void);
+
+#else
+
+static inline int s3c2410_pm_init(void)
+{
+       return 0;
+}
+#endif
+
+/* configuration for the IRQ mask over sleep */
+extern unsigned long s3c_irqwake_intmask;
+extern unsigned long s3c_irqwake_eintmask;
+
+/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */
+extern unsigned long s3c_irqwake_intallow;
+extern unsigned long s3c_irqwake_eintallow;
+
+/* Flags for PM Control */
+
+extern unsigned long s3c_pm_flags;
+
+/* from sleep.S */
+
+extern void s3c2410_cpu_suspend(unsigned long *saveblk);
+extern void s3c2410_cpu_resume(void);
+
+extern unsigned long s3c2410_sleep_save_phys;
+
+/* sleep save info */
+
+struct sleep_save {
+       unsigned long   reg;
+       unsigned long   val;
+};
+
+#define SAVE_ITEM(x) \
+       { .reg = (x) }
+
+extern void s3c2410_pm_do_save(struct sleep_save *ptr, int count);
+extern void s3c2410_pm_do_restore(struct sleep_save *ptr, int count);
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c
new file mode 100644 (file)
index 0000000..fb30783
--- /dev/null
@@ -0,0 +1,57 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 Drive Strength Control support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ *     29-Aug-2004 BJD  Start of drive-strength control
+*/
+
+#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/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-dsc.h>
+
+#include "s3c2440.h"
+#include "cpu.h"
+
+int s3c2440_set_dsc(unsigned int pin, unsigned int value)
+{
+       unsigned long base;
+       unsigned long val;
+       unsigned long flags;
+       unsigned long mask;
+
+       base = (pin & S3C2440_SELECT_DSC1) ? S3C2440_DSC1 : S3C2440_DSC0;
+       mask = 3 << S3C2440_DSC_GETSHIFT(pin);
+
+       local_irq_save(flags);
+
+       val = __raw_readl(base);
+       val &= ~mask;
+       val |= value & mask;
+       __raw_writel(val, base);
+
+       local_irq_restore(flags);
+       return 0;
+}
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c
new file mode 100644 (file)
index 0000000..f4bb10c
--- /dev/null
@@ -0,0 +1,192 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ *     24-Aug-2004 BJD  Start of s3c2440 support
+*/
+
+#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/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-serial.h>
+
+#include "s3c2440.h"
+#include "cpu.h"
+
+int s3c2440_clock_tick_rate = 12*1000*1000;  /* current timers at 12MHz */
+
+/* clock info */
+
+unsigned long s3c2440_baseclk = 12*1000*1000;  /* assume base is 12MHz */
+unsigned long s3c2440_hdiv;
+
+unsigned long s3c2440_fclk;
+unsigned long s3c2440_hclk;
+unsigned long s3c2440_pclk;
+
+static struct map_desc s3c2440_iodesc[] __initdata = {
+       IODESC_ENT(USBHOST),
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(LCD),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(ADC),
+};
+
+static struct resource s3c_uart0_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_UART0,
+               .end   = S3C2410_PA_UART0 + 0x3fff,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_S3CUART_RX0,
+               .end   = IRQ_S3CUART_ERR0,
+               .flags = IORESOURCE_IRQ,
+       }
+
+};
+
+static struct resource s3c_uart1_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_UART1,
+               .end   = S3C2410_PA_UART1 + 0x3fff,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_S3CUART_RX1,
+               .end   = IRQ_S3CUART_ERR1,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource s3c_uart2_resource[] = {
+       [0] = {
+               .start = S3C2410_PA_UART2,
+               .end   = S3C2410_PA_UART2 + 0x3fff,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_S3CUART_RX2,
+               .end   = IRQ_S3CUART_ERR2,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+/* our uart devices */
+
+static struct platform_device s3c_uart0 = {
+       .name             = "s3c2440-uart",
+       .id               = 0,
+       .num_resources    = ARRAY_SIZE(s3c_uart0_resource),
+       .resource         = s3c_uart0_resource,
+};
+
+
+static struct platform_device s3c_uart1 = {
+       .name             = "s3c2440-uart",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s3c_uart1_resource),
+       .resource         = s3c_uart1_resource,
+};
+
+static struct platform_device s3c_uart2 = {
+       .name             = "s3c2440-uart",
+       .id               = 2,
+       .num_resources    = ARRAY_SIZE(s3c_uart2_resource),
+       .resource         = s3c_uart2_resource,
+};
+
+static struct platform_device *uart_devices[] __initdata = {
+       &s3c_uart0,
+       &s3c_uart1,
+       &s3c_uart2
+};
+
+void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
+{
+       unsigned long tmp;
+       unsigned long camdiv;
+
+       /* register our io-tables */
+
+       iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
+       iotable_init(mach_desc, size);
+
+       /* now we've got our machine bits initialised, work out what
+        * clocks we've got */
+
+       s3c2440_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON),
+                                      s3c2440_baseclk);
+
+       tmp = __raw_readl(S3C2410_CLKDIVN);
+       camdiv = __raw_readl(S3C2440_CAMDIVN);
+
+       /* work out clock scalings */
+
+       switch (tmp & S3C2440_CLKDIVN_HDIVN_MASK) {
+       case S3C2440_CLKDIVN_HDIVN_1:
+               s3c2440_hdiv = 1;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_2:
+               s3c2440_hdiv = 1;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_4_8:
+               s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_3_6:
+               s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 6 : 3;
+               break;
+       }
+
+       s3c2440_hclk = s3c2440_fclk / s3c2440_hdiv;
+       s3c2440_pclk = s3c2440_hclk / ((tmp & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
+
+       /* print brieft summary of clocks, etc */
+
+       printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+              print_mhz(s3c2440_fclk), print_mhz(s3c2440_hclk),
+              print_mhz(s3c2440_pclk));
+}
+
+
+
+int __init s3c2440_init(void)
+{
+       int ret;
+
+       printk("S3C2440: Initialising architecture\n");
+
+       ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices));
+       if (ret)
+               return ret;
+
+       // todo: board specific inits?
+
+       return ret;
+}
+
diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/arch/arm/mach-s3c2410/s3c2440.h
new file mode 100644 (file)
index 0000000..bf49a66
--- /dev/null
@@ -0,0 +1,18 @@
+/* arch/arm/mach-s3c2410/s3c2440.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2440 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Modifications:
+ *     24-Aug-2004 BJD  Start of S3C2440 CPU support
+*/
+
+extern void s3c2440_init_irq(void);
+
+extern void s3c2440_init_time(void);
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
new file mode 100644 (file)
index 0000000..61768da
--- /dev/null
@@ -0,0 +1,180 @@
+/* linux/arch/arm/mach-s3c2410/sleep.S
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Power Manager (Suspend-To-RAM) support
+ *
+ * Based on PXA/SA1100 sleep code by:
+ *     Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ *     Cliff Brake, (c) 2001
+ *
+ * This 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/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+#include <asm/arch/map.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-serial.h>
+
+/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
+ * reset the UART configuration, only enable if you really need this!
+*/
+//#define CONFIG_DEBUG_RESUME
+
+       .text
+
+       /* s3c2410_cpu_suspend
+        *
+        * put the cpu into sleep mode
+        *
+        * entry:
+        *      r0 = sleep save block
+       */
+
+ENTRY(s3c2410_cpu_suspend)
+       stmfd   sp!, { r4 - r12, lr }
+
+       @@ store co-processor registers
+
+       mrc     p15, 0, r4, c15, c1, 0  @ CP access register
+       mrc     p15, 0, r5, c13, c0, 0  @ PID
+       mrc     p15, 0, r6, c3, c0, 0   @ Domain ID
+       mrc     p15, 0, r7, c2, c0, 0   @ translation table base address
+       mrc     p15, 0, r8, c2, c0, 0   @ auxiliary control register
+       mrc     p15, 0, r9, c1, c0, 0   @ control register
+
+       stmia   r0, { r4 - r13 }
+
+       @@ flush the caches to ensure everything is back out to
+       @@ SDRAM before the core powers down
+
+       bl      arm920_flush_kern_cache_all
+
+       @@ prepare cpu to sleep
+
+       ldr     r4, =S3C2410_REFRESH
+       ldr     r5, =S3C2410_MISCCR
+       ldr     r6, =S3C2410_CLKCON
+       ldr     r7, [ r4 ]              @ get REFRESH (and ensure in TLB)
+       ldr     r8, [ r5 ]              @ get MISCCR (and ensure in TLB)
+       ldr     r9, [ r6 ]              @ get CLKCON (and ensure in TLB)
+
+       orr     r7, r7, #S3C2410_REFRESH_SELF   @ SDRAM sleep command
+       orr     r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
+       orr     r9, r9, #S3C2410_CLKCON_POWER   @ power down command
+
+       teq     pc, #0                  @ first as a trial-run to load cache
+       bl      s3c2410_do_sleep
+       teq     r0, r0                  @ now do it for real
+       b       s3c2410_do_sleep        @
+
+       @@ align next bit of code to cache line
+       .align  8
+s3c2410_do_sleep:
+       streq   r7, [ r4 ]                      @ SDRAM sleep command
+       streq   r8, [ r5 ]                      @ SDRAM power-down config
+       streq   r9, [ r6 ]                      @ CPU sleep
+1:     beq     1b
+       mov     pc, r14
+
+       @@ return to the caller, after having the MMU
+       @@ turned on, this restores the last bits from the
+       @@ stack
+resume_with_mmu:
+       ldmfd   sp!, { r4 - r12, pc }
+
+       .ltorg
+
+       @@ the next bits sit in the .data segment, even though they
+       @@ happen to be code... the s3c2410_sleep_save_phys needs to be
+       @@ accessed by the resume code before it can restore the MMU.
+       @@ This means that the variable has to be close enough for the
+       @@ code to read it... since the .text segment needs to be RO,
+       @@ the data segment can be the only place to put this code.
+
+       .data
+
+       .global s3c2410_sleep_save_phys
+s3c2410_sleep_save_phys:
+       .word   0
+
+       /* s3c2410_cpu_resume
+        *
+        * resume code entry for bootloader to call
+        *
+        * we must put this code here in the data segment as we have no
+        * other way of restoring the stack pointer after sleep, and we
+        * must not write to the code segment (code is read-only)
+       */
+
+ENTRY(s3c2410_cpu_resume)
+       mov     r0, #PSR_I_BIT | PSR_F_BIT | MODE_SVC
+       msr     cpsr_c, r0
+
+       @@ load UART to allow us to print the two characters for
+       @@ resume debug
+
+       mov     r2, #S3C2410_PA_UART & 0xff000000
+       orr     r2, r2, #S3C2410_PA_UART & 0xff000
+
+#if 0
+       /* SMDK2440 LED set */
+       mov     r14, #S3C2410_PA_GPIO
+       ldr     r12, [ r14, #0x54 ]
+       bic     r12, r12, #3<<4
+       orr     r12, r12, #1<<7
+       str     r12, [ r14, #0x54 ]
+#endif
+
+#ifdef CONFIG_DEBUG_RESUME
+       mov     r3, #'L'
+       strb    r3, [ r2, #S3C2410_UTXH ]
+1001:
+       ldrb    r14, [ r3, #S3C2410_UTRSTAT ]
+       tst     r14, #S3C2410_UTRSTAT_TXE
+       beq     1001b
+#endif /* CONFIG_DEBUG_RESUME */
+
+       mov     r1, #0
+       mcr     p15, 0, r1, c8, c7, 0           @@ invalidate I & D TLBs
+       mcr     p15, 0, r1, c7, c7, 0           @@ invalidate I & D caches
+
+       ldr     r0, s3c2410_sleep_save_phys     @ address of restore block
+       ldmia   r0, { r4 - r13 }
+
+       mcr     p15, 0, r4, c15, c1, 0          @ CP access register
+       mcr     p15, 0, r5, c13, c0, 0          @ PID
+       mcr     p15, 0, r6, c3, c0, 0           @ Domain ID
+       mcr     p15, 0, r7, c2, c0, 0           @ translation table base
+       mcr     p15, 0, r8, c1, c1, 0           @ auxilliary control
+
+#ifdef CONFIG_DEBUG_RESUME
+       mov     r3, #'R'
+       strb    r3, [ r2, #S3C2410_UTXH ]
+#endif
+
+       ldr     r2, =resume_with_mmu
+       mcr     p15, 0, r9, c1, c0, 0           @ turn on MMU, etc
+       nop                                     @ second-to-last before mmu
+       mov     pc, r2                          @ go back to virtual address
+
+       .ltorg
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
new file mode 100644 (file)
index 0000000..b8f8ded
--- /dev/null
@@ -0,0 +1,123 @@
+/* linux/arch/arm/mach-s3c2410/usb-simtec.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * Simtec BAST and Thorcom VR1000 USB port support functions
+ *
+ * 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.
+ *
+ * Modifications:
+ *     14-Sep-2004 BJD  Created
+*/
+
+#define DEBUG
+
+#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/mach/irq.h>
+
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-irq.h>
+#include <asm/arch/usb-control.h>
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include "devs.h"
+#include "usb-simtec.h"
+
+/* control power and monitor over-current events on various Simtec
+ * designed boards.
+*/
+
+static void
+usb_simtec_powercontrol(int port, int to)
+{
+       pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
+
+       if (port == 1) {
+               s3c2410_gpio_setpin(S3C2410_GPB4, to ? 0:1);
+               pr_debug("GPBDAT now %08x\n", __raw_readl(S3C2410_GPBDAT));
+       }
+}
+
+static irqreturn_t
+usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs)
+{
+       struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;
+
+       if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
+               pr_debug("usb_simtec: over-current irq (oc detected)\n");
+               s3c2410_report_oc(info, 3);
+       } else {
+               pr_debug("usb_simtec: over-current irq (oc cleared)\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
+{
+       int ret;
+
+       if (on) {
+               pr_debug("claiming usb overccurent\n");
+               ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, SA_INTERRUPT,
+                                 "usb-oc", info);
+               if (ret != 0) {
+                       printk(KERN_ERR "failed to request usb oc irq\n");
+               }
+
+               set_irq_type(IRQ_USBOC, IRQT_BOTHEDGE);
+       } else {
+               free_irq(IRQ_USBOC, NULL);
+       }
+}
+
+static struct s3c2410_hcd_info usb_simtec_info = {
+       .port[0]        = {
+               .flags  = S3C_HCDFLG_USED
+       },
+       .port[1]        = {
+               .flags  = S3C_HCDFLG_USED
+       },
+
+       .power_control  = usb_simtec_powercontrol,
+       .enable_oc      = usb_simtec_enableoc,
+};
+
+
+int usb_simtec_init(void)
+{
+       printk("USB Power Control, (c) 2004 Simtec Electronics\n");
+       s3c_device_usb.dev.platform_data = &usb_simtec_info;
+
+       s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
+       s3c2410_gpio_setpin(S3C2410_GPB4, 1);
+
+       pr_debug("GPB: CON=%08x, DAT=%08x\n",
+                __raw_readl(S3C2410_GPBCON), __raw_readl(S3C2410_GPBDAT));
+
+       if (0) {
+               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST,
+                                     S3C2410_MISCCR_USBDEV);
+       }
+
+       return 0;
+}
diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
new file mode 100644 (file)
index 0000000..92c0cc8
--- /dev/null
@@ -0,0 +1,19 @@
+/* linux/arch/arm/mach-s3c2410/usb-simtec.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * Simtec BAST and Thorcom VR1000 USB port support functions
+ *
+ * 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.
+ *
+ * Modifications:
+ *     20-Aug-2004 BJD  Created
+*/
+
+extern int usb_simtec_init(void);
+
diff --git a/arch/arm/mach-sa1100/Makefile.boot b/arch/arm/mach-sa1100/Makefile.boot
new file mode 100644 (file)
index 0000000..a56ad04
--- /dev/null
@@ -0,0 +1,7 @@
+   zreladdr-y  := 0xc0008000
+ifeq ($(CONFIG_ARCH_SA1100),y)
+   zreladdr-$(CONFIG_SA1111)           := 0xc0208000
+endif
+params_phys-y  := 0xc0000100
+initrd_phys-y  := 0xc0800000
+
diff --git a/arch/arm/mach-shark/Makefile.boot b/arch/arm/mach-shark/Makefile.boot
new file mode 100644 (file)
index 0000000..4320f8b
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-y  := 0x08008000
+
diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig
new file mode 100644 (file)
index 0000000..8d787f4
--- /dev/null
@@ -0,0 +1,16 @@
+menu "Versatile platform type"
+       depends on ARCH_VERSATILE
+
+config ARCH_VERSATILE_PB
+       bool "Support Versatile/PB platform"
+       default y
+       help
+         Include support for the ARM(R) Versatile/PB platform.
+
+config MACH_VERSATILE_AB
+       bool "Support Versatile/AB platform"
+       default n
+       help
+         Include support for the ARM(R) Versatile/AP platform.
+
+endmenu
diff --git a/arch/arm/mach-versatile/Makefile.boot b/arch/arm/mach-versatile/Makefile.boot
new file mode 100644 (file)
index 0000000..c7e75ac
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x00008000
+params_phys-y  := 0x00000100
+initrd_phys-y  := 0x00800000
+
diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h
new file mode 100644 (file)
index 0000000..588c206
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  linux/arch/arm/mach-versatile/core.h
+ *
+ *  Copyright (C) 2004 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_VERSATILE_H
+#define __ASM_ARCH_VERSATILE_H
+
+#include <asm/hardware/amba.h>
+
+extern void __init versatile_init(void);
+extern void __init versatile_init_irq(void);
+extern void __init versatile_map_io(void);
+extern struct sys_timer versatile_timer;
+extern unsigned int mmc_status(struct device *dev);
+
+#define AMBA_DEVICE(name,busid,base,plat)                      \
+static struct amba_device name##_device = {                    \
+       .dev            = {                                     \
+               .coherent_dma_mask = ~0,                        \
+               .bus_id = busid,                                \
+               .platform_data = plat,                          \
+       },                                                      \
+       .res            = {                                     \
+               .start  = VERSATILE_##base##_BASE,              \
+               .end    = (VERSATILE_##base##_BASE) + SZ_4K - 1,\
+               .flags  = IORESOURCE_MEM,                       \
+       },                                                      \
+       .dma_mask       = ~0,                                   \
+       .irq            = base##_IRQ,                           \
+       /* .dma         = base##_DMA,*/                         \
+}
+
+#endif
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c
new file mode 100644 (file)
index 0000000..d332084
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  linux/arch/arm/mach-versatile/versatile_ab.c
+ *
+ *  Copyright (C) 2004 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/amba.h>
+
+#include <asm/mach/arch.h>
+
+#include "core.h"
+
+MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
+       MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+       BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(versatile_map_io)
+       INITIRQ(versatile_init_irq)
+       .timer          = &versatile_timer,
+       INIT_MACHINE(versatile_init)
+MACHINE_END
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
new file mode 100644 (file)
index 0000000..2702099
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  linux/arch/arm/mach-versatile/versatile_pb.c
+ *
+ *  Copyright (C) 2004 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/amba.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/mmc.h>
+
+#include "core.h"
+
+#if 1
+#define IRQ_MMCI1A     IRQ_VICSOURCE23
+#else
+#define IRQ_MMCI1A     IRQ_SIC_MMCI1A
+#endif
+
+static struct mmc_platform_data mmc1_plat_data = {
+       .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
+       .status         = mmc_status,
+};
+
+#define UART3_IRQ      { IRQ_SIC_UART3, NO_IRQ }
+#define UART3_DMA      { 0x86, 0x87 }
+#define SCI1_IRQ       { IRQ_SIC_SCI3, NO_IRQ }
+#define SCI1_DMA       { 0x88, 0x89 }
+#define MMCI1_IRQ      { IRQ_MMCI1A, IRQ_SIC_MMCI1B }
+#define MMCI1_DMA      { 0x85, 0 }
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define GPIO2_IRQ      { IRQ_GPIOINT2, NO_IRQ }
+#define GPIO2_DMA      { 0, 0 }
+#define GPIO3_IRQ      { IRQ_GPIOINT3, NO_IRQ }
+#define GPIO3_DMA      { 0, 0 }
+
+/*
+ * These devices are connected via the DMA APB bridge
+ */
+
+/* FPGA Primecells */
+AMBA_DEVICE(uart3, "fpga:09", UART3,    NULL);
+AMBA_DEVICE(sci1,  "fpga:0a", SCI1,     NULL);
+AMBA_DEVICE(mmc1,  "fpga:0b", MMCI1,    &mmc1_plat_data);
+
+/* DevChip Primecells */
+AMBA_DEVICE(gpio2, "dev:e6",  GPIO2,    NULL);
+AMBA_DEVICE(gpio3, "dev:e7",  GPIO3,    NULL);
+
+static struct amba_device *amba_devs[] __initdata = {
+       &uart3_device,
+       &gpio2_device,
+       &gpio3_device,
+       &sci1_device,
+       &mmc1_device,
+};
+
+static int __init versatile_pb_init(void)
+{
+       int i;
+
+       if (machine_is_versatile_pb()) {
+               for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+                       struct amba_device *d = amba_devs[i];
+                       amba_device_register(d, &iomem_resource);
+               }
+       }
+
+       return 0;
+}
+
+arch_initcall(versatile_pb_init);
+
+MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
+       MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+       BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000)
+       BOOT_PARAMS(0x00000100)
+       MAPIO(versatile_map_io)
+       INITIRQ(versatile_init_irq)
+       .timer          = &versatile_timer,
+       INIT_MACHINE(versatile_init)
+MACHINE_END
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
new file mode 100644 (file)
index 0000000..ff5f62c
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  linux/arch/arm/mm/flush.c
+ *
+ *  Copyright (C) 1995-2002 Russell King
+ *
+ * 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/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/cacheflush.h>
+#include <asm/system.h>
+
+static void __flush_dcache_page(struct address_space *mapping, struct page *page)
+{
+       struct mm_struct *mm = current->active_mm;
+       struct vm_area_struct *mpnt;
+       struct prio_tree_iter iter;
+       pgoff_t pgoff;
+
+       /*
+        * Writeback any data associated with the kernel mapping of this
+        * page.  This ensures that data in the physical page is mutually
+        * coherent with the kernels mapping.
+        */
+       __cpuc_flush_dcache_page(page_address(page));
+
+       /*
+        * If there's no mapping pointer here, then this page isn't
+        * visible to userspace yet, so there are no cache lines
+        * associated with any other aliases.
+        */
+       if (!mapping)
+               return;
+
+       /*
+        * There are possible user space mappings of this page:
+        * - VIVT cache: we need to also write back and invalidate all user
+        *   data in the current VM view associated with this page.
+        * - aliasing VIPT: we only need to find one mapping of this page.
+        */
+       pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+
+       flush_dcache_mmap_lock(mapping);
+       vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) {
+               unsigned long offset;
+
+               /*
+                * If this VMA is not in our MM, we can ignore it.
+                */
+               if (mpnt->vm_mm != mm)
+                       continue;
+               if (!(mpnt->vm_flags & VM_MAYSHARE))
+                       continue;
+               offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
+               flush_cache_page(mpnt, mpnt->vm_start + offset);
+               if (cache_is_vipt())
+                       break;
+       }
+       flush_dcache_mmap_unlock(mapping);
+}
+
+/*
+ * Ensure cache coherency between kernel mapping and userspace mapping
+ * of this page.
+ *
+ * We have three cases to consider:
+ *  - VIPT non-aliasing cache: fully coherent so nothing required.
+ *  - VIVT: fully aliasing, so we need to handle every alias in our
+ *          current VM view.
+ *  - VIPT aliasing: need to handle one alias in our current VM view.
+ *
+ * If we need to handle aliasing:
+ *  If the page only exists in the page cache and there are no user
+ *  space mappings, we can be lazy and remember that we may have dirty
+ *  kernel cache lines for later.  Otherwise, we assume we have
+ *  aliasing mappings.
+ */
+void flush_dcache_page(struct page *page)
+{
+       struct address_space *mapping = page_mapping(page);
+
+       if (cache_is_vipt_nonaliasing())
+               return;
+
+       if (mapping && !mapping_mapped(mapping))
+               set_bit(PG_dcache_dirty, &page->flags);
+       else
+               __flush_dcache_page(mapping, page);
+}
+EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/arm26/Kconfig.debug b/arch/arm26/Kconfig.debug
new file mode 100644 (file)
index 0000000..e2c920d
--- /dev/null
@@ -0,0 +1,60 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+# RMK wants arm kernels compiled with frame pointers so hardwire this to y.
+# If you know what you are doing and are willing to live without stack
+# traces, you can get a slightly smaller kernel by setting this option to
+# n, but then RMK will have to kill you ;).
+config FRAME_POINTER
+       bool
+       default y
+       help
+         If you say N here, the resulting kernel will be slightly smaller and
+         faster. However, when a problem occurs with the kernel, the
+         information that is reported is severely limited. Most people
+         should say Y here.
+
+config DEBUG_USER
+       bool "Verbose user fault messages"
+       help
+         When a user program crashes due to an exception, the kernel can
+         print a brief message explaining what the problem was. This is
+         sometimes helpful for debugging but serves no purpose on a
+         production system. Most people should say N here.
+
+config DEBUG_WAITQ
+       bool "Wait queue debugging"
+       depends on DEBUG_KERNEL
+
+config DEBUG_ERRORS
+       bool "Verbose kernel error messages"
+       depends on DEBUG_KERNEL
+       help
+         This option controls verbose debugging information which can be
+         printed when the kernel detects an internal error. This debugging
+         information is useful to kernel hackers when tracking down problems,
+         but mostly meaningless to other people. It's safe to say Y unless
+         you are concerned with the code size or don't want to see these
+         messages.
+
+config DEBUG_INFO
+       bool "Include GDB debugging information in kernel binary"
+       help
+         Say Y here to include source-level debugging information in the
+         `vmlinux' binary image. This is handy if you want to use gdb or
+         addr2line to debug the kernel. It has no impact on the in-memory
+         footprint of the running kernel but it can increase the amount of
+         time and disk space needed for compilation of the kernel. If in
+         doubt say N.
+
+# These options are only for real kernel hackers who want to get their hands dirty.
+config DEBUG_LL
+       bool "Kernel low-level debugging functions"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here to include definitions of printascii, printchar, printhex
+         in the kernel.  This is helpful if you are debugging code that
+         executes before the console is initialized.
+
+endmenu
diff --git a/arch/cris/Kconfig.debug b/arch/cris/Kconfig.debug
new file mode 100644 (file)
index 0000000..9864aad
--- /dev/null
@@ -0,0 +1,28 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+config PROFILE
+       bool "Kernel profiling support"
+
+config PROFILE_SHIFT
+       int "Profile shift count"
+       depends on PROFILE
+       default "2"
+
+config ETRAX_KGDB
+       bool "Use kernel GDB debugger"
+       ---help---
+         The CRIS version of gdb can be used to remotely debug a running
+         Linux kernel via the serial debug port.  Provided you have gdb-cris
+         installed, run gdb-cris vmlinux, then type
+
+         (gdb) set remotebaud 115200           <- kgdb uses 115200 as default
+         (gdb) target remote /dev/ttyS0        <- maybe you use another port
+
+         This should connect you to your booted kernel (or boot it now if you
+         didn't before).  The kernel halts when it boots, waiting for gdb if
+         this option is turned on!
+
+endmenu
diff --git a/arch/cris/arch-v10/kernel/crisksyms.c b/arch/cris/arch-v10/kernel/crisksyms.c
new file mode 100644 (file)
index 0000000..b332bf9
--- /dev/null
@@ -0,0 +1,17 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+
+/* Export shadow registers for the CPU I/O pins */
+EXPORT_SYMBOL(genconfig_shadow);
+EXPORT_SYMBOL(port_pa_data_shadow);
+EXPORT_SYMBOL(port_pa_dir_shadow);
+EXPORT_SYMBOL(port_pb_data_shadow);
+EXPORT_SYMBOL(port_pb_dir_shadow);
+EXPORT_SYMBOL(port_pb_config_shadow);
+EXPORT_SYMBOL(port_g_data_shadow);
+
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
diff --git a/arch/h8300/Kconfig.debug b/arch/h8300/Kconfig.debug
new file mode 100644 (file)
index 0000000..55034d0
--- /dev/null
@@ -0,0 +1,68 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config FULLDEBUG
+       bool "Full Symbolic/Source Debugging support"
+       help
+         Enable debugging symbols on kernel build.
+
+config HIGHPROFILE
+       bool "Use fast second timer for profiling"
+       help
+         Use a fast secondary clock to produce profiling information.
+
+config NO_KERNEL_MSG
+       bool "Suppress Kernel BUG Messages"
+       help
+         Do not output any debug BUG messages within the kernel.
+
+config GDB_MAGICPRINT
+       bool "Message Output for GDB MagicPrint service"
+       depends on (H8300H_SIM || H8S_SIM)
+       help
+         kernel messages output useing MagicPrint service from GDB
+
+config SYSCALL_PRINT
+       bool "SystemCall trace print"
+       help
+         outout history of systemcall
+
+config GDB_DEBUG
+       bool "Use gdb stub"
+       depends on (!H8300H_SIM && !H8S_SIM)
+       help
+         gdb stub exception support
+
+config CONFIG_SH_STANDARD_BIOS
+       bool "Use gdb protocol serial console"
+       depends on (!H8300H_SIM && !H8S_SIM)
+       help
+         serial console output using GDB protocol.
+         Require eCos/RedBoot
+
+config DEFAULT_CMDLINE
+       bool "Use buildin commandline"
+       default n
+       help
+         buildin kernel commandline enabled.
+
+config KERNEL_COMMAND
+       string "Buildin commmand string"
+       depends on DEFAULT_CMDLINE
+       help
+         buildin kernel commandline strings.
+
+config BLKDEV_RESERVE
+       bool "BLKDEV Reserved Memory"
+       default n
+       help
+         Reserved BLKDEV area.
+
+config CONFIG_BLKDEV_RESERVE_ADDRESS
+       hex 'start address'
+       depends on BLKDEV_RESERVE
+       help
+         BLKDEV start address.
+
+endmenu
diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug
new file mode 100644 (file)
index 0000000..cf069b7
--- /dev/null
@@ -0,0 +1,80 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+       bool "Early printk" if EMBEDDED
+       default y
+       help
+         Write kernel log output directly into the VGA buffer or to a serial
+         port.
+
+         This is useful for kernel debugging when your machine crashes very
+         early before the console code is initialized. For normal operation
+         it is not recommended because it looks ugly and doesn't cooperate
+         with klogd/syslogd or the X server. You should normally N here,
+         unless you want to debug such a crash.
+
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+
+config KPROBES
+       bool "Kprobes"
+       depends on DEBUG_KERNEL
+       help
+         Kprobes allows you to trap at almost any kernel address and
+         execute a callback function.  register_kprobe() establishes
+         a probepoint and specifies the callback.  Kprobes is useful
+         for kernel debugging, non-intrusive instrumentation and testing.
+         If in doubt, say "N".
+
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+config DEBUG_PAGEALLOC
+       bool "Page alloc debugging"
+       depends on DEBUG_KERNEL
+       help
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
+
+config 4KSTACKS
+       bool "Use 4Kb for kernel stacks instead of 8Kb"
+       help
+         If you say Y here the kernel will use a 4Kb stacksize for the
+         kernel stack attached to each process/thread. This facilitates
+         running more threads on a system and also reduces the pressure
+         on the VM subsystem for higher order allocations. This option
+         will also use IRQ stacks to compensate for the reduced stackspace.
+
+config SCHEDSTATS
+       bool "Collect scheduler statistics"
+       depends on DEBUG_KERNEL && PROC_FS
+       help
+         If you say Y here, additional code will be inserted into the
+         scheduler and related routines to collect statistics about
+         scheduler behavior and provide them in /proc/schedstat.  These
+         stats may be useful for both tuning and debugging the scheduler
+         If you aren't debugging the scheduler or trying to tune a specific
+         application, you can say N to avoid the very slight overhead
+         this adds.
+
+config X86_FIND_SMP_CONFIG
+       bool
+       depends on X86_LOCAL_APIC || X86_VOYAGER
+       default y
+
+config X86_MPPARSE
+       bool
+       depends on X86_LOCAL_APIC && !X86_VISWS
+       default y
+
+endmenu
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
new file mode 100644 (file)
index 0000000..726a5ca
--- /dev/null
@@ -0,0 +1,51 @@
+/* 
+ * Do early PCI probing for bug detection when the main PCI subsystem is 
+ * not up yet.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/pci-direct.h>
+#include <asm/acpi.h>
+
+static int __init check_bridge(int vendor, int device) 
+{
+       /* According to Nvidia all timer overrides are bogus. Just ignore
+          them all. */
+       if (vendor == PCI_VENDOR_ID_NVIDIA) { 
+               acpi_skip_timer_override = 1;           
+       }
+       return 0;
+}
+   
+void __init check_acpi_pci(void) 
+{ 
+       int num,slot,func; 
+
+       /* Assume the machine supports type 1. If not it will 
+          always read ffffffff and should not have any side effect. */
+
+       /* Poor man's PCI discovery */
+       for (num = 0; num < 32; num++) { 
+               for (slot = 0; slot < 32; slot++) { 
+                       for (func = 0; func < 8; func++) { 
+                               u32 class;
+                               u32 vendor;
+                               class = read_pci_config(num,slot,func,
+                                                       PCI_CLASS_REVISION);
+                               if (class == 0xffffffff)
+                                       break; 
+
+                               if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
+                                       continue; 
+                               
+                               vendor = read_pci_config(num, slot, func, 
+                                                        PCI_VENDOR_ID);
+                               
+                               if (check_bridge(vendor&0xffff, vendor >> 16))
+                                       return; 
+                       } 
+                       
+               }
+       }
+}
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
new file mode 100644 (file)
index 0000000..1e11401
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.3 $)
+ *
+ *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
+
+MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
+MODULE_DESCRIPTION("ACPI Processor P-States Driver");
+MODULE_LICENSE("GPL");
+
+
+struct cpufreq_acpi_io {
+       struct acpi_processor_performance       acpi_data;
+       struct cpufreq_frequency_table          *freq_table;
+};
+
+static struct cpufreq_acpi_io  *acpi_io_data[NR_CPUS];
+
+
+static int
+acpi_processor_write_port(
+       u16     port,
+       u8      bit_width,
+       u32     value)
+{
+       if (bit_width <= 8) {
+               outb(value, port);
+       } else if (bit_width <= 16) {
+               outw(value, port);
+       } else if (bit_width <= 32) {
+               outl(value, port);
+       } else {
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int
+acpi_processor_read_port(
+       u16     port,
+       u8      bit_width,
+       u32     *ret)
+{
+       *ret = 0;
+       if (bit_width <= 8) {
+               *ret = inb(port);
+       } else if (bit_width <= 16) {
+               *ret = inw(port);
+       } else if (bit_width <= 32) {
+               *ret = inl(port);
+       } else {
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int
+acpi_processor_set_performance (
+       struct cpufreq_acpi_io  *data,
+       unsigned int            cpu,
+       int                     state)
+{
+       u16                     port = 0;
+       u8                      bit_width = 0;
+       int                     ret = 0;
+       u32                     value = 0;
+       int                     i = 0;
+       struct cpufreq_freqs    cpufreq_freqs;
+       cpumask_t               saved_mask;
+       int                     retval;
+
+       dprintk("acpi_processor_set_performance\n");
+
+       /*
+        * TBD: Use something other than set_cpus_allowed.
+        * As set_cpus_allowed is a bit racy, 
+        * with any other set_cpus_allowed for this process.
+        */
+       saved_mask = current->cpus_allowed;
+       set_cpus_allowed(current, cpumask_of_cpu(cpu));
+       if (smp_processor_id() != cpu) {
+               return (-EAGAIN);
+       }
+       
+       if (state == data->acpi_data.state) {
+               dprintk("Already at target state (P%d)\n", state);
+               retval = 0;
+               goto migrate_end;
+       }
+
+       dprintk("Transitioning from P%d to P%d\n",
+               data->acpi_data.state, state);
+
+       /* cpufreq frequency struct */
+       cpufreq_freqs.cpu = cpu;
+       cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
+       cpufreq_freqs.new = data->freq_table[state].frequency;
+
+       /* notify cpufreq */
+       cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+
+       /*
+        * First we write the target state's 'control' value to the
+        * control_register.
+        */
+
+       port = data->acpi_data.control_register.address;
+       bit_width = data->acpi_data.control_register.bit_width;
+       value = (u32) data->acpi_data.states[state].control;
+
+       dprintk("Writing 0x%08x to port 0x%04x\n", value, port);
+
+       ret = acpi_processor_write_port(port, bit_width, value);
+       if (ret) {
+               dprintk("Invalid port width 0x%04x\n", bit_width);
+               retval = ret;
+               goto migrate_end;
+       }
+
+       /*
+        * Then we read the 'status_register' and compare the value with the
+        * target state's 'status' to make sure the transition was successful.
+        * Note that we'll poll for up to 1ms (100 cycles of 10us) before
+        * giving up.
+        */
+
+       port = data->acpi_data.status_register.address;
+       bit_width = data->acpi_data.status_register.bit_width;
+
+       dprintk("Looking for 0x%08x from port 0x%04x\n",
+               (u32) data->acpi_data.states[state].status, port);
+
+       for (i=0; i<100; i++) {
+               ret = acpi_processor_read_port(port, bit_width, &value);
+               if (ret) {      
+                       dprintk("Invalid port width 0x%04x\n", bit_width);
+                       retval = ret;
+                       goto migrate_end;
+               }
+               if (value == (u32) data->acpi_data.states[state].status)
+                       break;
+               udelay(10);
+       }
+
+       /* notify cpufreq */
+       cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+
+       if (value != (u32) data->acpi_data.states[state].status) {
+               unsigned int tmp = cpufreq_freqs.new;
+               cpufreq_freqs.new = cpufreq_freqs.old;
+               cpufreq_freqs.old = tmp;
+               cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+               cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+               printk(KERN_WARNING "acpi-cpufreq: Transition failed\n");
+               retval = -ENODEV;
+               goto migrate_end;
+       }
+
+       dprintk("Transition successful after %d microseconds\n", i * 10);
+
+       data->acpi_data.state = state;
+
+       retval = 0;
+migrate_end:
+       set_cpus_allowed(current, saved_mask);
+       return (retval);
+}
+
+
+static int
+acpi_cpufreq_target (
+       struct cpufreq_policy   *policy,
+       unsigned int target_freq,
+       unsigned int relation)
+{
+       struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+       unsigned int next_state = 0;
+       unsigned int result = 0;
+
+       dprintk("acpi_cpufreq_setpolicy\n");
+
+       result = cpufreq_frequency_table_target(policy,
+                       data->freq_table,
+                       target_freq,
+                       relation,
+                       &next_state);
+       if (result)
+               return (result);
+
+       result = acpi_processor_set_performance (data, policy->cpu, next_state);
+
+       return (result);
+}
+
+
+static int
+acpi_cpufreq_verify (
+       struct cpufreq_policy   *policy)
+{
+       unsigned int result = 0;
+       struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+       dprintk("acpi_cpufreq_verify\n");
+
+       result = cpufreq_frequency_table_verify(policy, 
+                       data->freq_table);
+
+       return (result);
+}
+
+
+static unsigned long
+acpi_cpufreq_guess_freq (
+       struct cpufreq_acpi_io  *data,
+       unsigned int            cpu)
+{
+       if (cpu_khz) {
+               /* search the closest match to cpu_khz */
+               unsigned int i;
+               unsigned long freq;
+               unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000;
+
+               for (i=0; i < (data->acpi_data.state_count - 1); i++) {
+                       freq = freqn;
+                       freqn = data->acpi_data.states[i+1].core_frequency * 1000;
+                       if ((2 * cpu_khz) > (freqn + freq)) {
+                               data->acpi_data.state = i;
+                               return (freq);
+                       }
+               }
+               data->acpi_data.state = data->acpi_data.state_count - 1;
+               return (freqn);
+       } else
+               /* assume CPU is at P0... */
+               data->acpi_data.state = 0;
+               return data->acpi_data.states[0].core_frequency * 1000;
+       
+}
+
+
+/* 
+ * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities
+ * of this driver
+ * @perf: processor-specific acpi_io_data struct
+ * @cpu: CPU being initialized
+ *
+ * To avoid issues with legacy OSes, some BIOSes require to be informed of
+ * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC 
+ * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in
+ * driver/acpi/processor.c
+ */
+static void 
+acpi_processor_cpu_init_pdc_est(
+               struct acpi_processor_performance *perf, 
+               unsigned int cpu,
+               struct acpi_object_list *obj_list
+               )
+{
+       union acpi_object *obj;
+       u32 *buf;
+       struct cpuinfo_x86 *c = cpu_data + cpu;
+       dprintk("acpi_processor_cpu_init_pdc_est\n");
+
+       if (!cpu_has(c, X86_FEATURE_EST))
+               return;
+
+       /* Initialize pdc. It will be used later. */
+       if (!obj_list)
+               return;
+               
+       if (!(obj_list->count && obj_list->pointer))
+               return;
+
+       obj = obj_list->pointer;
+       if ((obj->buffer.length == 12) && obj->buffer.pointer) {
+               buf = (u32 *)obj->buffer.pointer;
+                       buf[0] = ACPI_PDC_REVISION_ID;
+                       buf[1] = 1;
+                       buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
+               perf->pdc = obj_list;
+       }
+       return;
+}
+
+/* CPU specific PDC initialization */
+static void 
+acpi_processor_cpu_init_pdc(
+               struct acpi_processor_performance *perf, 
+               unsigned int cpu,
+               struct acpi_object_list *obj_list
+               )
+{
+       struct cpuinfo_x86 *c = cpu_data + cpu;
+       dprintk("acpi_processor_cpu_init_pdc\n");
+       perf->pdc = NULL;
+       if (cpu_has(c, X86_FEATURE_EST))
+               acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list);
+       return;
+}
+
+
+static int
+acpi_cpufreq_cpu_init (
+       struct cpufreq_policy   *policy)
+{
+       unsigned int            i;
+       unsigned int            cpu = policy->cpu;
+       struct cpufreq_acpi_io  *data;
+       unsigned int            result = 0;
+
+       union acpi_object               arg0 = {ACPI_TYPE_BUFFER};
+       u32                             arg0_buf[3];
+       struct acpi_object_list         arg_list = {1, &arg0};
+
+       dprintk("acpi_cpufreq_cpu_init\n");
+       /* setup arg_list for _PDC settings */
+        arg0.buffer.length = 12;
+        arg0.buffer.pointer = (u8 *) arg0_buf;
+
+       data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+       if (!data)
+               return (-ENOMEM);
+       memset(data, 0, sizeof(struct cpufreq_acpi_io));
+
+       acpi_io_data[cpu] = data;
+
+       acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list);
+       result = acpi_processor_register_performance(&data->acpi_data, cpu);
+       data->acpi_data.pdc = NULL;
+
+       if (result)
+               goto err_free;
+
+       /* capability check */
+       if (data->acpi_data.state_count <= 1) {
+               dprintk("No P-States\n");
+               result = -ENODEV;
+               goto err_unreg;
+       }
+       if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) ||
+           (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
+               dprintk("Unsupported address space [%d, %d]\n",
+                       (u32) (data->acpi_data.control_register.space_id),
+                       (u32) (data->acpi_data.status_register.space_id));
+               result = -ENODEV;
+               goto err_unreg;
+       }
+
+       /* alloc freq_table */
+       data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL);
+       if (!data->freq_table) {
+               result = -ENOMEM;
+               goto err_unreg;
+       }
+
+       /* detect transition latency */
+       policy->cpuinfo.transition_latency = 0;
+       for (i=0; i<data->acpi_data.state_count; i++) {
+               if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency)
+                       policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000;
+       }
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       /* The current speed is unknown and not detectable by ACPI...  */
+       policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
+
+       /* table init */
+       for (i=0; i<=data->acpi_data.state_count; i++)
+       {
+               data->freq_table[i].index = i;
+               if (i<data->acpi_data.state_count)
+                       data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000;
+               else
+                       data->freq_table[i].frequency = CPUFREQ_TABLE_END;
+       }
+
+       result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+       if (result) {
+               goto err_freqfree;
+       }
+
+       /* notify BIOS that we exist */
+       acpi_processor_notify_smm(THIS_MODULE);
+
+       printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n",
+              cpu);
+       for (i = 0; i < data->acpi_data.state_count; i++)
+               dprintk("     %cP%d: %d MHz, %d mW, %d uS\n",
+                       (i == data->acpi_data.state?'*':' '), i,
+                       (u32) data->acpi_data.states[i].core_frequency,
+                       (u32) data->acpi_data.states[i].power,
+                       (u32) data->acpi_data.states[i].transition_latency);
+
+       cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
+       return (result);
+
+ err_freqfree:
+       kfree(data->freq_table);
+ err_unreg:
+       acpi_processor_unregister_performance(&data->acpi_data, cpu);
+ err_free:
+       kfree(data);
+       acpi_io_data[cpu] = NULL;
+
+       return (result);
+}
+
+
+static int
+acpi_cpufreq_cpu_exit (
+       struct cpufreq_policy   *policy)
+{
+       struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
+
+
+       dprintk("acpi_cpufreq_cpu_exit\n");
+
+       if (data) {
+               cpufreq_frequency_table_put_attr(policy->cpu);
+               acpi_io_data[policy->cpu] = NULL;
+               acpi_processor_unregister_performance(&data->acpi_data, policy->cpu);
+               kfree(data);
+       }
+
+       return (0);
+}
+
+
+static struct freq_attr* acpi_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static struct cpufreq_driver acpi_cpufreq_driver = {
+       .verify         = acpi_cpufreq_verify,
+       .target         = acpi_cpufreq_target,
+       .init           = acpi_cpufreq_cpu_init,
+       .exit           = acpi_cpufreq_cpu_exit,
+       .name           = "acpi-cpufreq",
+       .owner          = THIS_MODULE,
+       .attr           = acpi_cpufreq_attr,
+};
+
+
+static int __init
+acpi_cpufreq_init (void)
+{
+       int                     result = 0;
+
+       dprintk("acpi_cpufreq_init\n");
+
+       result = cpufreq_register_driver(&acpi_cpufreq_driver);
+       
+       return (result);
+}
+
+
+static void __exit
+acpi_cpufreq_exit (void)
+{
+       dprintk("acpi_cpufreq_exit\n");
+
+       cpufreq_unregister_driver(&acpi_cpufreq_driver);
+
+       return;
+}
+
+
+late_initcall(acpi_cpufreq_init);
+module_exit(acpi_cpufreq_exit);
+
+MODULE_ALIAS("acpi");
diff --git a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c
new file mode 100644 (file)
index 0000000..e654e7b
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * (C) 2004  Sebastian Witt <se.witt@gmx.net>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *  Based upon reverse engineered information
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#define NFORCE2_XTAL 25
+#define NFORCE2_BOOTFSB 0x48
+#define NFORCE2_PLLENABLE 0xa8
+#define NFORCE2_PLLREG 0xa4
+#define NFORCE2_PLLADR 0xa0
+#define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div)
+
+#define NFORCE2_MIN_FSB 50
+#define NFORCE2_SAFE_DISTANCE 50
+
+/* Delay in ms between FSB changes */
+//#define NFORCE2_DELAY 10
+
+/* nforce2_chipset:
+ * FSB is changed using the chipset
+ */
+static struct pci_dev *nforce2_chipset_dev;
+
+/* fid:
+ * multiplier * 10
+ */
+static int fid = 0;
+
+/* min_fsb, max_fsb:
+ * minimum and maximum FSB (= FSB at boot time) 
+ */
+static int min_fsb = 0;
+static int max_fsb = 0;
+
+MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
+MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver");
+MODULE_LICENSE("GPL");
+
+module_param(fid, int, 0444);
+module_param(min_fsb, int, 0444);
+
+MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
+MODULE_PARM_DESC(min_fsb,
+                 "Minimum FSB to use, if not defined: current FSB - 50");
+
+/* DEBUG
+ *   Define it if you want verbose debug output, e.g. for bug reporting
+ */
+//#define NFORCE2_DEBUG
+
+#ifdef NFORCE2_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0)
+#endif
+
+/*
+ * nforce2_calc_fsb - calculate FSB
+ * @pll: PLL value
+ * 
+ *   Calculates FSB from PLL value
+ */
+static int nforce2_calc_fsb(int pll)
+{
+       unsigned char mul, div;
+
+       mul = (pll >> 8) & 0xff;
+       div = pll & 0xff;
+
+       if (div > 0)
+               return NFORCE2_XTAL * mul / div;
+
+       return 0;
+}
+
+/*
+ * nforce2_calc_pll - calculate PLL value
+ * @fsb: FSB
+ * 
+ *   Calculate PLL value for given FSB
+ */
+static int nforce2_calc_pll(unsigned int fsb)
+{
+       unsigned char xmul, xdiv;
+       unsigned char mul = 0, div = 0;
+       int tried = 0;
+
+       /* Try to calculate multiplier and divider up to 4 times */
+       while (((mul == 0) || (div == 0)) && (tried <= 3)) {
+               for (xdiv = 1; xdiv <= 0x80; xdiv++)
+                       for (xmul = 1; xmul <= 0xfe; xmul++)
+                               if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) ==
+                                   fsb + tried) {
+                                       mul = xmul;
+                                       div = xdiv;
+                               }
+               tried++;
+       }
+
+       if ((mul == 0) || (div == 0))
+               return -1;
+
+       return NFORCE2_PLL(mul, div);
+}
+
+/*
+ * nforce2_write_pll - write PLL value to chipset
+ * @pll: PLL value
+ * 
+ *   Writes new FSB PLL value to chipset
+ */
+static void nforce2_write_pll(int pll)
+{
+       int temp;
+
+       /* Set the pll addr. to 0x00 */
+       temp = 0x00;
+       pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLADR, temp);
+
+       /* Now write the value in all 64 registers */
+       for (temp = 0; temp <= 0x3f; temp++) {
+               pci_write_config_dword(nforce2_chipset_dev, 
+                                       NFORCE2_PLLREG, pll);
+       }
+
+       return;
+}
+
+/*
+ * nforce2_fsb_read - Read FSB
+ *
+ *   Read FSB from chipset
+ *   If bootfsb != 0, return FSB at boot-time
+ */
+static unsigned int nforce2_fsb_read(int bootfsb)
+{
+       struct pci_dev *nforce2_sub5;
+       u32 fsb, temp = 0;
+
+       
+       /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
+       nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
+                                      0x01EF,
+                                      PCI_ANY_ID,
+                                      PCI_ANY_ID,
+                                      NULL);
+       
+       if (!nforce2_sub5)
+               return 0;
+
+       pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb);
+       fsb /= 1000000;
+       
+       /* Check if PLL register is already set */
+       pci_read_config_byte(nforce2_chipset_dev, 
+                             NFORCE2_PLLENABLE, (u8 *)&temp);
+       
+       if(bootfsb || !temp)
+               return fsb;
+               
+       /* Use PLL register FSB value */
+       pci_read_config_dword(nforce2_chipset_dev, 
+                              NFORCE2_PLLREG, &temp);
+       fsb = nforce2_calc_fsb(temp);
+
+       return fsb;
+}
+
+/*
+ * nforce2_set_fsb - set new FSB
+ * @fsb: New FSB
+ * 
+ *   Sets new FSB
+ */
+static int nforce2_set_fsb(unsigned int fsb)
+{
+       u32 pll, temp = 0;
+       unsigned int tfsb;
+       int diff;
+
+       if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
+               printk(KERN_ERR "cpufreq: FSB %d is out of range!\n", fsb);
+               return -EINVAL;
+       }
+       
+       tfsb = nforce2_fsb_read(0);
+       if (!tfsb) {
+               printk(KERN_ERR "cpufreq: Error while reading the FSB\n");
+               return -EINVAL;
+       }
+
+       /* First write? Then set actual value */
+       pci_read_config_byte(nforce2_chipset_dev, 
+                             NFORCE2_PLLENABLE, (u8 *)&temp);
+       if (!temp) {
+               pll = nforce2_calc_pll(tfsb);
+
+               if (pll < 0)
+                       return -EINVAL;
+
+               nforce2_write_pll(pll);
+       }
+
+       /* Enable write access */
+       temp = 0x01;
+       pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8)temp);
+
+       diff = tfsb - fsb;
+
+       if (!diff)
+               return 0;
+
+       while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
+               if (diff < 0)
+                       tfsb++;
+               else
+                       tfsb--;
+
+               /* Calculate the PLL reg. value */
+               if ((pll = nforce2_calc_pll(tfsb)) == -1)
+                       return -EINVAL;
+               
+               nforce2_write_pll(pll);
+#ifdef NFORCE2_DELAY
+               mdelay(NFORCE2_DELAY);
+#endif
+       }
+
+       temp = 0x40;
+       pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLADR, (u8)temp);
+
+       return 0;
+}
+
+/**
+ * nforce2_get - get the CPU frequency
+ * @cpu: CPU number
+ * 
+ * Returns the CPU frequency
+ */
+static unsigned int nforce2_get(unsigned int cpu)
+{
+       if (cpu)
+               return 0;
+       return nforce2_fsb_read(0) * fid * 100;
+}
+
+/**
+ * nforce2_target - set a new CPUFreq policy
+ * @policy: new policy
+ * @target_freq: the target frequency
+ * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
+ *
+ * Sets a new CPUFreq policy.
+ */
+static int nforce2_target(struct cpufreq_policy *policy,
+                         unsigned int target_freq, unsigned int relation)
+{
+//        unsigned long         flags;
+       struct cpufreq_freqs freqs;
+       unsigned int target_fsb;
+
+       if ((target_freq > policy->max) || (target_freq < policy->min))
+               return -EINVAL;
+
+       target_fsb = target_freq / (fid * 100);
+
+       freqs.old = nforce2_get(policy->cpu);
+       freqs.new = target_fsb * fid * 100;
+       freqs.cpu = 0;          /* Only one CPU on nForce2 plattforms */
+
+       if (freqs.old == freqs.new)
+               return 0;
+
+       dprintk(KERN_INFO "cpufreq: Old CPU frequency %d kHz, new %d kHz\n",
+              freqs.old, freqs.new);
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       /* Disable IRQs */
+       //local_irq_save(flags);
+
+       if (nforce2_set_fsb(target_fsb) < 0)
+               printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n",
+                       target_fsb);
+       else
+               dprintk(KERN_INFO "cpufreq: Changed FSB successfully to %d\n",
+                       target_fsb);
+
+       /* Enable IRQs */
+       //local_irq_restore(flags);
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       return 0;
+}
+
+/**
+ * nforce2_verify - verifies a new CPUFreq policy
+ * @policy: new policy
+ */
+static int nforce2_verify(struct cpufreq_policy *policy)
+{
+       unsigned int fsb_pol_max;
+
+       fsb_pol_max = policy->max / (fid * 100);
+
+       if (policy->min < (fsb_pol_max * fid * 100))
+               policy->max = (fsb_pol_max + 1) * fid * 100;
+
+       cpufreq_verify_within_limits(policy,
+                                     policy->cpuinfo.min_freq,
+                                     policy->cpuinfo.max_freq);
+       return 0;
+}
+
+static int nforce2_cpu_init(struct cpufreq_policy *policy)
+{
+       unsigned int fsb;
+       unsigned int rfid;
+
+       /* capability check */
+       if (policy->cpu != 0)
+               return -ENODEV;
+
+       /* Get current FSB */
+       fsb = nforce2_fsb_read(0);
+
+       if (!fsb)
+               return -EIO;
+
+       /* FIX: Get FID from CPU */
+       if (!fid) {
+               if (!cpu_khz) {
+                       printk(KERN_WARNING
+                              "cpufreq: cpu_khz not set, can't calculate multiplier!\n");
+                       return -ENODEV;
+               }
+
+               fid = cpu_khz / (fsb * 100);
+               rfid = fid % 5;
+
+               if (rfid) {
+                       if (rfid > 2)
+                               fid += 5 - rfid;
+                       else
+                               fid -= rfid;
+               }
+       }
+
+       printk(KERN_INFO "cpufreq: FSB currently at %i MHz, FID %d.%d\n", fsb,
+              fid / 10, fid % 10);
+       
+       /* Set maximum FSB to FSB at boot time */
+       max_fsb = nforce2_fsb_read(1);
+       
+       if(!max_fsb)
+               return -EIO;
+
+       if (!min_fsb)
+               min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE;
+
+       if (min_fsb < NFORCE2_MIN_FSB)
+               min_fsb = NFORCE2_MIN_FSB;
+
+       /* cpuinfo and default policy values */
+       policy->cpuinfo.min_freq = min_fsb * fid * 100;
+       policy->cpuinfo.max_freq = max_fsb * fid * 100;
+       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       policy->cur = nforce2_get(policy->cpu);
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       return 0;
+}
+
+static int nforce2_cpu_exit(struct cpufreq_policy *policy)
+{
+       return 0;
+}
+
+static struct cpufreq_driver nforce2_driver = {
+       .name = "nforce2",
+       .verify = nforce2_verify,
+       .target = nforce2_target,
+       .get = nforce2_get,
+       .init = nforce2_cpu_init,
+       .exit = nforce2_cpu_exit,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
+ *
+ * Detects nForce2 A2 and C1 stepping
+ * 
+ */
+static unsigned int nforce2_detect_chipset(void)
+{
+       u8 revision;
+
+       nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
+                                             PCI_DEVICE_ID_NVIDIA_NFORCE2,
+                                             PCI_ANY_ID,
+                                             PCI_ANY_ID,
+                                             NULL);
+
+       if (nforce2_chipset_dev == NULL)
+               return -ENODEV;
+
+       pci_read_config_byte(nforce2_chipset_dev, PCI_REVISION_ID, &revision);
+
+       printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n",
+              revision);
+       printk(KERN_INFO
+              "cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n");
+
+       return 0;
+}
+
+/**
+ * nforce2_init - initializes the nForce2 CPUFreq driver
+ *
+ * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported
+ * devices, -EINVAL on problems during initiatization, and zero on
+ * success.
+ */
+static int __init nforce2_init(void)
+{
+       /* TODO: do we need to detect the processor? */
+
+       /* detect chipset */
+       if (nforce2_detect_chipset()) {
+               printk(KERN_ERR "cpufreq: No nForce2 chipset.\n");
+               return -ENODEV;
+       }
+
+       return cpufreq_register_driver(&nforce2_driver);
+}
+
+/**
+ * nforce2_exit - unregisters cpufreq module
+ *
+ *   Unregisters nForce2 FSB change support.
+ */
+static void __exit nforce2_exit(void)
+{
+       cpufreq_unregister_driver(&nforce2_driver);
+}
+
+module_init(nforce2_init);
+module_exit(nforce2_exit);
+
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
new file mode 100644 (file)
index 0000000..2bba6df
--- /dev/null
@@ -0,0 +1,140 @@
+#include <linux/init.h>
+#include <asm/processor.h>
+
+#define LVL_1_INST     1
+#define LVL_1_DATA     2
+#define LVL_2          3
+#define LVL_3          4
+#define LVL_TRACE      5
+
+struct _cache_table
+{
+       unsigned char descriptor;
+       char cache_type;
+       short size;
+};
+
+/* all the cache descriptor types we care about (no TLB or trace cache entries) */
+static struct _cache_table cache_table[] __initdata =
+{
+       { 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 */
+       { 0x0a, LVL_1_DATA, 8 },        /* 2 way set assoc, 32 byte line size */
+       { 0x0c, LVL_1_DATA, 16 },       /* 4-way set assoc, 32 byte line size */
+       { 0x22, LVL_3,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x23, LVL_3,      1024 },     /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x25, LVL_3,      2048 },     /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x29, LVL_3,      4096 },     /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x2c, LVL_1_DATA, 32 },       /* 8-way set assoc, 64 byte line size */
+       { 0x30, LVL_1_INST, 32 },       /* 8-way set assoc, 64 byte line size */
+       { 0x39, LVL_2,      128 },      /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x3b, LVL_2,      128 },      /* 2-way set assoc, sectored cache, 64 byte line size */
+       { 0x3c, LVL_2,      256 },      /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x41, LVL_2,      128 },      /* 4-way set assoc, 32 byte line size */
+       { 0x42, LVL_2,      256 },      /* 4-way set assoc, 32 byte line size */
+       { 0x43, LVL_2,      512 },      /* 4-way set assoc, 32 byte line size */
+       { 0x44, LVL_2,      1024 },     /* 4-way set assoc, 32 byte line size */
+       { 0x45, LVL_2,      2048 },     /* 4-way set assoc, 32 byte line size */
+       { 0x60, LVL_1_DATA, 16 },       /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x66, LVL_1_DATA, 8 },        /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x67, LVL_1_DATA, 16 },       /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x68, LVL_1_DATA, 32 },       /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x70, LVL_TRACE,  12 },       /* 8-way set assoc */
+       { 0x71, LVL_TRACE,  16 },       /* 8-way set assoc */
+       { 0x72, LVL_TRACE,  32 },       /* 8-way set assoc */
+       { 0x78, LVL_2,    1024 },       /* 4-way set assoc, 64 byte line size */
+       { 0x79, LVL_2,     128 },       /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x7a, LVL_2,     256 },       /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x7b, LVL_2,     512 },       /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x7c, LVL_2,    1024 },       /* 8-way set assoc, sectored cache, 64 byte line size */
+       { 0x7d, LVL_2,    2048 },       /* 8-way set assoc, 64 byte line size */
+       { 0x7f, LVL_2,     512 },       /* 2-way set assoc, 64 byte line size */
+       { 0x82, LVL_2,     256 },       /* 8-way set assoc, 32 byte line size */
+       { 0x83, LVL_2,     512 },       /* 8-way set assoc, 32 byte line size */
+       { 0x84, LVL_2,    1024 },       /* 8-way set assoc, 32 byte line size */
+       { 0x85, LVL_2,    2048 },       /* 8-way set assoc, 32 byte line size */
+       { 0x86, LVL_2,     512 },       /* 4-way set assoc, 64 byte line size */
+       { 0x87, LVL_2,    1024 },       /* 8-way set assoc, 64 byte line size */
+       { 0x00, 0, 0}
+};
+
+unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c)
+{
+       unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+
+       if (c->cpuid_level > 1) {
+               /* supports eax=2  call */
+               int i, j, n;
+               int regs[4];
+               unsigned char *dp = (unsigned char *)regs;
+
+               /* Number of times to iterate */
+               n = cpuid_eax(2) & 0xFF;
+
+               for ( i = 0 ; i < n ; i++ ) {
+                       cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
+
+                       /* If bit 31 is set, this is an unknown format */
+                       for ( j = 0 ; j < 3 ; j++ ) {
+                               if ( regs[j] < 0 ) regs[j] = 0;
+                       }
+
+                       /* Byte 0 is level count, not a descriptor */
+                       for ( j = 1 ; j < 16 ; j++ ) {
+                               unsigned char des = dp[j];
+                               unsigned char k = 0;
+
+                               /* look up this descriptor in the table */
+                               while (cache_table[k].descriptor != 0)
+                               {
+                                       if (cache_table[k].descriptor == des) {
+                                               switch (cache_table[k].cache_type) {
+                                               case LVL_1_INST:
+                                                       l1i += cache_table[k].size;
+                                                       break;
+                                               case LVL_1_DATA:
+                                                       l1d += cache_table[k].size;
+                                                       break;
+                                               case LVL_2:
+                                                       l2 += cache_table[k].size;
+                                                       break;
+                                               case LVL_3:
+                                                       l3 += cache_table[k].size;
+                                                       break;
+                                               case LVL_TRACE:
+                                                       trace += cache_table[k].size;
+                                                       break;
+                                               }
+
+                                               break;
+                                       }
+
+                                       k++;
+                               }
+                       }
+               }
+
+               if ( trace )
+                       printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
+               else if ( l1i )
+                       printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
+               if ( l1d )
+                       printk(", L1 D cache: %dK\n", l1d);
+               else
+                       printk("\n");
+               if ( l2 )
+                       printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
+               if ( l3 )
+                       printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
+
+               /*
+                * This assumes the L3 cache is shared; it typically lives in
+                * the northbridge.  The L1 caches are included by the L2
+                * cache, and so should not be included for the purpose of
+                * SMP switching weights.
+                */
+               c->x86_cache_size = l2 ? l2 : (l1i+l1d);
+       }
+
+       return l2;
+}
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
new file mode 100644 (file)
index 0000000..4d066cc
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ *  Kernel Probes (KProbes)
+ *  arch/i386/kernel/kprobes.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ *
+ * 2002-Oct    Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
+ *             Probes initial implementation ( includes contributions from
+ *             Rusty Russell).
+ * 2004-July   Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
+ *             interface to access function arguments.
+ */
+
+#include <linux/config.h>
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/spinlock.h>
+#include <linux/preempt.h>
+#include <asm/kdebug.h>
+
+/* kprobe_status settings */
+#define KPROBE_HIT_ACTIVE      0x00000001
+#define KPROBE_HIT_SS          0x00000002
+
+static struct kprobe *current_kprobe;
+static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;
+static struct pt_regs jprobe_saved_regs;
+static long *jprobe_saved_esp;
+/* copy of the kernel stack at the probe fire time */
+static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
+
+/*
+ * returns non-zero if opcode modifies the interrupt flag.
+ */
+static inline int is_IF_modifier(kprobe_opcode_t opcode)
+{
+       switch (opcode) {
+       case 0xfa:              /* cli */
+       case 0xfb:              /* sti */
+       case 0xcf:              /* iret/iretd */
+       case 0x9d:              /* popf/popfd */
+               return 1;
+       }
+       return 0;
+}
+
+void arch_prepare_kprobe(struct kprobe *p)
+{
+       memcpy(p->insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+}
+
+static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
+{
+       *p->addr = p->opcode;
+       regs->eip = (unsigned long)p->addr;
+}
+
+static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+       regs->eflags |= TF_MASK;
+       regs->eflags &= ~IF_MASK;
+       regs->eip = (unsigned long)&p->insn;
+}
+
+/*
+ * Interrupts are disabled on entry as trap3 is an interrupt gate and they
+ * remain disabled thorough out this function.
+ */
+static inline int kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p;
+       int ret = 0;
+       u8 *addr = (u8 *) (regs->eip - 1);
+
+       /* We're in an interrupt, but this is clear and BUG()-safe. */
+       preempt_disable();
+
+       /* Check we're not actually recursing */
+       if (kprobe_running()) {
+               /* We *are* holding lock here, so this is safe.
+                  Disarm the probe we just hit, and ignore it. */
+               p = get_kprobe(addr);
+               if (p) {
+                       disarm_kprobe(p, regs);
+                       ret = 1;
+               } else {
+                       p = current_kprobe;
+                       if (p->break_handler && p->break_handler(p, regs)) {
+                               goto ss_probe;
+                       }
+               }
+               /* If it's not ours, can't be delete race, (we hold lock). */
+               goto no_kprobe;
+       }
+
+       lock_kprobes();
+       p = get_kprobe(addr);
+       if (!p) {
+               unlock_kprobes();
+               if (*addr != BREAKPOINT_INSTRUCTION) {
+                       /*
+                        * The breakpoint instruction was removed right
+                        * after we hit it.  Another cpu has removed
+                        * either a probepoint or a debugger breakpoint
+                        * at this address.  In either case, no further
+                        * handling of this interrupt is appropriate.
+                        */
+                       ret = 1;
+               }
+               /* Not one of ours: let kernel handle it */
+               goto no_kprobe;
+       }
+
+       kprobe_status = KPROBE_HIT_ACTIVE;
+       current_kprobe = p;
+       kprobe_saved_eflags = kprobe_old_eflags
+           = (regs->eflags & (TF_MASK | IF_MASK));
+       if (is_IF_modifier(p->opcode))
+               kprobe_saved_eflags &= ~IF_MASK;
+
+       if (p->pre_handler(p, regs)) {
+               /* handler has already set things up, so skip ss setup */
+               return 1;
+       }
+
+      ss_probe:
+       prepare_singlestep(p, regs);
+       kprobe_status = KPROBE_HIT_SS;
+       return 1;
+
+      no_kprobe:
+       preempt_enable_no_resched();
+       return ret;
+}
+
+/*
+ * Called after single-stepping.  p->addr is the address of the
+ * instruction whose first byte has been replaced by the "int 3"
+ * instruction.  To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction.  The address of this
+ * copy is p->insn.
+ *
+ * This function prepares to return from the post-single-step
+ * interrupt.  We have to fix up the stack as follows:
+ *
+ * 0) Except in the case of absolute or indirect jump or call instructions,
+ * the new eip is relative to the copied instruction.  We need to make
+ * it relative to the original instruction.
+ *
+ * 1) If the single-stepped instruction was pushfl, then the TF and IF
+ * flags are set in the just-pushed eflags, and may need to be cleared.
+ *
+ * 2) If the single-stepped instruction was a call, the return address
+ * that is atop the stack is the address following the copied instruction.
+ * We need to make it the address following the original instruction.
+ */
+static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+{
+       unsigned long *tos = (unsigned long *)&regs->esp;
+       unsigned long next_eip = 0;
+       unsigned long copy_eip = (unsigned long)&p->insn;
+       unsigned long orig_eip = (unsigned long)p->addr;
+
+       switch (p->insn[0]) {
+       case 0x9c:              /* pushfl */
+               *tos &= ~(TF_MASK | IF_MASK);
+               *tos |= kprobe_old_eflags;
+               break;
+       case 0xe8:              /* call relative - Fix return addr */
+               *tos = orig_eip + (*tos - copy_eip);
+               break;
+       case 0xff:
+               if ((p->insn[1] & 0x30) == 0x10) {
+                       /* call absolute, indirect */
+                       /* Fix return addr; eip is correct. */
+                       next_eip = regs->eip;
+                       *tos = orig_eip + (*tos - copy_eip);
+               } else if (((p->insn[1] & 0x31) == 0x20) ||     /* jmp near, absolute indirect */
+                          ((p->insn[1] & 0x31) == 0x21)) {     /* jmp far, absolute indirect */
+                       /* eip is correct. */
+                       next_eip = regs->eip;
+               }
+               break;
+       case 0xea:              /* jmp absolute -- eip is correct */
+               next_eip = regs->eip;
+               break;
+       default:
+               break;
+       }
+
+       regs->eflags &= ~TF_MASK;
+       if (next_eip) {
+               regs->eip = next_eip;
+       } else {
+               regs->eip = orig_eip + (regs->eip - copy_eip);
+       }
+}
+
+/*
+ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
+ * remain disabled thoroughout this function.  And we hold kprobe lock.
+ */
+static inline int post_kprobe_handler(struct pt_regs *regs)
+{
+       if (!kprobe_running())
+               return 0;
+
+       if (current_kprobe->post_handler)
+               current_kprobe->post_handler(current_kprobe, regs, 0);
+
+       resume_execution(current_kprobe, regs);
+       regs->eflags |= kprobe_saved_eflags;
+
+       unlock_kprobes();
+       preempt_enable_no_resched();
+
+       /*
+        * if somebody else is singlestepping across a probe point, eflags
+        * will have TF set, in which case, continue the remaining processing
+        * of do_debug, as if this is not a probe hit.
+        */
+       if (regs->eflags & TF_MASK)
+               return 0;
+
+       return 1;
+}
+
+/* Interrupts disabled, kprobe_lock held. */
+static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       if (current_kprobe->fault_handler
+           && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
+               return 1;
+
+       if (kprobe_status & KPROBE_HIT_SS) {
+               resume_execution(current_kprobe, regs);
+               regs->eflags |= kprobe_old_eflags;
+
+               unlock_kprobes();
+               preempt_enable_no_resched();
+       }
+       return 0;
+}
+
+/*
+ * Wrapper routine to for handling exceptions.
+ */
+int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
+                            void *data)
+{
+       struct die_args *args = (struct die_args *)data;
+       switch (val) {
+       case DIE_INT3:
+               if (kprobe_handler(args->regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_DEBUG:
+               if (post_kprobe_handler(args->regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_GPF:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_PAGE_FAULT:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       unsigned long addr;
+
+       jprobe_saved_regs = *regs;
+       jprobe_saved_esp = &regs->esp;
+       addr = (unsigned long)jprobe_saved_esp;
+
+       /*
+        * TBD: As Linus pointed out, gcc assumes that the callee
+        * owns the argument space and could overwrite it, e.g.
+        * tailcall optimization. So, to be absolutely safe
+        * we also save and restore enough stack bytes to cover
+        * the argument area.
+        */
+       memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr));
+       regs->eflags &= ~IF_MASK;
+       regs->eip = (unsigned long)(jp->entry);
+       return 1;
+}
+
+void jprobe_return(void)
+{
+       preempt_enable_no_resched();
+       asm volatile ("       xchgl   %%ebx,%%esp     \n"
+                     "       int3                      \n"::"b"
+                     (jprobe_saved_esp):"memory");
+}
+void jprobe_return_end(void)
+{
+};
+
+int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       u8 *addr = (u8 *) (regs->eip - 1);
+       unsigned long stack_addr = (unsigned long)jprobe_saved_esp;
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+       if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
+               if (&regs->esp != jprobe_saved_esp) {
+                       struct pt_regs *saved_regs =
+                           container_of(jprobe_saved_esp, struct pt_regs, esp);
+                       printk("current esp %p does not match saved esp %p\n",
+                              &regs->esp, jprobe_saved_esp);
+                       printk("Saved registers for jprobe %p\n", jp);
+                       show_registers(saved_regs);
+                       printk("Current registers\n");
+                       show_registers(regs);
+                       BUG();
+               }
+               *regs = jprobe_saved_regs;
+               memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack,
+                      MIN_STACK_SIZE(stack_addr));
+               return 1;
+       }
+       return 0;
+}
diff --git a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
new file mode 100644 (file)
index 0000000..847ba44
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * This file contains work-arounds for x86 and x86_64 platform bugs.
+ */
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
+
+void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
+{
+       u8 config, rev;
+       u32 word;
+
+       /* BIOS may enable hardware IRQ balancing for
+        * E7520/E7320/E7525(revision ID 0x9 and below)
+        * based platforms.
+        * Disable SW irqbalance/affinity on those platforms.
+        */
+       pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
+       if (rev > 0x9)
+               return;
+
+       printk(KERN_INFO "Intel E7520/7320/7525 detected.");
+
+       /* enable access to config space*/
+       pci_read_config_byte(dev, 0xf4, &config);
+       config |= 0x2;
+       pci_write_config_byte(dev, 0xf4, config);
+
+       /* read xTPR register */
+       raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
+
+       if (!(word & (1 << 13))) {
+               printk(KERN_INFO "Disabling irq balancing and affinity\n");
+#ifdef CONFIG_IRQBALANCE
+               irqbalance_disable("");
+#endif
+               noirqdebug_setup("");
+               no_irq_affinity = 1;
+       }
+
+       config &= ~0x2;
+       /* disable access to config space*/
+       pci_write_config_byte(dev, 0xf4, config);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7320_MCH,  quirk_intel_irqbalance);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_intel_irqbalance);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_intel_irqbalance);
+#endif
diff --git a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall.lds.S
new file mode 100644 (file)
index 0000000..3a8329d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Linker script for vsyscall DSO.  The vsyscall page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page).  This script controls its layout.
+ */
+#include <asm/asm_offsets.h>
+
+SECTIONS
+{
+  . = VSYSCALL_BASE + SIZEOF_HEADERS;
+
+  .hash           : { *(.hash) }               :text
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+
+  /* This linker script is used both with -r and with -shared.
+     For the layouts to match, we need to skip more than enough
+     space for the dynamic symbol table et al.  If this amount
+     is insufficient, ld -shared will barf.  Just increase it here.  */
+  . = VSYSCALL_BASE + 0x400;
+
+  .text           : { *(.text) }               :text =0x90909090
+
+  .eh_frame_hdr   : { *(.eh_frame_hdr) }       :text :eh_frame_hdr
+  .eh_frame       : { KEEP (*(.eh_frame)) }    :text
+  .dynamic        : { *(.dynamic) }            :text :dynamic
+  .useless        : {
+       *(.got.plt) *(.got)
+       *(.data .data.* .gnu.linkonce.d.*)
+       *(.dynbss)
+       *(.bss .bss.* .gnu.linkonce.b.*)
+  }                                            :text
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+  dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+  eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+  LINUX_2.5 {
+    global:
+       __kernel_vsyscall;
+       __kernel_sigreturn;
+       __kernel_rt_sigreturn;
+
+    local: *;
+  };
+}
+
+/* The ELF entry point can be used to set the AT_SYSINFO value.  */
+ENTRY(__kernel_vsyscall);
diff --git a/arch/ia64/Kconfig.debug b/arch/ia64/Kconfig.debug
new file mode 100644 (file)
index 0000000..19edc8b
--- /dev/null
@@ -0,0 +1,64 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+choice
+       prompt "Physical memory granularity"
+       default IA64_GRANULE_64MB
+
+config IA64_GRANULE_16MB
+       bool "16MB"
+       help
+         IA-64 identity-mapped regions use a large page size called "granules".
+
+         Select "16MB" for a small granule size.
+         Select "64MB" for a large granule size.  This is the current default.
+
+config IA64_GRANULE_64MB
+       bool "64MB"
+       depends on !(IA64_GENERIC || IA64_HP_ZX1 || IA64_SGI_SN2)
+
+endchoice
+
+config IA64_PRINT_HAZARDS
+       bool "Print possible IA-64 dependency violations to console"
+       depends on DEBUG_KERNEL
+       help
+         Selecting this option prints more information for Illegal Dependency
+         Faults, that is, for Read-after-Write (RAW), Write-after-Write (WAW),
+         or Write-after-Read (WAR) violations.  This option is ignored if you
+         are compiling for an Itanium A step processor
+         (CONFIG_ITANIUM_ASTEP_SPECIFIC).  If you're unsure, select Y.
+
+config DISABLE_VHPT
+       bool "Disable VHPT"
+       depends on DEBUG_KERNEL
+       help
+         The Virtual Hash Page Table (VHPT) enhances virtual address
+         translation performance.  Normally you want the VHPT active but you
+         can select this option to disable the VHPT for debugging.  If you're
+         unsure, answer N.
+
+config IA64_DEBUG_CMPXCHG
+       bool "Turn on compare-and-exchange bug checking (slow!)"
+       depends on DEBUG_KERNEL
+       help
+         Selecting this option turns on bug checking for the IA-64
+         compare-and-exchange instructions.  This is slow!  Itaniums
+         from step B3 or later don't have this problem. If you're unsure,
+         select N.
+
+config IA64_DEBUG_IRQ
+       bool "Turn on irq debug checks (slow!)"
+       depends on DEBUG_KERNEL
+       help
+         Selecting this option turns on bug checking for the IA-64 irq_save
+         and restore instructions.  It's useful for tracking down spinlock
+         problems, but slow!  If you're unsure, select N.
+
+config SYSVIPC_COMPAT
+       bool
+       depends on COMPAT && SYSVIPC
+       default y
+
+endmenu
diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig
new file mode 100644 (file)
index 0000000..f16fd2e
--- /dev/null
@@ -0,0 +1,1132 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc2
+# Tue Sep 28 13:26:53 2004
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_HOTPLUG=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_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor type and features
+#
+CONFIG_IA64=y
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_TIME_INTERPOLATION=y
+CONFIG_EFI=y
+CONFIG_GENERIC_IOMAP=y
+# CONFIG_IA64_GENERIC is not set
+CONFIG_IA64_DIG=y
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+# CONFIG_NUMA is not set
+# CONFIG_VIRTUAL_MEM_MAP is not set
+# CONFIG_IA64_CYCLONE is not set
+CONFIG_IOSAPIC=y
+CONFIG_FORCE_MAX_ZONEORDER=18
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_PREEMPT=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_COMPAT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+
+#
+# Firmware Drivers
+#
+CONFIG_EFI_VARS=y
+CONFIG_EFI_PCDP=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+
+#
+# Power management and ACPI
+#
+CONFIG_PM=y
+CONFIG_ACPI=y
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=m
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_THERMAL=m
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+
+#
+# Bus options (PCI, PCMCIA)
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# 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_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_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=4096
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=m
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_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_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_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# 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_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# 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=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_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=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=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=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY 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 is not set
+
+#
+# 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_NET_FC 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=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=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA 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_ACPI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+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
+
+#
+# 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_HW_RANDOM is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+CONFIG_AGP=m
+CONFIG_AGP_I460=m
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=m
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HPET is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# 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=y
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+# CONFIG_SND_SEQUENCER_OSS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_OPL3_LIB=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+CONFIG_SND_CS4281=m
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VX222 is not set
+
+#
+# ALSA USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_UHCI_HCD=m
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=m
+CONFIG_USB_BLUETOOTH_TTY=m
+CONFIG_USB_MIDI=m
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+# 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_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=y
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+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=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_IA64_GRANULE_16MB is not set
+CONFIG_IA64_GRANULE_64MB=y
+# CONFIG_IA64_PRINT_HAZARDS is not set
+# CONFIG_DISABLE_VHPT is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
+CONFIG_SYSVIPC_COMPAT=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WHIRLPOOL is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
new file mode 100644 (file)
index 0000000..ce94125
--- /dev/null
@@ -0,0 +1,1028 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc2
+# Tue Sep 28 09:03:25 2004
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=20
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor type and features
+#
+CONFIG_IA64=y
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_TIME_INTERPOLATION=y
+CONFIG_EFI=y
+CONFIG_GENERIC_IOMAP=y
+# CONFIG_IA64_GENERIC is not set
+CONFIG_IA64_DIG=y
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_IA64_L1_CACHE_SHIFT=7
+# CONFIG_NUMA is not set
+CONFIG_VIRTUAL_MEM_MAP=y
+CONFIG_IA64_CYCLONE=y
+CONFIG_IOSAPIC=y
+CONFIG_FORCE_MAX_ZONEORDER=18
+CONFIG_SMP=y
+CONFIG_NR_CPUS=4
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_PREEMPT is not set
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_COMPAT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+
+#
+# Firmware Drivers
+#
+CONFIG_EFI_VARS=y
+CONFIG_EFI_PCDP=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+
+#
+# Power management and ACPI
+#
+CONFIG_PM=y
+CONFIG_ACPI=y
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=m
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_THERMAL=m
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_SYSTEM=y
+
+#
+# Bus options (PCI, PCMCIA)
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=m
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_ACPI=m
+# 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
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# 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_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_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=4096
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_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_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_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+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_QLOGIC_ISP is not set
+CONFIG_SCSI_QLOGIC_FC=y
+# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
+CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_QLA2XXX=y
+CONFIG_SCSI_QLA21XX=m
+CONFIG_SCSI_QLA22XX=m
+CONFIG_SCSI_QLA2300=m
+CONFIG_SCSI_QLA2322=m
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_CTL is not set
+
+#
+# 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=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+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_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# 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=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
+CONFIG_E100=m
+# CONFIG_E100_NAPI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI 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=y
+
+#
+# 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 is not set
+
+#
+# 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_NET_FC is not set
+# CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+CONFIG_GAMEPORT=m
+CONFIG_SOUND_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
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# 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=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA 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=y
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_ACPI=y
+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
+
+#
+# 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_HW_RANDOM is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+CONFIG_AGP=m
+CONFIG_AGP_I460=m
+CONFIG_DRM=y
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+CONFIG_RAW_DRIVER=m
+CONFIG_HPET=y
+# CONFIG_HPET_RTC_IRQ is not set
+CONFIG_HPET_MMAP=y
+CONFIG_MAX_RAW_DEVS=256
+
+#
+# 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=y
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_UHCI_HCD=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_STORAGE=m
+# 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_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+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_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+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=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_POSIX is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+# CONFIG_IA64_PRINT_HAZARDS is not set
+# CONFIG_DISABLE_VHPT is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
+CONFIG_SYSVIPC_COMPAT=y
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+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_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WHIRLPOOL is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
diff --git a/arch/ia64/kernel/domain.c b/arch/ia64/kernel/domain.c
new file mode 100644 (file)
index 0000000..c655353
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * arch/ia64/kernel/domain.c
+ * Architecture specific sched-domains builder.
+ *
+ * Copyright (C) 2004 Jesse Barnes
+ * Copyright (C) 2004 Silicon Graphics, Inc.
+ */
+
+#include <linux/sched.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/topology.h>
+
+#define SD_NODES_PER_DOMAIN 6
+
+#ifdef CONFIG_NUMA
+/**
+ * find_next_best_node - find the next node to include in a sched_domain
+ * @node: node whose sched_domain we're building
+ * @used_nodes: nodes already in the sched_domain
+ *
+ * Find the next node to include in a given scheduling domain.  Simply
+ * finds the closest node not already in the @used_nodes map.
+ *
+ * Should use nodemask_t.
+ */
+static int __devinit find_next_best_node(int node, unsigned long *used_nodes)
+{
+       int i, n, val, min_val, best_node = 0;
+
+       min_val = INT_MAX;
+
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               /* Start at @node */
+               n = (node + i) % MAX_NUMNODES;
+
+               if (!nr_cpus_node(n))
+                       continue;
+
+               /* Skip already used nodes */
+               if (test_bit(n, used_nodes))
+                       continue;
+
+               /* Simple min distance search */
+               val = node_distance(node, n);
+
+               if (val < min_val) {
+                       min_val = val;
+                       best_node = n;
+               }
+       }
+
+       set_bit(best_node, used_nodes);
+       return best_node;
+}
+
+/**
+ * sched_domain_node_span - get a cpumask for a node's sched_domain
+ * @node: node whose cpumask we're constructing
+ * @size: number of nodes to include in this span
+ *
+ * Given a node, construct a good cpumask for its sched_domain to span.  It
+ * should be one that prevents unnecessary balancing, but also spreads tasks
+ * out optimally.
+ */
+static cpumask_t __devinit sched_domain_node_span(int node)
+{
+       int i;
+       cpumask_t span, nodemask;
+       DECLARE_BITMAP(used_nodes, MAX_NUMNODES);
+
+       cpus_clear(span);
+       bitmap_zero(used_nodes, MAX_NUMNODES);
+
+       nodemask = node_to_cpumask(node);
+       cpus_or(span, span, nodemask);
+       set_bit(node, used_nodes);
+
+       for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
+               int next_node = find_next_best_node(node, used_nodes);
+               nodemask = node_to_cpumask(next_node);
+               cpus_or(span, span, nodemask);
+       }
+
+       return span;
+}
+#endif
+
+/*
+ * At the moment, CONFIG_SCHED_SMT is never defined, but leave it in so we
+ * can switch it on easily if needed.
+ */
+#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)
+{
+       return cpu;
+}
+#endif
+
+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)
+{
+#ifdef CONFIG_SCHED_SMT
+       return first_cpu(cpu_sibling_map[cpu]);
+#else
+       return cpu;
+#endif
+}
+
+#ifdef CONFIG_NUMA
+/*
+ * The init_sched_build_groups can't handle what we want to do with node
+ * groups, so roll our own. Now each node has its own list of groups which
+ * gets dynamically allocated.
+ */
+static DEFINE_PER_CPU(struct sched_domain, node_domains);
+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)
+{
+       return cpu_to_node(cpu);
+}
+#endif
+
+/*
+ * Set up scheduler domains and groups.  Callers must hold the hotplug lock.
+ */
+void __devinit arch_init_sched_domains(void)
+{
+       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.
+        */
+       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) {
+               int node = cpu_to_node(i);
+               int group;
+               struct sched_domain *sd = NULL, *p;
+               cpumask_t nodemask = node_to_cpumask(node);
+
+               cpus_and(nodemask, nodemask, cpu_default_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;
+                       group = cpu_to_allnodes_group(i);
+                       sd->groups = &sched_group_allnodes[group];
+                       p = sd;
+               } else
+                       p = NULL;
+
+               sd = &per_cpu(node_domains, i);
+               *sd = SD_NODE_INIT;
+               sd->span = sched_domain_node_span(node);
+               sd->parent = p;
+               cpus_and(sd->span, sd->span, cpu_default_map);
+#endif
+
+               p = sd;
+               sd = &per_cpu(phys_domains, i);
+               group = cpu_to_phys_group(i);
+               *sd = SD_CPU_INIT;
+               sd->span = nodemask;
+               sd->parent = p;
+               sd->groups = &sched_group_phys[group];
+
+#ifdef CONFIG_SCHED_SMT
+               p = sd;
+               sd = &per_cpu(cpu_domains, i);
+               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);
+               sd->parent = p;
+               sd->groups = &sched_group_cpus[group];
+#endif
+       }
+
+#ifdef CONFIG_SCHED_SMT
+       /* Set up CPU (sibling) groups */
+       for_each_cpu_mask(i, cpu_default_map) {
+               cpumask_t this_sibling_map = cpu_sibling_map[i];
+               cpus_and(this_sibling_map, this_sibling_map, cpu_default_map);
+               if (i != first_cpu(this_sibling_map))
+                       continue;
+
+               init_sched_build_groups(sched_group_cpus, this_sibling_map,
+                                               &cpu_to_cpu_group);
+       }
+#endif
+
+       /* Set up physical groups */
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               cpumask_t nodemask = node_to_cpumask(i);
+
+               cpus_and(nodemask, nodemask, cpu_default_map);
+               if (cpus_empty(nodemask))
+                       continue;
+
+               init_sched_build_groups(sched_group_phys, nodemask,
+                                               &cpu_to_phys_group);
+       }
+
+#ifdef CONFIG_NUMA
+       init_sched_build_groups(sched_group_allnodes, cpu_default_map,
+                               &cpu_to_allnodes_group);
+
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               /* Set up node groups */
+               struct sched_group *sg, *prev;
+               cpumask_t nodemask = node_to_cpumask(i);
+               cpumask_t domainspan;
+               cpumask_t covered = CPU_MASK_NONE;
+               int j;
+
+               cpus_and(nodemask, nodemask, cpu_default_map);
+               if (cpus_empty(nodemask))
+                       continue;
+
+               domainspan = sched_domain_node_span(i);
+               cpus_and(domainspan, domainspan, cpu_default_map);
+
+               sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+               sched_group_nodes[i] = sg;
+               for_each_cpu_mask(j, nodemask) {
+                       struct sched_domain *sd;
+                       sd = &per_cpu(node_domains, j);
+                       sd->groups = sg;
+                       if (sd->groups == NULL) {
+                               /* Turn off balancing if we have no groups */
+                               sd->flags = 0;
+                       }
+               }
+               if (!sg) {
+                       printk(KERN_WARNING
+                       "Can not alloc domain group for node %d\n", i);
+                       continue;
+               }
+               sg->cpu_power = 0;
+               sg->cpumask = nodemask;
+               cpus_or(covered, covered, nodemask);
+               prev = sg;
+
+               for (j = 0; j < MAX_NUMNODES; j++) {
+                       cpumask_t tmp, notcovered;
+                       int n = (i + j) % MAX_NUMNODES;
+
+                       cpus_complement(notcovered, covered);
+                       cpus_and(tmp, notcovered, cpu_default_map);
+                       cpus_and(tmp, tmp, domainspan);
+                       if (cpus_empty(tmp))
+                               break;
+
+                       nodemask = node_to_cpumask(n);
+                       cpus_and(tmp, tmp, nodemask);
+                       if (cpus_empty(tmp))
+                               continue;
+
+                       sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
+                       if (!sg) {
+                               printk(KERN_WARNING
+                               "Can not alloc domain group for node %d\n", j);
+                               break;
+                       }
+                       sg->cpu_power = 0;
+                       sg->cpumask = tmp;
+                       cpus_or(covered, covered, tmp);
+                       prev->next = sg;
+                       prev = sg;
+               }
+               prev->next = sched_group_nodes[i];
+       }
+#endif
+
+       /* Calculate CPU power for physical packages and nodes */
+       for_each_cpu_mask(i, cpu_default_map) {
+               int power;
+               struct sched_domain *sd;
+#ifdef CONFIG_SCHED_SMT
+               sd = &per_cpu(cpu_domains, i);
+               power = SCHED_LOAD_SCALE;
+               sd->groups->cpu_power = power;
+#endif
+
+               sd = &per_cpu(phys_domains, i);
+               power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+               sd->groups->cpu_power = power;
+
+#ifdef CONFIG_NUMA
+               sd = &per_cpu(allnodes_domains, i);
+               if (sd->groups) {
+                       power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+                       sd->groups->cpu_power = power;
+               }
+#endif
+       }
+
+#ifdef CONFIG_NUMA
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               struct sched_group *sg = sched_group_nodes[i];
+               int j;
+
+               if (sg == NULL)
+                       continue;
+next_sg:
+               for_each_cpu_mask(j, sg->cpumask) {
+                       struct sched_domain *sd;
+                       int power;
+
+                       sd = &per_cpu(phys_domains, j);
+                       if (j != first_cpu(sd->groups->cpumask)) {
+                               /*
+                                * Only add "power" once for each
+                                * physical package.
+                                */
+                               continue;
+                       }
+                       power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+                               (cpus_weight(sd->groups->cpumask)-1) / 10;
+
+                       sg->cpu_power += power;
+               }
+               sg = sg->next;
+               if (sg != sched_group_nodes[i])
+                       goto next_sg;
+       }
+#endif
+
+       /* Attach the domains */
+       for_each_online_cpu(i) {
+               struct sched_domain *sd;
+#ifdef CONFIG_SCHED_SMT
+               sd = &per_cpu(cpu_domains, i);
+#else
+               sd = &per_cpu(phys_domains, i);
+#endif
+               cpu_attach_domain(sd, i);
+       }
+}
+
+void __devinit arch_destroy_sched_domains(void)
+{
+#ifdef CONFIG_NUMA
+       int i;
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               struct sched_group *oldsg, *sg = sched_group_nodes[i];
+               if (sg == NULL)
+                       continue;
+               sg = sg->next;
+next_sg:
+               oldsg = sg;
+               sg = sg->next;
+               kfree(oldsg);
+               if (oldsg != sched_group_nodes[i])
+                       goto next_sg;
+               sched_group_nodes[i] = NULL;
+       }
+#endif
+}
+
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
new file mode 100644 (file)
index 0000000..90ed84b
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ * File:       mca_drv.c
+ * Purpose:    Generic MCA handling layer
+ *
+ * Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kallsyms.h>
+#include <linux/smp_lock.h>
+#include <linux/bootmem.h>
+#include <linux/acpi.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+
+#include <asm/delay.h>
+#include <asm/machvec.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/sal.h>
+#include <asm/mca.h>
+
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
+
+#include "mca_drv.h"
+
+/* max size of SAL error record (default) */
+static int sal_rec_max = 10000;
+
+/* from mca.c */
+static ia64_mca_sal_to_os_state_t *sal_to_os_handoff_state;
+static ia64_mca_os_to_sal_state_t *os_to_sal_handoff_state;
+
+/* from mca_drv_asm.S */
+extern void *mca_handler_bhhook(void);
+
+static spinlock_t mca_bh_lock = SPIN_LOCK_UNLOCKED;
+
+typedef enum {
+       MCA_IS_LOCAL  = 0,
+       MCA_IS_GLOBAL = 1
+} mca_type_t;
+
+#define MAX_PAGE_ISOLATE 32
+
+static struct page *page_isolate[MAX_PAGE_ISOLATE];
+static int num_page_isolate = 0;
+
+typedef enum {
+       ISOLATE_NG = 0,
+       ISOLATE_OK = 1
+} isolate_status_t;
+
+/*
+ *  This pool keeps pointers to the section part of SAL error record
+ */
+static struct {
+       slidx_list_t *buffer; /* section pointer list pool */
+       int          cur_idx; /* Current index of section pointer list pool */
+       int          max_idx; /* Maximum index of section pointer list pool */
+} slidx_pool;
+
+/**
+ * mca_page_isolate - isolate a poisoned page in order not to use it later
+ * @paddr:     poisoned memory location
+ *
+ * Return value:
+ *     ISOLATE_OK / ISOLATE_NG
+ */
+
+static isolate_status_t
+mca_page_isolate(unsigned long paddr)
+{
+       int i;
+       struct page *p;
+
+       /* whether physical address is valid or not */
+       if ( !ia64_phys_addr_valid(paddr) ) 
+               return ISOLATE_NG;
+
+       /* convert physical address to physical page number */
+       p = pfn_to_page(paddr>>PAGE_SHIFT);
+
+       /* check whether a page number have been already registered or not */
+       for( i = 0; i < num_page_isolate; i++ )
+               if( page_isolate[i] == p )
+                       return ISOLATE_OK; /* already listed */
+
+       /* limitation check */
+       if( num_page_isolate == MAX_PAGE_ISOLATE ) 
+               return ISOLATE_NG;
+
+       /* kick pages having attribute 'SLAB' or 'Reserved' */
+       if( PageSlab(p) || PageReserved(p) ) 
+               return ISOLATE_NG;
+
+       /* add attribute 'Reserved' and register the page */
+       SetPageReserved(p);
+       page_isolate[num_page_isolate++] = p;
+
+       return ISOLATE_OK;
+}
+
+/**
+ * mca_hanlder_bh - Kill the process which occurred memory read error
+ * @paddr:     poisoned address received from MCA Handler
+ */
+
+void
+mca_handler_bh(unsigned long paddr)
+{
+       printk(KERN_DEBUG "OS_MCA: process [pid: %d](%s) encounters MCA.\n",
+               current->pid, current->comm);
+
+       spin_lock(&mca_bh_lock);
+       if (mca_page_isolate(paddr) == ISOLATE_OK) {
+               printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr);
+       } else {
+               printk(KERN_DEBUG "Page isolation: ( %lx ) failure.\n", paddr);
+       }
+       spin_unlock(&mca_bh_lock);
+
+       /* This process is about to be killed itself */
+       force_sig(SIGKILL, current);
+       schedule();
+}
+
+/**
+ * mca_make_peidx - Make index of processor error section
+ * @slpi:      pointer to record of processor error section
+ * @peidx:     pointer to index of processor error section
+ */
+
+static void 
+mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx)
+{
+       /* 
+        * calculate the start address of
+        *   "struct cpuid_info" and "sal_processor_static_info_t".
+        */
+       u64 total_check_num = slpi->valid.num_cache_check
+                               + slpi->valid.num_tlb_check
+                               + slpi->valid.num_bus_check
+                               + slpi->valid.num_reg_file_check
+                               + slpi->valid.num_ms_check;
+       u64 head_size = sizeof(sal_log_mod_error_info_t) * total_check_num
+                       + sizeof(sal_log_processor_info_t);
+       u64 mid_size  = slpi->valid.cpuid_info * sizeof(struct sal_cpuid_info);
+
+       peidx_head(peidx)   = slpi;
+       peidx_mid(peidx)    = (struct sal_cpuid_info *)
+               (slpi->valid.cpuid_info ? ((char*)slpi + head_size) : NULL);
+       peidx_bottom(peidx) = (sal_processor_static_info_t *)
+               (slpi->valid.psi_static_struct ?
+                       ((char*)slpi + head_size + mid_size) : NULL);
+}
+
+/**
+ * mca_make_slidx -  Make index of SAL error record 
+ * @buffer:    pointer to SAL error record
+ * @slidx:     pointer to index of SAL error record
+ *
+ * Return value:
+ *     1 if record has platform error / 0 if not
+ */
+#define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \
+        { slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \
+          hl->hdr = ptr; \
+          list_add(&hl->list, &(sect)); \
+          slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; }
+
+static int 
+mca_make_slidx(void *buffer, slidx_table_t *slidx)
+{
+       int platform_err = 0;
+       int record_len = ((sal_log_record_header_t*)buffer)->len;
+       u32 ercd_pos;
+       int sects;
+       sal_log_section_hdr_t *sp;
+
+       /*
+        * Initialize index referring current record
+        */
+       INIT_LIST_HEAD(&(slidx->proc_err));
+       INIT_LIST_HEAD(&(slidx->mem_dev_err));
+       INIT_LIST_HEAD(&(slidx->sel_dev_err));
+       INIT_LIST_HEAD(&(slidx->pci_bus_err));
+       INIT_LIST_HEAD(&(slidx->smbios_dev_err));
+       INIT_LIST_HEAD(&(slidx->pci_comp_err));
+       INIT_LIST_HEAD(&(slidx->plat_specific_err));
+       INIT_LIST_HEAD(&(slidx->host_ctlr_err));
+       INIT_LIST_HEAD(&(slidx->plat_bus_err));
+       INIT_LIST_HEAD(&(slidx->unsupported));
+
+       /*
+        * Extract a Record Header
+        */
+       slidx->header = buffer;
+
+       /*
+        * Extract each section records
+        * (arranged from "int ia64_log_platform_info_print()")
+        */
+       for (ercd_pos = sizeof(sal_log_record_header_t), sects = 0;
+               ercd_pos < record_len; ercd_pos += sp->len, sects++) {
+               sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos);
+               if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) {
+                       LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp);
+               } else if (!efi_guidcmp(sp->guid, SAL_PLAT_BUS_ERR_SECT_GUID)) {
+                       platform_err = 1;
+                       LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp);
+               } else {
+                       LOG_INDEX_ADD_SECT_PTR(slidx->unsupported, sp);
+               }
+       }
+       slidx->n_sections = sects;
+
+       return platform_err;
+}
+
+/**
+ * init_record_index_pools - Initialize pool of lists for SAL record index
+ *
+ * Return value:
+ *     0 on Success / -ENOMEM on Failure
+ */
+static int 
+init_record_index_pools(void)
+{
+       int i;
+       int rec_max_size;  /* Maximum size of SAL error records */
+       int sect_min_size; /* Minimum size of SAL error sections */
+       /* minimum size table of each section */
+       static int sal_log_sect_min_sizes[] = { 
+               sizeof(sal_log_processor_info_t) + sizeof(sal_processor_static_info_t),
+               sizeof(sal_log_mem_dev_err_info_t),
+               sizeof(sal_log_sel_dev_err_info_t),
+               sizeof(sal_log_pci_bus_err_info_t),
+               sizeof(sal_log_smbios_dev_err_info_t),
+               sizeof(sal_log_pci_comp_err_info_t),
+               sizeof(sal_log_plat_specific_err_info_t),
+               sizeof(sal_log_host_ctlr_err_info_t),
+               sizeof(sal_log_plat_bus_err_info_t),
+       };
+
+       /*
+        * MCA handler cannot allocate new memory on flight,
+        * so we preallocate enough memory to handle a SAL record.
+        *
+        * Initialize a handling set of slidx_pool:
+        *   1. Pick up the max size of SAL error records
+        *   2. Pick up the min size of SAL error sections
+        *   3. Allocate the pool as enough to 2 SAL records
+        *     (now we can estimate the maxinum of section in a record.)
+        */
+
+       /* - 1 - */
+       rec_max_size = sal_rec_max;
+
+       /* - 2 - */
+       sect_min_size = sal_log_sect_min_sizes[0];
+       for (i = 1; i < sizeof sal_log_sect_min_sizes/sizeof(size_t); i++)
+               if (sect_min_size > sal_log_sect_min_sizes[i])
+                       sect_min_size = sal_log_sect_min_sizes[i];
+
+       /* - 3 - */
+       slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1;
+       slidx_pool.buffer = (slidx_list_t *) kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL);
+
+       return slidx_pool.buffer ? 0 : -ENOMEM;
+}
+
+
+/*****************************************************************************
+ * Recovery functions                                                        *
+ *****************************************************************************/
+
+/**
+ * is_mca_global - Check whether this MCA is global or not
+ * @peidx:     pointer of index of processor error section
+ * @pbci:      pointer to pal_bus_check_info_t
+ *
+ * Return value:
+ *     MCA_IS_LOCAL / MCA_IS_GLOBAL
+ */
+
+static mca_type_t
+is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci)
+{
+       pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx);
+
+       /* 
+        * PAL can request a rendezvous, if the MCA has a global scope.
+        * If "rz_always" flag is set, SAL requests MCA rendezvous 
+        * in spite of global MCA.
+        * Therefore it is local MCA when rendezvous has not been requested.
+        * Failed to rendezvous, the system must be down.
+        */
+       switch (sal_to_os_handoff_state->imsto_rendez_state) {
+               case -1: /* SAL rendezvous unsuccessful */
+                       return MCA_IS_GLOBAL;
+               case  0: /* SAL rendezvous not required */
+                       return MCA_IS_LOCAL;
+               case  1: /* SAL rendezvous successful int */
+               case  2: /* SAL rendezvous successful int with init */
+               default:
+                       break;
+       }
+
+       /*
+        * If One or more Cache/TLB/Reg_File/Uarch_Check is here,
+        * it would be a local MCA. (i.e. processor internal error)
+        */
+       if (psp->tc || psp->cc || psp->rc || psp->uc)
+               return MCA_IS_LOCAL;
+       
+       /*
+        * Bus_Check structure with Bus_Check.ib (internal bus error) flag set
+        * would be a global MCA. (e.g. a system bus address parity error)
+        */
+       if (!pbci || pbci->ib)
+               return MCA_IS_GLOBAL;
+
+       /*
+        * Bus_Check structure with Bus_Check.eb (external bus error) flag set
+        * could be either a local MCA or a global MCA.
+        *
+        * Referring Bus_Check.bsi:
+        *   0: Unknown/unclassified
+        *   1: BERR#
+        *   2: BINIT#
+        *   3: Hard Fail
+        * (FIXME: Are these SGI specific or generic bsi values?)
+        */
+       if (pbci->eb)
+               switch (pbci->bsi) {
+                       case 0:
+                               /* e.g. a load from poisoned memory */
+                               return MCA_IS_LOCAL;
+                       case 1:
+                       case 2:
+                       case 3:
+                               return MCA_IS_GLOBAL;
+               }
+
+       return MCA_IS_GLOBAL;
+}
+
+/**
+ * recover_from_read_error - Try to recover the errors which type are "read"s.
+ * @slidx:     pointer of index of SAL error record
+ * @peidx:     pointer of index of processor error section
+ * @pbci:      pointer of pal_bus_check_info
+ *
+ * Return value:
+ *     1 on Success / 0 on Failure
+ */
+
+static int
+recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci)
+{
+       sal_log_mod_error_info_t *smei;
+       pal_min_state_area_t *pmsa;
+       struct ia64_psr *psr1, *psr2;
+       ia64_fptr_t *mca_hdlr_bh = (ia64_fptr_t*)mca_handler_bhhook;
+
+       /* Is target address valid? */
+       if (!pbci->tv)
+               return 0;
+
+       /*
+        * cpu read or memory-mapped io read
+        *
+        *    offending process  affected process  OS MCA do
+        *     kernel mode        kernel mode       down system
+        *     kernel mode        user   mode       kill the process
+        *     user   mode        kernel mode       down system (*)
+        *     user   mode        user   mode       kill the process
+        *
+        * (*) You could terminate offending user-mode process
+        *    if (pbci->pv && pbci->pl != 0) *and* if you sure
+        *    the process not have any locks of kernel.
+        */
+
+       psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr);
+
+       /*
+        *  Check the privilege level of interrupted context.
+        *   If it is user-mode, then terminate affected process.
+        */
+       if (psr1->cpl != 0) {
+               smei = peidx_bus_check(peidx, 0);
+               if (smei->valid.target_identifier) {
+                       /*
+                        *  setup for resume to bottom half of MCA,
+                        * "mca_handler_bhhook"
+                        */
+                       pmsa = (pal_min_state_area_t *)(sal_to_os_handoff_state->pal_min_state | (6ul<<61));
+                       /* pass to bhhook as 1st argument (gr8) */
+                       pmsa->pmsa_gr[8-1] = smei->target_identifier;
+                       /* set interrupted return address (but no use) */
+                       pmsa->pmsa_br0 = pmsa->pmsa_iip;
+                       /* change resume address to bottom half */
+                       pmsa->pmsa_iip = mca_hdlr_bh->fp;
+                       pmsa->pmsa_gr[1-1] = mca_hdlr_bh->gp;
+                       /* set cpl with kernel mode */
+                       psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr;
+                       psr2->cpl = 0;
+                       psr2->ri  = 0;
+
+                       return 1;
+               }
+
+       }
+
+       return 0;
+}
+
+/**
+ * recover_from_platform_error - Recover from platform error.
+ * @slidx:     pointer of index of SAL error record
+ * @peidx:     pointer of index of processor error section
+ * @pbci:      pointer of pal_bus_check_info
+ *
+ * Return value:
+ *     1 on Success / 0 on Failure
+ */
+
+static int
+recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci)
+{
+       int status = 0;
+       pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx);
+
+       if (psp->bc && pbci->eb && pbci->bsi == 0) {
+               switch(pbci->type) {
+               case 1: /* partial read */
+               case 3: /* full line(cpu) read */
+               case 9: /* I/O space read */
+                       status = recover_from_read_error(slidx, peidx, pbci);
+                       break;
+               case 0: /* unknown */
+               case 2: /* partial write */
+               case 4: /* full line write */
+               case 5: /* implicit or explicit write-back operation */
+               case 6: /* snoop probe */
+               case 7: /* incoming or outgoing ptc.g */
+               case 8: /* write coalescing transactions */
+               case 10: /* I/O space write */
+               case 11: /* inter-processor interrupt message(IPI) */
+               case 12: /* interrupt acknowledge or external task priority cycle */
+               default:
+                       break;
+               }
+       }
+
+       return status;
+}
+
+/**
+ * recover_from_processor_error
+ * @platform:  whether there are some platform error section or not
+ * @slidx:     pointer of index of SAL error record
+ * @peidx:     pointer of index of processor error section
+ * @pbci:      pointer of pal_bus_check_info
+ *
+ * Return value:
+ *     1 on Success / 0 on Failure
+ */
+/*
+ *  Later we try to recover when below all conditions are satisfied.
+ *   1. Only one processor error section is exist.
+ *   2. BUS_CHECK is exist and the others are not exist.(Except TLB_CHECK)
+ *   3. The entry of BUS_CHECK_INFO is 1.
+ *   4. "External bus error" flag is set and the others are not set.
+ */
+
+static int
+recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci)
+{
+       pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx);
+
+       /* 
+        * We cannot recover errors with other than bus_check.
+        */
+       if (psp->cc || psp->rc || psp->uc) 
+               return 0;
+
+       /*
+        * If there is no bus error, record is weird but we need not to recover.
+        */
+       if (psp->bc == 0 || pbci == NULL)
+               return 1;
+
+       /*
+        * Sorry, we cannot handle so many.
+        */
+       if (peidx_bus_check_num(peidx) > 1)
+               return 0;
+       /*
+        * Well, here is only one bus error.
+        */
+       if (pbci->ib || pbci->cc)
+               return 0;
+       if (pbci->eb && pbci->bsi > 0)
+               return 0;
+       if (psp->ci == 0)
+               return 0;
+
+       /*
+        * This is a local MCA and estimated as recoverble external bus error.
+        * (e.g. a load from poisoned memory)
+        * This means "there are some platform errors".
+        */
+       if (platform) 
+               return recover_from_platform_error(slidx, peidx, pbci);
+       /* 
+        * On account of strange SAL error record, we cannot recover. 
+        */
+       return 0;
+}
+
+/**
+ * mca_try_to_recover - Try to recover from MCA
+ * @rec:       pointer to a SAL error record
+ *
+ * Return value:
+ *     1 on Success / 0 on Failure
+ */
+
+static int
+mca_try_to_recover(void *rec, 
+       ia64_mca_sal_to_os_state_t *sal_to_os_state,
+       ia64_mca_os_to_sal_state_t *os_to_sal_state)
+{
+       int platform_err;
+       int n_proc_err;
+       slidx_table_t slidx;
+       peidx_table_t peidx;
+       pal_bus_check_info_t pbci;
+
+       /* handoff state from/to mca.c */
+       sal_to_os_handoff_state = sal_to_os_state;
+       os_to_sal_handoff_state = os_to_sal_state;
+
+       /* Make index of SAL error record */
+       platform_err = mca_make_slidx(rec, &slidx);
+
+       /* Count processor error sections */
+       n_proc_err = slidx_count(&slidx, proc_err);
+
+        /* Now, OS can recover when there is one processor error section */
+       if (n_proc_err > 1)
+               return 0;
+       else if (n_proc_err == 0) {
+               /* Weird SAL record ... We need not to recover */
+
+               return 1;
+       }
+
+       /* Make index of processor error section */
+       mca_make_peidx((sal_log_processor_info_t*)slidx_first_entry(&slidx.proc_err)->hdr, &peidx);
+
+       /* Extract Processor BUS_CHECK[0] */
+       *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0);
+
+       /* Check whether MCA is global or not */
+       if (is_mca_global(&peidx, &pbci))
+               return 0;
+       
+       /* Try to recover a processor error */
+       return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci);
+}
+
+/*
+ * =============================================================================
+ */
+
+int __init mca_external_handler_init(void)
+{
+       if (init_record_index_pools())
+               return -ENOMEM;
+
+       /* register external mca handlers */
+       if (ia64_reg_MCA_extension(mca_try_to_recover)){        
+               printk(KERN_ERR "ia64_reg_MCA_extension failed.\n");
+               kfree(slidx_pool.buffer);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+void __exit mca_external_handler_exit(void)
+{
+       /* unregister external mca handlers */
+       ia64_unreg_MCA_extension();
+       kfree(slidx_pool.buffer);
+}
+
+module_init(mca_external_handler_init);
+module_exit(mca_external_handler_exit);
+
+module_param(sal_rec_max, int, 0644);
+MODULE_PARM_DESC(sal_rec_max, "Max size of SAL error record");
+
+MODULE_DESCRIPTION("ia64 platform dependent mca handler driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h
new file mode 100644 (file)
index 0000000..0227b76
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * File:       mca_drv.h
+ * Purpose:    Define helpers for Generic MCA handling
+ *
+ * Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ */
+/*
+ * Processor error section: 
+ *
+ *  +-sal_log_processor_info_t *info-------------+
+ *  | sal_log_section_hdr_t header;              |
+ *  | ...                                        |
+ *  | sal_log_mod_error_info_t info[0];          |
+ *  +-+----------------+-------------------------+
+ *    | CACHE_CHECK    |  ^ num_cache_check v
+ *    +----------------+
+ *    | TLB_CHECK      |  ^ num_tlb_check v
+ *    +----------------+
+ *    | BUS_CHECK      |  ^ num_bus_check v
+ *    +----------------+
+ *    | REG_FILE_CHECK |  ^ num_reg_file_check v
+ *    +----------------+
+ *    | MS_CHECK       |  ^ num_ms_check v
+ *  +-struct cpuid_info *id----------------------+
+ *  | regs[5];                                   |
+ *  | reserved;                                  |
+ *  +-sal_processor_static_info_t *regs----------+
+ *  | valid;                                     |
+ *  | ...                                        |
+ *  | fr[128];                                   |
+ *  +--------------------------------------------+
+ */
+
+/* peidx: index of processor error section */
+typedef struct peidx_table {
+       sal_log_processor_info_t        *info;
+       struct sal_cpuid_info           *id;
+       sal_processor_static_info_t     *regs;
+} peidx_table_t;
+
+#define peidx_head(p)   (((p)->info))
+#define peidx_mid(p)    (((p)->id))
+#define peidx_bottom(p) (((p)->regs))
+
+#define peidx_psp(p)           (&(peidx_head(p)->proc_state_parameter))
+#define peidx_field_valid(p)   (&(peidx_head(p)->valid))
+#define peidx_minstate_area(p) (&(peidx_bottom(p)->min_state_area))
+
+#define peidx_cache_check_num(p)    (peidx_head(p)->valid.num_cache_check)
+#define peidx_tlb_check_num(p)      (peidx_head(p)->valid.num_tlb_check)
+#define peidx_bus_check_num(p)      (peidx_head(p)->valid.num_bus_check)
+#define peidx_reg_file_check_num(p) (peidx_head(p)->valid.num_reg_file_check)
+#define peidx_ms_check_num(p)       (peidx_head(p)->valid.num_ms_check)
+
+#define peidx_cache_check_idx(p, n)    (n)
+#define peidx_tlb_check_idx(p, n)      (peidx_cache_check_idx(p, peidx_cache_check_num(p)) + n)
+#define peidx_bus_check_idx(p, n)      (peidx_tlb_check_idx(p, peidx_tlb_check_num(p)) + n)
+#define peidx_reg_file_check_idx(p, n) (peidx_bus_check_idx(p, peidx_bus_check_num(p)) + n)
+#define peidx_ms_check_idx(p, n)       (peidx_reg_file_check_idx(p, peidx_reg_file_check_num(p)) + n)
+
+#define peidx_mod_error_info(p, name, n) \
+({     int __idx = peidx_##name##_idx(p, n); \
+       sal_log_mod_error_info_t *__ret = NULL; \
+       if (peidx_##name##_num(p) > n) /*BUG*/ \
+               __ret = &(peidx_head(p)->info[__idx]); \
+       __ret; })
+
+#define peidx_cache_check(p, n)    peidx_mod_error_info(p, cache_check, n)
+#define peidx_tlb_check(p, n)      peidx_mod_error_info(p, tlb_check, n)
+#define peidx_bus_check(p, n)      peidx_mod_error_info(p, bus_check, n)
+#define peidx_reg_file_check(p, n) peidx_mod_error_info(p, reg_file_check, n)
+#define peidx_ms_check(p, n)       peidx_mod_error_info(p, ms_check, n)
+
+#define peidx_check_info(proc, name, n) \
+({ \
+       sal_log_mod_error_info_t *__info = peidx_mod_error_info(proc, name, n);\
+       u64 __temp = __info && __info->valid.check_info \
+               ? __info->check_info : 0; \
+       __temp; })
+
+/* slidx: index of SAL log error record */
+
+typedef struct slidx_list {
+       struct list_head list;
+       sal_log_section_hdr_t *hdr;
+} slidx_list_t;
+
+typedef struct slidx_table {
+       sal_log_record_header_t *header;
+       int n_sections;                 /* # of section headers */
+       struct list_head proc_err;
+       struct list_head mem_dev_err;
+       struct list_head sel_dev_err;
+       struct list_head pci_bus_err;
+       struct list_head smbios_dev_err;
+       struct list_head pci_comp_err;
+       struct list_head plat_specific_err;
+       struct list_head host_ctlr_err;
+       struct list_head plat_bus_err;
+       struct list_head unsupported;   /* list of unsupported sections */
+} slidx_table_t;
+
+#define slidx_foreach_entry(pos, head) \
+       list_for_each_entry(pos, head, list)
+#define slidx_first_entry(head) \
+       (((head)->next != (head)) ? list_entry((head)->next, typeof(slidx_list_t), list) : NULL)
+#define slidx_count(slidx, sec) \
+({     int __count = 0; \
+       slidx_list_t *__pos; \
+       slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\
+       __count; })
+
diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S
new file mode 100644 (file)
index 0000000..bcfa05a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * File:        mca_drv_asm.S
+ * Purpose:     Assembly portion of Generic MCA handling
+ *
+ * Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ */
+#include <linux/config.h>
+#include <linux/threads.h>
+
+#include <asm/asmmacro.h>
+#include <asm/processor.h>
+
+GLOBAL_ENTRY(mca_handler_bhhook)
+       invala                                          // clear RSE ?
+       ;;                                              //
+       cover                                           // 
+       ;;                                              //
+       clrrrb                                          //
+       ;;                                              
+       alloc           r16=ar.pfs,0,2,1,0              // make a new frame
+       ;;
+       mov             r13=IA64_KR(CURRENT)            // current task pointer
+       ;;
+       adds            r12=IA64_TASK_THREAD_KSP_OFFSET,r13
+       ;;
+       ld8             r12=[r12]                       // stack pointer
+       ;;
+       mov             loc0=r16
+       movl            loc1=mca_handler_bh             // recovery C function
+       ;;
+       mov             out0=r8                         // poisoned address
+       mov             b6=loc1
+       ;;
+       mov             loc1=rp
+       ;;
+       br.call.sptk.many    rp=b6                      // not return ...
+       ;;
+       mov             ar.pfs=loc0
+       mov             rp=loc1
+       ;;
+       mov             r8=r0
+       br.ret.sptk.many rp
+       ;;
+END(mca_handler_bhhook)
diff --git a/arch/ia64/oprofile/perfmon.c b/arch/ia64/oprofile/perfmon.c
new file mode 100644 (file)
index 0000000..bfc82cc
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * @file perfmon.c
+ *
+ * @remark Copyright 2003 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <asm/perfmon.h>
+#include <asm/ptrace.h>
+#include <asm/errno.h>
+
+static int allow_ints;
+
+static int
+perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg,
+                struct pt_regs *regs, unsigned long stamp)
+{
+       int cpu = smp_processor_id();
+       unsigned long eip = instruction_pointer(regs);
+       int event = arg->pmd_eventid;
+       arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1;
+
+       /* the owner of the oprofile event buffer may have exited
+        * without perfmon being shutdown (e.g. SIGSEGV)
+        */
+       if (allow_ints)
+               oprofile_add_sample(eip, !user_mode(regs), event, cpu);
+       return 0;
+}
+
+
+static int perfmon_start(void)
+{
+       allow_ints = 1;
+       return 0;
+}
+
+
+static void perfmon_stop(void)
+{
+       allow_ints = 0;
+}
+
+
+#define OPROFILE_FMT_UUID { \
+       0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c }
+
+static pfm_buffer_fmt_t oprofile_fmt = {
+       .fmt_name           = "oprofile_format",
+       .fmt_uuid           = OPROFILE_FMT_UUID,
+       .fmt_handler        = perfmon_handler,
+};
+
+
+static char * get_cpu_type(void)
+{
+       __u8 family = local_cpu_data->family;
+
+       switch (family) {
+               case 0x07:
+                       return "ia64/itanium";
+               case 0x1f:
+                       return "ia64/itanium2";
+               default:
+                       return "ia64/ia64";
+       }
+}
+
+
+/* all the ops are handled via userspace for IA64 perfmon */
+static struct oprofile_operations perfmon_ops = {
+       .start = perfmon_start,
+       .stop = perfmon_stop,
+};
+
+static int using_perfmon;
+
+int perfmon_init(struct oprofile_operations ** ops)
+{
+       int ret = pfm_register_buffer_fmt(&oprofile_fmt);
+       if (ret)
+               return -ENODEV;
+
+       perfmon_ops.cpu_type = get_cpu_type();
+       *ops = &perfmon_ops;
+       using_perfmon = 1;
+       printk(KERN_INFO "oprofile: using perfmon.\n");
+       return 0;
+}
+
+
+void perfmon_exit(void)
+{
+       if (!using_perfmon)
+               return;
+
+       pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid);
+}
diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/arch/ia64/sn/include/pci/pcibr_provider.h
new file mode 100644 (file)
index 0000000..b1f05ff
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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) 1992-1997,2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
+#define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
+
+/* Workarounds */
+#define PV907516 (1 << 1) /* TIOCP: Don't write the write buffer flush reg */
+
+#define BUSTYPE_MASK                    0x1
+
+/* Macros given a pcibus structure */
+#define IS_PCIX(ps)     ((ps)->pbi_bridge_mode & BUSTYPE_MASK)
+#define IS_PCI_BRIDGE_ASIC(asic) (asic == PCIIO_ASIC_TYPE_PIC || \
+                asic == PCIIO_ASIC_TYPE_TIOCP)
+#define IS_PIC_SOFT(ps)     (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_PIC)
+
+
+/* 
+ * The different PCI Bridge types supported on the SGI Altix platforms
+ */
+#define PCIBR_BRIDGETYPE_UNKNOWN       -1
+#define PCIBR_BRIDGETYPE_PIC            2
+#define PCIBR_BRIDGETYPE_TIOCP          3
+
+/*
+ * Bridge 64bit Direct Map Attributes
+ */
+#define PCI64_ATTR_PREF                 (1ull << 59)
+#define PCI64_ATTR_PREC                 (1ull << 58)
+#define PCI64_ATTR_VIRTUAL              (1ull << 57)
+#define PCI64_ATTR_BAR                  (1ull << 56)
+#define PCI64_ATTR_SWAP                 (1ull << 55)
+#define PCI64_ATTR_VIRTUAL1             (1ull << 54)
+
+#define PCI32_LOCAL_BASE                0
+#define PCI32_MAPPED_BASE               0x40000000
+#define PCI32_DIRECT_BASE               0x80000000
+
+#define IS_PCI32_MAPPED(x)              ((uint64_t)(x) < PCI32_DIRECT_BASE && \
+                                         (uint64_t)(x) >= PCI32_MAPPED_BASE)
+#define IS_PCI32_DIRECT(x)              ((uint64_t)(x) >= PCI32_MAPPED_BASE)
+
+
+/*
+ * Bridge PMU Address Transaltion Entry Attibutes
+ */
+#define PCI32_ATE_V                     (0x1 << 0)
+#define PCI32_ATE_CO                    (0x1 << 1)
+#define PCI32_ATE_PREC                  (0x1 << 2)
+#define PCI32_ATE_PREF                  (0x1 << 3)
+#define PCI32_ATE_BAR                   (0x1 << 4)
+#define PCI32_ATE_ADDR_SHFT             12
+
+#define MINIMAL_ATES_REQUIRED(addr, size) \
+       (IOPG(IOPGOFF(addr) + (size) - 1) == IOPG((size) - 1))
+
+#define MINIMAL_ATE_FLAG(addr, size) \
+       (MINIMAL_ATES_REQUIRED((uint64_t)addr, size) ? 1 : 0)
+
+/* bit 29 of the pci address is the SWAP bit */
+#define ATE_SWAPSHIFT                   29
+#define ATE_SWAP_ON(x)                  ((x) |= (1 << ATE_SWAPSHIFT))
+#define ATE_SWAP_OFF(x)                 ((x) &= ~(1 << ATE_SWAPSHIFT))
+
+/*
+ * I/O page size
+ */
+#if PAGE_SIZE < 16384
+#define IOPFNSHIFT                      12      /* 4K per mapped page */
+#else
+#define IOPFNSHIFT                      14      /* 16K per mapped page */
+#endif
+
+#define IOPGSIZE                        (1 << IOPFNSHIFT)
+#define IOPG(x)                         ((x) >> IOPFNSHIFT)
+#define IOPGOFF(x)                      ((x) & (IOPGSIZE-1))
+
+#define PCIBR_DEV_SWAP_DIR              (1ull << 19)
+#define PCIBR_CTRL_PAGE_SIZE            (0x1 << 21)
+
+/*
+ * PMU resources.
+ */
+struct ate_resource{
+       uint64_t *ate;
+       uint64_t num_ate;
+       uint64_t lowest_free_index;
+};
+
+struct pcibus_info {
+       struct pcibus_bussoft   pbi_buscommon;   /* common header */
+       uint32_t                pbi_moduleid;
+       short                   pbi_bridge_type;
+       short                   pbi_bridge_mode;
+
+       struct ate_resource     pbi_int_ate_resource;
+       uint64_t                pbi_int_ate_size;
+       
+       uint64_t                pbi_dir_xbase;
+       char                    pbi_hub_xid;
+
+       uint64_t                pbi_devreg[8];
+       spinlock_t              pbi_lock;
+
+       uint32_t                pbi_valid_devices;
+       uint32_t                pbi_enabled_devices;
+};
+
+/*
+ * pcibus_info structure locking macros
+ */
+inline static unsigned long
+pcibr_lock(struct pcibus_info *pcibus_info)
+{
+       unsigned long flag;
+       spin_lock_irqsave(&pcibus_info->pbi_lock, flag);
+       return(flag);
+}
+#define pcibr_unlock(pcibus_info, flag)  spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag)
+
+extern void *pcibr_bus_fixup(struct pcibus_bussoft *);
+extern uint64_t pcibr_dma_map(struct pcidev_info *, unsigned long, size_t, unsigned int);
+extern void pcibr_dma_unmap(struct pcidev_info *, dma_addr_t, int);
+
+/*
+ * prototypes for the bridge asic register access routines in pcibr_reg.c
+ */
+extern void             pcireg_control_bit_clr(struct pcibus_info *, uint64_t);
+extern void             pcireg_control_bit_set(struct pcibus_info *, uint64_t);
+extern uint64_t         pcireg_tflush_get(struct pcibus_info *);
+extern uint64_t         pcireg_intr_status_get(struct pcibus_info *);
+extern void             pcireg_intr_enable_bit_clr(struct pcibus_info *, uint64_t);
+extern void             pcireg_intr_enable_bit_set(struct pcibus_info *, uint64_t);
+extern void             pcireg_intr_addr_addr_set(struct pcibus_info *, int, uint64_t);
+extern void             pcireg_force_intr_set(struct pcibus_info *, int);
+extern uint64_t         pcireg_wrb_flush_get(struct pcibus_info *, int);
+extern void             pcireg_int_ate_set(struct pcibus_info *, int, uint64_t);
+extern uint64_t *      pcireg_int_ate_addr(struct pcibus_info *, int);
+extern void            pcibr_force_interrupt(struct sn_irq_info *sn_irq_info);
+extern void            pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info);
+extern int             pcibr_ate_alloc(struct pcibus_info *, int);
+extern void            pcibr_ate_free(struct pcibus_info *, int);
+extern void            ate_write(struct pcibus_info *, int, int, uint64_t);
+#endif
diff --git a/arch/ia64/sn/include/pci/pcibus_provider_defs.h b/arch/ia64/sn/include/pci/pcibus_provider_defs.h
new file mode 100644 (file)
index 0000000..0706561
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
+#define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
+
+/*
+ * SN pci asic types.  Do not ever renumber these or reuse values.  The
+ * values must agree with what prom thinks they are.
+ */
+
+#define PCIIO_ASIC_TYPE_UNKNOWN        0
+#define PCIIO_ASIC_TYPE_PPB    1
+#define PCIIO_ASIC_TYPE_PIC    2
+#define PCIIO_ASIC_TYPE_TIOCP  3
+
+/*
+ * Common pciio bus provider data.  There should be one of these as the
+ * first field in any pciio based provider soft structure (e.g. pcibr_soft
+ * tioca_soft, etc).
+ */
+
+struct pcibus_bussoft {
+       uint32_t                bs_asic_type;   /* chipset type */
+       uint32_t                bs_xid;         /* xwidget id */
+       uint64_t                bs_persist_busnum; /* Persistent Bus Number */
+       uint64_t                bs_legacy_io;   /* legacy io pio addr */
+       uint64_t                bs_legacy_mem;  /* legacy mem pio addr */
+       uint64_t                bs_base;        /* widget base */
+       struct xwidget_info     *bs_xwidget_info;
+};
+
+/*
+ * DMA mapping flags
+ */
+
+#define SN_PCIDMA_CONSISTENT    0x0001
+
+#endif                         /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
diff --git a/arch/ia64/sn/include/pci/pcidev.h b/arch/ia64/sn/include/pci/pcidev.h
new file mode 100644 (file)
index 0000000..81eb95d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_PCIDEV_H
+#define _ASM_IA64_SN_PCI_PCIDEV_H
+
+#include <linux/pci.h>
+
+extern struct sn_irq_info **sn_irq;
+
+#define SN_PCIDEV_INFO(pci_dev) \
+        ((struct pcidev_info *)(pci_dev)->sysdata)
+
+/*
+ * Given a pci_bus, return the sn pcibus_bussoft struct.  Note that
+ * this only works for root busses, not for busses represented by PPB's.
+ */
+
+#define SN_PCIBUS_BUSSOFT(pci_bus) \
+        ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
+
+/*
+ * Given a struct pci_dev, return the sn pcibus_bussoft struct.  Note
+ * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due
+ * due to possible PPB's in the path.
+ */
+
+#define SN_PCIDEV_BUSSOFT(pci_dev) \
+       (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info)
+
+#define PCIIO_BUS_NONE 255      /* bus 255 reserved */
+#define PCIIO_SLOT_NONE 255
+#define PCIIO_FUNC_NONE 255
+#define PCIIO_VENDOR_ID_NONE   (-1)
+
+struct pcidev_info {
+       uint64_t                pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */
+       uint64_t                pdi_slot_host_handle;   /* Bus and devfn Host pci_dev */
+
+       struct pcibus_bussoft   *pdi_pcibus_info;       /* Kernel common bus soft */
+       struct pcidev_info      *pdi_host_pcidev_info;  /* Kernel Host pci_dev */
+       struct pci_dev          *pdi_linux_pcidev;      /* Kernel pci_dev */
+
+       struct sn_irq_info      *pdi_sn_irq_info;
+};
+
+extern void sn_irq_fixup(struct pci_dev *pci_dev,
+                        struct sn_irq_info *sn_irq_info);
+
+#endif                         /* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/arch/ia64/sn/include/pci/pic.h b/arch/ia64/sn/include/pci/pic.h
new file mode 100644 (file)
index 0000000..fd18ace
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_PIC_H
+#define _ASM_IA64_SN_PCI_PIC_H
+
+/*
+ * PIC AS DEVICE ZERO
+ * ------------------
+ *
+ * PIC handles PCI/X busses.  PCI/X requires that the 'bridge' (i.e. PIC)
+ * be designated as 'device 0'.   That is a departure from earlier SGI
+ * PCI bridges.  Because of that we use config space 1 to access the
+ * config space of the first actual PCI device on the bus. 
+ * Here's what the PIC manual says:
+ *
+ *     The current PCI-X bus specification now defines that the parent
+ *     hosts bus bridge (PIC for example) must be device 0 on bus 0. PIC
+ *     reduced the total number of devices from 8 to 4 and removed the
+ *     device registers and windows, now only supporting devices 0,1,2, and
+ *     3. PIC did leave all 8 configuration space windows. The reason was
+ *     there was nothing to gain by removing them. Here in lies the problem.
+ *     The device numbering we do using 0 through 3 is unrelated to the device
+ *     numbering which PCI-X requires in configuration space. In the past we
+ *     correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc.
+ *     PCI-X requires we start a 1, not 0 and currently the PX brick
+ *     does associate our:
+ * 
+ *         device 0 with configuration space window 1,
+ *         device 1 with configuration space window 2, 
+ *         device 2 with configuration space window 3,
+ *         device 3 with configuration space window 4.
+ *
+ * The net effect is that all config space access are off-by-one with 
+ * relation to other per-slot accesses on the PIC.   
+ * Here is a table that shows some of that:
+ *
+ *                               Internal Slot#
+ *           |
+ *           |     0         1        2         3
+ * ----------|---------------------------------------
+ * config    |  0x21000   0x22000  0x23000   0x24000
+ *           |
+ * even rrb  |  0[0]      n/a      1[0]      n/a       [] == implied even/odd
+ *           |
+ * odd rrb   |  n/a       0[1]     n/a       1[1]
+ *           |
+ * int dev   |  00       01        10        11
+ *           |
+ * ext slot# |  1        2         3         4
+ * ----------|---------------------------------------
+ */
+
+#define PIC_ATE_TARGETID_SHFT           8
+#define PIC_HOST_INTR_ADDR              0x0000FFFFFFFFFFFFUL
+#define PIC_PCI64_ATTR_TARG_SHFT        60
+
+
+/*****************************************************************************
+ *********************** PIC MMR structure mapping ***************************
+ *****************************************************************************/
+
+/* NOTE: PIC WAR. PV#854697.  PIC does not allow writes just to [31:0]
+ * of a 64-bit register.  When writing PIC registers, always write the 
+ * entire 64 bits.
+ */
+
+struct pic {
+
+    /* 0x000000-0x00FFFF -- Local Registers */
+
+    /* 0x000000-0x000057 -- Standard Widget Configuration */
+    uint64_t           p_wid_id;                       /* 0x000000 */
+    uint64_t           p_wid_stat;                     /* 0x000008 */
+    uint64_t           p_wid_err_upper;                /* 0x000010 */
+    uint64_t           p_wid_err_lower;                /* 0x000018 */
+    #define p_wid_err p_wid_err_lower
+    uint64_t           p_wid_control;                  /* 0x000020 */
+    uint64_t           p_wid_req_timeout;              /* 0x000028 */
+    uint64_t           p_wid_int_upper;                /* 0x000030 */
+    uint64_t           p_wid_int_lower;                /* 0x000038 */
+    #define p_wid_int p_wid_int_lower
+    uint64_t           p_wid_err_cmdword;              /* 0x000040 */
+    uint64_t           p_wid_llp;                      /* 0x000048 */
+    uint64_t           p_wid_tflush;                   /* 0x000050 */
+
+    /* 0x000058-0x00007F -- Bridge-specific Widget Configuration */
+    uint64_t           p_wid_aux_err;                  /* 0x000058 */
+    uint64_t           p_wid_resp_upper;               /* 0x000060 */
+    uint64_t           p_wid_resp_lower;               /* 0x000068 */
+    #define p_wid_resp p_wid_resp_lower
+    uint64_t           p_wid_tst_pin_ctrl;             /* 0x000070 */
+    uint64_t           p_wid_addr_lkerr;               /* 0x000078 */
+
+    /* 0x000080-0x00008F -- PMU & MAP */
+    uint64_t           p_dir_map;                      /* 0x000080 */
+    uint64_t           _pad_000088;                    /* 0x000088 */
+
+    /* 0x000090-0x00009F -- SSRAM */
+    uint64_t           p_map_fault;                    /* 0x000090 */
+    uint64_t           _pad_000098;                    /* 0x000098 */
+
+    /* 0x0000A0-0x0000AF -- Arbitration */
+    uint64_t           p_arb;                          /* 0x0000A0 */
+    uint64_t           _pad_0000A8;                    /* 0x0000A8 */
+
+    /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */
+    uint64_t           p_ate_parity_err;               /* 0x0000B0 */
+    uint64_t           _pad_0000B8;                    /* 0x0000B8 */
+
+    /* 0x0000C0-0x0000FF -- PCI/GIO */
+    uint64_t           p_bus_timeout;                  /* 0x0000C0 */
+    uint64_t           p_pci_cfg;                      /* 0x0000C8 */
+    uint64_t           p_pci_err_upper;                /* 0x0000D0 */
+    uint64_t           p_pci_err_lower;                /* 0x0000D8 */
+    #define p_pci_err p_pci_err_lower
+    uint64_t           _pad_0000E0[4];                 /* 0x0000{E0..F8} */
+
+    /* 0x000100-0x0001FF -- Interrupt */
+    uint64_t           p_int_status;                   /* 0x000100 */
+    uint64_t           p_int_enable;                   /* 0x000108 */
+    uint64_t           p_int_rst_stat;                 /* 0x000110 */
+    uint64_t           p_int_mode;                     /* 0x000118 */
+    uint64_t           p_int_device;                   /* 0x000120 */
+    uint64_t           p_int_host_err;                 /* 0x000128 */
+    uint64_t           p_int_addr[8];                  /* 0x0001{30,,,68} */
+    uint64_t           p_err_int_view;                 /* 0x000170 */
+    uint64_t           p_mult_int;                     /* 0x000178 */
+    uint64_t           p_force_always[8];              /* 0x0001{80,,,B8} */
+    uint64_t           p_force_pin[8];                 /* 0x0001{C0,,,F8} */
+
+    /* 0x000200-0x000298 -- Device */
+    uint64_t           p_device[4];                    /* 0x0002{00,,,18} */
+    uint64_t           _pad_000220[4];                 /* 0x0002{20,,,38} */
+    uint64_t           p_wr_req_buf[4];                /* 0x0002{40,,,58} */
+    uint64_t           _pad_000260[4];                 /* 0x0002{60,,,78} */
+    uint64_t           p_rrb_map[2];                   /* 0x0002{80,,,88} */
+    #define p_even_resp p_rrb_map[0]                   /* 0x000280 */
+    #define p_odd_resp  p_rrb_map[1]                   /* 0x000288 */
+    uint64_t           p_resp_status;                  /* 0x000290 */
+    uint64_t           p_resp_clear;                   /* 0x000298 */
+
+    uint64_t           _pad_0002A0[12];                /* 0x0002{A0..F8} */
+
+    /* 0x000300-0x0003F8 -- Buffer Address Match Registers */
+    struct {
+       uint64_t        upper;                          /* 0x0003{00,,,F0} */
+       uint64_t        lower;                          /* 0x0003{08,,,F8} */
+    } p_buf_addr_match[16];
+
+    /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */
+    struct {
+       uint64_t        flush_w_touch;                  /* 0x000{400,,,5C0} */
+       uint64_t        flush_wo_touch;                 /* 0x000{408,,,5C8} */
+       uint64_t        inflight;                       /* 0x000{410,,,5D0} */
+       uint64_t        prefetch;                       /* 0x000{418,,,5D8} */
+       uint64_t        total_pci_retry;                /* 0x000{420,,,5E0} */
+       uint64_t        max_pci_retry;                  /* 0x000{428,,,5E8} */
+       uint64_t        max_latency;                    /* 0x000{430,,,5F0} */
+       uint64_t        clear_all;                      /* 0x000{438,,,5F8} */
+    } p_buf_count[8];
+
+    
+    /* 0x000600-0x0009FF -- PCI/X registers */
+    uint64_t           p_pcix_bus_err_addr;            /* 0x000600 */
+    uint64_t           p_pcix_bus_err_attr;            /* 0x000608 */
+    uint64_t           p_pcix_bus_err_data;            /* 0x000610 */
+    uint64_t           p_pcix_pio_split_addr;          /* 0x000618 */
+    uint64_t           p_pcix_pio_split_attr;          /* 0x000620 */
+    uint64_t           p_pcix_dma_req_err_attr;        /* 0x000628 */
+    uint64_t           p_pcix_dma_req_err_addr;        /* 0x000630 */
+    uint64_t           p_pcix_timeout;                 /* 0x000638 */
+
+    uint64_t           _pad_000640[120];               /* 0x000{640,,,9F8} */
+
+    /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */
+    struct {
+       uint64_t        p_buf_addr;                     /* 0x000{A00,,,AF0} */
+       uint64_t        p_buf_attr;                     /* 0X000{A08,,,AF8} */
+    } p_pcix_read_buf_64[16];
+
+    struct {
+       uint64_t        p_buf_addr;                     /* 0x000{B00,,,BE0} */
+       uint64_t        p_buf_attr;                     /* 0x000{B08,,,BE8} */
+       uint64_t        p_buf_valid;                    /* 0x000{B10,,,BF0} */
+       uint64_t        __pad1;                         /* 0x000{B18,,,BF8} */
+    } p_pcix_write_buf_64[8];
+
+    /* End of Local Registers -- Start of Address Map space */
+
+    char               _pad_000c00[0x010000 - 0x000c00];
+
+    /* 0x010000-0x011fff -- Internal ATE RAM (Auto Parity Generation) */
+    uint64_t           p_int_ate_ram[1024];            /* 0x010000-0x011fff */
+
+    /* 0x012000-0x013fff -- Internal ATE RAM (Manual Parity Generation) */
+    uint64_t           p_int_ate_ram_mp[1024];         /* 0x012000-0x013fff */
+
+    char               _pad_014000[0x18000 - 0x014000];
+
+    /* 0x18000-0x197F8 -- PIC Write Request Ram */
+    uint64_t           p_wr_req_lower[256];            /* 0x18000 - 0x187F8 */
+    uint64_t           p_wr_req_upper[256];            /* 0x18800 - 0x18FF8 */
+    uint64_t           p_wr_req_parity[256];           /* 0x19000 - 0x197F8 */
+
+    char               _pad_019800[0x20000 - 0x019800];
+
+    /* 0x020000-0x027FFF -- PCI Device Configuration Spaces */
+    union {
+       uint8_t         c[0x1000 / 1];                  /* 0x02{0000,,,7FFF} */
+       uint16_t        s[0x1000 / 2];                  /* 0x02{0000,,,7FFF} */
+       uint32_t        l[0x1000 / 4];                  /* 0x02{0000,,,7FFF} */
+       uint64_t        d[0x1000 / 8];                  /* 0x02{0000,,,7FFF} */
+       union {
+           uint8_t     c[0x100 / 1];
+           uint16_t    s[0x100 / 2];
+           uint32_t    l[0x100 / 4];
+           uint64_t    d[0x100 / 8];
+       } f[8];
+    } p_type0_cfg_dev[8];                              /* 0x02{0000,,,7FFF} */
+
+    /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */
+    union {
+       uint8_t         c[0x1000 / 1];                  /* 0x028000-0x029000 */
+       uint16_t        s[0x1000 / 2];                  /* 0x028000-0x029000 */
+       uint32_t        l[0x1000 / 4];                  /* 0x028000-0x029000 */
+       uint64_t        d[0x1000 / 8];                  /* 0x028000-0x029000 */
+       union {
+           uint8_t     c[0x100 / 1];
+           uint16_t    s[0x100 / 2];
+           uint32_t    l[0x100 / 4];
+           uint64_t    d[0x100 / 8];
+       } f[8];
+    } p_type1_cfg;                                     /* 0x028000-0x029000 */
+
+    char               _pad_029000[0x030000-0x029000];
+
+    /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */
+    union {
+       uint8_t         c[8 / 1];
+       uint16_t        s[8 / 2];
+       uint32_t        l[8 / 4];
+       uint64_t        d[8 / 8];
+    } p_pci_iack;                                      /* 0x030000-0x030007 */
+
+    char               _pad_030007[0x040000-0x030008];
+
+    /* 0x040000-0x030007 -- PCIX Special Cycle */
+    union {
+       uint8_t         c[8 / 1];
+       uint16_t        s[8 / 2];
+       uint32_t        l[8 / 4];
+       uint64_t        d[8 / 8];
+    } p_pcix_cycle;                                    /* 0x040000-0x040007 */
+};
+
+#endif                          /* _ASM_IA64_SN_PCI_PIC_H */
diff --git a/arch/ia64/sn/include/pci/tiocp.h b/arch/ia64/sn/include/pci/tiocp.h
new file mode 100644 (file)
index 0000000..f07c83b
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_IA64_SN_PCI_TIOCP_H
+#define _ASM_IA64_SN_PCI_TIOCP_H
+
+#define TIOCP_HOST_INTR_ADDR            0x003FFFFFFFFFFFFFUL
+#define TIOCP_PCI64_CMDTYPE_MEM         (0x1ull << 60)
+
+
+/*****************************************************************************
+ *********************** TIOCP MMR structure mapping ***************************
+ *****************************************************************************/
+
+struct tiocp{
+
+    /* 0x000000-0x00FFFF -- Local Registers */
+
+    /* 0x000000-0x000057 -- (Legacy Widget Space) Configuration */
+    uint64_t           cp_id;                          /* 0x000000 */
+    uint64_t           cp_stat;                        /* 0x000008 */
+    uint64_t           cp_err_upper;                   /* 0x000010 */
+    uint64_t           cp_err_lower;                   /* 0x000018 */
+    #define cp_err cp_err_lower
+    uint64_t           cp_control;                     /* 0x000020 */
+    uint64_t           cp_req_timeout;                 /* 0x000028 */
+    uint64_t           cp_intr_upper;                  /* 0x000030 */
+    uint64_t           cp_intr_lower;                  /* 0x000038 */
+    #define cp_intr cp_intr_lower
+    uint64_t           cp_err_cmdword;                 /* 0x000040 */
+    uint64_t           _pad_000048;                    /* 0x000048 */
+    uint64_t           cp_tflush;                      /* 0x000050 */
+
+    /* 0x000058-0x00007F -- Bridge-specific Configuration */
+    uint64_t           cp_aux_err;                     /* 0x000058 */
+    uint64_t           cp_resp_upper;                  /* 0x000060 */
+    uint64_t           cp_resp_lower;                  /* 0x000068 */
+    #define cp_resp cp_resp_lower
+    uint64_t           cp_tst_pin_ctrl;                /* 0x000070 */
+    uint64_t           cp_addr_lkerr;                  /* 0x000078 */
+
+    /* 0x000080-0x00008F -- PMU & MAP */
+    uint64_t           cp_dir_map;                     /* 0x000080 */
+    uint64_t           _pad_000088;                    /* 0x000088 */
+
+    /* 0x000090-0x00009F -- SSRAM */
+    uint64_t           cp_map_fault;                   /* 0x000090 */
+    uint64_t           _pad_000098;                    /* 0x000098 */
+
+    /* 0x0000A0-0x0000AF -- Arbitration */
+    uint64_t           cp_arb;                         /* 0x0000A0 */
+    uint64_t           _pad_0000A8;                    /* 0x0000A8 */
+
+    /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */
+    uint64_t           cp_ate_parity_err;              /* 0x0000B0 */
+    uint64_t           _pad_0000B8;                    /* 0x0000B8 */
+
+    /* 0x0000C0-0x0000FF -- PCI/GIO */
+    uint64_t           cp_bus_timeout;                 /* 0x0000C0 */
+    uint64_t           cp_pci_cfg;                     /* 0x0000C8 */
+    uint64_t           cp_pci_err_upper;               /* 0x0000D0 */
+    uint64_t           cp_pci_err_lower;               /* 0x0000D8 */
+    #define cp_pci_err cp_pci_err_lower
+    uint64_t           _pad_0000E0[4];                 /* 0x0000{E0..F8} */
+
+    /* 0x000100-0x0001FF -- Interrupt */
+    uint64_t           cp_int_status;                  /* 0x000100 */
+    uint64_t           cp_int_enable;                  /* 0x000108 */
+    uint64_t           cp_int_rst_stat;                /* 0x000110 */
+    uint64_t           cp_int_mode;                    /* 0x000118 */
+    uint64_t           cp_int_device;                  /* 0x000120 */
+    uint64_t           cp_int_host_err;                /* 0x000128 */
+    uint64_t           cp_int_addr[8];                 /* 0x0001{30,,,68} */
+    uint64_t           cp_err_int_view;                /* 0x000170 */
+    uint64_t           cp_mult_int;                    /* 0x000178 */
+    uint64_t           cp_force_always[8];             /* 0x0001{80,,,B8} */
+    uint64_t           cp_force_pin[8];                /* 0x0001{C0,,,F8} */
+
+    /* 0x000200-0x000298 -- Device */
+    uint64_t           cp_device[4];                   /* 0x0002{00,,,18} */
+    uint64_t           _pad_000220[4];                 /* 0x0002{20,,,38} */
+    uint64_t           cp_wr_req_buf[4];               /* 0x0002{40,,,58} */
+    uint64_t           _pad_000260[4];                 /* 0x0002{60,,,78} */
+    uint64_t           cp_rrb_map[2];                  /* 0x0002{80,,,88} */
+    #define cp_even_resp cp_rrb_map[0]                 /* 0x000280 */
+    #define cp_odd_resp  cp_rrb_map[1]                 /* 0x000288 */
+    uint64_t           cp_resp_status;                 /* 0x000290 */
+    uint64_t           cp_resp_clear;                  /* 0x000298 */
+
+    uint64_t           _pad_0002A0[12];                /* 0x0002{A0..F8} */
+
+    /* 0x000300-0x0003F8 -- Buffer Address Match Registers */
+    struct {
+       uint64_t        upper;                          /* 0x0003{00,,,F0} */
+       uint64_t        lower;                          /* 0x0003{08,,,F8} */
+    } cp_buf_addr_match[16];
+
+    /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */
+    struct {
+       uint64_t        flush_w_touch;                  /* 0x000{400,,,5C0} */
+       uint64_t        flush_wo_touch;                 /* 0x000{408,,,5C8} */
+       uint64_t        inflight;                       /* 0x000{410,,,5D0} */
+       uint64_t        prefetch;                       /* 0x000{418,,,5D8} */
+       uint64_t        total_pci_retry;                /* 0x000{420,,,5E0} */
+       uint64_t        max_pci_retry;                  /* 0x000{428,,,5E8} */
+       uint64_t        max_latency;                    /* 0x000{430,,,5F0} */
+       uint64_t        clear_all;                      /* 0x000{438,,,5F8} */
+    } cp_buf_count[8];
+
+    
+    /* 0x000600-0x0009FF -- PCI/X registers */
+    uint64_t           cp_pcix_bus_err_addr;           /* 0x000600 */
+    uint64_t           cp_pcix_bus_err_attr;           /* 0x000608 */
+    uint64_t           cp_pcix_bus_err_data;           /* 0x000610 */
+    uint64_t           cp_pcix_pio_split_addr;         /* 0x000618 */
+    uint64_t           cp_pcix_pio_split_attr;         /* 0x000620 */
+    uint64_t           cp_pcix_dma_req_err_attr;       /* 0x000628 */
+    uint64_t           cp_pcix_dma_req_err_addr;       /* 0x000630 */
+    uint64_t           cp_pcix_timeout;                /* 0x000638 */
+
+    uint64_t           _pad_000640[24];                /* 0x000{640,,,6F8} */
+
+    /* 0x000700-0x000737 -- Debug Registers */
+    uint64_t           cp_ct_debug_ctl;                /* 0x000700 */
+    uint64_t           cp_br_debug_ctl;                /* 0x000708 */
+    uint64_t           cp_mux3_debug_ctl;              /* 0x000710 */
+    uint64_t           cp_mux4_debug_ctl;              /* 0x000718 */
+    uint64_t           cp_mux5_debug_ctl;              /* 0x000720 */
+    uint64_t           cp_mux6_debug_ctl;              /* 0x000728 */
+    uint64_t           cp_mux7_debug_ctl;              /* 0x000730 */
+
+    uint64_t           _pad_000738[89];                /* 0x000{738,,,9F8} */
+
+    /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */
+    struct {
+       uint64_t        cp_buf_addr;                    /* 0x000{A00,,,AF0} */
+       uint64_t        cp_buf_attr;                    /* 0X000{A08,,,AF8} */
+    } cp_pcix_read_buf_64[16];
+
+    struct {
+       uint64_t        cp_buf_addr;                    /* 0x000{B00,,,BE0} */
+       uint64_t        cp_buf_attr;                    /* 0x000{B08,,,BE8} */
+       uint64_t        cp_buf_valid;                   /* 0x000{B10,,,BF0} */
+       uint64_t        __pad1;                         /* 0x000{B18,,,BF8} */
+    } cp_pcix_write_buf_64[8];
+
+    /* End of Local Registers -- Start of Address Map space */
+
+    char               _pad_000c00[0x010000 - 0x000c00];
+
+    /* 0x010000-0x011FF8 -- Internal ATE RAM (Auto Parity Generation) */
+    uint64_t           cp_int_ate_ram[1024];           /* 0x010000-0x011FF8 */
+
+    char               _pad_012000[0x14000 - 0x012000];
+
+    /* 0x014000-0x015FF8 -- Internal ATE RAM (Manual Parity Generation) */
+    uint64_t           cp_int_ate_ram_mp[1024];        /* 0x014000-0x015FF8 */
+
+    char               _pad_016000[0x18000 - 0x016000];
+
+    /* 0x18000-0x197F8 -- TIOCP Write Request Ram */
+    uint64_t           cp_wr_req_lower[256];           /* 0x18000 - 0x187F8 */
+    uint64_t           cp_wr_req_upper[256];           /* 0x18800 - 0x18FF8 */
+    uint64_t           cp_wr_req_parity[256];          /* 0x19000 - 0x197F8 */
+
+    char               _pad_019800[0x1C000 - 0x019800];
+
+    /* 0x1C000-0x1EFF8 -- TIOCP Read Response Ram */
+    uint64_t           cp_rd_resp_lower[512];          /* 0x1C000 - 0x1CFF8 */
+    uint64_t           cp_rd_resp_upper[512];          /* 0x1D000 - 0x1DFF8 */
+    uint64_t           cp_rd_resp_parity[512];         /* 0x1E000 - 0x1EFF8 */
+
+    char               _pad_01F000[0x20000 - 0x01F000];
+
+    /* 0x020000-0x021FFF -- Host Device (CP) Configuration Space (not used)  */
+    char               _pad_020000[0x021000 - 0x20000];
+
+    /* 0x021000-0x027FFF -- PCI Device Configuration Spaces */
+    union {
+       uint8_t         c[0x1000 / 1];                  /* 0x02{0000,,,7FFF} */
+       uint16_t        s[0x1000 / 2];                  /* 0x02{0000,,,7FFF} */
+       uint32_t        l[0x1000 / 4];                  /* 0x02{0000,,,7FFF} */
+       uint64_t        d[0x1000 / 8];                  /* 0x02{0000,,,7FFF} */
+       union {
+           uint8_t     c[0x100 / 1];
+           uint16_t    s[0x100 / 2];
+           uint32_t    l[0x100 / 4];
+           uint64_t    d[0x100 / 8];
+       } f[8];
+    } cp_type0_cfg_dev[7];                             /* 0x02{1000,,,7FFF} */
+
+    /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */
+    union {
+       uint8_t         c[0x1000 / 1];                  /* 0x028000-0x029000 */
+       uint16_t        s[0x1000 / 2];                  /* 0x028000-0x029000 */
+       uint32_t        l[0x1000 / 4];                  /* 0x028000-0x029000 */
+       uint64_t        d[0x1000 / 8];                  /* 0x028000-0x029000 */
+       union {
+           uint8_t     c[0x100 / 1];
+           uint16_t    s[0x100 / 2];
+           uint32_t    l[0x100 / 4];
+           uint64_t    d[0x100 / 8];
+       } f[8];
+    } cp_type1_cfg;                                    /* 0x028000-0x029000 */
+
+    char               _pad_029000[0x030000-0x029000];
+
+    /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */
+    union {
+       uint8_t         c[8 / 1];
+       uint16_t        s[8 / 2];
+       uint32_t        l[8 / 4];
+       uint64_t        d[8 / 8];
+    } cp_pci_iack;                                     /* 0x030000-0x030007 */
+
+    char               _pad_030007[0x040000-0x030008];
+
+    /* 0x040000-0x040007 -- PCIX Special Cycle */
+    union {
+       uint8_t         c[8 / 1];
+       uint16_t        s[8 / 2];
+       uint32_t        l[8 / 4];
+       uint64_t        d[8 / 8];
+    } cp_pcix_cycle;                                   /* 0x040000-0x040007 */
+
+    char               _pad_040007[0x200000-0x040008];
+
+    /* 0x200000-0x7FFFFF -- PCI/GIO Device Spaces */
+    union {
+       uint8_t         c[0x100000 / 1];
+       uint16_t        s[0x100000 / 2];
+       uint32_t        l[0x100000 / 4];
+       uint64_t        d[0x100000 / 8];
+    } cp_devio_raw[6];                                 /* 0x200000-0x7FFFFF */
+
+    #define cp_devio(n)  cp_devio_raw[((n)<2)?(n*2):(n+2)]
+
+    char               _pad_800000[0xA00000-0x800000];
+
+    /* 0xA00000-0xBFFFFF -- PCI/GIO Device Spaces w/flush  */
+    union {
+       uint8_t         c[0x100000 / 1];
+       uint16_t        s[0x100000 / 2];
+       uint32_t        l[0x100000 / 4];
+       uint64_t        d[0x100000 / 8];
+    } cp_devio_raw_flush[6];                           /* 0xA00000-0xBFFFFF */
+
+    #define cp_devio_flush(n)  cp_devio_raw_flush[((n)<2)?(n*2):(n+2)]
+
+};
+
+#endif         /* _ASM_IA64_SN_PCI_TIOCP_H */
diff --git a/arch/ia64/sn/include/shub.h b/arch/ia64/sn/include/shub.h
new file mode 100644 (file)
index 0000000..44e2bef
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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-2004 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_SHUB_H
+#define _ASM_IA64_SN_SHUB_H
+
+
+#define MD_MEM_BANKS            4
+
+
+/*
+ * Junk Bus Address Space
+ *   The junk bus is used to access the PROM, LED's, and UART. It's 
+ *   accessed through the local block MMR space. The data path is
+ *   16 bits wide. This space requires address bits 31-27 to be set, and
+ *   is further divided by address bits 26:15.
+ *   The LED addresses are write-only. To read the LEDs, you need to use
+ *   SH_JUNK_BUS_LED0-3, defined in shub_mmr.h
+ *             
+ */
+#define SH_REAL_JUNK_BUS_LED0           0x7fed00000UL
+#define SH_REAL_JUNK_BUS_LED1           0x7fed10000UL
+#define SH_REAL_JUNK_BUS_LED2           0x7fed20000UL
+#define SH_REAL_JUNK_BUS_LED3           0x7fed30000UL
+#define SH_JUNK_BUS_UART0               0x7fed40000UL
+#define SH_JUNK_BUS_UART1               0x7fed40008UL
+#define SH_JUNK_BUS_UART2               0x7fed40010UL
+#define SH_JUNK_BUS_UART3               0x7fed40018UL
+#define SH_JUNK_BUS_UART4               0x7fed40020UL
+#define SH_JUNK_BUS_UART5               0x7fed40028UL
+#define SH_JUNK_BUS_UART6               0x7fed40030UL
+#define SH_JUNK_BUS_UART7               0x7fed40038UL
+
+#endif /* _ASM_IA64_SN_SHUB_H */
diff --git a/arch/ia64/sn/include/shubio.h b/arch/ia64/sn/include/shubio.h
new file mode 100644 (file)
index 0000000..fbd880e
--- /dev/null
@@ -0,0 +1,3476 @@
+/*
+ * 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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_SHUBIO_H
+#define _ASM_IA64_SN_SHUBIO_H
+
+#define HUB_WIDGET_ID_MAX 0xf
+#define IIO_NUM_ITTES   7
+#define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
+
+#define    IIO_WID                   0x00400000    /* Crosstalk Widget Identification */
+                                                   /* This register is also accessible from
+                                                    * Crosstalk at address 0x0.  */
+#define    IIO_WSTAT                 0x00400008    /* Crosstalk Widget Status */
+#define    IIO_WCR                   0x00400020    /* Crosstalk Widget Control Register */
+#define    IIO_ILAPR                 0x00400100    /* IO Local Access Protection Register */
+#define    IIO_ILAPO                 0x00400108    /* IO Local Access Protection Override */
+#define    IIO_IOWA                  0x00400110    /* IO Outbound Widget Access */
+#define    IIO_IIWA                  0x00400118    /* IO Inbound Widget Access */
+#define    IIO_IIDEM                 0x00400120    /* IO Inbound Device Error Mask */
+#define    IIO_ILCSR                 0x00400128    /* IO LLP Control and Status Register */
+#define    IIO_ILLR                  0x00400130    /* IO LLP Log Register    */
+#define    IIO_IIDSR                 0x00400138    /* IO Interrupt Destination */
+
+#define    IIO_IGFX0                 0x00400140    /* IO Graphics Node-Widget Map 0 */
+#define    IIO_IGFX1                 0x00400148    /* IO Graphics Node-Widget Map 1 */
+
+#define    IIO_ISCR0                 0x00400150    /* IO Scratch Register 0 */
+#define    IIO_ISCR1                 0x00400158    /* IO Scratch Register 1 */
+
+#define    IIO_ITTE1                 0x00400160    /* IO Translation Table Entry 1 */
+#define    IIO_ITTE2                 0x00400168    /* IO Translation Table Entry 2 */
+#define    IIO_ITTE3                 0x00400170    /* IO Translation Table Entry 3 */
+#define    IIO_ITTE4                 0x00400178    /* IO Translation Table Entry 4 */
+#define    IIO_ITTE5                 0x00400180    /* IO Translation Table Entry 5 */
+#define    IIO_ITTE6                 0x00400188    /* IO Translation Table Entry 6 */
+#define    IIO_ITTE7                 0x00400190    /* IO Translation Table Entry 7 */
+
+#define    IIO_IPRB0                 0x00400198    /* IO PRB Entry 0         */
+#define    IIO_IPRB8                 0x004001A0    /* IO PRB Entry 8         */
+#define    IIO_IPRB9                 0x004001A8    /* IO PRB Entry 9         */
+#define    IIO_IPRBA                 0x004001B0    /* IO PRB Entry A         */
+#define    IIO_IPRBB                 0x004001B8    /* IO PRB Entry B         */
+#define    IIO_IPRBC                 0x004001C0    /* IO PRB Entry C         */
+#define    IIO_IPRBD                 0x004001C8    /* IO PRB Entry D         */
+#define    IIO_IPRBE                 0x004001D0    /* IO PRB Entry E         */
+#define    IIO_IPRBF                 0x004001D8    /* IO PRB Entry F         */
+
+#define    IIO_IXCC                  0x004001E0    /* IO Crosstalk Credit Count Timeout */
+#define    IIO_IMEM                  0x004001E8    /* IO Miscellaneous Error Mask */
+#define    IIO_IXTT                  0x004001F0    /* IO Crosstalk Timeout Threshold */
+#define    IIO_IECLR                 0x004001F8    /* IO Error Clear Register */
+#define    IIO_IBCR                  0x00400200    /* IO BTE Control Register */
+
+#define    IIO_IXSM                  0x00400208    /* IO Crosstalk Spurious Message */
+#define    IIO_IXSS                  0x00400210    /* IO Crosstalk Spurious Sideband */
+
+#define    IIO_ILCT                  0x00400218    /* IO LLP Channel Test    */
+
+#define    IIO_IIEPH1                0x00400220    /* IO Incoming Error Packet Header, Part 1 */
+#define    IIO_IIEPH2                0x00400228    /* IO Incoming Error Packet Header, Part 2 */
+
+
+#define    IIO_ISLAPR                0x00400230    /* IO SXB Local Access Protection Regster */
+#define    IIO_ISLAPO                0x00400238    /* IO SXB Local Access Protection Override */
+
+#define    IIO_IWI                   0x00400240    /* IO Wrapper Interrupt Register */
+#define    IIO_IWEL                  0x00400248    /* IO Wrapper Error Log Register */
+#define    IIO_IWC                   0x00400250    /* IO Wrapper Control Register */
+#define    IIO_IWS                   0x00400258    /* IO Wrapper Status Register */
+#define    IIO_IWEIM                 0x00400260    /* IO Wrapper Error Interrupt Masking Register */
+
+#define    IIO_IPCA                  0x00400300    /* IO PRB Counter Adjust */
+
+#define    IIO_IPRTE0_A              0x00400308    /* IO PIO Read Address Table Entry 0, Part A */
+#define    IIO_IPRTE1_A              0x00400310    /* IO PIO Read Address Table Entry 1, Part A */
+#define    IIO_IPRTE2_A              0x00400318    /* IO PIO Read Address Table Entry 2, Part A */
+#define    IIO_IPRTE3_A               0x00400320    /* IO PIO Read Address Table Entry 3, Part A */
+#define    IIO_IPRTE4_A               0x00400328    /* IO PIO Read Address Table Entry 4, Part A */
+#define    IIO_IPRTE5_A               0x00400330    /* IO PIO Read Address Table Entry 5, Part A */
+#define    IIO_IPRTE6_A               0x00400338    /* IO PIO Read Address Table Entry 6, Part A */
+#define    IIO_IPRTE7_A               0x00400340    /* IO PIO Read Address Table Entry 7, Part A */
+
+#define    IIO_IPRTE0_B              0x00400348    /* IO PIO Read Address Table Entry 0, Part B */
+#define    IIO_IPRTE1_B              0x00400350    /* IO PIO Read Address Table Entry 1, Part B */
+#define    IIO_IPRTE2_B              0x00400358    /* IO PIO Read Address Table Entry 2, Part B */
+#define    IIO_IPRTE3_B               0x00400360    /* IO PIO Read Address Table Entry 3, Part B */
+#define    IIO_IPRTE4_B               0x00400368    /* IO PIO Read Address Table Entry 4, Part B */
+#define    IIO_IPRTE5_B               0x00400370    /* IO PIO Read Address Table Entry 5, Part B */
+#define    IIO_IPRTE6_B               0x00400378    /* IO PIO Read Address Table Entry 6, Part B */
+#define    IIO_IPRTE7_B               0x00400380    /* IO PIO Read Address Table Entry 7, Part B */
+
+#define    IIO_IPDR                  0x00400388    /* IO PIO Deallocation Register */
+#define    IIO_ICDR                  0x00400390    /* IO CRB Entry Deallocation Register */
+#define    IIO_IFDR                  0x00400398    /* IO IOQ FIFO Depth Register */
+#define    IIO_IIAP                  0x004003A0    /* IO IIQ Arbitration Parameters */
+#define    IIO_ICMR                  0x004003A8    /* IO CRB Management Register */
+#define    IIO_ICCR                  0x004003B0    /* IO CRB Control Register */
+#define    IIO_ICTO                  0x004003B8    /* IO CRB Timeout         */
+#define    IIO_ICTP                  0x004003C0    /* IO CRB Timeout Prescalar */
+
+#define    IIO_ICRB0_A               0x00400400    /* IO CRB Entry 0_A       */
+#define    IIO_ICRB0_B               0x00400408    /* IO CRB Entry 0_B       */
+#define    IIO_ICRB0_C               0x00400410    /* IO CRB Entry 0_C       */
+#define    IIO_ICRB0_D               0x00400418    /* IO CRB Entry 0_D       */
+#define    IIO_ICRB0_E               0x00400420    /* IO CRB Entry 0_E       */
+
+#define    IIO_ICRB1_A               0x00400430    /* IO CRB Entry 1_A       */
+#define    IIO_ICRB1_B               0x00400438    /* IO CRB Entry 1_B       */
+#define    IIO_ICRB1_C               0x00400440    /* IO CRB Entry 1_C       */
+#define    IIO_ICRB1_D               0x00400448    /* IO CRB Entry 1_D       */
+#define    IIO_ICRB1_E               0x00400450    /* IO CRB Entry 1_E       */
+
+#define    IIO_ICRB2_A               0x00400460    /* IO CRB Entry 2_A       */
+#define    IIO_ICRB2_B               0x00400468    /* IO CRB Entry 2_B       */
+#define    IIO_ICRB2_C               0x00400470    /* IO CRB Entry 2_C       */
+#define    IIO_ICRB2_D               0x00400478    /* IO CRB Entry 2_D       */
+#define    IIO_ICRB2_E               0x00400480    /* IO CRB Entry 2_E       */
+
+#define    IIO_ICRB3_A               0x00400490    /* IO CRB Entry 3_A       */
+#define    IIO_ICRB3_B               0x00400498    /* IO CRB Entry 3_B       */
+#define    IIO_ICRB3_C               0x004004a0    /* IO CRB Entry 3_C       */
+#define    IIO_ICRB3_D               0x004004a8    /* IO CRB Entry 3_D       */
+#define    IIO_ICRB3_E               0x004004b0    /* IO CRB Entry 3_E       */
+
+#define    IIO_ICRB4_A               0x004004c0    /* IO CRB Entry 4_A       */
+#define    IIO_ICRB4_B               0x004004c8    /* IO CRB Entry 4_B       */
+#define    IIO_ICRB4_C               0x004004d0    /* IO CRB Entry 4_C       */
+#define    IIO_ICRB4_D               0x004004d8    /* IO CRB Entry 4_D       */
+#define    IIO_ICRB4_E               0x004004e0    /* IO CRB Entry 4_E       */
+
+#define    IIO_ICRB5_A               0x004004f0    /* IO CRB Entry 5_A       */
+#define    IIO_ICRB5_B               0x004004f8    /* IO CRB Entry 5_B       */
+#define    IIO_ICRB5_C               0x00400500    /* IO CRB Entry 5_C       */
+#define    IIO_ICRB5_D               0x00400508    /* IO CRB Entry 5_D       */
+#define    IIO_ICRB5_E               0x00400510    /* IO CRB Entry 5_E       */
+
+#define    IIO_ICRB6_A               0x00400520    /* IO CRB Entry 6_A       */
+#define    IIO_ICRB6_B               0x00400528    /* IO CRB Entry 6_B       */
+#define    IIO_ICRB6_C               0x00400530    /* IO CRB Entry 6_C       */
+#define    IIO_ICRB6_D               0x00400538    /* IO CRB Entry 6_D       */
+#define    IIO_ICRB6_E               0x00400540    /* IO CRB Entry 6_E       */
+
+#define    IIO_ICRB7_A               0x00400550    /* IO CRB Entry 7_A       */
+#define    IIO_ICRB7_B               0x00400558    /* IO CRB Entry 7_B       */
+#define    IIO_ICRB7_C               0x00400560    /* IO CRB Entry 7_C       */
+#define    IIO_ICRB7_D               0x00400568    /* IO CRB Entry 7_D       */
+#define    IIO_ICRB7_E               0x00400570    /* IO CRB Entry 7_E       */
+
+#define    IIO_ICRB8_A               0x00400580    /* IO CRB Entry 8_A       */
+#define    IIO_ICRB8_B               0x00400588    /* IO CRB Entry 8_B       */
+#define    IIO_ICRB8_C               0x00400590    /* IO CRB Entry 8_C       */
+#define    IIO_ICRB8_D               0x00400598    /* IO CRB Entry 8_D       */
+#define    IIO_ICRB8_E               0x004005a0    /* IO CRB Entry 8_E       */
+
+#define    IIO_ICRB9_A               0x004005b0    /* IO CRB Entry 9_A       */
+#define    IIO_ICRB9_B               0x004005b8    /* IO CRB Entry 9_B       */
+#define    IIO_ICRB9_C               0x004005c0    /* IO CRB Entry 9_C       */
+#define    IIO_ICRB9_D               0x004005c8    /* IO CRB Entry 9_D       */
+#define    IIO_ICRB9_E               0x004005d0    /* IO CRB Entry 9_E       */
+
+#define    IIO_ICRBA_A               0x004005e0    /* IO CRB Entry A_A       */
+#define    IIO_ICRBA_B               0x004005e8    /* IO CRB Entry A_B       */
+#define    IIO_ICRBA_C               0x004005f0    /* IO CRB Entry A_C       */
+#define    IIO_ICRBA_D               0x004005f8    /* IO CRB Entry A_D       */
+#define    IIO_ICRBA_E               0x00400600    /* IO CRB Entry A_E       */
+
+#define    IIO_ICRBB_A               0x00400610    /* IO CRB Entry B_A       */
+#define    IIO_ICRBB_B               0x00400618    /* IO CRB Entry B_B       */
+#define    IIO_ICRBB_C               0x00400620    /* IO CRB Entry B_C       */
+#define    IIO_ICRBB_D               0x00400628    /* IO CRB Entry B_D       */
+#define    IIO_ICRBB_E               0x00400630    /* IO CRB Entry B_E       */
+
+#define    IIO_ICRBC_A               0x00400640    /* IO CRB Entry C_A       */
+#define    IIO_ICRBC_B               0x00400648    /* IO CRB Entry C_B       */
+#define    IIO_ICRBC_C               0x00400650    /* IO CRB Entry C_C       */
+#define    IIO_ICRBC_D               0x00400658    /* IO CRB Entry C_D       */
+#define    IIO_ICRBC_E               0x00400660    /* IO CRB Entry C_E       */
+
+#define    IIO_ICRBD_A               0x00400670    /* IO CRB Entry D_A       */
+#define    IIO_ICRBD_B               0x00400678    /* IO CRB Entry D_B       */
+#define    IIO_ICRBD_C               0x00400680    /* IO CRB Entry D_C       */
+#define    IIO_ICRBD_D               0x00400688    /* IO CRB Entry D_D       */
+#define    IIO_ICRBD_E               0x00400690    /* IO CRB Entry D_E       */
+
+#define    IIO_ICRBE_A               0x004006a0    /* IO CRB Entry E_A       */
+#define    IIO_ICRBE_B               0x004006a8    /* IO CRB Entry E_B       */
+#define    IIO_ICRBE_C               0x004006b0    /* IO CRB Entry E_C       */
+#define    IIO_ICRBE_D               0x004006b8    /* IO CRB Entry E_D       */
+#define    IIO_ICRBE_E               0x004006c0    /* IO CRB Entry E_E       */
+
+#define    IIO_ICSML                 0x00400700    /* IO CRB Spurious Message Low */
+#define    IIO_ICSMM                 0x00400708    /* IO CRB Spurious Message Middle */
+#define    IIO_ICSMH                 0x00400710    /* IO CRB Spurious Message High */
+
+#define    IIO_IDBSS                 0x00400718    /* IO Debug Submenu Select */
+
+#define    IIO_IBLS0                 0x00410000    /* IO BTE Length Status 0 */
+#define    IIO_IBSA0                 0x00410008    /* IO BTE Source Address 0 */
+#define    IIO_IBDA0                 0x00410010    /* IO BTE Destination Address 0 */
+#define    IIO_IBCT0                 0x00410018    /* IO BTE Control Terminate 0 */
+#define    IIO_IBNA0                 0x00410020    /* IO BTE Notification Address 0 */
+#define    IIO_IBIA0                 0x00410028    /* IO BTE Interrupt Address 0 */
+#define    IIO_IBLS1                 0x00420000    /* IO BTE Length Status 1 */
+#define    IIO_IBSA1                 0x00420008    /* IO BTE Source Address 1 */
+#define    IIO_IBDA1                 0x00420010    /* IO BTE Destination Address 1 */
+#define    IIO_IBCT1                 0x00420018    /* IO BTE Control Terminate 1 */
+#define    IIO_IBNA1                 0x00420020    /* IO BTE Notification Address 1 */
+#define    IIO_IBIA1                 0x00420028    /* IO BTE Interrupt Address 1 */
+
+#define    IIO_IPCR                  0x00430000    /* IO Performance Control */
+#define    IIO_IPPR                  0x00430008    /* IO Performance Profiling */
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register echoes some information from the         *
+ * LB_REV_ID register. It is available through Crosstalk as described   *
+ * above. The REV_NUM and MFG_NUM fields receive their values from      *
+ * the REVISION and MANUFACTURER fields in the LB_REV_ID register.      *
+ * The PART_NUM field's value is the Crosstalk device ID number that    *
+ * Steve Miller assigned to the SHub chip.                              *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_wid_u {
+       uint64_t        ii_wid_regval;
+       struct  {
+               uint64_t        w_rsvd_1                  :      1;
+               uint64_t        w_mfg_num                 :     11;
+               uint64_t        w_part_num                :     16;
+               uint64_t        w_rev_num                 :      4;
+               uint64_t        w_rsvd                    :     32;
+       } ii_wid_fld_s;
+} ii_wid_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  The fields in this register are set upon detection of an error      *
+ * and cleared by various mechanisms, as explained in the               *
+ * description.                                                         *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_wstat_u {
+       uint64_t        ii_wstat_regval;
+       struct  {
+               uint64_t        w_pending                 :      4;
+               uint64_t        w_xt_crd_to               :      1;
+               uint64_t        w_xt_tail_to              :      1;
+               uint64_t        w_rsvd_3                  :      3;
+               uint64_t       w_tx_mx_rty               :      1;
+               uint64_t        w_rsvd_2                  :      6;
+               uint64_t        w_llp_tx_cnt              :      8;
+               uint64_t        w_rsvd_1                  :      8;
+               uint64_t        w_crazy                   :      1;
+               uint64_t        w_rsvd                    :     31;
+       } ii_wstat_fld_s;
+} ii_wstat_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This is a read-write enabled register. It controls     *
+ * various aspects of the Crosstalk flow control.                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_wcr_u {
+       uint64_t        ii_wcr_regval;
+       struct  {
+               uint64_t        w_wid                     :      4;
+               uint64_t        w_tag                     :      1;
+               uint64_t        w_rsvd_1                  :      8;
+               uint64_t        w_dst_crd                 :      3;
+               uint64_t        w_f_bad_pkt               :      1;
+               uint64_t        w_dir_con                 :      1;
+               uint64_t        w_e_thresh                :      5;
+               uint64_t        w_rsvd                    :     41;
+       } ii_wcr_fld_s;
+} ii_wcr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register's value is a bit vector that guards      *
+ * access to local registers within the II as well as to external       *
+ * Crosstalk widgets. Each bit in the register corresponds to a         *
+ * particular region in the system; a region consists of one, two or    *
+ * four nodes (depending on the value of the REGION_SIZE field in the   *
+ * LB_REV_ID register, which is documented in Section 8.3.1.1). The     *
+ * protection provided by this register applies to PIO read             *
+ * operations as well as PIO write operations. The II will perform a    *
+ * PIO read or write request only if the bit for the requestor's        *
+ * region is set; otherwise, the II will not perform the requested      *
+ * operation and will return an error response. When a PIO read or      *
+ * write request targets an external Crosstalk widget, then not only    *
+ * must the bit for the requestor's region be set in the ILAPR, but     *
+ * also the target widget's bit in the IOWA register must be set in     *
+ * order for the II to perform the requested operation; otherwise,      *
+ * the II will return an error response. Hence, the protection          *
+ * provided by the IOWA register supplements the protection provided    *
+ * by the ILAPR for requests that target external Crosstalk widgets.    *
+ * This register itself can be accessed only by the nodes whose         *
+ * region ID bits are enabled in this same register. It can also be     *
+ * accessed through the IAlias space by the local processors.           *
+ * The reset value of this register allows access by all nodes.         *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ilapr_u {
+       uint64_t        ii_ilapr_regval;
+       struct  {
+               uint64_t        i_region                  :     64;
+       } ii_ilapr_fld_s;
+} ii_ilapr_u_t;
+
+
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  A write to this register of the 64-bit value           *
+ * "SGIrules" in ASCII, will cause the bit in the ILAPR register        *
+ * corresponding to the region of the requestor to be set (allow        *
+ * access). A write of any other value will be ignored. Access          *
+ * protection for this register is "SGIrules".                          *
+ * This register can also be accessed through the IAlias space.         *
+ * However, this access will not change the access permissions in the   *
+ * ILAPR.                                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ilapo_u {
+       uint64_t        ii_ilapo_regval;
+       struct  {
+               uint64_t        i_io_ovrride            :       64;
+       } ii_ilapo_fld_s;
+} ii_ilapo_u_t;
+
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register qualifies all the PIO and Graphics writes launched    *
+ * from the SHUB towards a widget.                                      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iowa_u {
+       uint64_t        ii_iowa_regval;
+       struct  {
+               uint64_t        i_w0_oac                  :      1;
+               uint64_t        i_rsvd_1                  :      7;
+                uint64_t       i_wx_oac                  :      8;
+               uint64_t        i_rsvd                    :     48;
+       } ii_iowa_fld_s;
+} ii_iowa_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register qualifies all the requests launched      *
+ * from a widget towards the Shub. This register is intended to be      *
+ * used by software in case of misbehaving widgets.                     *
+ *                                                                      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iiwa_u {
+       uint64_t        ii_iiwa_regval;
+       struct  {
+               uint64_t        i_w0_iac                  :      1;
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_wx_iac                  :      8;
+               uint64_t        i_rsvd                    :     48;
+       } ii_iiwa_fld_s;
+} ii_iiwa_u_t;
+
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register qualifies all the operations launched    *
+ * from a widget towards the SHub. It allows individual access          *
+ * control for up to 8 devices per widget. A device refers to           *
+ * individual DMA master hosted by a widget.                            *
+ * The bits in each field of this register are cleared by the Shub      *
+ * upon detection of an error which requires the device to be           *
+ * disabled. These fields assume that 0=TNUM=7 (i.e., Bridge-centric    *
+ * Crosstalk). Whether or not a device has access rights to this        *
+ * Shub is determined by an AND of the device enable bit in the         *
+ * appropriate field of this register and the corresponding bit in      *
+ * the Wx_IAC field (for the widget which this device belongs to).      *
+ * The bits in this field are set by writing a 1 to them. Incoming      *
+ * replies from Crosstalk are not subject to this access control        *
+ * mechanism.                                                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iidem_u {
+       uint64_t        ii_iidem_regval;
+       struct  {
+               uint64_t        i_w8_dxs                  :      8;
+               uint64_t        i_w9_dxs                  :      8;
+               uint64_t        i_wa_dxs                  :      8;
+               uint64_t        i_wb_dxs                  :      8;
+               uint64_t        i_wc_dxs                  :      8;
+               uint64_t        i_wd_dxs                  :      8;
+               uint64_t        i_we_dxs                  :      8;
+               uint64_t        i_wf_dxs                  :      8;
+       } ii_iidem_fld_s;
+} ii_iidem_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the various programmable fields necessary    *
+ * for controlling and observing the LLP signals.                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ilcsr_u {
+       uint64_t        ii_ilcsr_regval;
+       struct  {
+               uint64_t        i_nullto                  :      6;
+               uint64_t        i_rsvd_4                  :      2;
+               uint64_t        i_wrmrst                  :      1;
+               uint64_t        i_rsvd_3                  :      1;
+               uint64_t        i_llp_en                  :      1;
+               uint64_t        i_bm8                     :      1;
+               uint64_t        i_llp_stat                :      2;
+               uint64_t        i_remote_power            :      1;
+               uint64_t        i_rsvd_2                  :      1;
+               uint64_t        i_maxrtry                 :     10;
+               uint64_t        i_d_avail_sel             :      2;
+               uint64_t        i_rsvd_1                  :      4;
+               uint64_t        i_maxbrst                 :     10;
+                uint64_t       i_rsvd                    :     22;
+
+       } ii_ilcsr_fld_s;
+} ii_ilcsr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This is simply a status registers that monitors the LLP error       *
+ * rate.                                                                *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_illr_u {
+       uint64_t        ii_illr_regval;
+       struct  {
+               uint64_t        i_sn_cnt                  :     16;
+               uint64_t        i_cb_cnt                  :     16;
+               uint64_t        i_rsvd                    :     32;
+       } ii_illr_fld_s;
+} ii_illr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  All II-detected non-BTE error interrupts are           *
+ * specified via this register.                                         *
+ * NOTE: The PI interrupt register address is hardcoded in the II. If   *
+ * PI_ID==0, then the II sends an interrupt request (Duplonet PWRI      *
+ * packet) to address offset 0x0180_0090 within the local register      *
+ * address space of PI0 on the node specified by the NODE field. If     *
+ * PI_ID==1, then the II sends the interrupt request to address         *
+ * offset 0x01A0_0090 within the local register address space of PI1    *
+ * on the node specified by the NODE field.                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iidsr_u {
+       uint64_t        ii_iidsr_regval;
+       struct  {
+               uint64_t        i_level                   :      8;
+               uint64_t        i_pi_id                   :      1;
+               uint64_t        i_node                    :     11;
+               uint64_t       i_rsvd_3                  :      4;
+               uint64_t        i_enable                  :      1;
+               uint64_t        i_rsvd_2                  :      3;
+               uint64_t        i_int_sent                :      2;
+               uint64_t       i_rsvd_1                  :      2;
+               uint64_t        i_pi0_forward_int         :      1;
+               uint64_t        i_pi1_forward_int         :      1;
+               uint64_t        i_rsvd                    :     30;
+       } ii_iidsr_fld_s;
+} ii_iidsr_u_t;
+
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are two instances of this register. This register is used     *
+ * for matching up the incoming responses from the graphics widget to   *
+ * the processor that initiated the graphics operation. The             *
+ * write-responses are converted to graphics credits and returned to    *
+ * the processor so that the processor interface can manage the flow    *
+ * control.                                                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_igfx0_u {
+       uint64_t        ii_igfx0_regval;
+       struct  {
+               uint64_t        i_w_num                   :      4;
+               uint64_t       i_pi_id                   :      1;
+               uint64_t        i_n_num                   :     12;
+               uint64_t       i_p_num                   :      1;
+               uint64_t       i_rsvd                    :     46;
+       } ii_igfx0_fld_s;
+} ii_igfx0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are two instances of this register. This register is used     *
+ * for matching up the incoming responses from the graphics widget to   *
+ * the processor that initiated the graphics operation. The             *
+ * write-responses are converted to graphics credits and returned to    *
+ * the processor so that the processor interface can manage the flow    *
+ * control.                                                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_igfx1_u {
+       uint64_t        ii_igfx1_regval;
+       struct  {
+               uint64_t        i_w_num                   :      4;
+               uint64_t       i_pi_id                   :      1;
+               uint64_t        i_n_num                   :     12;
+               uint64_t       i_p_num                   :      1;
+               uint64_t       i_rsvd                    :     46;
+       } ii_igfx1_fld_s;
+} ii_igfx1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are two instances of this registers. These registers are      *
+ * used as scratch registers for software use.                          *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iscr0_u {
+       uint64_t        ii_iscr0_regval;
+       struct  {
+               uint64_t        i_scratch                 :     64;
+       } ii_iscr0_fld_s;
+} ii_iscr0_u_t;
+
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are two instances of this registers. These registers are      *
+ * used as scratch registers for software use.                          *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iscr1_u {
+       uint64_t        ii_iscr1_regval;
+       struct  {
+               uint64_t        i_scratch                 :     64;
+       } ii_iscr1_fld_s;
+} ii_iscr1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a Shub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the SHub is thus the lower 16 GBytes per widget       * 
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the Shub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte1_u {
+       uint64_t        ii_itte1_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_w_num                   :      4;
+               uint64_t        i_iosp                    :      1;
+               uint64_t        i_rsvd                    :     51;
+       } ii_itte1_fld_s;
+} ii_itte1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a Shub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the Shub is thus the lower 16 GBytes per widget       *
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the Shub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte2_u {
+       uint64_t        ii_itte2_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_w_num                   :      4;
+               uint64_t        i_iosp                    :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_itte2_fld_s;
+} ii_itte2_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a Shub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the Shub is thus the lower 16 GBytes per widget       *
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the SHub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte3_u {
+       uint64_t        ii_itte3_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t       i_rsvd_1                  :      3;
+               uint64_t       i_w_num                   :      4;
+               uint64_t       i_iosp                    :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_itte3_fld_s;
+} ii_itte3_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a SHub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the SHub is thus the lower 16 GBytes per widget       *
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the SHub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte4_u {
+       uint64_t        ii_itte4_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t       i_w_num                   :      4;
+               uint64_t       i_iosp                    :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_itte4_fld_s;
+} ii_itte4_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a SHub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the Shub is thus the lower 16 GBytes per widget       *
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the Shub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte5_u {
+       uint64_t        ii_itte5_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t       i_rsvd_1                  :      3;
+               uint64_t       i_w_num                   :      4;
+               uint64_t       i_iosp                    :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_itte5_fld_s;
+} ii_itte5_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a Shub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the Shub is thus the lower 16 GBytes per widget       *
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the Shub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte6_u {
+       uint64_t        ii_itte6_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t       i_rsvd_1                  :      3;
+               uint64_t       i_w_num                   :      4;
+               uint64_t       i_iosp                    :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_itte6_fld_s;
+} ii_itte6_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are seven instances of translation table entry   *
+ * registers. Each register maps a Shub Big Window to a 48-bit          *
+ * address on Crosstalk.                                                *
+ * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window      *
+ * number) are used to select one of these 7 registers. The Widget      *
+ * number field is then derived from the W_NUM field for synthesizing   *
+ * a Crosstalk packet. The 5 bits of OFFSET are concatenated with       *
+ * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34]      *
+ * are padded with zeros. Although the maximum Crosstalk space          *
+ * addressable by the Shub is thus the lower 16 GBytes per widget       *
+ * (M-mode), however only <SUP >7</SUP>/<SUB >32nds</SUB> of this       *
+ * space can be accessed.                                               *
+ * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big         *
+ * Window number) are used to select one of these 7 registers. The      *
+ * Widget number field is then derived from the W_NUM field for         *
+ * synthesizing a Crosstalk packet. The 5 bits of OFFSET are            *
+ * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP      *
+ * field is used as Crosstalk[47], and remainder of the Crosstalk       *
+ * address bits (Crosstalk[46:34]) are always zero. While the maximum   *
+ * Crosstalk space addressable by the SHub is thus the lower            *
+ * 8-GBytes per widget (N-mode), only <SUP >7</SUP>/<SUB >32nds</SUB>   *
+ * of this space can be accessed.                                       *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_itte7_u {
+       uint64_t        ii_itte7_regval;
+       struct  {
+               uint64_t        i_offset                  :      5;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t       i_w_num                   :      4;
+               uint64_t       i_iosp                    :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_itte7_fld_s;
+} ii_itte7_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprb0_u {
+       uint64_t        ii_iprb0_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t       i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprb0_fld_s;
+} ii_iprb0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprb8_u {
+       uint64_t        ii_iprb8_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t       i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t       i_rsvd_1                  :      2;
+               uint64_t       i_m                       :      2;
+               uint64_t       i_f                       :      1;
+               uint64_t       i_of_cnt                  :      5;
+               uint64_t       i_error                   :      1;
+               uint64_t       i_rd_to                   :      1;
+               uint64_t       i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t       i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprb8_fld_s;
+} ii_iprb8_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprb9_u {
+       uint64_t        ii_iprb9_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t        i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprb9_fld_s;
+} ii_iprb9_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.        *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ *                                                                      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprba_u {
+       uint64_t        ii_iprba_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t       i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprba_fld_s;
+} ii_iprba_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprbb_u {
+       uint64_t        ii_iprbb_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t        i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprbb_fld_s;
+} ii_iprbb_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprbc_u {
+       uint64_t        ii_iprbc_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t        i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprbc_fld_s;
+} ii_iprbc_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprbd_u {
+       uint64_t        ii_iprbd_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t        i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprbd_fld_s;
+} ii_iprbd_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of SHub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprbe_u {
+       uint64_t        ii_iprbe_regval;
+       struct  {
+               uint64_t        i_c                       :      8;
+               uint64_t        i_na                      :     14;
+               uint64_t        i_rsvd_2                  :      2;
+               uint64_t        i_nb                      :     14;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_m                       :      2;
+               uint64_t        i_f                       :      1;
+               uint64_t        i_of_cnt                  :      5;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rd_to                   :      1;
+               uint64_t        i_spur_wr                 :      1;
+               uint64_t        i_spur_rd                 :      1;
+               uint64_t        i_rsvd                    :     11;
+               uint64_t        i_mult_err                :      1;
+       } ii_iprbe_fld_s;
+} ii_iprbe_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 9 instances of this register, one per        *
+ * actual widget in this implementation of Shub and Crossbow.           *
+ * Note: Crossbow only has ports for Widgets 8 through F, widget 0      *
+ * refers to Crossbow's internal space.                                 *
+ * This register contains the state elements per widget that are        *
+ * necessary to manage the PIO flow control on Crosstalk and on the     *
+ * Router Network. See the PIO Flow Control chapter for a complete      *
+ * description of this register                                         *
+ * The SPUR_WR bit requires some explanation. When this register is     *
+ * written, the new value of the C field is captured in an internal     *
+ * register so the hardware can remember what the programmer wrote      *
+ * into the credit counter. The SPUR_WR bit sets whenever the C field   *
+ * increments above this stored value, which indicates that there       *
+ * have been more responses received than requests sent. The SPUR_WR    *
+ * bit cannot be cleared until a value is written to the IPRBx          *
+ * register; the write will correct the C field and capture its new     *
+ * value in the internal register. Even if IECLR[E_PRB_x] is set, the   *
+ * SPUR_WR bit will persist if IPRBx hasn't yet been written.           *
+ * .                                                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprbf_u {
+        uint64_t       ii_iprbf_regval;
+        struct  {
+                uint64_t       i_c                       :      8;
+                uint64_t       i_na                      :     14;
+                uint64_t       i_rsvd_2                  :      2;
+                uint64_t       i_nb                      :     14;
+                uint64_t       i_rsvd_1                  :      2;
+                uint64_t       i_m                       :      2;
+                uint64_t       i_f                       :      1;
+                uint64_t       i_of_cnt                  :      5;
+                uint64_t       i_error                   :      1;
+                uint64_t       i_rd_to                   :      1;
+                uint64_t       i_spur_wr                 :      1;
+                uint64_t       i_spur_rd                 :      1;
+                uint64_t       i_rsvd                    :     11;
+                uint64_t       i_mult_err                :      1;
+        } ii_iprbe_fld_s;
+} ii_iprbf_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register specifies the timeout value to use for monitoring     *
+ * Crosstalk credits which are used outbound to Crosstalk. An           *
+ * internal counter called the Crosstalk Credit Timeout Counter         *
+ * increments every 128 II clocks. The counter starts counting          *
+ * anytime the credit count drops below a threshold, and resets to      *
+ * zero (stops counting) anytime the credit count is at or above the    *
+ * threshold. The threshold is 1 credit in direct connect mode and 2    *
+ * in Crossbow connect mode. When the internal Crosstalk Credit         *
+ * Timeout Counter reaches the value programmed in this register, a     *
+ * Crosstalk Credit Timeout has occurred. The internal counter is not   *
+ * readable from software, and stops counting at its maximum value,     *
+ * so it cannot cause more than one interrupt.                          *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ixcc_u {
+       uint64_t        ii_ixcc_regval;
+       struct  {
+               uint64_t        i_time_out                :     26;
+               uint64_t        i_rsvd                    :     38;
+       } ii_ixcc_fld_s;
+} ii_ixcc_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register qualifies all the PIO and DMA            *
+ * operations launched from widget 0 towards the SHub. In               *
+ * addition, it also qualifies accesses by the BTE streams.             *
+ * The bits in each field of this register are cleared by the SHub      *
+ * upon detection of an error which requires widget 0 or the BTE        *
+ * streams to be terminated. Whether or not widget x has access         *
+ * rights to this SHub is determined by an AND of the device            *
+ * enable bit in the appropriate field of this register and bit 0 in    *
+ * the Wx_IAC field. The bits in this field are set by writing a 1 to   *
+ * them. Incoming replies from Crosstalk are not subject to this        *
+ * access control mechanism.                                            *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_imem_u {
+       uint64_t        ii_imem_regval;
+       struct  {
+               uint64_t        i_w0_esd                  :      1;
+               uint64_t        i_rsvd_3                  :      3;
+               uint64_t        i_b0_esd                  :      1;
+               uint64_t        i_rsvd_2                  :      3;
+               uint64_t        i_b1_esd                  :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_clr_precise             :      1;
+               uint64_t       i_rsvd                    :     51;
+       } ii_imem_fld_s;
+} ii_imem_u_t;
+
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register specifies the timeout value to use for   *
+ * monitoring Crosstalk tail flits coming into the Shub in the          *
+ * TAIL_TO field. An internal counter associated with this register     *
+ * is incremented every 128 II internal clocks (7 bits). The counter    *
+ * starts counting anytime a header micropacket is received and stops   *
+ * counting (and resets to zero) any time a micropacket with a Tail     *
+ * bit is received. Once the counter reaches the threshold value        *
+ * programmed in this register, it generates an interrupt to the        *
+ * processor that is programmed into the IIDSR. The counter saturates   *
+ * (does not roll over) at its maximum value, so it cannot cause        *
+ * another interrupt until after it is cleared.                         *
+ * The register also contains the Read Response Timeout values. The     *
+ * Prescalar is 23 bits, and counts II clocks. An internal counter      *
+ * increments on every II clock and when it reaches the value in the    *
+ * Prescalar field, all IPRTE registers with their valid bits set       *
+ * have their Read Response timers bumped. Whenever any of them match   *
+ * the value in the RRSP_TO field, a Read Response Timeout has          *
+ * occurred, and error handling occurs as described in the Error        *
+ * Handling section of this document.                                   *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ixtt_u {
+       uint64_t        ii_ixtt_regval;
+       struct  {
+               uint64_t        i_tail_to                 :     26;
+               uint64_t        i_rsvd_1                  :      6;
+               uint64_t        i_rrsp_ps                 :     23;
+               uint64_t        i_rrsp_to                 :      5;
+               uint64_t        i_rsvd                    :      4;
+       } ii_ixtt_fld_s;
+} ii_ixtt_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  Writing a 1 to the fields of this register clears the appropriate   *
+ * error bits in other areas of SHub. Note that when the                *
+ * E_PRB_x bits are used to clear error bits in PRB registers,          *
+ * SPUR_RD and SPUR_WR may persist, because they require additional     *
+ * action to clear them. See the IPRBx and IXSS Register                *
+ * specifications.                                                      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ieclr_u {
+       uint64_t        ii_ieclr_regval;
+       struct  {
+               uint64_t        i_e_prb_0                 :      1;
+               uint64_t        i_rsvd                    :      7;
+               uint64_t        i_e_prb_8                 :      1;
+               uint64_t        i_e_prb_9                 :      1;
+               uint64_t        i_e_prb_a                 :      1;
+               uint64_t        i_e_prb_b                 :      1;
+               uint64_t        i_e_prb_c                 :      1;
+               uint64_t        i_e_prb_d                 :      1;
+               uint64_t        i_e_prb_e                 :      1;
+               uint64_t        i_e_prb_f                 :      1;
+               uint64_t        i_e_crazy                 :      1;
+               uint64_t        i_e_bte_0                 :      1;
+               uint64_t        i_e_bte_1                 :      1;
+               uint64_t        i_reserved_1              :     10;
+               uint64_t        i_spur_rd_hdr             :      1;
+               uint64_t        i_cam_intr_to             :      1;
+               uint64_t        i_cam_overflow            :      1;
+               uint64_t        i_cam_read_miss           :      1;
+               uint64_t        i_ioq_rep_underflow       :      1;
+               uint64_t        i_ioq_req_underflow       :      1;
+               uint64_t        i_ioq_rep_overflow        :      1;
+               uint64_t        i_ioq_req_overflow        :      1;
+               uint64_t        i_iiq_rep_overflow        :      1;
+               uint64_t        i_iiq_req_overflow        :      1;
+               uint64_t        i_ii_xn_rep_cred_overflow :      1;
+               uint64_t        i_ii_xn_req_cred_overflow :      1;
+               uint64_t        i_ii_xn_invalid_cmd       :      1;
+               uint64_t        i_xn_ii_invalid_cmd       :      1;
+               uint64_t        i_reserved_2              :     21;
+       } ii_ieclr_fld_s;
+} ii_ieclr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register controls both BTEs. SOFT_RESET is intended for        *
+ * recovery after an error. COUNT controls the total number of CRBs     *
+ * that both BTEs (combined) can use, which affects total BTE           *
+ * bandwidth.                                                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibcr_u {
+       uint64_t        ii_ibcr_regval;
+       struct  {
+               uint64_t        i_count                   :      4;
+               uint64_t        i_rsvd_1                  :      4;
+               uint64_t        i_soft_reset              :      1;
+               uint64_t        i_rsvd                    :     55;
+       } ii_ibcr_fld_s;
+} ii_ibcr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the header of a spurious read response       *
+ * received from Crosstalk. A spurious read response is defined as a    *
+ * read response received by II from a widget for which (1) the SIDN    *
+ * has a value between 1 and 7, inclusive (II never sends requests to   *
+ * these widgets (2) there is no valid IPRTE register which             *
+ * corresponds to the TNUM, or (3) the widget indicated in SIDN is      *
+ * not the same as the widget recorded in the IPRTE register            *
+ * referenced by the TNUM. If this condition is true, and if the        *
+ * IXSS[VALID] bit is clear, then the header of the spurious read       *
+ * response is capture in IXSM and IXSS, and IXSS[VALID] is set. The    *
+ * errant header is thereby captured, and no further spurious read      *
+ * respones are captured until IXSS[VALID] is cleared by setting the    *
+ * appropriate bit in IECLR.Everytime a spurious read response is       *
+ * detected, the SPUR_RD bit of the PRB corresponding to the incoming   *
+ * message's SIDN field is set. This always happens, regarless of       *
+ * whether a header is captured. The programmer should check            *
+ * IXSM[SIDN] to determine which widget sent the spurious response,     *
+ * because there may be more than one SPUR_RD bit set in the PRB        *
+ * registers. The widget indicated by IXSM[SIDN] was the first          *
+ * spurious read response to be received since the last time            *
+ * IXSS[VALID] was clear. The SPUR_RD bit of the corresponding PRB      *
+ * will be set. Any SPUR_RD bits in any other PRB registers indicate    *
+ * spurious messages from other widets which were detected after the    *
+ * header was captured..                                                *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ixsm_u {
+       uint64_t        ii_ixsm_regval;
+       struct  {
+               uint64_t        i_byte_en                 :     32;
+               uint64_t        i_reserved                :      1;
+               uint64_t        i_tag                     :      3;
+               uint64_t        i_alt_pactyp              :      4;
+               uint64_t        i_bo                      :      1;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_vbpm                    :      1;
+               uint64_t        i_gbr                     :      1;
+               uint64_t        i_ds                      :      2;
+               uint64_t        i_ct                      :      1;
+               uint64_t        i_tnum                    :      5;
+               uint64_t        i_pactyp                  :      4;
+               uint64_t        i_sidn                    :      4;
+               uint64_t        i_didn                    :      4;
+       } ii_ixsm_fld_s;
+} ii_ixsm_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the sideband bits of a spurious read         *
+ * response received from Crosstalk.                                    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ixss_u {
+       uint64_t        ii_ixss_regval;
+       struct  {
+               uint64_t        i_sideband                :      8;
+               uint64_t        i_rsvd                    :     55;
+               uint64_t        i_valid                   :      1;
+       } ii_ixss_fld_s;
+} ii_ixss_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register enables software to access the II LLP's test port.    *
+ * Refer to the LLP 2.5 documentation for an explanation of the test    *
+ * port. Software can write to this register to program the values      *
+ * for the control fields (TestErrCapture, TestClear, TestFlit,         *
+ * TestMask and TestSeed). Similarly, software can read from this       *
+ * register to obtain the values of the test port's status outputs      *
+ * (TestCBerr, TestValid and TestData).                                 *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ilct_u {
+       uint64_t        ii_ilct_regval;
+       struct  {
+               uint64_t        i_test_seed               :     20;
+               uint64_t        i_test_mask               :      8;
+               uint64_t        i_test_data               :     20;
+               uint64_t        i_test_valid              :      1;
+               uint64_t        i_test_cberr              :      1;
+               uint64_t        i_test_flit               :      3;
+               uint64_t        i_test_clear              :      1;
+               uint64_t        i_test_err_capture        :      1;
+               uint64_t        i_rsvd                    :      9;
+       } ii_ilct_fld_s;
+} ii_ilct_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  If the II detects an illegal incoming Duplonet packet (request or   *
+ * reply) when VALID==0 in the IIEPH1 register, then it saves the       *
+ * contents of the packet's header flit in the IIEPH1 and IIEPH2        *
+ * registers, sets the VALID bit in IIEPH1, clears the OVERRUN bit,     *
+ * and assigns a value to the ERR_TYPE field which indicates the        *
+ * specific nature of the error. The II recognizes four different       *
+ * types of errors: short request packets (ERR_TYPE==2), short reply    *
+ * packets (ERR_TYPE==3), long request packets (ERR_TYPE==4) and long   *
+ * reply packets (ERR_TYPE==5). The encodings for these types of        *
+ * errors were chosen to be consistent with the same types of errors    *
+ * indicated by the ERR_TYPE field in the LB_ERROR_HDR1 register (in    *
+ * the LB unit). If the II detects an illegal incoming Duplonet         *
+ * packet when VALID==1 in the IIEPH1 register, then it merely sets     *
+ * the OVERRUN bit to indicate that a subsequent error has happened,    *
+ * and does nothing further.                                            *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iieph1_u {
+       uint64_t        ii_iieph1_regval;
+       struct  {
+               uint64_t        i_command                 :      7;
+               uint64_t        i_rsvd_5                  :      1;
+               uint64_t        i_suppl                   :     14;
+               uint64_t        i_rsvd_4                  :      1;
+               uint64_t        i_source                  :     14;
+               uint64_t        i_rsvd_3                  :      1;
+               uint64_t        i_err_type                :      4;
+               uint64_t        i_rsvd_2                  :      4;
+               uint64_t        i_overrun                 :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_valid                   :      1;
+               uint64_t        i_rsvd                    :     13;
+       } ii_iieph1_fld_s;
+} ii_iieph1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register holds the Address field from the header flit of an    *
+ * incoming erroneous Duplonet packet, along with the tail bit which    *
+ * accompanied this header flit. This register is essentially an        *
+ * extension of IIEPH1. Two registers were necessary because the 64     *
+ * bits available in only a single register were insufficient to        *
+ * capture the entire header flit of an erroneous packet.               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iieph2_u {
+       uint64_t        ii_iieph2_regval;
+       struct  {
+               uint64_t        i_rsvd_0                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_rsvd_1                  :     10;
+               uint64_t        i_tail                    :      1;
+               uint64_t        i_rsvd                    :      3;
+       } ii_iieph2_fld_s;
+} ii_iieph2_u_t;
+
+
+/******************************/
+
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register's value is a bit vector that guards access from SXBs  *
+ * to local registers within the II as well as to external Crosstalk    *
+ * widgets                                                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_islapr_u {
+       uint64_t        ii_islapr_regval;
+       struct  {
+               uint64_t        i_region                  :     64;
+       } ii_islapr_fld_s;
+} ii_islapr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  A write to this register of the 56-bit value "Pup+Bun" will cause  *
+ * the bit in the ISLAPR register corresponding to the region of the   *
+ * requestor to be set (access allowed).                               (
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_islapo_u {
+       uint64_t        ii_islapo_regval;
+       struct  {
+               uint64_t        i_io_sbx_ovrride          :     56;
+               uint64_t        i_rsvd                    :      8;
+       } ii_islapo_fld_s;
+} ii_islapo_u_t;
+
+/************************************************************************
+ *                                                                      *
+ *  Determines how long the wrapper will wait aftr an interrupt is     *
+ * initially issued from the II before it times out the outstanding    *
+ * interrupt and drops it from the interrupt queue.                    * 
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iwi_u {
+       uint64_t        ii_iwi_regval;
+       struct  {
+               uint64_t        i_prescale                :     24;
+               uint64_t        i_rsvd                    :      8;
+               uint64_t        i_timeout                 :      8;
+               uint64_t        i_rsvd1                   :      8;
+               uint64_t        i_intrpt_retry_period     :      8;
+               uint64_t        i_rsvd2                   :      8;
+       } ii_iwi_fld_s;
+} ii_iwi_u_t;
+
+/************************************************************************
+ *                                                                      *
+ *  Log errors which have occurred in the II wrapper. The errors are   *
+ * cleared by writing to the IECLR register.                           * 
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iwel_u {
+       uint64_t        ii_iwel_regval;
+       struct  {
+               uint64_t        i_intr_timed_out          :      1;
+               uint64_t        i_rsvd                    :      7;
+               uint64_t        i_cam_overflow            :      1;
+               uint64_t        i_cam_read_miss           :      1;
+               uint64_t        i_rsvd1                   :      2;
+               uint64_t        i_ioq_rep_underflow       :      1;
+               uint64_t        i_ioq_req_underflow       :      1;
+               uint64_t        i_ioq_rep_overflow        :      1;
+               uint64_t        i_ioq_req_overflow        :      1;
+               uint64_t        i_iiq_rep_overflow        :      1;
+               uint64_t        i_iiq_req_overflow        :      1;
+               uint64_t        i_rsvd2                   :      6;
+               uint64_t        i_ii_xn_rep_cred_over_under:     1;
+               uint64_t        i_ii_xn_req_cred_over_under:     1;
+               uint64_t        i_rsvd3                   :      6;
+               uint64_t        i_ii_xn_invalid_cmd       :      1;
+               uint64_t        i_xn_ii_invalid_cmd       :      1;
+               uint64_t        i_rsvd4                   :     30;
+       } ii_iwel_fld_s;
+} ii_iwel_u_t;
+
+/************************************************************************
+ *                                                                      *
+ *  Controls the II wrapper.                                           * 
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iwc_u {
+       uint64_t        ii_iwc_regval;
+       struct  {
+               uint64_t        i_dma_byte_swap           :      1;
+               uint64_t        i_rsvd                    :      3;
+               uint64_t        i_cam_read_lines_reset    :      1;
+               uint64_t        i_rsvd1                   :      3;
+               uint64_t        i_ii_xn_cred_over_under_log:     1;
+               uint64_t        i_rsvd2                   :     19;
+               uint64_t        i_xn_rep_iq_depth         :      5;
+               uint64_t        i_rsvd3                   :      3;
+               uint64_t        i_xn_req_iq_depth         :      5;
+               uint64_t        i_rsvd4                   :      3;
+               uint64_t        i_iiq_depth               :      6;
+               uint64_t        i_rsvd5                   :     12;
+               uint64_t        i_force_rep_cred          :      1;
+               uint64_t        i_force_req_cred          :      1;
+       } ii_iwc_fld_s;
+} ii_iwc_u_t;
+
+/************************************************************************
+ *                                                                      *
+ *  Status in the II wrapper.                                          * 
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iws_u {
+       uint64_t        ii_iws_regval;
+       struct  {
+               uint64_t        i_xn_rep_iq_credits       :      5;
+               uint64_t        i_rsvd                    :      3;
+               uint64_t        i_xn_req_iq_credits       :      5;
+               uint64_t        i_rsvd1                   :     51;
+       } ii_iws_fld_s;
+} ii_iws_u_t;
+
+/************************************************************************
+ *                                                                      *
+ *  Masks errors in the IWEL register.                                 *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iweim_u {
+       uint64_t        ii_iweim_regval;
+       struct  {
+               uint64_t        i_intr_timed_out          :      1;
+               uint64_t        i_rsvd                    :      7;
+               uint64_t        i_cam_overflow            :      1;
+               uint64_t        i_cam_read_miss           :      1;
+               uint64_t        i_rsvd1                   :      2;
+               uint64_t        i_ioq_rep_underflow       :      1;
+               uint64_t        i_ioq_req_underflow       :      1;
+               uint64_t        i_ioq_rep_overflow        :      1;
+               uint64_t        i_ioq_req_overflow        :      1;
+               uint64_t        i_iiq_rep_overflow        :      1;
+               uint64_t        i_iiq_req_overflow        :      1;
+               uint64_t        i_rsvd2                   :      6;
+               uint64_t        i_ii_xn_rep_cred_overflow :      1;
+               uint64_t        i_ii_xn_req_cred_overflow :      1;
+               uint64_t        i_rsvd3                   :      6;
+               uint64_t        i_ii_xn_invalid_cmd       :      1;
+               uint64_t        i_xn_ii_invalid_cmd       :      1;
+               uint64_t        i_rsvd4                   :     30;
+       } ii_iweim_fld_s;
+} ii_iweim_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  A write to this register causes a particular field in the           *
+ * corresponding widget's PRB entry to be adjusted up or down by 1.     *
+ * This counter should be used when recovering from error and reset     *
+ * conditions. Note that software would be capable of causing           *
+ * inadvertent overflow or underflow of these counters.                 *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ipca_u {
+       uint64_t        ii_ipca_regval;
+       struct  {
+               uint64_t        i_wid                     :      4;
+               uint64_t        i_adjust                  :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_field                   :      2;
+               uint64_t        i_rsvd                    :     54;
+       } ii_ipca_fld_s;
+} ii_ipca_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+
+typedef union ii_iprte0a_u {
+       uint64_t        ii_iprte0a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t       i_vld                     :      1;
+       } ii_iprte0a_fld_s;
+} ii_iprte0a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte1a_u {
+       uint64_t        ii_iprte1a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t       i_vld                     :      1;
+       } ii_iprte1a_fld_s;
+} ii_iprte1a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte2a_u {
+       uint64_t        ii_iprte2a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t       i_vld                     :      1;
+       } ii_iprte2a_fld_s;
+} ii_iprte2a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte3a_u {
+       uint64_t        ii_iprte3a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t        i_vld                     :      1;
+       } ii_iprte3a_fld_s;
+} ii_iprte3a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte4a_u {
+       uint64_t        ii_iprte4a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t        i_vld                     :      1;
+       } ii_iprte4a_fld_s;
+} ii_iprte4a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte5a_u {
+       uint64_t        ii_iprte5a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t        i_vld                     :      1;
+       } ii_iprte5a_fld_s;
+} ii_iprte5a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte6a_u {
+       uint64_t        ii_iprte6a_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :     54;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t        i_vld                     :      1;
+       } ii_iprte6a_fld_s;
+} ii_iprte6a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte7a_u {
+        uint64_t       ii_iprte7a_regval;
+        struct  {
+                uint64_t       i_rsvd_1                  :     54;
+                uint64_t       i_widget                  :      4;
+                uint64_t       i_to_cnt                  :      5;
+                uint64_t       i_vld                     :      1;
+        } ii_iprtea7_fld_s;
+} ii_iprte7a_u_t;
+
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+
+typedef union ii_iprte0b_u {
+       uint64_t        ii_iprte0b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+       } ii_iprte0b_fld_s;
+} ii_iprte0b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte1b_u {
+       uint64_t        ii_iprte1b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+       } ii_iprte1b_fld_s;
+} ii_iprte1b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte2b_u {
+       uint64_t        ii_iprte2b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+       } ii_iprte2b_fld_s;
+} ii_iprte2b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte3b_u {
+       uint64_t        ii_iprte3b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+       } ii_iprte3b_fld_s;
+} ii_iprte3b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte4b_u {
+       uint64_t        ii_iprte4b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+       } ii_iprte4b_fld_s;
+} ii_iprte4b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte5b_u {
+       uint64_t        ii_iprte5b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+       } ii_iprte5b_fld_s;
+} ii_iprte5b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte6b_u {
+       uint64_t        ii_iprte6b_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+
+       } ii_iprte6b_fld_s;
+} ii_iprte6b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  There are 8 instances of this register. This register contains      *
+ * the information that the II has to remember once it has launched a   *
+ * PIO Read operation. The contents are used to form the correct        *
+ * Router Network packet and direct the Crosstalk reply to the          *
+ * appropriate processor.                                               *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iprte7b_u {
+        uint64_t       ii_iprte7b_regval;
+        struct  {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_address                 :     47;
+               uint64_t        i_init                    :      3;
+               uint64_t       i_source                  :     11;
+        } ii_iprte7b_fld_s;
+} ii_iprte7b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  SHub II contains a feature which did not exist in      *
+ * the Hub which automatically cleans up after a Read Response          *
+ * timeout, including deallocation of the IPRTE and recovery of IBuf    *
+ * space. The inclusion of this register in SHub is for backward        *
+ * compatibility                                                        *
+ * A write to this register causes an entry from the table of           *
+ * outstanding PIO Read Requests to be freed and returned to the        *
+ * stack of free entries. This register is used in handling the         *
+ * timeout errors that result in a PIO Reply never returning from       *
+ * Crosstalk.                                                           *
+ * Note that this register does not affect the contents of the IPRTE    *
+ * registers. The Valid bits in those registers have to be              *
+ * specifically turned off by software.                                 *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ipdr_u {
+       uint64_t        ii_ipdr_regval;
+       struct  {
+               uint64_t        i_te                      :      3;
+               uint64_t        i_rsvd_1                  :      1;
+               uint64_t        i_pnd                     :      1;
+               uint64_t        i_init_rpcnt              :      1;
+               uint64_t        i_rsvd                    :     58;
+       } ii_ipdr_fld_s;
+} ii_ipdr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  A write to this register causes a CRB entry to be returned to the   *
+ * queue of free CRBs. The entry should have previously been cleared    *
+ * (mark bit) via backdoor access to the pertinent CRB entry. This      *
+ * register is used in the last step of handling the errors that are    *
+ * captured and marked in CRB entries.  Briefly: 1) first error for     *
+ * DMA write from a particular device, and first error for a            *
+ * particular BTE stream, lead to a marked CRB entry, and processor     *
+ * interrupt, 2) software reads the error information captured in the   *
+ * CRB entry, and presumably takes some corrective action, 3)           *
+ * software clears the mark bit, and finally 4) software writes to      *
+ * the ICDR register to return the CRB entry to the list of free CRB    *
+ * entries.                                                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icdr_u {
+       uint64_t        ii_icdr_regval;
+       struct  {
+               uint64_t        i_crb_num                 :      4;
+               uint64_t        i_pnd                     :      1;
+               uint64_t       i_rsvd                    :     59;
+       } ii_icdr_fld_s;
+} ii_icdr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register provides debug access to two FIFOs inside of II.      *
+ * Both IOQ_MAX* fields of this register contain the instantaneous      *
+ * depth (in units of the number of available entries) of the           *
+ * associated IOQ FIFO.  A read of this register will return the        *
+ * number of free entries on each FIFO at the time of the read.  So     *
+ * when a FIFO is idle, the associated field contains the maximum       *
+ * depth of the FIFO.  This register is writable for debug reasons      *
+ * and is intended to be written with the maximum desired FIFO depth    *
+ * while the FIFO is idle. Software must assure that II is idle when    *
+ * this register is written. If there are any active entries in any     *
+ * of these FIFOs when this register is written, the results are        *
+ * undefined.                                                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ifdr_u {
+       uint64_t        ii_ifdr_regval;
+       struct  {
+               uint64_t        i_ioq_max_rq              :      7;
+               uint64_t        i_set_ioq_rq              :      1;
+               uint64_t        i_ioq_max_rp              :      7;
+               uint64_t        i_set_ioq_rp              :      1;
+               uint64_t        i_rsvd                    :     48;
+       } ii_ifdr_fld_s;
+} ii_ifdr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register allows the II to become sluggish in removing          *
+ * messages from its inbound queue (IIQ). This will cause messages to   *
+ * back up in either virtual channel. Disabling the "molasses" mode     *
+ * subsequently allows the II to be tested under stress. In the         *
+ * sluggish ("Molasses") mode, the localized effects of congestion      *
+ * can be observed.                                                     *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iiap_u {
+        uint64_t       ii_iiap_regval;
+        struct  {
+                uint64_t       i_rq_mls                  :      6;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_rp_mls                  :      6;
+               uint64_t       i_rsvd                    :     50;
+        } ii_iiap_fld_s;
+} ii_iiap_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register allows several parameters of CRB operation to be      *
+ * set. Note that writing to this register can have catastrophic side   *
+ * effects, if the CRB is not quiescent, i.e. if the CRB is             *
+ * processing protocol messages when the write occurs.                  *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icmr_u {
+       uint64_t        ii_icmr_regval;
+       struct  {
+               uint64_t        i_sp_msg                  :      1;
+               uint64_t        i_rd_hdr                  :      1;
+               uint64_t        i_rsvd_4                  :      2;
+               uint64_t        i_c_cnt                   :      4;
+               uint64_t        i_rsvd_3                  :      4;
+               uint64_t        i_clr_rqpd                :      1;
+               uint64_t        i_clr_rppd                :      1;
+               uint64_t        i_rsvd_2                  :      2;
+               uint64_t        i_fc_cnt                  :      4;
+               uint64_t        i_crb_vld                 :     15;
+               uint64_t        i_crb_mark                :     15;
+               uint64_t        i_rsvd_1                  :      2;
+               uint64_t        i_precise                 :      1;
+               uint64_t        i_rsvd                    :     11;
+       } ii_icmr_fld_s;
+} ii_icmr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register allows control of the table portion of the CRB        *
+ * logic via software. Control operations from this register have       *
+ * priority over all incoming Crosstalk or BTE requests.                *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_iccr_u {
+       uint64_t        ii_iccr_regval;
+       struct  {
+               uint64_t        i_crb_num                 :      4;
+               uint64_t        i_rsvd_1                  :      4;
+               uint64_t        i_cmd                     :      8;
+               uint64_t        i_pending                 :      1;
+               uint64_t        i_rsvd                    :     47;
+       } ii_iccr_fld_s;
+} ii_iccr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register allows the maximum timeout value to be programmed.    *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icto_u {
+       uint64_t        ii_icto_regval;
+       struct  {
+               uint64_t        i_timeout                 :      8;
+               uint64_t        i_rsvd                    :     56;
+       } ii_icto_fld_s;
+} ii_icto_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register allows the timeout prescalar to be programmed. An     *
+ * internal counter is associated with this register. When the          *
+ * internal counter reaches the value of the PRESCALE field, the        *
+ * timer registers in all valid CRBs are incremented (CRBx_D[TIMEOUT]   *
+ * field). The internal counter resets to zero, and then continues      *
+ * counting.                                                            *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ictp_u {
+       uint64_t        ii_ictp_regval;
+       struct  {
+               uint64_t        i_prescale                :     24;
+               uint64_t        i_rsvd                    :     40;
+       } ii_ictp_fld_s;
+} ii_ictp_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
+ * used for Crosstalk operations (both cacheline and partial            *
+ * operations) or BTE/IO. Because the CRB entries are very wide, five   *
+ * registers (_A to _E) are required to read and write each entry.      *
+ * The CRB Entry registers can be conceptualized as rows and columns    *
+ * (illustrated in the table above). Each row contains the 4            *
+ * registers required for a single CRB Entry. The first doubleword      *
+ * (column) for each entry is labeled A, and the second doubleword      *
+ * (higher address) is labeled B, the third doubleword is labeled C,    *
+ * the fourth doubleword is labeled D and the fifth doubleword is       *
+ * labeled E. All CRB entries have their addresses on a quarter         *
+ * cacheline aligned boundary.                   *
+ * Upon reset, only the following fields are initialized: valid         *
+ * (VLD), priority count, timeout, timeout valid, and context valid.    *
+ * All other bits should be cleared by software before use (after       *
+ * recovering any potential error state from before the reset).         *
+ * The following four tables summarize the format for the four          *
+ * registers that are used for each ICRB# Entry.                        *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icrb0_a_u {
+       uint64_t        ii_icrb0_a_regval;
+       struct  {
+               uint64_t        ia_iow                    :      1;
+               uint64_t        ia_vld                    :      1;
+               uint64_t        ia_addr                   :     47;
+               uint64_t        ia_tnum                   :      5;
+               uint64_t        ia_sidn                   :      4;
+               uint64_t       ia_rsvd                   :      6;
+       } ii_icrb0_a_fld_s;
+} ii_icrb0_a_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
+ * used for Crosstalk operations (both cacheline and partial            *
+ * operations) or BTE/IO. Because the CRB entries are very wide, five   *
+ * registers (_A to _E) are required to read and write each entry.      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icrb0_b_u {
+       uint64_t        ii_icrb0_b_regval;
+       struct  {
+               uint64_t        ib_xt_err                 :      1;
+               uint64_t        ib_mark                   :      1;
+               uint64_t        ib_ln_uce                 :      1;
+               uint64_t        ib_errcode                :      3;
+               uint64_t        ib_error                  :      1;
+               uint64_t        ib_stall__bte_1           :      1;
+               uint64_t        ib_stall__bte_0           :      1;
+               uint64_t        ib_stall__intr            :      1;
+               uint64_t        ib_stall_ib               :      1;
+               uint64_t        ib_intvn                  :      1;
+               uint64_t        ib_wb                     :      1;
+               uint64_t        ib_hold                   :      1;
+               uint64_t        ib_ack                    :      1;
+               uint64_t        ib_resp                   :      1;
+               uint64_t        ib_ack_cnt                :     11;
+               uint64_t        ib_rsvd                   :      7;
+               uint64_t        ib_exc                    :      5;
+               uint64_t        ib_init                   :      3;
+               uint64_t        ib_imsg                   :      8;
+               uint64_t        ib_imsgtype               :      2;
+               uint64_t        ib_use_old                :      1;
+               uint64_t        ib_rsvd_1                 :     11;
+       } ii_icrb0_b_fld_s;
+} ii_icrb0_b_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
+ * used for Crosstalk operations (both cacheline and partial            *
+ * operations) or BTE/IO. Because the CRB entries are very wide, five   *
+ * registers (_A to _E) are required to read and write each entry.      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icrb0_c_u {
+       uint64_t        ii_icrb0_c_regval;
+       struct  {
+               uint64_t        ic_source                 :     15;
+               uint64_t        ic_size                   :      2;
+               uint64_t        ic_ct                     :      1;
+               uint64_t        ic_bte_num                :      1;
+               uint64_t        ic_gbr                    :      1;
+               uint64_t        ic_resprqd                :      1;
+               uint64_t        ic_bo                     :      1;
+               uint64_t        ic_suppl                  :     15;
+               uint64_t        ic_rsvd                   :     27;
+       } ii_icrb0_c_fld_s;
+} ii_icrb0_c_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
+ * used for Crosstalk operations (both cacheline and partial            *
+ * operations) or BTE/IO. Because the CRB entries are very wide, five   *
+ * registers (_A to _E) are required to read and write each entry.      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icrb0_d_u {
+       uint64_t        ii_icrb0_d_regval;
+       struct  {
+               uint64_t        id_pa_be                  :     43;
+               uint64_t        id_bte_op                 :      1;
+               uint64_t        id_pr_psc                 :      4;
+               uint64_t        id_pr_cnt                 :      4;
+               uint64_t        id_sleep                  :      1;
+               uint64_t        id_rsvd                   :     11;
+       } ii_icrb0_d_fld_s;
+} ii_icrb0_d_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  There are 15 CRB Entries (ICRB0 to ICRBE) that are     *
+ * used for Crosstalk operations (both cacheline and partial            *
+ * operations) or BTE/IO. Because the CRB entries are very wide, five   *
+ * registers (_A to _E) are required to read and write each entry.      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icrb0_e_u {
+       uint64_t        ii_icrb0_e_regval;
+       struct  {
+               uint64_t        ie_timeout                :      8;
+               uint64_t        ie_context                :     15;
+               uint64_t        ie_rsvd                   :      1;
+               uint64_t        ie_tvld                   :      1;
+               uint64_t        ie_cvld                   :      1;
+               uint64_t        ie_rsvd_0                 :     38;
+       } ii_icrb0_e_fld_s;
+} ii_icrb0_e_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the lower 64 bits of the header of the       *
+ * spurious message captured by II. Valid when the SP_MSG bit in ICMR   *
+ * register is set.                                                     *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icsml_u {
+       uint64_t        ii_icsml_regval;
+       struct  {
+               uint64_t        i_tt_addr                 :     47;
+               uint64_t        i_newsuppl_ex             :     14;
+               uint64_t        i_reserved                :      2;
+               uint64_t       i_overflow                :      1;
+       } ii_icsml_fld_s;
+} ii_icsml_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the middle 64 bits of the header of the      *
+ * spurious message captured by II. Valid when the SP_MSG bit in ICMR   *
+ * register is set.                                                     *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icsmm_u {
+       uint64_t        ii_icsmm_regval;
+       struct  {
+               uint64_t        i_tt_ack_cnt              :     11;
+               uint64_t        i_reserved                :     53;
+       } ii_icsmm_fld_s;
+} ii_icsmm_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the microscopic state, all the inputs to     *
+ * the protocol table, captured with the spurious message. Valid when   *
+ * the SP_MSG bit in the ICMR register is set.                          *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_icsmh_u {
+       uint64_t        ii_icsmh_regval;
+       struct  {
+               uint64_t        i_tt_vld                  :      1;
+               uint64_t        i_xerr                    :      1;
+               uint64_t        i_ft_cwact_o              :      1;
+               uint64_t        i_ft_wact_o               :      1;
+               uint64_t       i_ft_active_o             :      1;
+               uint64_t        i_sync                    :      1;
+               uint64_t        i_mnusg                   :      1;
+               uint64_t        i_mnusz                   :      1;
+               uint64_t        i_plusz                   :      1;
+               uint64_t        i_plusg                   :      1;
+               uint64_t        i_tt_exc                  :      5;
+               uint64_t        i_tt_wb                   :      1;
+               uint64_t        i_tt_hold                 :      1;
+               uint64_t        i_tt_ack                  :      1;
+               uint64_t        i_tt_resp                 :      1;
+               uint64_t        i_tt_intvn                :      1;
+               uint64_t        i_g_stall_bte1            :      1;
+               uint64_t        i_g_stall_bte0            :      1;
+               uint64_t        i_g_stall_il              :      1;
+               uint64_t        i_g_stall_ib              :      1;
+               uint64_t        i_tt_imsg                 :      8;
+               uint64_t        i_tt_imsgtype             :      2;
+               uint64_t        i_tt_use_old              :      1;
+               uint64_t        i_tt_respreqd             :      1;
+               uint64_t        i_tt_bte_num              :      1;
+               uint64_t        i_cbn                     :      1;
+               uint64_t        i_match                   :      1;
+               uint64_t        i_rpcnt_lt_34             :      1;
+               uint64_t        i_rpcnt_ge_34             :      1;
+               uint64_t        i_rpcnt_lt_18             :      1;
+               uint64_t        i_rpcnt_ge_18             :      1;
+               uint64_t       i_rpcnt_lt_2              :      1;
+               uint64_t        i_rpcnt_ge_2              :      1;
+               uint64_t        i_rqcnt_lt_18             :      1;
+               uint64_t        i_rqcnt_ge_18             :      1;
+               uint64_t        i_rqcnt_lt_2              :      1;
+               uint64_t        i_rqcnt_ge_2              :      1;
+               uint64_t        i_tt_device               :      7;
+               uint64_t        i_tt_init                 :      3;
+               uint64_t        i_reserved                :      5;
+       } ii_icsmh_fld_s;
+} ii_icsmh_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  The Shub DEBUG unit provides a 3-bit selection signal to the        *
+ * II core and a 3-bit selection signal to the fsbclk domain in the II  *
+ * wrapper.                                                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_idbss_u {
+       uint64_t        ii_idbss_regval;
+       struct  {
+               uint64_t        i_iioclk_core_submenu     :      3;
+               uint64_t        i_rsvd                    :      5;
+               uint64_t        i_fsbclk_wrapper_submenu  :      3;
+               uint64_t        i_rsvd_1                  :      5;
+               uint64_t        i_iioclk_menu             :      5;
+               uint64_t        i_rsvd_2                  :     43;
+       } ii_idbss_fld_s;
+} ii_idbss_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register is used to set up the length for a       *
+ * transfer and then to monitor the progress of that transfer. This     *
+ * register needs to be initialized before a transfer is started. A     *
+ * legitimate write to this register will set the Busy bit, clear the   *
+ * Error bit, and initialize the length to the value desired.           *
+ * While the transfer is in progress, hardware will decrement the       *
+ * length field with each successful block that is copied. Once the     *
+ * transfer completes, hardware will clear the Busy bit. The length     *
+ * field will also contain the number of cache lines left to be         *
+ * transferred.                                                         *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibls0_u {
+       uint64_t        ii_ibls0_regval;
+       struct  {
+               uint64_t        i_length                  :     16;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_busy                    :      1;
+               uint64_t       i_rsvd                    :     43;
+       } ii_ibls0_fld_s;
+} ii_ibls0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register should be loaded before a transfer is started. The    *
+ * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
+ * address as described in Section 1.3, Figure2 and Figure3. Since      *
+ * the bottom 7 bits of the address are always taken to be zero, BTE    *
+ * transfers are always cacheline-aligned.                              *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibsa0_u {
+       uint64_t        ii_ibsa0_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_addr                    :     42;
+               uint64_t       i_rsvd                    :     15;
+       } ii_ibsa0_fld_s;
+} ii_ibsa0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register should be loaded before a transfer is started. The    *
+ * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
+ * address as described in Section 1.3, Figure2 and Figure3. Since      *
+ * the bottom 7 bits of the address are always taken to be zero, BTE    *
+ * transfers are always cacheline-aligned.                              *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibda0_u {
+       uint64_t        ii_ibda0_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_addr                    :     42;
+               uint64_t        i_rsvd                    :     15;
+       } ii_ibda0_fld_s;
+} ii_ibda0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  Writing to this register sets up the attributes of the transfer     *
+ * and initiates the transfer operation. Reading this register has      *
+ * the side effect of terminating any transfer in progress. Note:       *
+ * stopping a transfer midstream could have an adverse impact on the    *
+ * other BTE. If a BTE stream has to be stopped (due to error           *
+ * handling for example), both BTE streams should be stopped and        *
+ * their transfers discarded.                                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibct0_u {
+       uint64_t        ii_ibct0_regval;
+       struct  {
+               uint64_t        i_zerofill                :      1;
+               uint64_t        i_rsvd_2                  :      3;
+               uint64_t        i_notify                  :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t       i_poison                  :      1;
+               uint64_t       i_rsvd                    :     55;
+       } ii_ibct0_fld_s;
+} ii_ibct0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the address to which the WINV is sent.       *
+ * This address has to be cache line aligned.                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibna0_u {
+       uint64_t        ii_ibna0_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_addr                    :     42;
+               uint64_t        i_rsvd                    :     15;
+       } ii_ibna0_fld_s;
+} ii_ibna0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the programmable level as well as the node   *
+ * ID and PI unit of the processor to which the interrupt will be       *
+ * sent.                                                                *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibia0_u {
+       uint64_t        ii_ibia0_regval;
+       struct  {
+               uint64_t        i_rsvd_2                   :     1;
+               uint64_t        i_node_id                 :     11;
+               uint64_t        i_rsvd_1                  :      4;
+               uint64_t        i_level                   :      7;
+               uint64_t       i_rsvd                    :     41;
+       } ii_ibia0_fld_s;
+} ii_ibia0_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ * Description:  This register is used to set up the length for a       *
+ * transfer and then to monitor the progress of that transfer. This     *
+ * register needs to be initialized before a transfer is started. A     *
+ * legitimate write to this register will set the Busy bit, clear the   *
+ * Error bit, and initialize the length to the value desired.           *
+ * While the transfer is in progress, hardware will decrement the       *
+ * length field with each successful block that is copied. Once the     *
+ * transfer completes, hardware will clear the Busy bit. The length     *
+ * field will also contain the number of cache lines left to be         *
+ * transferred.                                                         *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibls1_u {
+       uint64_t        ii_ibls1_regval;
+       struct  {
+               uint64_t        i_length                  :     16;
+               uint64_t        i_error                   :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_busy                    :      1;
+               uint64_t       i_rsvd                    :     43;
+       } ii_ibls1_fld_s;
+} ii_ibls1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register should be loaded before a transfer is started. The    *
+ * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
+ * address as described in Section 1.3, Figure2 and Figure3. Since      *
+ * the bottom 7 bits of the address are always taken to be zero, BTE    *
+ * transfers are always cacheline-aligned.                              *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibsa1_u {
+       uint64_t        ii_ibsa1_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_addr                    :     33;
+               uint64_t        i_rsvd                    :     24;
+       } ii_ibsa1_fld_s;
+} ii_ibsa1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register should be loaded before a transfer is started. The    *
+ * address to be loaded in bits 39:0 is the 40-bit TRex+ physical       *
+ * address as described in Section 1.3, Figure2 and Figure3. Since      *
+ * the bottom 7 bits of the address are always taken to be zero, BTE    *
+ * transfers are always cacheline-aligned.                              *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibda1_u {
+       uint64_t        ii_ibda1_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_addr                    :     33;
+               uint64_t        i_rsvd                    :     24;
+       } ii_ibda1_fld_s;
+} ii_ibda1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  Writing to this register sets up the attributes of the transfer     *
+ * and initiates the transfer operation. Reading this register has      *
+ * the side effect of terminating any transfer in progress. Note:       *
+ * stopping a transfer midstream could have an adverse impact on the    *
+ * other BTE. If a BTE stream has to be stopped (due to error           *
+ * handling for example), both BTE streams should be stopped and        *
+ * their transfers discarded.                                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibct1_u {
+       uint64_t        ii_ibct1_regval;
+       struct  {
+               uint64_t        i_zerofill                :      1;
+               uint64_t        i_rsvd_2                  :      3;
+               uint64_t        i_notify                  :      1;
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_poison                  :      1;
+               uint64_t        i_rsvd                    :     55;
+       } ii_ibct1_fld_s;
+} ii_ibct1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the address to which the WINV is sent.       *
+ * This address has to be cache line aligned.                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibna1_u {
+       uint64_t        ii_ibna1_regval;
+       struct  {
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_addr                    :     33;
+               uint64_t       i_rsvd                    :     24;
+       } ii_ibna1_fld_s;
+} ii_ibna1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register contains the programmable level as well as the node   *
+ * ID and PI unit of the processor to which the interrupt will be       *
+ * sent.                                                                *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ibia1_u {
+       uint64_t        ii_ibia1_regval;
+       struct  {
+               uint64_t        i_pi_id                   :      1;
+               uint64_t        i_node_id                 :      8;
+               uint64_t        i_rsvd_1                  :      7;
+               uint64_t        i_level                   :      7;
+               uint64_t        i_rsvd                    :     41;
+       } ii_ibia1_fld_s;
+} ii_ibia1_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *  This register defines the resources that feed information into      *
+ * the two performance counters located in the IO Performance           *
+ * Profiling Register. There are 17 different quantities that can be    *
+ * measured. Given these 17 different options, the two performance      *
+ * counters have 15 of them in common; menu selections 0 through 0xE    *
+ * are identical for each performance counter. As for the other two     *
+ * options, one is available from one performance counter and the       *
+ * other is available from the other performance counter. Hence, the    *
+ * II supports all 17*16=272 possible combinations of quantities to     *
+ * measure.                                                             *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ipcr_u {
+       uint64_t        ii_ipcr_regval;
+       struct  {
+               uint64_t        i_ippr0_c                 :      4;
+               uint64_t        i_ippr1_c                 :      4;
+               uint64_t        i_icct                    :      8;
+               uint64_t       i_rsvd                    :     48;
+       } ii_ipcr_fld_s;
+} ii_ipcr_u_t;
+
+
+/************************************************************************
+ *                                                                      *
+ *                                                                      *
+ *                                                                      *
+ ************************************************************************/
+
+typedef union ii_ippr_u {
+       uint64_t        ii_ippr_regval;
+       struct  {
+               uint64_t        i_ippr0                   :     32;
+               uint64_t        i_ippr1                   :     32;
+       } ii_ippr_fld_s;
+} ii_ippr_u_t;
+
+
+
+/**************************************************************************
+ *                                                                        *
+ * The following defines which were not formed into structures are        *
+ * probably indentical to another register, and the name of the           *
+ * register is provided against each of these registers. This             *
+ * information needs to be checked carefully                              *
+ *                                                                        *
+ *           IIO_ICRB1_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB1_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB1_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB1_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB1_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB2_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB2_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB2_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB2_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB2_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB3_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB3_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB3_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB3_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB3_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB4_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB4_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB4_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB4_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB4_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB5_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB5_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB5_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB5_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB5_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB6_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB6_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB6_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB6_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB6_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB7_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB7_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB7_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB7_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB7_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB8_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB8_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB8_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB8_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB8_E                IIO_ICRB0_E                       *
+ *           IIO_ICRB9_A                IIO_ICRB0_A                       *
+ *           IIO_ICRB9_B                IIO_ICRB0_B                       *
+ *           IIO_ICRB9_C                IIO_ICRB0_C                       *
+ *           IIO_ICRB9_D                IIO_ICRB0_D                       *
+ *           IIO_ICRB9_E                IIO_ICRB0_E                       *
+ *           IIO_ICRBA_A                IIO_ICRB0_A                       *
+ *           IIO_ICRBA_B                IIO_ICRB0_B                       *
+ *           IIO_ICRBA_C                IIO_ICRB0_C                       *
+ *           IIO_ICRBA_D                IIO_ICRB0_D                       *
+ *           IIO_ICRBA_E                IIO_ICRB0_E                       *
+ *           IIO_ICRBB_A                IIO_ICRB0_A                       *
+ *           IIO_ICRBB_B                IIO_ICRB0_B                       *
+ *           IIO_ICRBB_C                IIO_ICRB0_C                       *
+ *           IIO_ICRBB_D                IIO_ICRB0_D                       *
+ *           IIO_ICRBB_E                IIO_ICRB0_E                       *
+ *           IIO_ICRBC_A                IIO_ICRB0_A                       *
+ *           IIO_ICRBC_B                IIO_ICRB0_B                       *
+ *           IIO_ICRBC_C                IIO_ICRB0_C                       *
+ *           IIO_ICRBC_D                IIO_ICRB0_D                       *
+ *           IIO_ICRBC_E                IIO_ICRB0_E                       *
+ *           IIO_ICRBD_A                IIO_ICRB0_A                       *
+ *           IIO_ICRBD_B                IIO_ICRB0_B                       *
+ *           IIO_ICRBD_C                IIO_ICRB0_C                       *
+ *           IIO_ICRBD_D                IIO_ICRB0_D                       *
+ *           IIO_ICRBD_E                IIO_ICRB0_E                       *
+ *           IIO_ICRBE_A                IIO_ICRB0_A                       *
+ *           IIO_ICRBE_B                IIO_ICRB0_B                       *
+ *           IIO_ICRBE_C                IIO_ICRB0_C                       *
+ *           IIO_ICRBE_D                IIO_ICRB0_D                       *
+ *           IIO_ICRBE_E                IIO_ICRB0_E                       *
+ *                                                                        *
+ **************************************************************************/
+
+
+/*
+ * Slightly friendlier names for some common registers.
+ */
+#define IIO_WIDGET              IIO_WID      /* Widget identification */
+#define IIO_WIDGET_STAT         IIO_WSTAT    /* Widget status register */
+#define IIO_WIDGET_CTRL         IIO_WCR      /* Widget control register */
+#define IIO_PROTECT             IIO_ILAPR    /* IO interface protection */
+#define IIO_PROTECT_OVRRD       IIO_ILAPO    /* IO protect override */
+#define IIO_OUTWIDGET_ACCESS    IIO_IOWA     /* Outbound widget access */
+#define IIO_INWIDGET_ACCESS     IIO_IIWA     /* Inbound widget access */
+#define IIO_INDEV_ERR_MASK      IIO_IIDEM    /* Inbound device error mask */
+#define IIO_LLP_CSR             IIO_ILCSR    /* LLP control and status */
+#define IIO_LLP_LOG             IIO_ILLR     /* LLP log */
+#define IIO_XTALKCC_TOUT        IIO_IXCC     /* Xtalk credit count timeout*/
+#define IIO_XTALKTT_TOUT        IIO_IXTT     /* Xtalk tail timeout */
+#define IIO_IO_ERR_CLR          IIO_IECLR    /* IO error clear */
+#define IIO_IGFX_0             IIO_IGFX0
+#define IIO_IGFX_1             IIO_IGFX1
+#define IIO_IBCT_0             IIO_IBCT0
+#define IIO_IBCT_1             IIO_IBCT1
+#define IIO_IBLS_0             IIO_IBLS0
+#define IIO_IBLS_1             IIO_IBLS1
+#define IIO_IBSA_0             IIO_IBSA0
+#define IIO_IBSA_1             IIO_IBSA1
+#define IIO_IBDA_0             IIO_IBDA0
+#define IIO_IBDA_1             IIO_IBDA1
+#define IIO_IBNA_0             IIO_IBNA0
+#define IIO_IBNA_1             IIO_IBNA1
+#define IIO_IBIA_0             IIO_IBIA0
+#define IIO_IBIA_1             IIO_IBIA1
+#define IIO_IOPRB_0            IIO_IPRB0
+
+#define IIO_PRTE_A(_x)         (IIO_IPRTE0_A + (8 * (_x)))
+#define IIO_PRTE_B(_x)         (IIO_IPRTE0_B + (8 * (_x)))
+#define IIO_NUM_PRTES          8       /* Total number of PRB table entries */
+#define IIO_WIDPRTE_A(x)       IIO_PRTE_A(((x) - 8)) /* widget ID to its PRTE num */
+#define IIO_WIDPRTE_B(x)       IIO_PRTE_B(((x) - 8)) /* widget ID to its PRTE num */
+
+#define IIO_NUM_IPRBS          (9) 
+
+#define IIO_LLP_CSR_IS_UP               0x00002000
+#define IIO_LLP_CSR_LLP_STAT_MASK       0x00003000
+#define IIO_LLP_CSR_LLP_STAT_SHFT       12
+
+#define IIO_LLP_CB_MAX  0xffff /* in ILLR CB_CNT, Max Check Bit errors */
+#define IIO_LLP_SN_MAX  0xffff /* in ILLR SN_CNT, Max Sequence Number errors */
+
+/* key to IIO_PROTECT_OVRRD */
+#define IIO_PROTECT_OVRRD_KEY   0x53474972756c6573ull   /* "SGIrules" */
+
+/* BTE register names */
+#define IIO_BTE_STAT_0          IIO_IBLS_0   /* Also BTE length/status 0 */
+#define IIO_BTE_SRC_0           IIO_IBSA_0   /* Also BTE source address  0 */
+#define IIO_BTE_DEST_0          IIO_IBDA_0   /* Also BTE dest. address 0 */
+#define IIO_BTE_CTRL_0          IIO_IBCT_0   /* Also BTE control/terminate 0 */
+#define IIO_BTE_NOTIFY_0        IIO_IBNA_0   /* Also BTE notification 0 */
+#define IIO_BTE_INT_0           IIO_IBIA_0   /* Also BTE interrupt 0 */
+#define IIO_BTE_OFF_0           0            /* Base offset from BTE 0 regs. */
+#define IIO_BTE_OFF_1          (IIO_IBLS_1 - IIO_IBLS_0) /* Offset from base to BTE 1 */
+
+/* BTE register offsets from base */
+#define BTEOFF_STAT             0
+#define BTEOFF_SRC              (IIO_BTE_SRC_0 - IIO_BTE_STAT_0)
+#define BTEOFF_DEST             (IIO_BTE_DEST_0 - IIO_BTE_STAT_0)
+#define BTEOFF_CTRL             (IIO_BTE_CTRL_0 - IIO_BTE_STAT_0)
+#define BTEOFF_NOTIFY           (IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0)
+#define BTEOFF_INT              (IIO_BTE_INT_0 - IIO_BTE_STAT_0)
+
+
+/* names used in shub diags */
+#define IIO_BASE_BTE0   IIO_IBLS_0             
+#define IIO_BASE_BTE1   IIO_IBLS_1             
+
+/*
+ * Macro which takes the widget number, and returns the
+ * IO PRB address of that widget.
+ * value _x is expected to be a widget number in the range
+ * 0, 8 - 0xF
+ */
+#define IIO_IOPRB(_x)   (IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \
+                        (_x) : \
+                        (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) )
+
+
+/* GFX Flow Control Node/Widget Register */
+#define IIO_IGFX_W_NUM_BITS    4       /* size of widget num field */
+#define IIO_IGFX_W_NUM_MASK    ((1<<IIO_IGFX_W_NUM_BITS)-1)
+#define IIO_IGFX_W_NUM_SHIFT   0
+#define IIO_IGFX_PI_NUM_BITS   1       /* size of PI num field */
+#define IIO_IGFX_PI_NUM_MASK   ((1<<IIO_IGFX_PI_NUM_BITS)-1)
+#define IIO_IGFX_PI_NUM_SHIFT  4
+#define IIO_IGFX_N_NUM_BITS    8       /* size of node num field */
+#define IIO_IGFX_N_NUM_MASK    ((1<<IIO_IGFX_N_NUM_BITS)-1)
+#define IIO_IGFX_N_NUM_SHIFT   5
+#define IIO_IGFX_P_NUM_BITS    1       /* size of processor num field */
+#define IIO_IGFX_P_NUM_MASK    ((1<<IIO_IGFX_P_NUM_BITS)-1)
+#define IIO_IGFX_P_NUM_SHIFT   16
+#define IIO_IGFX_INIT(widget, pi, node, cpu)                           (\
+       (((widget) & IIO_IGFX_W_NUM_MASK) << IIO_IGFX_W_NUM_SHIFT) |     \
+       (((pi)     & IIO_IGFX_PI_NUM_MASK)<< IIO_IGFX_PI_NUM_SHIFT)|     \
+       (((node)   & IIO_IGFX_N_NUM_MASK) << IIO_IGFX_N_NUM_SHIFT) |     \
+       (((cpu)    & IIO_IGFX_P_NUM_MASK) << IIO_IGFX_P_NUM_SHIFT))
+
+
+/* Scratch registers (all bits available) */
+#define IIO_SCRATCH_REG0        IIO_ISCR0
+#define IIO_SCRATCH_REG1        IIO_ISCR1
+#define IIO_SCRATCH_MASK        0xffffffffffffffffUL
+
+#define IIO_SCRATCH_BIT0_0      0x0000000000000001UL
+#define IIO_SCRATCH_BIT0_1      0x0000000000000002UL
+#define IIO_SCRATCH_BIT0_2      0x0000000000000004UL
+#define IIO_SCRATCH_BIT0_3      0x0000000000000008UL
+#define IIO_SCRATCH_BIT0_4      0x0000000000000010UL
+#define IIO_SCRATCH_BIT0_5      0x0000000000000020UL
+#define IIO_SCRATCH_BIT0_6      0x0000000000000040UL
+#define IIO_SCRATCH_BIT0_7      0x0000000000000080UL
+#define IIO_SCRATCH_BIT0_8      0x0000000000000100UL
+#define IIO_SCRATCH_BIT0_9      0x0000000000000200UL
+#define IIO_SCRATCH_BIT0_A      0x0000000000000400UL
+
+#define IIO_SCRATCH_BIT1_0      0x0000000000000001UL
+#define IIO_SCRATCH_BIT1_1      0x0000000000000002UL
+/* IO Translation Table Entries */
+#define IIO_NUM_ITTES   7               /* ITTEs numbered 0..6 */
+                                        /* Hw manuals number them 1..7! */
+/*
+ * IIO_IMEM Register fields.
+ */
+#define IIO_IMEM_W0ESD  0x1UL             /* Widget 0 shut down due to error */
+#define IIO_IMEM_B0ESD  (1UL << 4)        /* BTE 0 shut down due to error */
+#define IIO_IMEM_B1ESD  (1UL << 8)        /* BTE 1 Shut down due to error */
+
+/*
+ * As a permanent workaround for a bug in the PI side of the shub, we've
+ * redefined big window 7 as small window 0.
+ XXX does this still apply for SN1??
+ */
+#define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
+
+/*
+ * Use the top big window as a surrogate for the first small window
+ */
+#define SWIN0_BIGWIN            HUB_NUM_BIG_WINDOW
+
+#define ILCSR_WARM_RESET        0x100
+
+/*
+ * CRB manipulation macros
+ *      The CRB macros are slightly complicated, since there are up to
+ *      four registers associated with each CRB entry.
+ */
+#define IIO_NUM_CRBS            15      /* Number of CRBs */
+#define IIO_NUM_PC_CRBS         4       /* Number of partial cache CRBs */
+#define IIO_ICRB_OFFSET         8
+#define IIO_ICRB_0              IIO_ICRB0_A
+#define IIO_ICRB_ADDR_SHFT     2       /* Shift to get proper address */
+/* XXX - This is now tuneable:
+        #define IIO_FIRST_PC_ENTRY 12
+ */
+
+#define IIO_ICRB_A(_x)  ((u64)(IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x))))
+#define IIO_ICRB_B(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET))
+#define IIO_ICRB_C(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET))
+#define IIO_ICRB_D(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET))
+#define IIO_ICRB_E(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET))
+
+#define TNUM_TO_WIDGET_DEV(_tnum)      (_tnum & 0x7)
+
+/*
+ * values for "ecode" field
+ */
+#define IIO_ICRB_ECODE_DERR     0       /* Directory error due to IIO access */
+#define IIO_ICRB_ECODE_PERR     1       /* Poison error on IO access */
+#define IIO_ICRB_ECODE_WERR     2       /* Write error by IIO access
+                                         * e.g. WINV to a Read only line. */
+#define IIO_ICRB_ECODE_AERR     3       /* Access error caused by IIO access */
+#define IIO_ICRB_ECODE_PWERR    4       /* Error on partial write       */
+#define IIO_ICRB_ECODE_PRERR    5       /* Error on partial read        */
+#define IIO_ICRB_ECODE_TOUT     6       /* CRB timeout before deallocating */
+#define IIO_ICRB_ECODE_XTERR    7       /* Incoming xtalk pkt had error bit */
+
+/*
+ * Values for field imsgtype
+ */
+#define IIO_ICRB_IMSGT_XTALK    0       /* Incoming Meessage from Xtalk */
+#define IIO_ICRB_IMSGT_BTE      1       /* Incoming message from BTE    */
+#define IIO_ICRB_IMSGT_SN1NET   2       /* Incoming message from SN1 net */
+#define IIO_ICRB_IMSGT_CRB      3       /* Incoming message from CRB ???  */
+
+/*
+ * values for field initiator.
+ */
+#define IIO_ICRB_INIT_XTALK     0       /* Message originated in xtalk  */
+#define IIO_ICRB_INIT_BTE0      0x1     /* Message originated in BTE 0  */
+#define IIO_ICRB_INIT_SN1NET    0x2     /* Message originated in SN1net */
+#define IIO_ICRB_INIT_CRB       0x3     /* Message originated in CRB ?  */
+#define IIO_ICRB_INIT_BTE1      0x5     /* MEssage originated in BTE 1  */
+
+/*
+ * Number of credits Hub widget has while sending req/response to
+ * xbow.
+ * Value of 3 is required by Xbow 1.1
+ * We may be able to increase this to 4 with Xbow 1.2.
+ */
+#define       HUBII_XBOW_CREDIT       3
+#define       HUBII_XBOW_REV2_CREDIT  4
+
+/*
+ * Number of credits that xtalk devices should use when communicating
+ * with a SHub (depth of SHub's queue).
+ */
+#define HUB_CREDIT 4
+
+/*
+ * Some IIO_PRB fields
+ */
+#define IIO_PRB_MULTI_ERR      (1LL << 63)
+#define IIO_PRB_SPUR_RD                (1LL << 51)
+#define IIO_PRB_SPUR_WR                (1LL << 50)
+#define IIO_PRB_RD_TO          (1LL << 49)
+#define IIO_PRB_ERROR          (1LL << 48)
+
+/*************************************************************************
+
+ Some of the IIO field masks and shifts are defined here.
+ This is in order to maintain compatibility in SN0 and SN1 code
+**************************************************************************/
+
+/*
+ * ICMR register fields
+ * (Note: the IIO_ICMR_P_CNT and IIO_ICMR_PC_VLD from Hub are not
+ * present in SHub)
+ */
+
+#define IIO_ICMR_CRB_VLD_SHFT   20
+#define IIO_ICMR_CRB_VLD_MASK   (0x7fffUL << IIO_ICMR_CRB_VLD_SHFT)
+
+#define IIO_ICMR_FC_CNT_SHFT    16
+#define IIO_ICMR_FC_CNT_MASK    (0xf << IIO_ICMR_FC_CNT_SHFT)
+
+#define IIO_ICMR_C_CNT_SHFT     4
+#define IIO_ICMR_C_CNT_MASK     (0xf << IIO_ICMR_C_CNT_SHFT)
+
+#define IIO_ICMR_PRECISE        (1UL << 52)
+#define IIO_ICMR_CLR_RPPD       (1UL << 13)
+#define IIO_ICMR_CLR_RQPD       (1UL << 12)
+
+/*
+ * IIO PIO Deallocation register field masks : (IIO_IPDR)
+ XXX present but not needed in bedrock?  See the manual.
+ */
+#define IIO_IPDR_PND    (1 << 4)
+
+/*
+ * IIO CRB deallocation register field masks: (IIO_ICDR)
+ */
+#define IIO_ICDR_PND    (1 << 4)
+
+/* 
+ * IO BTE Length/Status (IIO_IBLS) register bit field definitions
+ */
+#define IBLS_BUSY              (0x1UL << 20)
+#define IBLS_ERROR_SHFT                16
+#define IBLS_ERROR             (0x1UL << IBLS_ERROR_SHFT)
+#define IBLS_LENGTH_MASK       0xffff
+
+/*
+ * IO BTE Control/Terminate register (IBCT) register bit field definitions
+ */
+#define IBCT_POISON            (0x1UL << 8)
+#define IBCT_NOTIFY            (0x1UL << 4)
+#define IBCT_ZFIL_MODE         (0x1UL << 0)
+
+/*
+ * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2)
+ */
+#define IIEPH1_VALID           (1UL << 44)
+#define IIEPH1_OVERRUN         (1UL << 40)
+#define IIEPH1_ERR_TYPE_SHFT   32
+#define IIEPH1_ERR_TYPE_MASK   0xf
+#define IIEPH1_SOURCE_SHFT     20
+#define IIEPH1_SOURCE_MASK     11
+#define IIEPH1_SUPPL_SHFT      8
+#define IIEPH1_SUPPL_MASK      11
+#define IIEPH1_CMD_SHFT                0
+#define IIEPH1_CMD_MASK                7
+
+#define IIEPH2_TAIL            (1UL << 40)
+#define IIEPH2_ADDRESS_SHFT    0
+#define IIEPH2_ADDRESS_MASK    38
+
+#define IIEPH1_ERR_SHORT_REQ   2
+#define IIEPH1_ERR_SHORT_REPLY 3
+#define IIEPH1_ERR_LONG_REQ    4
+#define IIEPH1_ERR_LONG_REPLY  5
+
+/*
+ * IO Error Clear register bit field definitions
+ */
+#define IECLR_PI1_FWD_INT      (1UL << 31)  /* clear PI1_FORWARD_INT in iidsr */
+#define IECLR_PI0_FWD_INT      (1UL << 30)  /* clear PI0_FORWARD_INT in iidsr */
+#define IECLR_SPUR_RD_HDR      (1UL << 29)  /* clear valid bit in ixss reg */
+#define IECLR_BTE1             (1UL << 18)  /* clear bte error 1 */
+#define IECLR_BTE0             (1UL << 17)  /* clear bte error 0 */
+#define IECLR_CRAZY            (1UL << 16)  /* clear crazy bit in wstat reg */
+#define IECLR_PRB_F            (1UL << 15)  /* clear err bit in PRB_F reg */
+#define IECLR_PRB_E            (1UL << 14)  /* clear err bit in PRB_E reg */
+#define IECLR_PRB_D            (1UL << 13)  /* clear err bit in PRB_D reg */
+#define IECLR_PRB_C            (1UL << 12)  /* clear err bit in PRB_C reg */
+#define IECLR_PRB_B            (1UL << 11)  /* clear err bit in PRB_B reg */
+#define IECLR_PRB_A            (1UL << 10)  /* clear err bit in PRB_A reg */
+#define IECLR_PRB_9            (1UL << 9)   /* clear err bit in PRB_9 reg */
+#define IECLR_PRB_8            (1UL << 8)   /* clear err bit in PRB_8 reg */
+#define IECLR_PRB_0            (1UL << 0)   /* clear err bit in PRB_0 reg */
+
+/*
+ * IIO CRB control register Fields: IIO_ICCR 
+ */
+#define        IIO_ICCR_PENDING        (0x10000)
+#define        IIO_ICCR_CMD_MASK       (0xFF)
+#define        IIO_ICCR_CMD_SHFT       (7)
+#define        IIO_ICCR_CMD_NOP        (0x0)   /* No Op */
+#define        IIO_ICCR_CMD_WAKE       (0x100) /* Reactivate CRB entry and process */
+#define        IIO_ICCR_CMD_TIMEOUT    (0x200) /* Make CRB timeout & mark invalid */
+#define        IIO_ICCR_CMD_EJECT      (0x400) /* Contents of entry written to memory 
+                                        * via a WB
+                                        */
+#define        IIO_ICCR_CMD_FLUSH      (0x800)
+
+/*
+ *
+ * CRB Register description.
+ *
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING
+ *
+ * Many of the fields in CRB are status bits used by hardware
+ * for implementation of the protocol. It's very dangerous to
+ * mess around with the CRB registers.
+ *
+ * It's OK to read the CRB registers and try to make sense out of the
+ * fields in CRB.
+ *
+ * Updating CRB requires all activities in Hub IIO to be quiesced.
+ * otherwise, a write to CRB could corrupt other CRB entries.
+ * CRBs are here only as a back door peek to shub IIO's status.
+ * Quiescing implies  no dmas no PIOs
+ * either directly from the cpu or from sn0net.
+ * this is not something that can be done easily. So, AVOID updating
+ * CRBs.
+ */
+
+/*
+ * Easy access macros for CRBs, all 5 registers (A-E)
+ */
+typedef ii_icrb0_a_u_t icrba_t;
+#define a_sidn          ii_icrb0_a_fld_s.ia_sidn
+#define a_tnum          ii_icrb0_a_fld_s.ia_tnum
+#define a_addr          ii_icrb0_a_fld_s.ia_addr
+#define a_valid         ii_icrb0_a_fld_s.ia_vld
+#define a_iow           ii_icrb0_a_fld_s.ia_iow
+#define a_regvalue     ii_icrb0_a_regval
+
+typedef ii_icrb0_b_u_t icrbb_t;
+#define b_use_old       ii_icrb0_b_fld_s.ib_use_old
+#define b_imsgtype      ii_icrb0_b_fld_s.ib_imsgtype
+#define b_imsg          ii_icrb0_b_fld_s.ib_imsg
+#define b_initiator     ii_icrb0_b_fld_s.ib_init
+#define b_exc           ii_icrb0_b_fld_s.ib_exc
+#define b_ackcnt        ii_icrb0_b_fld_s.ib_ack_cnt
+#define b_resp          ii_icrb0_b_fld_s.ib_resp
+#define b_ack           ii_icrb0_b_fld_s.ib_ack
+#define b_hold          ii_icrb0_b_fld_s.ib_hold
+#define b_wb            ii_icrb0_b_fld_s.ib_wb
+#define b_intvn         ii_icrb0_b_fld_s.ib_intvn
+#define b_stall_ib      ii_icrb0_b_fld_s.ib_stall_ib
+#define b_stall_int     ii_icrb0_b_fld_s.ib_stall__intr
+#define b_stall_bte_0   ii_icrb0_b_fld_s.ib_stall__bte_0
+#define b_stall_bte_1   ii_icrb0_b_fld_s.ib_stall__bte_1
+#define b_error         ii_icrb0_b_fld_s.ib_error
+#define b_ecode         ii_icrb0_b_fld_s.ib_errcode
+#define b_lnetuce       ii_icrb0_b_fld_s.ib_ln_uce
+#define b_mark          ii_icrb0_b_fld_s.ib_mark
+#define b_xerr          ii_icrb0_b_fld_s.ib_xt_err
+#define b_regvalue     ii_icrb0_b_regval
+
+typedef ii_icrb0_c_u_t icrbc_t;
+#define c_suppl         ii_icrb0_c_fld_s.ic_suppl
+#define c_barrop        ii_icrb0_c_fld_s.ic_bo
+#define c_doresp        ii_icrb0_c_fld_s.ic_resprqd
+#define c_gbr           ii_icrb0_c_fld_s.ic_gbr
+#define c_btenum        ii_icrb0_c_fld_s.ic_bte_num
+#define c_cohtrans      ii_icrb0_c_fld_s.ic_ct
+#define c_xtsize        ii_icrb0_c_fld_s.ic_size
+#define c_source        ii_icrb0_c_fld_s.ic_source
+#define c_regvalue     ii_icrb0_c_regval
+
+
+typedef ii_icrb0_d_u_t icrbd_t;
+#define d_sleep         ii_icrb0_d_fld_s.id_sleep
+#define d_pricnt        ii_icrb0_d_fld_s.id_pr_cnt
+#define d_pripsc        ii_icrb0_d_fld_s.id_pr_psc
+#define d_bteop         ii_icrb0_d_fld_s.id_bte_op
+#define d_bteaddr       ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/
+#define d_benable       ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/
+#define d_regvalue     ii_icrb0_d_regval
+
+typedef ii_icrb0_e_u_t icrbe_t;
+#define icrbe_ctxtvld   ii_icrb0_e_fld_s.ie_cvld
+#define icrbe_toutvld   ii_icrb0_e_fld_s.ie_tvld
+#define icrbe_context   ii_icrb0_e_fld_s.ie_context
+#define icrbe_timeout   ii_icrb0_e_fld_s.ie_timeout
+#define e_regvalue     ii_icrb0_e_regval
+
+
+/* Number of widgets supported by shub */
+#define HUB_NUM_WIDGET          9
+#define HUB_WIDGET_ID_MIN       0x8
+#define HUB_WIDGET_ID_MAX       0xf
+
+#define HUB_WIDGET_PART_NUM     0xc120
+#define MAX_HUBS_PER_XBOW       2
+
+/* A few more #defines for backwards compatibility */
+#define iprb_t          ii_iprb0_u_t
+#define iprb_regval     ii_iprb0_regval
+#define iprb_mult_err  ii_iprb0_fld_s.i_mult_err
+#define iprb_spur_rd   ii_iprb0_fld_s.i_spur_rd
+#define iprb_spur_wr   ii_iprb0_fld_s.i_spur_wr
+#define iprb_rd_to     ii_iprb0_fld_s.i_rd_to
+#define iprb_ovflow     ii_iprb0_fld_s.i_of_cnt
+#define iprb_error      ii_iprb0_fld_s.i_error
+#define iprb_ff         ii_iprb0_fld_s.i_f
+#define iprb_mode       ii_iprb0_fld_s.i_m
+#define iprb_bnakctr    ii_iprb0_fld_s.i_nb
+#define iprb_anakctr    ii_iprb0_fld_s.i_na
+#define iprb_xtalkctr   ii_iprb0_fld_s.i_c
+
+#define LNK_STAT_WORKING        0x2            /* LLP is working */
+
+#define IIO_WSTAT_ECRAZY        (1ULL << 32)    /* Hub gone crazy */
+#define IIO_WSTAT_TXRETRY       (1ULL << 9)     /* Hub Tx Retry timeout */
+#define IIO_WSTAT_TXRETRY_MASK  (0x7F)   /* should be 0xFF?? */
+#define IIO_WSTAT_TXRETRY_SHFT  (16)
+#define IIO_WSTAT_TXRETRY_CNT(w)        (((w) >> IIO_WSTAT_TXRETRY_SHFT) & \
+                                          IIO_WSTAT_TXRETRY_MASK)
+
+/* Number of II perf. counters we can multiplex at once */
+
+#define IO_PERF_SETS   32
+
+/* Bit for the widget in inbound access register */
+#define IIO_IIWA_WIDGET(_w)     ((uint64_t)(1ULL << _w))
+/* Bit for the widget in outbound access register */
+#define IIO_IOWA_WIDGET(_w)     ((uint64_t)(1ULL << _w))
+
+/* NOTE: The following define assumes that we are going to get
+ * widget numbers from 8 thru F and the device numbers within
+ * widget from 0 thru 7.
+ */
+#define IIO_IIDEM_WIDGETDEV_MASK(w, d)  ((uint64_t)(1ULL << (8 * ((w) - 8) + (d))))
+
+/* IO Interrupt Destination Register */
+#define IIO_IIDSR_SENT_SHIFT    28
+#define IIO_IIDSR_SENT_MASK     0x30000000
+#define IIO_IIDSR_ENB_SHIFT     24
+#define IIO_IIDSR_ENB_MASK      0x01000000
+#define IIO_IIDSR_NODE_SHIFT    9
+#define IIO_IIDSR_NODE_MASK     0x000ff700
+#define IIO_IIDSR_PI_ID_SHIFT   8
+#define IIO_IIDSR_PI_ID_MASK    0x00000100
+#define IIO_IIDSR_LVL_SHIFT     0
+#define IIO_IIDSR_LVL_MASK      0x000000ff
+
+/* Xtalk timeout threshhold register (IIO_IXTT) */
+#define IXTT_RRSP_TO_SHFT      55         /* read response timeout */
+#define IXTT_RRSP_TO_MASK      (0x1FULL << IXTT_RRSP_TO_SHFT)
+#define IXTT_RRSP_PS_SHFT      32         /* read responsed TO prescalar */
+#define IXTT_RRSP_PS_MASK      (0x7FFFFFULL << IXTT_RRSP_PS_SHFT)
+#define IXTT_TAIL_TO_SHFT      0          /* tail timeout counter threshold */
+#define IXTT_TAIL_TO_MASK      (0x3FFFFFFULL << IXTT_TAIL_TO_SHFT)
+
+/*
+ * The IO LLP control status register and widget control register
+ */
+
+typedef union hubii_wcr_u {
+        uint64_t      wcr_reg_value;
+        struct {
+         uint64_t      wcr_widget_id:   4,     /* LLP crossbar credit */
+                       wcr_tag_mode:    1,     /* Tag mode */
+                       wcr_rsvd1:       8,     /* Reserved */
+                       wcr_xbar_crd:    3,     /* LLP crossbar credit */
+                       wcr_f_bad_pkt:   1,     /* Force bad llp pkt enable */
+                       wcr_dir_con:     1,     /* widget direct connect */
+                       wcr_e_thresh:    5,     /* elasticity threshold */
+                       wcr_rsvd:       41;     /* unused */
+        } wcr_fields_s;
+} hubii_wcr_t;
+
+#define iwcr_dir_con    wcr_fields_s.wcr_dir_con
+
+/* The structures below are defined to extract and modify the ii
+performance registers */
+
+/* io_perf_sel allows the caller to specify what tests will be
+   performed */
+
+typedef union io_perf_sel {
+        uint64_t perf_sel_reg;
+        struct {
+               uint64_t        perf_ippr0 :  4,
+                               perf_ippr1 :  4,
+                               perf_icct  :  8,
+                               perf_rsvd  : 48;
+        } perf_sel_bits;
+} io_perf_sel_t;
+
+/* io_perf_cnt is to extract the count from the shub registers. Due to
+   hardware problems there is only one counter, not two. */
+
+typedef union io_perf_cnt {
+        uint64_t      perf_cnt;
+        struct {
+               uint64_t        perf_cnt   : 20,
+                               perf_rsvd2 : 12,
+                               perf_rsvd1 : 32;
+        } perf_cnt_bits;
+
+} io_perf_cnt_t;
+
+typedef union iprte_a {
+       uint64_t        entry;
+       struct {
+               uint64_t        i_rsvd_1                  :      3;
+               uint64_t        i_addr                    :     38;
+               uint64_t        i_init                    :      3;
+               uint64_t        i_source                  :      8;
+               uint64_t        i_rsvd                    :      2;
+               uint64_t        i_widget                  :      4;
+               uint64_t        i_to_cnt                  :      5;
+               uint64_t       i_vld                     :      1;
+       } iprte_fields;
+} iprte_a_t;
+
+#endif /* _ASM_IA64_SN_SHUBIO_H */
+
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
new file mode 100644 (file)
index 0000000..1180604
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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) 1992 - 1997, 2000,2002-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/delay.h>
+#include <asm/sn/sn_sal.h>
+#include "ioerror.h"
+#include <asm/sn/addrs.h>
+#include "shubio.h"
+#include <asm/sn/geo.h>
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
+#include <asm/sn/bte.h>
+
+void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
+extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
+                                 int);
+static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep)
+{
+       struct hubdev_info *hubdev_info;
+       struct ia64_sal_retval ret_stuff;
+       nasid_t nasid;
+
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+       hubdev_info = (struct hubdev_info *)arg;
+       nasid = hubdev_info->hdi_nasid;
+       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
+                       (u64) nasid, 0, 0, 0, 0, 0, 0);
+
+       if ((int)ret_stuff.v0)
+               panic("hubii_eint_handler(): Fatal TIO Error");
+
+       if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
+               (void)hubiio_crb_error_handler(hubdev_info);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Free the hub CRB "crbnum" which encountered an error.
+ * Assumption is, error handling was successfully done,
+ * and we now want to return the CRB back to Hub for normal usage.
+ *
+ * In order to free the CRB, all that's needed is to de-allocate it
+ *
+ * Assumption:
+ *      No other processor is mucking around with the hub control register.
+ *      So, upper layer has to single thread this.
+ */
+void hubiio_crb_free(struct hubdev_info *hubdev_info, int crbnum)
+{
+       ii_icrb0_b_u_t icrbb;
+
+       /*
+        * The hardware does NOT clear the mark bit, so it must get cleared
+        * here to be sure the error is not processed twice.
+        */
+       icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hubdev_info->hdi_nasid,
+                                              IIO_ICRB_B(crbnum));
+       icrbb.b_mark = 0;
+       REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICRB_B(crbnum),
+                    icrbb.ii_icrb0_b_regval);
+       /*
+        * Deallocate the register wait till hub indicates it's done.
+        */
+       REMOTE_HUB_S(hubdev_info->hdi_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum));
+       while (REMOTE_HUB_L(hubdev_info->hdi_nasid, IIO_ICDR) & IIO_ICDR_PND)
+               udelay(1);
+
+}
+
+/*
+ * hubiio_crb_error_handler
+ *
+ *     This routine gets invoked when a hub gets an error 
+ *     interrupt. So, the routine is running in interrupt context
+ *     at error interrupt level.
+ * Action:
+ *     It's responsible for identifying ALL the CRBs that are marked
+ *     with error, and process them. 
+ *     
+ *     If you find the CRB that's marked with error, map this to the
+ *     reason it caused error, and invoke appropriate error handler.
+ *
+ *     XXX Be aware of the information in the context register.
+ *
+ * NOTE:
+ *     Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt
+ *     handler can be run on any node. (not necessarily the node 
+ *     corresponding to the hub that encountered error).
+ */
+
+void hubiio_crb_error_handler(struct hubdev_info *hubdev_info)
+{
+       nasid_t nasid;
+       ii_icrb0_a_u_t icrba;   /* II CRB Register A */
+       ii_icrb0_b_u_t icrbb;   /* II CRB Register B */
+       ii_icrb0_c_u_t icrbc;   /* II CRB Register C */
+       ii_icrb0_d_u_t icrbd;   /* II CRB Register D */
+       ii_icrb0_e_u_t icrbe;   /* II CRB Register D */
+       int i;
+       int num_errors = 0;     /* Num of errors handled */
+       ioerror_t ioerror;
+
+       nasid = hubdev_info->hdi_nasid;
+
+       /*
+        * XXX - Add locking for any recovery actions
+        */
+       /*
+        * Scan through all CRBs in the Hub, and handle the errors
+        * in any of the CRBs marked.
+        */
+       for (i = 0; i < IIO_NUM_CRBS; i++) {
+               /* Check this crb entry to see if it is in error. */
+               icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
+
+               if (icrbb.b_mark == 0) {
+                       continue;
+               }
+
+               icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
+
+               IOERROR_INIT(&ioerror);
+
+               /* read other CRB error registers. */
+               icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
+               icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
+               icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
+
+               IOERROR_SETVALUE(&ioerror, errortype, icrbb.b_ecode);
+
+               /* Check if this error is due to BTE operation,
+                * and handle it separately.
+                */
+               if (icrbd.d_bteop ||
+                   ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 ||
+                     icrbb.b_initiator == IIO_ICRB_INIT_BTE1) &&
+                    (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE ||
+                     icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))) {
+
+                       int bte_num;
+
+                       if (icrbd.d_bteop)
+                               bte_num = icrbc.c_btenum;
+                       else    /* b_initiator bit 2 gives BTE number */
+                               bte_num = (icrbb.b_initiator & 0x4) >> 2;
+
+                       hubiio_crb_free(hubdev_info, i);
+
+                       bte_crb_error_handler(nasid_to_cnodeid(nasid), bte_num,
+                                             i, &ioerror, icrbd.d_bteop);
+                       num_errors++;
+                       continue;
+               }
+       }
+}
+
+/*
+ * Function    : hub_error_init
+ * Purpose     : initialize the error handling requirements for a given hub.
+ * Parameters  : cnode, the compact nodeid.
+ * Assumptions : Called only once per hub, either by a local cpu. Or by a
+ *                     remote cpu, when this hub is headless.(cpuless)
+ * Returns     : None
+ */
+void hub_error_init(struct hubdev_info *hubdev_info)
+{
+       if (request_irq(SGI_II_ERROR, (void *)hub_eint_handler, SA_SHIRQ,
+                       "SN_hub_error", (void *)hubdev_info))
+               printk("hub_error_init: Failed to request_irq for 0x%p\n",
+                   hubdev_info);
+       return;
+}
+
+
+/*
+ * Function    : ice_error_init
+ * Purpose     : initialize the error handling requirements for a given tio.
+ * Parameters  : cnode, the compact nodeid.
+ * Assumptions : Called only once per tio.
+ * Returns     : None
+ */
+void ice_error_init(struct hubdev_info *hubdev_info)
+{
+        if (request_irq
+            (SGI_TIO_ERROR, (void *)hub_eint_handler, SA_SHIRQ, "SN_TIO_error",
+             (void *)hubdev_info))
+                printk("ice_error_init: request_irq() error hubdev_info 0x%p\n",
+                       hubdev_info);
+        return;
+}
+
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
new file mode 100644 (file)
index 0000000..abb0f42
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/bootmem.h>
+#include <asm/sn/types.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include "pci/pcibus_provider_defs.h"
+#include "pci/pcidev.h"
+#include "pci/pcibr_provider.h"
+#include "xtalk/xwidgetdev.h"
+#include <asm/sn/geo.h>
+#include "xtalk/hubdev.h"
+#include <asm/sn/io.h>
+#include <asm/sn/simulator.h>
+
+char master_baseio_wid;
+nasid_t master_nasid = INVALID_NASID;  /* Partition Master */
+
+struct slab_info {
+       struct hubdev_info hubdev;
+};
+
+struct brick {
+       moduleid_t id;          /* Module ID of this module        */
+       struct slab_info slab_info[MAX_SLABS + 1];
+};
+
+int sn_ioif_inited = 0;                /* SN I/O infrastructure initialized? */
+
+/*
+ * Retrieve the DMA Flush List given nasid.  This list is needed 
+ * to implement the WAR - Flush DMA data on PIO Reads.
+ */
+static inline uint64_t
+sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
+{
+
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff,
+                       (u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
+                       (u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0,
+                       0);
+       return ret_stuff.v0;
+
+}
+
+/*
+ * Retrieve the hub device info structure for the given nasid.
+ */
+static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
+{
+
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff,
+                       (u64) SN_SAL_IOIF_GET_HUBDEV_INFO,
+                       (u64) handle, (u64) address, 0, 0, 0, 0, 0);
+       return ret_stuff.v0;
+}
+
+/*
+ * Retrieve the pci bus information given the bus number.
+ */
+static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
+{
+
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff,
+                       (u64) SN_SAL_IOIF_GET_PCIBUS_INFO,
+                       (u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0);
+       return ret_stuff.v0;
+}
+
+/*
+ * Retrieve the pci device information given the bus and device|function number.
+ */
+static inline uint64_t
+sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, 
+                       u64 sn_irq_info)
+{
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff,
+                       (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
+                       (u64) segment, (u64) bus_number, (u64) devfn, 
+                       (u64) pci_dev,
+                       sn_irq_info, 0, 0);
+       return ret_stuff.v0;
+}
+
+/*
+ * sn_alloc_pci_sysdata() - This routine allocates a pci controller
+ *     which is expected as the pci_dev and pci_bus sysdata by the Linux
+ *     PCI infrastructure.
+ */
+static inline struct pci_controller *sn_alloc_pci_sysdata(void)
+{
+       struct pci_controller *pci_sysdata;
+
+       pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL);
+       if (!pci_sysdata)
+               BUG();
+
+       memset(pci_sysdata, 0, sizeof(*pci_sysdata));
+       return pci_sysdata;
+}
+
+/*
+ * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
+ *     each node in the system.
+ */
+static void sn_fixup_ionodes(void)
+{
+
+       struct sn_flush_device_list *sn_flush_device_list;
+       struct hubdev_info *hubdev;
+       uint64_t status;
+       uint64_t nasid;
+       int i, widget;
+
+       for (i = 0; i < numionodes; i++) {
+               hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
+               nasid = cnodeid_to_nasid(i);
+               status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
+               if (status)
+                       continue;
+
+               for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++)
+                       hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev;
+
+               if (!hubdev->hdi_flush_nasid_list.widget_p)
+                       continue;
+
+               hubdev->hdi_flush_nasid_list.widget_p =
+                   kmalloc((HUB_WIDGET_ID_MAX + 1) *
+                           sizeof(struct sn_flush_device_list *), GFP_KERNEL);
+
+               memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0,
+                      (HUB_WIDGET_ID_MAX + 1) *
+                      sizeof(struct sn_flush_device_list *));
+
+               for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
+                       sn_flush_device_list = kmalloc(DEV_PER_WIDGET *
+                                                      sizeof(struct
+                                                             sn_flush_device_list),
+                                                      GFP_KERNEL);
+                       memset(sn_flush_device_list, 0x0,
+                              DEV_PER_WIDGET *
+                              sizeof(struct sn_flush_device_list));
+
+                       status =
+                           sal_get_widget_dmaflush_list(nasid, widget,
+                                                        (uint64_t)
+                                                        __pa
+                                                        (sn_flush_device_list));
+                       if (status) {
+                               kfree(sn_flush_device_list);
+                               continue;
+                       }
+
+                       hubdev->hdi_flush_nasid_list.widget_p[widget] =
+                           sn_flush_device_list;
+               }
+
+               if (!(i & 1))
+                       hub_error_init(hubdev);
+               else
+                       ice_error_init(hubdev);
+       }
+
+}
+
+/*
+ * sn_pci_fixup_slot() - This routine sets up a slot's resources
+ * consistent with the Linux PCI abstraction layer.  Resources acquired
+ * from our PCI provider include PIO maps to BAR space and interrupt
+ * objects.
+ */
+static void sn_pci_fixup_slot(struct pci_dev *dev)
+{
+       int idx;
+       int segment = 0;
+       uint64_t size;
+       struct sn_irq_info *sn_irq_info;
+       struct pci_dev *host_pci_dev;
+       int status = 0;
+
+       SN_PCIDEV_INFO(dev) = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+       if (SN_PCIDEV_INFO(dev) <= 0)
+               BUG();          /* Cannot afford to run out of memory */
+       memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info));
+
+       sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+       if (sn_irq_info <= 0)
+               BUG();          /* Cannot afford to run out of memory */
+       memset(sn_irq_info, 0, sizeof(struct sn_irq_info));
+
+       /* Call to retrieve pci device information needed by kernel. */
+       status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, 
+                                    dev->devfn,
+                                    (u64) __pa(SN_PCIDEV_INFO(dev)),
+                                    (u64) __pa(sn_irq_info));
+       if (status)
+               BUG();          /* Cannot get platform pci device information information */
+
+       /* Copy over PIO Mapped Addresses */
+       for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
+               unsigned long start, end, addr;
+
+               if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx])
+                       continue;
+
+               start = dev->resource[idx].start;
+               end = dev->resource[idx].end;
+               size = end - start;
+               addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx];
+               addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
+               dev->resource[idx].start = addr;
+               dev->resource[idx].end = addr + size;
+               if (dev->resource[idx].flags & IORESOURCE_IO)
+                       dev->resource[idx].parent = &ioport_resource;
+               else
+                       dev->resource[idx].parent = &iomem_resource;
+       }
+
+       /* set up host bus linkages */
+       host_pci_dev =
+           pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32,
+                         SN_PCIDEV_INFO(dev)->
+                         pdi_slot_host_handle & 0xffffffff);
+       SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
+           SN_PCIDEV_INFO(host_pci_dev);
+       SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
+       SN_PCIDEV_INFO(dev)->pdi_pcibus_info = SN_PCIBUS_BUSSOFT(dev->bus);
+
+       /* Only set up IRQ stuff if this device has a host bus context */
+       if (SN_PCIDEV_BUSSOFT(dev) && sn_irq_info->irq_irq) {
+               SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
+               dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
+               sn_irq_fixup(dev, sn_irq_info);
+       }
+}
+
+/*
+ * sn_pci_controller_fixup() - This routine sets up a bus's resources
+ * consistent with the Linux PCI abstraction layer.
+ */
+static void sn_pci_controller_fixup(int segment, int busnum)
+{
+       int status = 0;
+       int nasid, cnode;
+       struct pci_bus *bus;
+       struct pci_controller *controller;
+       struct pcibus_bussoft *prom_bussoft_ptr;
+       struct hubdev_info *hubdev_info;
+       void *provider_soft;
+
+       status =
+           sal_get_pcibus_info((u64) segment, (u64) busnum,
+                               (u64) ia64_tpa(&prom_bussoft_ptr));
+       if (status > 0) {
+               return;         /* bus # does not exist */
+       }
+
+       prom_bussoft_ptr = __va(prom_bussoft_ptr);
+       controller = sn_alloc_pci_sysdata();
+       /* controller non-zero is BUG'd in sn_alloc_pci_sysdata */
+
+       bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+       if (bus == NULL) {
+               return;         /* error, or bus already scanned */
+       }
+
+       /*
+        * Per-provider fixup.  Copies the contents from prom to local
+        * area and links SN_PCIBUS_BUSSOFT().
+        *
+        * Note:  Provider is responsible for ensuring that prom_bussoft_ptr
+        * represents an asic-type that it can handle.
+        */
+
+       if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) {
+               return;         /* no further fixup necessary */
+       }
+
+       provider_soft = pcibr_bus_fixup(prom_bussoft_ptr);
+       if (provider_soft == NULL) {
+               return;         /* fixup failed or not applicable */
+       }
+
+       /*
+        * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
+        * after this point.
+        */
+
+       PCI_CONTROLLER(bus) = controller;
+       SN_PCIBUS_BUSSOFT(bus) = provider_soft;
+
+       nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
+       cnode = nasid_to_cnodeid(nasid);
+       hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
+       SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
+           &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
+}
+
+/*
+ * Ugly hack to get PCI setup until we have a proper ACPI namespace.
+ */
+
+#define PCI_BUSES_TO_SCAN 256
+
+static int __init sn_pci_init(void)
+{
+       int i = 0;
+       struct pci_dev *pci_dev = NULL;
+       extern void sn_init_cpei_timer(void);
+#ifdef CONFIG_PROC_FS
+       extern void register_sn_procfs(void);
+#endif
+
+       if (!ia64_platform_is("sn2") || IS_RUNNING_ON_SIMULATOR())
+               return 0;
+
+       /*
+        * This is needed to avoid bounce limit checks in the blk layer
+        */
+       ia64_max_iommu_merge_mask = ~PAGE_MASK;
+       sn_fixup_ionodes();
+       sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL);
+       if (sn_irq <= 0)
+               BUG();          /* Canno afford to run out of memory. */
+       memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS);
+
+       sn_init_cpei_timer();
+
+#ifdef CONFIG_PROC_FS
+       register_sn_procfs();
+#endif
+
+       for (i = 0; i < PCI_BUSES_TO_SCAN; i++) {
+               sn_pci_controller_fixup(0, i);
+       }
+
+       /*
+        * Generic Linux PCI Layer has created the pci_bus and pci_dev 
+        * structures - time for us to add our SN PLatform specific 
+        * information.
+        */
+
+       while ((pci_dev =
+               pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+               sn_pci_fixup_slot(pci_dev);
+       }
+
+       sn_ioif_inited = 1;     /* sn I/O infrastructure now initialized */
+
+       return 0;
+}
+
+/*
+ * hubdev_init_node() - Creates the HUB data structure and link them to it's 
+ *     own NODE specific data area.
+ */
+void hubdev_init_node(nodepda_t * npda, cnodeid_t node)
+{
+
+       struct hubdev_info *hubdev_info;
+
+       if (node >= numnodes)   /* Headless/memless IO nodes */
+               hubdev_info =
+                   (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(0),
+                                                            sizeof(struct
+                                                                   hubdev_info));
+       else
+               hubdev_info =
+                   (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(node),
+                                                            sizeof(struct
+                                                                   hubdev_info));
+       npda->pdinfo = (void *)hubdev_info;
+
+}
+
+geoid_t
+cnodeid_get_geoid(cnodeid_t cnode)
+{
+
+       struct hubdev_info *hubdev;
+
+       hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
+       return hubdev->hdi_geoid;
+
+}
+
+subsys_initcall(sn_pci_init);
diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c
new file mode 100644 (file)
index 0000000..a98d674
--- /dev/null
@@ -0,0 +1,75 @@
+/* 
+ * 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) 2000-2003 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/delay.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>
+
+/**
+ * sn_io_addr - convert an in/out port to an i/o address
+ * @port: port to convert
+ *
+ * Legacy in/out instructions are converted to ld/st instructions
+ * on IA64.  This routine will convert a port number into a valid 
+ * SN i/o address.  Used by sn_in*() and sn_out*().
+ */
+void *sn_io_addr(unsigned long port)
+{
+       if (!IS_RUNNING_ON_SIMULATOR()) {
+               /* On sn2, legacy I/O ports don't point at anything */
+               if (port < (64 * 1024))
+                       return NULL;
+               return ((void *)(port | __IA64_UNCACHED_OFFSET));
+       } else {
+               /* but the simulator uses them... */
+               unsigned long io_base;
+               unsigned long addr;
+
+               /*
+                * word align port, but need more than 10 bits
+                * for accessing registers in bedrock local block
+                * (so we don't do port&0xfff)
+                */
+               if ((port >= 0x1f0 && port <= 0x1f7) ||
+                   port == 0x3f6 || port == 0x3f7) {
+                       io_base = (0xc000000fcc000000UL |
+                                  ((unsigned long)get_nasid() << 38));
+                       addr = io_base | ((port >> 2) << 12) | (port & 0xfff);
+               } else {
+                       addr = __ia64_get_io_port_base() | ((port >> 2) << 2);
+               }
+               return (void *)addr;
+       }
+}
+
+EXPORT_SYMBOL(sn_io_addr);
+
+/**
+ * __sn_mmiowb - I/O space memory barrier
+ *
+ * See include/asm-ia64/io.h and Documentation/DocBook/deviceiobook.tmpl
+ * for details.
+ *
+ * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear.
+ * See PV 871084 for details about the WAR about zero value.
+ *
+ */
+void __sn_mmiowb(void)
+{
+       while ((((volatile unsigned long)(*pda->pio_write_status_addr)) &
+               SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) !=
+              SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK)
+               cpu_relax();
+}
+
+EXPORT_SYMBOL(__sn_mmiowb);
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
new file mode 100644 (file)
index 0000000..8a810d3
--- /dev/null
@@ -0,0 +1,652 @@
+/* 
+ * 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 Silicon Graphics, Inc. All rights reserved.
+ *
+ * SGI Altix topology and hardware performance monitoring API.
+ * Mark Goodwin <markgw@sgi.com>. 
+ *
+ * Creates /proc/sgi_sn/sn_topology (read-only) to export
+ * info about Altix nodes, routers, CPUs and NumaLink
+ * interconnection/topology.
+ *
+ * Also creates a dynamic misc device named "sn_hwperf"
+ * that supports an ioctl interface to call down into SAL
+ * to discover hw objects, topology and to read/write
+ * memory mapped registers, e.g. for performance monitoring.
+ * The "sn_hwperf" device is registered only after the procfs
+ * file is first opened, i.e. only if/when it's needed. 
+ *
+ * This API is used by SGI Performance Co-Pilot and other
+ * tools, see http://oss.sgi.com/projects/pcp
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/seq_file.h>
+#include <linux/miscdevice.h>
+#include <linux/cpumask.h>
+#include <linux/smp_lock.h>
+#include <asm/processor.h>
+#include <asm/topology.h>
+#include <asm/smp.h>
+#include <asm/semaphore.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <asm-ia64/sal.h>
+#include <asm-ia64/sn/sn_sal.h>
+#include <asm-ia64/sn/sn2/sn_hwperf.h>
+
+static void *sn_hwperf_salheap = NULL;
+static int sn_hwperf_obj_cnt = 0;
+static nasid_t sn_hwperf_master_nasid = INVALID_NASID;
+static int sn_hwperf_init(void);
+static DECLARE_MUTEX(sn_hwperf_init_mutex);
+
+static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret)
+{
+       int e;
+       u64 sz;
+       struct sn_hwperf_object_info *objbuf = NULL;
+
+       if ((e = sn_hwperf_init()) < 0) {
+               printk("sn_hwperf_init failed: err %d\n", e);
+               goto out;
+       }
+
+       sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info);
+       if ((objbuf = (struct sn_hwperf_object_info *) vmalloc(sz)) == NULL) {
+               printk("sn_hwperf_enum_objects: vmalloc(%d) failed\n", (int)sz);
+               e = -ENOMEM;
+               goto out;
+       }
+
+       e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, SN_HWPERF_ENUM_OBJECTS,
+               0, sz, (u64) objbuf, 0, 0, NULL);
+       if (e != SN_HWPERF_OP_OK) {
+               e = -EINVAL;
+               vfree(objbuf);
+       }
+
+out:
+       *nobj = sn_hwperf_obj_cnt;
+       *ret = objbuf;
+       return e;
+}
+
+static int sn_hwperf_geoid_to_cnode(char *location)
+{
+       int cnode;
+       int mod, slot, slab;
+       int cmod, cslot, cslab;
+
+       if (sscanf(location, "%03dc%02d#%d", &mod, &slot, &slab) != 3)
+               return -1;
+       for (cnode = 0; cnode < numnodes; cnode++) {
+               /* XXX: need a better way than this ... */
+               if (sscanf(NODEPDA(cnode)->hwg_node_name,
+                  "hw/module/%03dc%02d/slab/%d", &cmod, &cslot, &cslab) == 3) {
+                       if (mod == cmod && slot == cslot && slab == cslab)
+                               break;
+               }
+       }
+
+       return cnode < numnodes ? cnode : -1;
+}
+
+static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj)
+{
+       if (!obj->sn_hwp_this_part)
+               return -1;
+       return sn_hwperf_geoid_to_cnode(obj->location);
+}
+
+static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj,
+                               struct sn_hwperf_object_info *objs)
+{
+       int ordinal;
+       struct sn_hwperf_object_info *p;
+
+       for (ordinal=0, p=objs; p != obj; p++) {
+               if (SN_HWPERF_FOREIGN(p))
+                       continue;
+               if (p->location[3] == obj->location[3])
+                       ordinal++;
+       }
+
+       return ordinal;
+}
+
+#ifndef MODULE_IOBRICK 
+/* this will be available when ioif TIO support is added */
+#define MODULE_IOBRICK (MODULE_OPUSBRICK+1)
+#endif
+
+static const char *sn_hwperf_get_brickname(struct sn_hwperf_object_info *obj,
+                               struct sn_hwperf_object_info *objs, int *ordinal)
+{
+       int i;
+       const char *objtype = NULL;
+
+       for (i=0; i < MAX_BRICK_TYPES; i++) {
+               if (brick_types[i] != obj->location[3])
+                       continue;
+               switch (i) {
+               case MODULE_CBRICK:
+                   objtype = "node";
+                   *ordinal = sn_hwperf_obj_to_cnode(obj); /* cnodeid */
+                   break;
+
+               case MODULE_RBRICK:
+                   objtype = "router";
+                   *ordinal = sn_hwperf_generic_ordinal(obj, objs);
+                   break;
+
+               case MODULE_IOBRICK:
+                   objtype = "ionode";
+                   *ordinal = sn_hwperf_generic_ordinal(obj, objs);
+                   break;
+               }
+               break;
+       }
+
+       if (i == MAX_BRICK_TYPES) {
+               objtype = "other";
+               *ordinal = sn_hwperf_generic_ordinal(obj, objs);
+       }
+
+       return objtype;
+}
+
+static int sn_topology_show(struct seq_file *s, void *d)
+{
+       int sz;
+       int pt;
+       int e;
+       int i;
+       int j;
+       const char *brickname;
+       int ordinal;
+       cpumask_t cpumask;
+       char slice;
+       struct cpuinfo_ia64 *c;
+       struct sn_hwperf_port_info *ptdata;
+       struct sn_hwperf_object_info *p;
+       struct sn_hwperf_object_info *obj = d;  /* this object */
+       struct sn_hwperf_object_info *objs = s->private; /* all objects */
+
+       if (obj == objs) {
+               seq_printf(s, "# sn_topology version 1\n");
+               seq_printf(s, "# objtype ordinal location partition"
+                       " [attribute value [, ...]]\n");
+       }
+
+       if (SN_HWPERF_FOREIGN(obj)) {
+               /* private in another partition: not interesting */
+               return 0;
+       }
+
+       for (i = 0; obj->name[i]; i++) {
+               if (obj->name[i] == ' ')
+                       obj->name[i] = '_';
+       }
+
+       brickname = sn_hwperf_get_brickname(obj, objs, &ordinal);
+       seq_printf(s, "%s %d %s %s asic %s", brickname, ordinal, obj->location,
+               obj->sn_hwp_this_part ? "local" : "shared", obj->name);
+
+       if (obj->location[3] != 'c')
+               seq_putc(s, '\n');
+       else {
+               seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));
+               for (i=0; i < numnodes; i++) {
+                       seq_printf(s, i ? ":%d" : ", dist %d",
+                               node_distance(ordinal, i));
+               }
+               seq_putc(s, '\n');
+
+               /*
+                * CPUs on this node
+                */
+               cpumask = node_to_cpumask(ordinal);
+               for_each_online_cpu(i) {
+                       if (cpu_isset(i, cpumask)) {
+                               slice = 'a' + cpuid_to_slice(i);
+                               c = cpu_data(i);
+                               seq_printf(s, "cpu %d %s%c local"
+                                       " freq %luMHz, arch ia64",
+                                       i, obj->location, slice,
+                                       c->proc_freq / 1000000);
+                               for_each_online_cpu(j) {
+                                       seq_printf(s, j ? ":%d" : ", dist %d",
+                                               node_distance(
+                                                   cpuid_to_cnodeid(i),
+                                                   cpuid_to_cnodeid(j)));
+                               }
+                               seq_putc(s, '\n');
+                       }
+               }
+       }
+
+       if (obj->ports) {
+               /*
+                * numalink ports
+                */
+               sz = obj->ports * sizeof(struct sn_hwperf_port_info);
+               if ((ptdata = vmalloc(sz)) == NULL)
+                       return -ENOMEM;
+               e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+                                     SN_HWPERF_ENUM_PORTS, obj->id, sz,
+                                     (u64) ptdata, 0, 0, NULL);
+               if (e != SN_HWPERF_OP_OK)
+                       return -EINVAL;
+               for (ordinal=0, p=objs; p != obj; p++) {
+                       if (!SN_HWPERF_FOREIGN(p))
+                               ordinal += p->ports;
+               }
+               for (pt = 0; pt < obj->ports; pt++) {
+                       for (p = objs, i = 0; i < sn_hwperf_obj_cnt; i++, p++) {
+                               if (ptdata[pt].conn_id == p->id) {
+                                       break;
+                               }
+                       }
+                       if (i >= sn_hwperf_obj_cnt)
+                               continue;
+                       seq_printf(s, "numalink %d %s-%d",
+                           ordinal+pt, obj->location, ptdata[pt].port);
+
+                       if (obj->sn_hwp_this_part && p->sn_hwp_this_part)
+                               /* both ends local to this partition */
+                               seq_puts(s, " local");
+                       else if (!obj->sn_hwp_this_part && !p->sn_hwp_this_part)
+                               /* both ends of the link in foreign partiton */
+                               seq_puts(s, " foreign");
+                       else
+                               /* link straddles a partition */
+                               seq_puts(s, " shared");
+
+                       /*
+                        * Unlikely, but strictly should query the LLP config
+                        * registers because an NL4R can be configured to run
+                        * NL3 protocol, even when not talking to an NL3 router.
+                        * Ditto for node-node.
+                        */
+                       seq_printf(s, " endpoint %s-%d, protocol %s\n",
+                               p->location, ptdata[pt].conn_port,
+                               strcmp(obj->name, "NL3Router") == 0 ||
+                               strcmp(p->name, "NL3Router") == 0 ?
+                               "LLP3" : "LLP4");
+               }
+               vfree(ptdata);
+       }
+
+       return 0;
+}
+
+static void *sn_topology_start(struct seq_file *s, loff_t * pos)
+{
+       struct sn_hwperf_object_info *objs = s->private;
+
+       if (*pos < sn_hwperf_obj_cnt)
+               return (void *)(objs + *pos);
+
+       return NULL;
+}
+
+static void *sn_topology_next(struct seq_file *s, void *v, loff_t * pos)
+{
+       ++*pos;
+       return sn_topology_start(s, pos);
+}
+
+static void sn_topology_stop(struct seq_file *m, void *v)
+{
+       return;
+}
+
+/*
+ * /proc/sgi_sn/sn_topology, read-only using seq_file
+ */
+static struct seq_operations sn_topology_seq_ops = {
+       .start = sn_topology_start,
+       .next = sn_topology_next,
+       .stop = sn_topology_stop,
+       .show = sn_topology_show
+};
+
+struct sn_hwperf_op_info {
+       u64 op;
+       struct sn_hwperf_ioctl_args *a;
+       void *p;
+       int *v0;
+       int ret;
+};
+
+static void sn_hwperf_call_sal(void *info)
+{
+       struct sn_hwperf_op_info *op_info = info;
+       int r;
+
+       r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op_info->op,
+                     op_info->a->arg, op_info->a->sz,
+                     (u64) op_info->p, 0, 0, op_info->v0);
+       op_info->ret = r;
+}
+
+static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info)
+{
+       u32 cpu;
+       u32 use_ipi;
+       int r = 0;
+       cpumask_t save_allowed;
+       
+       cpu = (op_info->a->arg & SN_HWPERF_ARG_CPU_MASK) >> 32;
+       use_ipi = op_info->a->arg & SN_HWPERF_ARG_USE_IPI_MASK;
+       op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;
+
+       if (cpu != SN_HWPERF_ARG_ANY_CPU) {
+               if (cpu >= num_online_cpus() || !cpu_online(cpu)) {
+                       r = -EINVAL;
+                       goto out;
+               }
+       }
+
+       if (cpu == SN_HWPERF_ARG_ANY_CPU || cpu == get_cpu()) {
+               /* don't care, or already on correct cpu */
+               sn_hwperf_call_sal(op_info);
+       }
+       else {
+               if (use_ipi) {
+                       /* use an interprocessor interrupt to call SAL */
+                       smp_call_function_single(cpu, sn_hwperf_call_sal,
+                               op_info, 1, 1);
+               }
+               else {
+                       /* migrate the task before calling SAL */ 
+                       save_allowed = current->cpus_allowed;
+                       set_cpus_allowed(current, cpumask_of_cpu(cpu));
+                       sn_hwperf_call_sal(op_info);
+                       set_cpus_allowed(current, save_allowed);
+               }
+       }
+       r = op_info->ret;
+
+out:
+       return r;
+}
+
+/*
+ * ioctl for "sn_hwperf" misc device
+ */
+static int
+sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
+{
+       struct sn_hwperf_ioctl_args a;
+       struct cpuinfo_ia64 *cdata;
+       struct sn_hwperf_object_info *objs;
+       struct sn_hwperf_object_info *cpuobj;
+       struct sn_hwperf_op_info op_info;
+       void *p = NULL;
+       int nobj;
+       char slice;
+       int node;
+       int r;
+       int v0;
+       int i;
+       int j;
+
+       unlock_kernel();
+
+       /* only user requests are allowed here */
+       if ((op & SN_HWPERF_OP_MASK) < 10) {
+               r = -EINVAL;
+               goto error;
+       }
+       r = copy_from_user(&a, (const void *)arg,
+               sizeof(struct sn_hwperf_ioctl_args));
+       if (r != 0) {
+               r = -EFAULT;
+               goto error;
+       }
+
+       /*
+        * Allocate memory to hold a kernel copy of the user buffer. The
+        * buffer contents are either copied in or out (or both) of user
+        * space depending on the flags encoded in the requested operation.
+        */
+       if (a.ptr) {
+               p = vmalloc(a.sz);
+               if (!p) {
+                       r = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       if (op & SN_HWPERF_OP_MEM_COPYIN) {
+               r = copy_from_user(p, (const void *)a.ptr, a.sz);
+               if (r != 0) {
+                       r = -EFAULT;
+                       goto error;
+               }
+       }
+
+       switch (op) {
+       case SN_HWPERF_GET_CPU_INFO:
+               if (a.sz == sizeof(u64)) {
+                       /* special case to get size needed */
+                       *(u64 *) p = (u64) num_online_cpus() *
+                               sizeof(struct sn_hwperf_object_info);
+               } else
+               if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) {
+                       r = -ENOMEM;
+                       goto error;
+               } else
+               if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
+                       memset(p, 0, a.sz);
+                       for (i = 0; i < nobj; i++) {
+                               node = sn_hwperf_obj_to_cnode(objs + i);
+                               for_each_online_cpu(j) {
+                                       if (node != cpu_to_node(j))
+                                               continue;
+                                       cpuobj = (struct sn_hwperf_object_info *) p + j;
+                                       slice = 'a' + cpuid_to_slice(j);
+                                       cdata = cpu_data(j);
+                                       cpuobj->id = j;
+                                       snprintf(cpuobj->name,
+                                                sizeof(cpuobj->name),
+                                                "CPU %luMHz %s",
+                                                cdata->proc_freq / 1000000,
+                                                cdata->vendor);
+                                       snprintf(cpuobj->location,
+                                                sizeof(cpuobj->location),
+                                                "%s%c", objs[i].location,
+                                                slice);
+                               }
+                       }
+
+                       vfree(objs);
+               }
+               break;
+
+       case SN_HWPERF_GET_NODE_NASID:
+               if (a.sz != sizeof(u64) ||
+                  (node = a.arg) < 0 || node >= numnodes) {
+                       r = -EINVAL;
+                       goto error;
+               }
+               *(u64 *)p = (u64)cnodeid_to_nasid(node);
+               break;
+
+       case SN_HWPERF_GET_OBJ_NODE:
+               if (a.sz != sizeof(u64) || a.arg < 0) {
+                       r = -EINVAL;
+                       goto error;
+               }
+               if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
+                       if (a.arg >= nobj) {
+                               r = -EINVAL;
+                               vfree(objs);
+                               goto error;
+                       }
+                       if (objs[(i = a.arg)].id != a.arg) {
+                               for (i = 0; i < nobj; i++) {
+                                       if (objs[i].id == a.arg)
+                                               break;
+                               }
+                       }
+                       if (i == nobj) {
+                               r = -EINVAL;
+                               vfree(objs);
+                               goto error;
+                       }
+                       *(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);
+                       vfree(objs);
+               }
+               break;
+
+       case SN_HWPERF_GET_MMRS:
+       case SN_HWPERF_SET_MMRS:
+       case SN_HWPERF_OBJECT_DISTANCE:
+               op_info.p = p;
+               op_info.a = &a;
+               op_info.v0 = &v0;
+               op_info.op = op;
+               r = sn_hwperf_op_cpu(&op_info);
+               break;
+
+       default:
+               /* all other ops are a direct SAL call */
+               r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op,
+                             a.arg, a.sz, (u64) p, 0, 0, &v0);
+               a.v0 = v0;
+               break;
+       }
+
+       if (op & SN_HWPERF_OP_MEM_COPYOUT) {
+               r = copy_to_user((void *)a.ptr, p, a.sz);
+               if (r != 0) {
+                       r = -EFAULT;
+                       goto error;
+               }
+       }
+
+error:
+       if (p)
+               vfree(p);
+
+       lock_kernel();
+       return r;
+}
+
+static struct file_operations sn_hwperf_fops = {
+       .ioctl = sn_hwperf_ioctl,
+};
+
+static struct miscdevice sn_hwperf_dev = {
+       MISC_DYNAMIC_MINOR,
+       "sn_hwperf",
+       &sn_hwperf_fops
+};
+
+static int sn_hwperf_init(void)
+{
+       u64 v;
+       int salr;
+       int e = 0;
+
+       /* single threaded, once-only initialization */
+       down(&sn_hwperf_init_mutex);
+       if (sn_hwperf_salheap) {
+               up(&sn_hwperf_init_mutex);
+               return e;
+       }
+
+       /*
+        * The PROM code needs a fixed reference node. For convenience the
+        * same node as the console I/O is used.
+        */
+       sn_hwperf_master_nasid = (nasid_t) ia64_sn_get_console_nasid();
+
+       /*
+        * Request the needed size and install the PROM scratch area.
+        * The PROM keeps various tracking bits in this memory area.
+        */
+       salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+                                (u64) SN_HWPERF_GET_HEAPSIZE, 0,
+                                (u64) sizeof(u64), (u64) &v, 0, 0, NULL);
+       if (salr != SN_HWPERF_OP_OK) {
+               e = -EINVAL;
+               goto out;
+       }
+
+       if ((sn_hwperf_salheap = vmalloc(v)) == NULL) {
+               e = -ENOMEM;
+               goto out;
+       }
+       salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+                                SN_HWPERF_INSTALL_HEAP, 0, v,
+                                (u64) sn_hwperf_salheap, 0, 0, NULL);
+       if (salr != SN_HWPERF_OP_OK) {
+               e = -EINVAL;
+               goto out;
+       }
+
+       salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,
+                                SN_HWPERF_OBJECT_COUNT, 0,
+                                sizeof(u64), (u64) &v, 0, 0, NULL);
+       if (salr != SN_HWPERF_OP_OK) {
+               e = -EINVAL;
+               goto out;
+       }
+       sn_hwperf_obj_cnt = (int)v;
+
+out:
+       if (e < 0 && sn_hwperf_salheap) {
+               vfree(sn_hwperf_salheap);
+               sn_hwperf_salheap = NULL;
+               sn_hwperf_obj_cnt = 0;
+       }
+
+       if (!e) {
+               /*
+                * Register a dynamic misc device for ioctl. Platforms
+                * supporting hotplug will create /dev/sn_hwperf, else
+                * user can to look up the minor number in /proc/misc.
+                */
+               if ((e = misc_register(&sn_hwperf_dev)) != 0) {
+                       printk(KERN_ERR "sn_hwperf_init: misc register "
+                              "for \"sn_hwperf\" failed, err %d\n", e);
+               }
+       }
+
+       up(&sn_hwperf_init_mutex);
+       return e;
+}
+
+int sn_topology_open(struct inode *inode, struct file *file)
+{
+       int e;
+       struct seq_file *seq;
+       struct sn_hwperf_object_info *objbuf;
+       int nobj;
+
+       if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {
+               e = seq_open(file, &sn_topology_seq_ops);
+               seq = file->private_data;
+               seq->private = objbuf;
+       }
+
+       return e;
+}
+
+int sn_topology_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+
+       if (seq->private)
+               vfree(seq->private);
+       return seq_release(inode, file);
+}
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
new file mode 100644 (file)
index 0000000..71f311d
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * 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) 2000,2002-2004 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Routines for PCI DMA mapping.  See Documentation/DMA-mapping.txt for
+ * a description of how these routines should be used.
+ */
+
+#include <linux/module.h>
+#include <asm/sn/sn_sal.h>
+#include "pci/pcibus_provider_defs.h"
+#include "pci/pcidev.h"
+#include "pci/pcibr_provider.h"
+
+void sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+                    int direction);
+
+/**
+ * sn_pci_alloc_consistent - allocate memory for coherent DMA
+ * @hwdev: device to allocate for
+ * @size: size of the region
+ * @dma_handle: DMA (bus) address
+ *
+ * pci_alloc_consistent() returns a pointer to a memory region suitable for
+ * coherent DMA traffic to/from a PCI device.  On SN platforms, this means
+ * that @dma_handle will have the %PCIIO_DMA_CMD flag set.
+ *
+ * This interface is usually used for "command" streams (e.g. the command
+ * queue for a SCSI controller).  See Documentation/DMA-mapping.txt for
+ * more information.
+ *
+ * Also known as platform_pci_alloc_consistent() by the IA64 machvec code.
+ */
+void *sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                             dma_addr_t * dma_handle)
+{
+       void *cpuaddr;
+       unsigned long phys_addr;
+       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev);
+
+       if (bussoft == NULL) {
+               return NULL;
+       }
+
+       if (! IS_PCI_BRIDGE_ASIC(bussoft->bs_asic_type)) {
+               return NULL;            /* unsupported asic type */
+       }
+
+       /*
+        * Allocate the memory.
+        * FIXME: We should be doing alloc_pages_node for the node closest
+        *        to the PCI device.
+        */
+       if (!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size))))
+               return NULL;
+
+       memset(cpuaddr, 0x0, size);
+
+       /* physical addr. of the memory we just got */
+       phys_addr = __pa(cpuaddr);
+
+       /*
+        * 64 bit address translations should never fail.
+        * 32 bit translations can fail if there are insufficient mapping
+        *   resources.
+        */
+
+       *dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size, SN_PCIDMA_CONSISTENT);
+       if (!*dma_handle) {
+               printk(KERN_ERR
+                      "sn_pci_alloc_consistent():  failed  *dma_handle = 0x%lx hwdev->dev.coherent_dma_mask = 0x%lx \n",
+                      *dma_handle, hwdev->dev.coherent_dma_mask);
+               free_pages((unsigned long)cpuaddr, get_order(size));
+               return NULL;
+       }
+
+       return cpuaddr;
+}
+
+/**
+ * sn_pci_free_consistent - free memory associated with coherent DMAable region
+ * @hwdev: device to free for
+ * @size: size to free
+ * @vaddr: kernel virtual address to free
+ * @dma_handle: DMA address associated with this region
+ *
+ * Frees the memory allocated by pci_alloc_consistent().  Also known
+ * as platform_pci_free_consistent() by the IA64 machvec code.
+ */
+void
+sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+                      dma_addr_t dma_handle)
+{
+       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev);
+
+       if (! bussoft) {
+               return;
+       }
+
+       pcibr_dma_unmap(pcidev_info, dma_handle, 0);
+       free_pages((unsigned long)vaddr, get_order(size));
+}
+
+/**
+ * sn_pci_map_sg - map a scatter-gather list for DMA
+ * @hwdev: device to map for
+ * @sg: scatterlist to map
+ * @nents: number of entries
+ * @direction: direction of the DMA transaction
+ *
+ * Maps each entry of @sg for DMA.  Also known as platform_pci_map_sg by the
+ * IA64 machvec code.
+ */
+int
+sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+             int direction)
+{
+
+       int i;
+       unsigned long phys_addr;
+       struct scatterlist *saved_sg = sg;
+       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev);
+
+       /* can't go anywhere w/o a direction in life */
+       if (direction == PCI_DMA_NONE)
+               BUG();
+
+       if (! bussoft) {
+               return 0;
+       }
+
+       /* SN cannot support DMA addresses smaller than 32 bits. */
+       if (hwdev->dma_mask < 0x7fffffff)
+               return 0;
+
+       /*
+        * Setup a DMA address for each entry in the
+        * scatterlist.
+        */
+       for (i = 0; i < nents; i++, sg++) {
+               phys_addr =
+                   __pa((unsigned long)page_address(sg->page) + sg->offset);
+               sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr, sg->length, 0);
+
+               if (!sg->dma_address) {
+                       printk(KERN_ERR "sn_pci_map_sg: Unable to allocate "
+                              "anymore page map entries.\n");
+                       /*
+                        * We will need to free all previously allocated entries.
+                        */
+                       if (i > 0) {
+                               sn_pci_unmap_sg(hwdev, saved_sg, i, direction);
+                       }
+                       return (0);
+               }
+
+               sg->dma_length = sg->length;
+       }
+
+       return nents;
+
+}
+
+/**
+ * sn_pci_unmap_sg - unmap a scatter-gather list
+ * @hwdev: device to unmap
+ * @sg: scatterlist to unmap
+ * @nents: number of scatterlist entries
+ * @direction: DMA direction
+ *
+ * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
+ * concerning calls here are the same as for pci_unmap_single() below.  Also
+ * known as sn_pci_unmap_sg() by the IA64 machvec code.
+ */
+void
+sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+               int direction)
+{
+       int i;
+       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev);
+
+       /* can't go anywhere w/o a direction in life */
+       if (direction == PCI_DMA_NONE)
+               BUG();
+
+       if (! bussoft) {
+               return;
+       }
+
+       for (i = 0; i < nents; i++, sg++) {
+               pcibr_dma_unmap(pcidev_info, sg->dma_address, direction);
+               sg->dma_address = (dma_addr_t) NULL;
+               sg->dma_length = 0;
+       }
+}
+
+/**
+ * sn_pci_map_single - map a single region for DMA
+ * @hwdev: device to map for
+ * @ptr: kernel virtual address of the region to map
+ * @size: size of the region
+ * @direction: DMA direction
+ *
+ * Map the region pointed to by @ptr for DMA and return the
+ * DMA address.   Also known as platform_pci_map_single() by
+ * the IA64 machvec code.
+ *
+ * We map this to the one step pcibr_dmamap_trans interface rather than
+ * the two step pcibr_dmamap_alloc/pcibr_dmamap_addr because we have
+ * no way of saving the dmamap handle from the alloc to later free
+ * (which is pretty much unacceptable).
+ *
+ * TODO: simplify our interface;
+ *       get rid of dev_desc and vhdl (seems redundant given a pci_dev);
+ *       figure out how to save dmamap handle so can use two step.
+ */
+dma_addr_t
+sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
+{
+       dma_addr_t dma_addr;
+       unsigned long phys_addr;
+       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev);
+
+       if (direction == PCI_DMA_NONE)
+               BUG();
+
+       if (bussoft == NULL) {
+               return 0;
+       }
+
+       if (! IS_PCI_BRIDGE_ASIC(bussoft->bs_asic_type)) {
+               return 0;               /* unsupported asic type */
+       }
+
+       /* SN cannot support DMA addresses smaller than 32 bits. */
+       if (hwdev->dma_mask < 0x7fffffff)
+               return 0;
+
+       /*
+        * Call our dmamap interface
+        */
+
+       phys_addr = __pa(ptr);
+       dma_addr = pcibr_dma_map(pcidev_info, phys_addr, size, 0);
+       if (!dma_addr) {
+               printk(KERN_ERR "pci_map_single: Unable to allocate anymore "
+                      "page map entries.\n");
+               return 0;
+       }
+       return ((dma_addr_t) dma_addr);
+}
+
+/**
+ * sn_pci_dma_sync_single_* - make sure all DMAs or CPU accesses
+ * have completed
+ * @hwdev: device to sync
+ * @dma_handle: DMA address to sync
+ * @size: size of region
+ * @direction: DMA direction
+ *
+ * This routine is supposed to sync the DMA region specified
+ * by @dma_handle into the 'coherence domain'.  We do not need to do
+ * anything on our platform.
+ */
+void
+sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size,
+                   int direction)
+{
+       struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
+       struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev);
+
+       if (direction == PCI_DMA_NONE)
+               BUG();
+
+       if (bussoft == NULL) {
+               return;
+       }
+
+       if (! IS_PCI_BRIDGE_ASIC(bussoft->bs_asic_type)) {
+               return;         /* unsupported asic type */
+       }
+
+       pcibr_dma_unmap(pcidev_info, dma_addr, direction);
+}
+
+/**
+ * sn_dma_supported - test a DMA mask
+ * @hwdev: device to test
+ * @mask: DMA mask to test
+ *
+ * Return whether the given PCI device DMA address mask can be supported
+ * properly.  For example, if your device can only drive the low 24-bits
+ * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
+ * this function.  Of course, SN only supports devices that have 32 or more
+ * address bits when using the PMU.  We could theoretically support <32 bit
+ * cards using direct mapping, but we'll worry about that later--on the off
+ * chance that someone actually wants to use such a card.
+ */
+int sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+{
+       if (mask < 0x7fffffff)
+               return 0;
+       return 1;
+}
+
+/*
+ * New generic DMA routines just wrap sn2 PCI routines until we
+ * support other bus types (if ever).
+ */
+
+int sn_dma_supported(struct device *dev, u64 mask)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return sn_pci_dma_supported(to_pci_dev(dev), mask);
+}
+
+EXPORT_SYMBOL(sn_dma_supported);
+
+int sn_dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       if (!sn_dma_supported(dev, dma_mask))
+               return 0;
+
+       *dev->dma_mask = dma_mask;
+       return 1;
+}
+
+EXPORT_SYMBOL(sn_dma_set_mask);
+
+void *sn_dma_alloc_coherent(struct device *dev, size_t size,
+                           dma_addr_t * dma_handle, int flag)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return sn_pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+}
+
+EXPORT_SYMBOL(sn_dma_alloc_coherent);
+
+void
+sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+                    dma_addr_t dma_handle)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       sn_pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
+}
+
+EXPORT_SYMBOL(sn_dma_free_coherent);
+
+dma_addr_t
+sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+                 int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return sn_pci_map_single(to_pci_dev(dev), cpu_addr, size,
+                                (int)direction);
+}
+
+EXPORT_SYMBOL(sn_dma_map_single);
+
+void
+sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+                   int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       sn_pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
+}
+
+EXPORT_SYMBOL(sn_dma_unmap_single);
+
+dma_addr_t
+sn_dma_map_page(struct device *dev, struct page *page,
+               unsigned long offset, size_t size, int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_map_page(to_pci_dev(dev), page, offset, size,
+                           (int)direction);
+}
+
+EXPORT_SYMBOL(sn_dma_map_page);
+
+void
+sn_dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+                 int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
+}
+
+EXPORT_SYMBOL(sn_dma_unmap_page);
+
+int
+sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+             int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return sn_pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+}
+
+EXPORT_SYMBOL(sn_dma_map_sg);
+
+void
+sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+               int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       sn_pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
+}
+
+EXPORT_SYMBOL(sn_dma_unmap_sg);
+
+void
+sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                          size_t size, int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+}
+
+EXPORT_SYMBOL(sn_dma_sync_single_for_cpu);
+
+void
+sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                             size_t size, int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+}
+
+EXPORT_SYMBOL(sn_dma_sync_single_for_device);
+
+void
+sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+                      int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+}
+
+EXPORT_SYMBOL(sn_dma_sync_sg_for_cpu);
+
+void
+sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+                         int nelems, int direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+}
+
+int sn_dma_mapping_error(dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+EXPORT_SYMBOL(sn_dma_sync_sg_for_device);
+EXPORT_SYMBOL(sn_pci_unmap_single);
+EXPORT_SYMBOL(sn_pci_map_single);
+EXPORT_SYMBOL(sn_pci_map_sg);
+EXPORT_SYMBOL(sn_pci_unmap_sg);
+EXPORT_SYMBOL(sn_pci_alloc_consistent);
+EXPORT_SYMBOL(sn_pci_free_consistent);
+EXPORT_SYMBOL(sn_pci_dma_supported);
+EXPORT_SYMBOL(sn_dma_mapping_error);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
new file mode 100644 (file)
index 0000000..9d68546
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <asm/sn/sn_sal.h>
+#include "pci/pcibus_provider_defs.h"
+#include "pci/pcidev.h"
+#include "pci/pcibr_provider.h"
+
+int pcibr_invalidate_ate = 0;  /* by default don't invalidate ATE on free */
+
+/*
+ * mark_ate: Mark the ate as either free or inuse.
+ */
+static void mark_ate(struct ate_resource *ate_resource, int start, int number,
+                    uint64_t value)
+{
+
+       uint64_t *ate = ate_resource->ate;
+       int index;
+       int length = 0;
+
+       for (index = start; length < number; index++, length++)
+               ate[index] = value;
+
+}
+
+/*
+ * find_free_ate:  Find the first free ate index starting from the given
+ *                index for the desired consequtive count.
+ */
+static int find_free_ate(struct ate_resource *ate_resource, int start,
+                        int count)
+{
+
+       uint64_t *ate = ate_resource->ate;
+       int index;
+       int start_free;
+
+       for (index = start; index < ate_resource->num_ate;) {
+               if (!ate[index]) {
+                       int i;
+                       int free;
+                       free = 0;
+                       start_free = index;     /* Found start free ate */
+                       for (i = start_free; i < ate_resource->num_ate; i++) {
+                               if (!ate[i]) {  /* This is free */
+                                       if (++free == count)
+                                               return start_free;
+                               } else {
+                                       index = i + 1;
+                                       break;
+                               }
+                       }
+               } else
+                       index++;        /* Try next ate */
+       }
+
+       return -1;
+}
+
+/*
+ * free_ate_resource:  Free the requested number of ATEs.
+ */
+static inline void free_ate_resource(struct ate_resource *ate_resource,
+                                    int start)
+{
+
+       mark_ate(ate_resource, start, ate_resource->ate[start], 0);
+       if ((ate_resource->lowest_free_index > start) ||
+           (ate_resource->lowest_free_index < 0))
+               ate_resource->lowest_free_index = start;
+
+}
+
+/*
+ * alloc_ate_resource:  Allocate the requested number of ATEs.
+ */
+static inline int alloc_ate_resource(struct ate_resource *ate_resource,
+                                    int ate_needed)
+{
+
+       int start_index;
+
+       /*
+        * Check for ate exhaustion.
+        */
+       if (ate_resource->lowest_free_index < 0)
+               return -1;
+
+       /*
+        * Find the required number of free consequtive ates.
+        */
+       start_index =
+           find_free_ate(ate_resource, ate_resource->lowest_free_index,
+                         ate_needed);
+       if (start_index >= 0)
+               mark_ate(ate_resource, start_index, ate_needed, ate_needed);
+
+       ate_resource->lowest_free_index =
+           find_free_ate(ate_resource, ate_resource->lowest_free_index, 1);
+
+       return start_index;
+}
+
+/*
+ * Allocate "count" contiguous Bridge Address Translation Entries
+ * on the specified bridge to be used for PCI to XTALK mappings.
+ * Indices in rm map range from 1..num_entries.  Indicies returned
+ * to caller range from 0..num_entries-1.
+ *
+ * Return the start index on success, -1 on failure.
+ */
+int pcibr_ate_alloc(struct pcibus_info *pcibus_info, int count)
+{
+       int status = 0;
+       uint64_t flag;
+
+       flag = pcibr_lock(pcibus_info);
+       status = alloc_ate_resource(&pcibus_info->pbi_int_ate_resource, count);
+
+       if (status < 0) {
+               /* Failed to allocate */
+               pcibr_unlock(pcibus_info, flag);
+               return -1;
+       }
+
+       pcibr_unlock(pcibus_info, flag);
+
+       return status;
+}
+
+/*
+ * Setup an Address Translation Entry as specified.  Use either the Bridge
+ * internal maps or the external map RAM, as appropriate.
+ */
+static inline uint64_t *pcibr_ate_addr(struct pcibus_info *pcibus_info,
+                                      int ate_index)
+{
+       if (ate_index < pcibus_info->pbi_int_ate_size) {
+               return pcireg_int_ate_addr(pcibus_info, ate_index);
+       }
+       panic("pcibr_ate_addr: invalid ate_index 0x%x", ate_index);
+}
+
+/*
+ * Update the ate.
+ */
+void inline
+ate_write(struct pcibus_info *pcibus_info, int ate_index, int count,
+         volatile uint64_t ate)
+{
+       while (count-- > 0) {
+               if (ate_index < pcibus_info->pbi_int_ate_size) {
+                       pcireg_int_ate_set(pcibus_info, ate_index, ate);
+               } else {
+                       panic("ate_write: invalid ate_index 0x%x", ate_index);
+               }
+               ate_index++;
+               ate += IOPGSIZE;
+       }
+
+       pcireg_tflush_get(pcibus_info); /* wait until Bridge PIO complete */
+}
+
+void pcibr_ate_free(struct pcibus_info *pcibus_info, int index)
+{
+
+       volatile uint64_t ate;
+       int count;
+       uint64_t flags;
+
+       if (pcibr_invalidate_ate) {
+               /* For debugging purposes, clear the valid bit in the ATE */
+               ate = *pcibr_ate_addr(pcibus_info, index);
+               count = pcibus_info->pbi_int_ate_resource.ate[index];
+               ate_write(pcibus_info, index, count, (ate & ~PCI32_ATE_V));
+       }
+
+       flags = pcibr_lock(pcibus_info);
+       free_ate_resource(&pcibus_info->pbi_int_ate_resource, index);
+       pcibr_unlock(pcibus_info, flags);
+}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
new file mode 100644 (file)
index 0000000..b1d66ac
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * 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-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/geo.h>
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
+#include "pci/pcibus_provider_defs.h"
+#include "pci/pcidev.h"
+#include "pci/tiocp.h"
+#include "pci/pic.h"
+#include "pci/pcibr_provider.h"
+#include "pci/tiocp.h"
+#include "tio.h"
+#include <asm/sn/addrs.h>
+
+extern int sn_ioif_inited;
+
+/* =====================================================================
+ *    DMA MANAGEMENT
+ *
+ *      The Bridge ASIC provides three methods of doing DMA: via a "direct map"
+ *      register available in 32-bit PCI space (which selects a contiguous 2G
+ *     address space on some other widget), via "direct" addressing via 64-bit
+ *      PCI space (all destination information comes from the PCI address,
+ *      including transfer attributes), and via a "mapped" region that allows 
+ *      a bunch of different small mappings to be established with the PMU.
+ *
+ *      For efficiency, we most prefer to use the 32bit direct mapping facility,
+ *      since it requires no resource allocations. The advantage of using the
+ *      PMU over the 64-bit direct is that single-cycle PCI addressing can be
+ *      used; the advantage of using 64-bit direct over PMU addressing is that
+ *      we do not have to allocate entries in the PMU.
+ */
+
+static uint64_t
+pcibr_dmamap_ate32(struct pcidev_info *info,
+                  uint64_t paddr, size_t req_size, uint64_t flags)
+{
+
+       struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
+       struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
+           pdi_pcibus_info;
+       uint8_t internal_device = (PCI_SLOT(pcidev_info->pdi_host_pcidev_info->
+                                           pdi_linux_pcidev->devfn)) - 1;
+       int ate_count;
+       int ate_index;
+       uint64_t ate_flags = flags | PCI32_ATE_V;
+       uint64_t ate;
+       uint64_t pci_addr;
+       uint64_t xio_addr;
+       uint64_t offset;
+
+       /* PIC in PCI-X mode does not supports 32bit PageMap mode */
+       if (IS_PIC_SOFT(pcibus_info) && IS_PCIX(pcibus_info)) {
+               return 0;
+       }
+
+       /* Calculate the number of ATEs needed. */
+       if (!(MINIMAL_ATE_FLAG(paddr, req_size))) {
+               ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */
+                                +req_size      /* max mapping bytes */
+                                - 1) + 1;      /* round UP */
+       } else {                /* assume requested target is page aligned */
+               ate_count = IOPG(req_size       /* max mapping bytes */
+                                - 1) + 1;      /* round UP */
+       }
+
+       /* Get the number of ATEs required. */
+       ate_index = pcibr_ate_alloc(pcibus_info, ate_count);
+       if (ate_index < 0)
+               return 0;
+
+       /* In PCI-X mode, Prefetch not supported */
+       if (IS_PCIX(pcibus_info))
+               ate_flags &= ~(PCI32_ATE_PREF);
+
+       xio_addr =
+           IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+           PHYS_TO_TIODMA(paddr);
+       offset = IOPGOFF(xio_addr);
+       ate = ate_flags | (xio_addr - offset);
+
+       /* If PIC, put the targetid in the ATE */
+       if (IS_PIC_SOFT(pcibus_info)) {
+               ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT);
+       }
+       ate_write(pcibus_info, ate_index, ate_count, ate);
+
+       /*
+        * Set up the DMA mapped Address.
+        */
+       pci_addr = PCI32_MAPPED_BASE + offset + IOPGSIZE * ate_index;
+
+       /*
+        * If swap was set in device in pcibr_endian_set()
+        * we need to turn swapping on.
+        */
+       if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR)
+               ATE_SWAP_ON(pci_addr);
+
+       return pci_addr;
+}
+
+static uint64_t
+pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr,
+                       uint64_t dma_attributes)
+{
+       struct pcibus_info *pcibus_info = (struct pcibus_info *)
+           ((info->pdi_host_pcidev_info)->pdi_pcibus_info);
+       uint64_t pci_addr;
+
+       /* Translate to Crosstalk View of Physical Address */
+       pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+                   PHYS_TO_TIODMA(paddr)) | dma_attributes;
+
+       /* Handle Bus mode */
+       if (IS_PCIX(pcibus_info))
+               pci_addr &= ~PCI64_ATTR_PREF;
+
+       /* Handle Bridge Chipset differences */
+       if (IS_PIC_SOFT(pcibus_info)) {
+               pci_addr |=
+                   ((uint64_t) pcibus_info->
+                    pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT);
+       } else
+               pci_addr |= TIOCP_PCI64_CMDTYPE_MEM;
+
+       /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */
+       if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn))
+               pci_addr |= PCI64_ATTR_VIRTUAL;
+
+       return pci_addr;
+
+}
+
+static uint64_t
+pcibr_dmatrans_direct32(struct pcidev_info * info,
+                       uint64_t paddr, size_t req_size, uint64_t flags)
+{
+
+       struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
+       struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
+           pdi_pcibus_info;
+       uint64_t xio_addr;
+
+       uint64_t xio_base;
+       uint64_t offset;
+       uint64_t endoff;
+
+       if (IS_PCIX(pcibus_info)) {
+               return 0;
+       }
+
+       xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+           PHYS_TO_TIODMA(paddr);
+
+       xio_base = pcibus_info->pbi_dir_xbase;
+       offset = xio_addr - xio_base;
+       endoff = req_size + offset;
+       if ((req_size > (1ULL << 31)) ||        /* Too Big */
+           (xio_addr < xio_base) ||    /* Out of range for mappings */
+           (endoff > (1ULL << 31))) {  /* Too Big */
+               return 0;
+       }
+
+       return PCI32_DIRECT_BASE | offset;
+
+}
+
+/*
+ * Wrapper routine for free'ing DMA maps
+ * DMA mappings for Direct 64 and 32 do not have any DMA maps.
+ */
+void
+pcibr_dma_unmap(struct pcidev_info *pcidev_info, dma_addr_t dma_handle,
+               int direction)
+{
+       struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
+           pdi_pcibus_info;
+
+       if (IS_PCI32_MAPPED(dma_handle)) {
+               int ate_index;
+
+               ate_index =
+                   IOPG((ATE_SWAP_OFF(dma_handle) - PCI32_MAPPED_BASE));
+               pcibr_ate_free(pcibus_info, ate_index);
+       }
+}
+
+/*
+ * On SN systems there is a race condition between a PIO read response and 
+ * DMA's.  In rare cases, the read response may beat the DMA, causing the
+ * driver to think that data in memory is complete and meaningful.  This code
+ * eliminates that race.  This routine is called by the PIO read routines
+ * after doing the read.  For PIC this routine then forces a fake interrupt
+ * on another line, which is logically associated with the slot that the PIO
+ * is addressed to.  It then spins while watching the memory location that
+ * the interrupt is targetted to.  When the interrupt response arrives, we 
+ * are sure that the DMA has landed in memory and it is safe for the driver
+ * to proceed. For TIOCP use the Device(x) Write Request Buffer Flush 
+ * Bridge register since it ensures the data has entered the coherence domain,
+ * unlike the PIC Device(x) Write Request Buffer Flush register.
+ */
+
+void sn_dma_flush(uint64_t addr)
+{
+       nasid_t nasid;
+       int is_tio;
+       int wid_num;
+       int i, j;
+       int bwin;
+       uint64_t flags;
+       struct hubdev_info *hubinfo;
+       volatile struct sn_flush_device_list *p;
+       struct sn_flush_nasid_entry *flush_nasid_list;
+
+       if (!sn_ioif_inited)
+               return;
+
+       nasid = NASID_GET(addr);
+       if (-1 == nasid_to_cnodeid(nasid))
+               return;
+
+       hubinfo = (NODEPDA(nasid_to_cnodeid(nasid)))->pdinfo;
+
+       if (!hubinfo) {
+               BUG();
+       }
+       is_tio = (nasid & 1);
+       if (is_tio) {
+               wid_num = TIO_SWIN_WIDGETNUM(addr);
+               bwin = TIO_BWIN_WINDOWNUM(addr);
+       } else {
+               wid_num = SWIN_WIDGETNUM(addr);
+               bwin = BWIN_WINDOWNUM(addr);
+       }
+
+       flush_nasid_list = &hubinfo->hdi_flush_nasid_list;
+       if (flush_nasid_list->widget_p == NULL)
+               return;
+       if (bwin > 0) {
+               uint64_t itte = flush_nasid_list->iio_itte[bwin];
+
+               if (is_tio) {
+                       wid_num = (itte >> TIO_ITTE_WIDGET_SHIFT) &
+                           TIO_ITTE_WIDGET_MASK;
+               } else {
+                       wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) &
+                           IIO_ITTE_WIDGET_MASK;
+               }
+       }
+       if (flush_nasid_list->widget_p == NULL)
+               return;
+       if (flush_nasid_list->widget_p[wid_num] == NULL)
+               return;
+       p = &flush_nasid_list->widget_p[wid_num][0];
+
+       /* find a matching BAR */
+       for (i = 0; i < DEV_PER_WIDGET; i++) {
+               for (j = 0; j < PCI_ROM_RESOURCE; j++) {
+                       if (p->sfdl_bar_list[j].start == 0)
+                               break;
+                       if (addr >= p->sfdl_bar_list[j].start
+                           && addr <= p->sfdl_bar_list[j].end)
+                               break;
+               }
+               if (j < PCI_ROM_RESOURCE && p->sfdl_bar_list[j].start != 0)
+                       break;
+               p++;
+       }
+
+       /* if no matching BAR, return without doing anything. */
+       if (i == DEV_PER_WIDGET)
+               return;
+
+       /*
+        * For TIOCP use the Device(x) Write Request Buffer Flush Bridge
+        * register since it ensures the data has entered the coherence
+        * domain, unlike PIC
+        */
+       if (is_tio) {
+               uint32_t tio_id = REMOTE_HUB_L(nasid, TIO_NODE_ID);
+               uint32_t revnum = XWIDGET_PART_REV_NUM(tio_id);
+
+               /* TIOCP BRINGUP WAR (PV907516): Don't write buffer flush reg */
+               if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) {
+                       return;
+               } else {
+                       pcireg_wrb_flush_get(p->sfdl_pcibus_info,
+                                            (p->sfdl_slot - 1));
+               }
+       } else {
+               spin_lock_irqsave(&((struct sn_flush_device_list *)p)->
+                                 sfdl_flush_lock, flags);
+
+               p->sfdl_flush_value = 0;
+
+               /* force an interrupt. */
+               *(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
+
+               /* wait for the interrupt to come back. */
+               while (*(p->sfdl_flush_addr) != 0x10f) ;
+
+               /* okay, everything is synched up. */
+               spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
+       }
+       return;
+}
+
+/*
+ * Wrapper DMA interface.  Called from pci_dma.c routines.
+ */
+
+uint64_t
+pcibr_dma_map(struct pcidev_info * pcidev_info, unsigned long phys_addr,
+             size_t size, unsigned int flags)
+{
+       dma_addr_t dma_handle;
+       struct pci_dev *pcidev = pcidev_info->pdi_linux_pcidev;
+
+       if (flags & SN_PCIDMA_CONSISTENT) {
+               /* sn_pci_alloc_consistent interfaces */
+               if (pcidev->dev.coherent_dma_mask == ~0UL) {
+                       dma_handle =
+                           pcibr_dmatrans_direct64(pcidev_info, phys_addr,
+                                                   PCI64_ATTR_BAR);
+               } else {
+                       dma_handle =
+                           (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
+                                                           phys_addr, size,
+                                                           PCI32_ATE_BAR);
+               }
+       } else {
+               /* map_sg/map_single interfaces */
+
+               /* SN cannot support DMA addresses smaller than 32 bits. */
+               if (pcidev->dma_mask < 0x7fffffff) {
+                       return 0;
+               }
+
+               if (pcidev->dma_mask == ~0UL) {
+                       /*
+                        * Handle the most common case: 64 bit cards.  This
+                        * call should always succeed.
+                        */
+
+                       dma_handle =
+                           pcibr_dmatrans_direct64(pcidev_info, phys_addr,
+                                                   PCI64_ATTR_PREF);
+               } else {
+                       /* Handle 32-63 bit cards via direct mapping */
+                       dma_handle =
+                           pcibr_dmatrans_direct32(pcidev_info, phys_addr,
+                                                   size, 0);
+                       if (!dma_handle) {
+                               /*
+                                * It is a 32 bit card and we cannot do direct mapping,
+                                * so we use an ATE.
+                                */
+
+                               dma_handle =
+                                   pcibr_dmamap_ate32(pcidev_info, phys_addr,
+                                                      size, PCI32_ATE_PREF);
+                       }
+               }
+       }
+
+       return dma_handle;
+}
+
+EXPORT_SYMBOL(sn_dma_flush);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
new file mode 100644 (file)
index 0000000..92bd278
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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-2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/sn/sn_sal.h>
+#include "xtalk/xwidgetdev.h"
+#include <asm/sn/geo.h>
+#include "xtalk/hubdev.h"
+#include "pci/pcibus_provider_defs.h"
+#include "pci/pcidev.h"
+#include "pci/pcibr_provider.h"
+#include <asm/sn/addrs.h>
+
+
+static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
+{
+       struct ia64_sal_retval ret_stuff;
+       uint64_t busnum;
+       int segment;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       segment = 0;
+       busnum = soft->pbi_buscommon.bs_persist_busnum;
+       SAL_CALL_NOLOCK(ret_stuff,
+                       (u64) SN_SAL_IOIF_ERROR_INTERRUPT,
+                       (u64) segment, (u64) busnum, 0, 0, 0, 0, 0);
+
+       return (int)ret_stuff.v0;
+}
+
+/* 
+ * PCI Bridge Error interrupt handler.  Gets invoked whenever a PCI 
+ * bridge sends an error interrupt.
+ */
+static irqreturn_t
+pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *regs)
+{
+       struct pcibus_info *soft = (struct pcibus_info *)arg;
+
+       if (sal_pcibr_error_interrupt(soft) < 0) {
+               panic("pcibr_error_intr_handler(): Fatal Bridge Error");
+       }
+       return IRQ_HANDLED;
+}
+
+void *
+pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft)
+{
+       int nasid, cnode, j;
+       struct hubdev_info *hubdev_info;
+       struct pcibus_info *soft;
+       struct sn_flush_device_list *sn_flush_device_list;
+
+       if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) {
+               return NULL;
+       }
+
+       /*
+        * Allocate kernel bus soft and copy from prom.
+        */
+
+       soft = kmalloc(sizeof(struct pcibus_info), GFP_KERNEL);
+       if (!soft) {
+               return NULL;
+       }
+
+       memcpy(soft, prom_bussoft, sizeof(struct pcibus_info));
+       soft->pbi_buscommon.bs_base =
+           (((u64) soft->pbi_buscommon.
+             bs_base << 4) >> 4) | __IA64_UNCACHED_OFFSET;
+
+       spin_lock_init(&soft->pbi_lock);
+
+       /*
+        * register the bridge's error interrupt handler
+        */
+       if (request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler,
+                       SA_SHIRQ, "PCIBR error", (void *)(soft))) {
+               printk(KERN_WARNING
+                      "pcibr cannot allocate interrupt for error handler\n");
+       }
+
+       /* 
+        * Update the Bridge with the "kernel" pagesize 
+        */
+       if (PAGE_SIZE < 16384) {
+               pcireg_control_bit_clr(soft, PCIBR_CTRL_PAGE_SIZE);
+       } else {
+               pcireg_control_bit_set(soft, PCIBR_CTRL_PAGE_SIZE);
+       }
+
+       nasid = NASID_GET(soft->pbi_buscommon.bs_base);
+       cnode = nasid_to_cnodeid(nasid);
+       hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
+
+       if (hubdev_info->hdi_flush_nasid_list.widget_p) {
+               sn_flush_device_list = hubdev_info->hdi_flush_nasid_list.
+                   widget_p[(int)soft->pbi_buscommon.bs_xid];
+               if (sn_flush_device_list) {
+                       for (j = 0; j < DEV_PER_WIDGET;
+                            j++, sn_flush_device_list++) {
+                               if (sn_flush_device_list->sfdl_slot == -1)
+                                       continue;
+                               if (sn_flush_device_list->
+                                   sfdl_persistent_busnum ==
+                                   soft->pbi_buscommon.bs_persist_busnum)
+                                       sn_flush_device_list->sfdl_pcibus_info =
+                                           soft;
+                       }
+               }
+       }
+
+       /* Setup the PMU ATE map */
+       soft->pbi_int_ate_resource.lowest_free_index = 0;
+       soft->pbi_int_ate_resource.ate =
+           kmalloc(soft->pbi_int_ate_size * sizeof(uint64_t), GFP_KERNEL);
+       memset(soft->pbi_int_ate_resource.ate, 0,
+              (soft->pbi_int_ate_size * sizeof(uint64_t)));
+
+       return soft;
+}
+
+void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)
+{
+       struct pcidev_info *pcidev_info;
+       struct pcibus_info *pcibus_info;
+       int bit = sn_irq_info->irq_int_bit;
+
+       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+       if (pcidev_info) {
+               pcibus_info =
+                   (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
+                   pdi_pcibus_info;
+               pcireg_force_intr_set(pcibus_info, bit);
+       }
+}
+
+void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info)
+{
+       struct pcidev_info *pcidev_info;
+       struct pcibus_info *pcibus_info;
+       int bit = sn_irq_info->irq_int_bit;
+       uint64_t xtalk_addr = sn_irq_info->irq_xtalkaddr;
+
+       pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+       if (pcidev_info) {
+               pcibus_info =
+                   (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->
+                   pdi_pcibus_info;
+
+               /* Disable the device's IRQ   */
+               pcireg_intr_enable_bit_clr(pcibus_info, bit);
+
+               /* Change the device's IRQ    */
+               pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr);
+
+               /* Re-enable the device's IRQ */
+               pcireg_intr_enable_bit_set(pcibus_info, bit);
+
+               pcibr_force_interrupt(sn_irq_info);
+       }
+}
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
new file mode 100644 (file)
index 0000000..bacc0b2
--- /dev/null
@@ -0,0 +1,441 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+mainmenu "Linux Kernel Configuration"
+
+config M32R
+       bool
+       default y
+
+config SBUS
+       bool
+
+config UID16
+       bool
+       default y
+
+config GENERIC_ISA_DMA
+       bool
+       default y
+
+source "init/Kconfig"
+
+
+menu "Processor type and features"
+
+choice
+       prompt "Platform Type"
+       default PLAT_MAPPI
+
+config PLAT_MAPPI
+       bool "Mappi-I"
+       help
+         The Mappi-I is an FPGA board for SOC (System-On-a-Chip) prototyping.
+         You can operate a Linux system on this board by using an M32R
+         softmacro core, which is a fully-synthesizable functional model
+         described in Verilog-HDL.
+
+         The Mappi-I board was the first platform, which had been used
+         to port and develop a Linux system for the M32R processor.
+         Currently, the Mappi-II, an heir to the Mappi-I, is available.
+
+config PLAT_USRV
+       bool "uServer"
+
+config PLAT_M32700UT
+       bool "M32700UT"
+       help
+         The M3T-M32700UT is an evaluation board based on uT-Engine
+         specification.  This board has an M32700 (Chaos) evaluation chip.
+         You can say Y for SMP, because the M32700 is a single chip
+         multiprocessor.
+
+config PLAT_OPSPUT
+       bool "OPSPUT"
+       help
+         The OPSPUT is an evaluation board based on uT-Engine
+         specification.  This board has a OPSP-REP chip.
+
+config PLAT_OAKS32R
+       bool "OAKS32R"
+       help
+         The OAKS32R is a tiny, inexpensive evaluation board.
+         Please note that if you say Y here and choose chip "M32102",
+         say N for MMU and select a no-MMU version kernel, otherwise
+         a kernel with MMU support will not work, because the M32102
+         is a microcontroller for embedded systems and it has no MMU.
+
+config PLAT_MAPPI2
+       bool "Mappi-II(M3A-ZA36/M3A-ZA52)"
+
+endchoice
+
+choice
+       prompt "Processor family"
+       default CHIP_M32700
+
+config CHIP_M32700
+       bool "M32700 (Chaos)"
+
+config CHIP_M32102
+       bool "M32102"
+
+config CHIP_VDEC2
+       bool "VDEC2"
+
+config CHIP_OPSP
+       bool "OPSP"
+
+endchoice
+
+config MMU
+       bool "Support for memory management hardware"
+       depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP
+       default y
+
+config TLB_ENTRIES
+       int "TLB Entries"
+       depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP
+       default 32 if CHIP_M32700 || CHIP_OPSP
+       default 16 if CHIP_VDEC2
+
+
+config ISA_M32R
+        bool
+       depends on CHIP_M32102
+       default y
+
+config ISA_M32R2
+       bool
+       depends on CHIP_M32700 || CHIP_VDEC2 || CHIP_OPSP
+       default y
+
+config ISA_DSP_LEVEL2
+       bool
+       depends on CHIP_M32700 || CHIP_OPSP
+       default y
+
+config ISA_DUAL_ISSUE
+       bool
+       depends on CHIP_M32700 || CHIP_OPSP
+       default y
+
+config BUS_CLOCK
+       int "Bus Clock [Hz] (integer)"
+       default "70000000" if PLAT_MAPPI
+       default "25000000" if PLAT_USRV
+       default "50000000" if PLAT_M32700UT
+       default "50000000" if PLAT_OPSPUT
+       default "33333333" if PLAT_OAKS32R
+       default "20000000" if PLAT_MAPPI2
+
+config TIMER_DIVIDE
+       int "Timer divider (integer)"
+       default "128"
+
+config CPU_LITTLE_ENDIAN
+        bool "Generate little endian code"
+       default n
+
+config MEMORY_START
+       hex "Physical memory start address (hex)"
+       default "08000000" if PLAT_MAPPI || PLAT_MAPPI2
+       default "08000000" if PLAT_USRV
+       default "08000000" if PLAT_M32700UT
+       default "08000000" if PLAT_OPSPUT
+       default "01000000" if PLAT_OAKS32R
+
+config MEMORY_SIZE
+       hex "Physical memory size (hex)"
+       default "04000000" if PLAT_MAPPI || PLAT_MAPPI2
+       default "02000000" if PLAT_USRV
+       default "01000000" if PLAT_M32700UT
+       default "01000000" if PLAT_OPSPUT
+       default "00800000" if PLAT_OAKS32R
+
+config NOHIGHMEM
+       bool
+       default y
+
+config DISCONTIGMEM
+       bool "Internal RAM Support"
+       depends on CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP
+       default y
+
+config IRAM_START
+       hex "Internal memory start address (hex)"
+       default "00f00000"
+       depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM
+
+config IRAM_SIZE
+       hex "Internal memory size (hex)"
+       depends on (CHIP_M32700 || CHIP_M32102 || CHIP_VDEC2 || CHIP_OPSP) && DISCONTIGMEM
+       default "00080000" if CHIP_M32700
+       default "00010000" if CHIP_M32102 || CHIP_OPSP
+       default "00008000" if CHIP_VDEC2
+
+#
+# Define implied options from the CPU selection here
+#
+
+config RWSEM_GENERIC_SPINLOCK
+       bool
+       depends on M32R
+       default y
+
+config RWSEM_XCHGADD_ALGORITHM
+       bool
+       default 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.
+
+         Say Y here if you are building a kernel for a desktop, embedded
+         or real-time system.  Say N if you are unsure.
+
+config HAVE_DEC_LOCK
+       bool
+       depends on (SMP || PREEMPT)
+       default n
+
+config SMP
+       bool "Symmetric multi-processing support"
+       ---help---
+         This enables support for systems with more than one CPU. If you have
+         a system with only one CPU, like most personal computers, say N. If
+         you have a system with more than one CPU, say Y.
+
+         If you say N here, the kernel will run on single and multiprocessor
+         machines, but will use only one CPU of a multiprocessor machine. If
+         you say Y here, the kernel will run on many, but not all,
+         singleprocessor machines. On a singleprocessor machine, the kernel
+         will run faster if you say N here.
+
+         People using multiprocessor machines who say Y here should also say
+         Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+         Management" code will be disabled if you say Y here.
+
+         See also the <file:Documentation/smp.tex>,
+         <file:Documentation/smp.txt> and the SMP-HOWTO available at
+         <http://www.linuxdoc.org/docs.html#howto>.
+
+         If you don't know what to do here, say N.
+
+config CHIP_M32700_TS1
+       bool "Workaround code for the M32700 TS1 chip's bug"
+       depends on (CHIP_M32700 && SMP)
+       default n
+
+config NR_CPUS
+       int "Maximum number of CPUs (2-32)"
+       range 2 32
+       depends on SMP
+       default "2"
+       help
+         This allows you to specify the maximum number of CPUs which this
+         kernel will support.  The maximum supported value is 32 and the
+         minimum value which makes sense is 2.
+
+         This is purely to save memory - each supported CPU adds
+         approximately eight kilobytes to the kernel image.
+
+# Common NUMA Features
+config NUMA
+       bool "Numa Memory Allocation Support"
+       depends on SMP
+       default n
+
+# turning this on wastes a bunch of space.
+# Summit needs it only when NUMA is on
+config BOOT_IOREMAP
+       bool
+       depends on NUMA
+       default n
+
+endmenu
+
+
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+
+config PCI
+       bool "PCI support"
+       default n
+       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.
+
+choice
+       prompt "PCI access mode"
+       depends on PCI
+       default PCI_GOANY
+
+config PCI_GOBIOS
+       bool "BIOS"
+       ---help---
+         On PCI systems, the BIOS can be used to detect the PCI devices and
+         determine their configuration. However, some old PCI motherboards
+         have BIOS bugs and may crash if this is done. Also, some embedded
+         PCI-based systems don't have any BIOS at all. Linux can also try to
+         detect the PCI hardware directly without using the BIOS.
+
+         With this option, you can specify how Linux should detect the PCI
+         devices. If you choose "BIOS", the BIOS will be used, if you choose
+         "Direct", the BIOS won't be used, and if you choose "Any", the
+         kernel will try the direct access method and falls back to the BIOS
+         if that doesn't work. If unsure, go with the default, which is
+         "Any".
+
+config PCI_GODIRECT
+       bool "Direct"
+
+config PCI_GOANY
+       bool "Any"
+
+endchoice
+
+config PCI_BIOS
+       bool
+       depends on PCI && (PCI_GOBIOS || PCI_GOANY)
+       default y
+
+config PCI_DIRECT
+       bool
+       depends on PCI && (PCI_GODIRECT || PCI_GOANY)
+       default y
+
+source "drivers/pci/Kconfig"
+
+config ISA
+       bool "ISA support"
+       help
+         Find out whether you have ISA slots on your motherboard.  ISA is the
+         name of a bus system, i.e. the way the CPU talks to the other stuff
+         inside your box.  If you have ISA, say Y, otherwise N.
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/m32r/oprofile/Kconfig"
+
+menu "Kernel hacking"
+
+config DEBUG_KERNEL
+       bool "Kernel debugging"
+       help
+         Say Y here if you are developing drivers or trying to debug and
+         identify kernel problems.
+
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+
+config DEBUG_SLAB
+       bool "Debug memory allocations"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here to have the kernel do limited verification on memory
+         allocation as well as poisoning memory on free to catch use of freed
+         memory.
+
+config DEBUG_IOVIRT
+       bool "Memory mapped I/O debugging"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here to get warned whenever an attempt is made to do I/O on
+         obviously invalid addresses such as those generated when ioremap()
+         calls are forgotten.  Memory mapped I/O will go through an extra
+         check to catch access to unmapped ISA addresses, an access method
+         that can still be used by old drivers that are being ported from
+         2.0/2.2.
+
+config MAGIC_SYSRQ
+       bool "Magic SysRq key"
+       depends on DEBUG_KERNEL
+       help
+         If you say Y here, you will have some control over the system even
+         if the system crashes for example during kernel debugging (e.g., you
+         will be able to flush the buffer cache to disk, reboot the system
+         immediately or dump some status information). This is accomplished
+         by pressing various keys while holding SysRq (Alt+PrintScreen). It
+         also works on a serial console (on PC hardware at least), if you
+         send a BREAK and then within 5 seconds a command keypress. The
+         keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+         unless you really know what this hack does.
+
+config DEBUG_SPINLOCK
+       bool "Spinlock debugging"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here and build SMP to catch missing spinlock initialization
+         and certain other kinds of spinlock errors commonly made.  This is
+         best used in conjunction with the NMI watchdog so that spinlock
+         deadlocks are also debuggable.
+
+config DEBUG_PAGEALLOC
+       bool "Page alloc debugging"
+       depends on DEBUG_KERNEL
+       help
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
+
+config DEBUG_INFO
+       bool "Compile the kernel with debug info"
+       depends on DEBUG_KERNEL
+       help
+          If you say Y here the resulting kernel image will include
+         debugging info resulting in a larger kernel image.
+         Say Y here only if you plan to use gdb to debug the kernel.
+         If you don't debug the kernel, you can say N.
+
+config DEBUG_SPINLOCK_SLEEP
+       bool "Sleep-inside-spinlock checking"
+       help
+         If you say Y here, various routines which may sleep will become very
+         noisy if they are called with a spinlock held.
+
+config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         and slower, but it will give very useful debugging information.
+         If you don't debug the kernel, you can say N, but we may not be able
+         to solve problems without frame pointers.
+
+endmenu
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
diff --git a/arch/m32r/Kconfig.debug b/arch/m32r/Kconfig.debug
new file mode 100644 (file)
index 0000000..36788c2
--- /dev/null
@@ -0,0 +1,34 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+config DEBUG_PAGEALLOC
+       bool "Page alloc debugging"
+       depends on DEBUG_KERNEL
+       help
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
+
+config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         and slower, but it will give very useful debugging information.
+         If you don't debug the kernel, you can say N, but we may not be able
+         to solve problems without frame pointers.
+
+endmenu
diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile
new file mode 100644 (file)
index 0000000..63ea62a
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# m32r/Makefile
+#
+
+LDFLAGS                :=
+OBJCOPYFLAGS   := -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux        := -e startup_32
+LDFLAGS_BLOB   := --format binary --oformat elf32-m32r
+
+CFLAGS += -pipe -fno-schedule-insns
+CFLAGS_KERNEL += -mmodel=medium
+CFLAGS_MODULE += -mmodel=large
+
+ifdef CONFIG_CHIP_VDEC2
+cflags-$(CONFIG_ISA_M32R2)     += -DNO_FPU -Wa,-bitinst
+aflags-$(CONFIG_ISA_M32R2)     += -DNO_FPU -Wa,-bitinst
+else
+cflags-$(CONFIG_ISA_M32R2)     += -DNO_FPU -m32r2
+aflags-$(CONFIG_ISA_M32R2)     += -DNO_FPU -m32r2
+endif
+
+cflags-$(CONFIG_ISA_M32R)      += -DNO_FPU
+aflags-$(CONFIG_ISA_M32R)      += -DNO_FPU -Wa,-no-bitinst
+
+CFLAGS += $(cflags-y)
+AFLAGS += $(aflags-y)
+
+CHECKFLAGS     := $(CHECK) -D__m32r__
+
+head-y := arch/m32r/kernel/head.o arch/m32r/kernel/init_task.o
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+libs-y += arch/m32r/lib/ $(LIBGCC)
+core-y += arch/m32r/kernel/    \
+          arch/m32r/mm/        \
+          arch/m32r/boot/
+
+drivers-$(CONFIG_OPROFILE)     += arch/m32r/oprofile/
+
+boot := arch/m32r/boot
+
+.PHONY: zImage
+
+zImage: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+compressed: zImage
+
+archclean:
+       $(Q)$(MAKE) $(clean)=$(boot)
+
+define archhelp
+       @echo '  zImage                 - Compressed kernel image (arch/m32r/boot/zImage)'
+endef
diff --git a/arch/m32r/boot/Makefile b/arch/m32r/boot/Makefile
new file mode 100644 (file)
index 0000000..af2cef4
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# arch/m32r/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.
+
+targets := zImage
+subdir- := compressed
+
+obj-y  := setup.o
+
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+       $(call if_changed,objcopy)
+       @echo 'Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: FORCE
+       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
diff --git a/arch/m32r/boot/compressed/Makefile b/arch/m32r/boot/compressed/Makefile
new file mode 100644 (file)
index 0000000..a8f130d
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets                := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o \
+                  m32r-sio.o piggy.o vmlinux.lds
+EXTRA_AFLAGS   := -traditional
+
+OBJECTS = $(obj)/head.o $(obj)/misc.o $(obj)/m32r_sio.o
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+#
+#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x2000])
+#IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+0x00400000])
+
+LDFLAGS_vmlinux := -T
+
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) $(obj)/piggy.o FORCE
+       $(call if_changed,ld)
+       @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.S FORCE
+       $(CPP) $(EXTRA_AFLAGS) -C -P -I include $< >$@
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-m32r-linux -T
+OBJCOPYFLAGS += -R .empty_zero_page
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+       $(call if_changed,ld)
diff --git a/arch/m32r/boot/compressed/boot.h b/arch/m32r/boot/compressed/boot.h
new file mode 100644 (file)
index 0000000..9272e38
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 1. load vmlinuz
+ *
+ * CONFIG_MEMORY_START         +-----------------------+
+ *                             |        vmlinuz        |
+ *                             +-----------------------+
+ * 2. decompressed
+ *
+ * CONFIG_MEMORY_START         +-----------------------+
+ *                             |        vmlinuz        |
+ *                             +-----------------------+
+ *                             |                       |
+ * BOOT_RELOC_ADDR             +-----------------------+
+ *                             |                       |
+ * KERNEL_DECOMPRESS_ADDR      +-----------------------+
+ *                             |       vmlinux         |
+ *                             +-----------------------+
+ *
+ * 3. relocate copy & jump code
+ *
+ * CONFIG_MEMORY_START         +-----------------------+
+ *                             |        vmlinuz        |
+ *                             +-----------------------+
+ *                             |                       |
+ * BOOT_RELOC_ADDR             +-----------------------+
+ *                             |    boot(copy&jump)    |
+ * KERNEL_DECOMPRESS_ADDR      +-----------------------+
+ *                             |       vmlinux         |
+ *                             +-----------------------+
+ *
+ * 4. relocate decompressed kernel
+ *
+ * CONFIG_MEMORY_START         +-----------------------+
+ *                             |        vmlinux        |
+ *                             +-----------------------+
+ *                             |                       |
+ * BOOT_RELOC_ADDR             +-----------------------+
+ *                             |     boot(copy&jump)   |
+ * KERNEL_DECOMPRESS_ADDR      +-----------------------+
+ *                             |                       |
+ *                             +-----------------------+
+ *
+ */
+#ifdef __ASSEMBLY__
+#define __val(x)       x
+#else
+#define __val(x)       (x)
+#endif
+
+#define DECOMPRESS_OFFSET_BASE __val(0x00900000)
+#define BOOT_RELOC_SIZE                __val(0x00001000)
+
+#define KERNEL_EXEC_ADDR       __val(CONFIG_MEMORY_START)
+#define KERNEL_DECOMPRESS_ADDR __val(CONFIG_MEMORY_START + \
+                                     DECOMPRESS_OFFSET_BASE + BOOT_RELOC_SIZE)
+#define KERNEL_ENTRY           __val(CONFIG_MEMORY_START + 0x1000)
+
+#define BOOT_EXEC_ADDR         __val(CONFIG_MEMORY_START)
+#define BOOT_RELOC_ADDR                __val(CONFIG_MEMORY_START + DECOMPRESS_OFFSET_BASE)
diff --git a/arch/m32r/boot/compressed/head.S b/arch/m32r/boot/compressed/head.S
new file mode 100644 (file)
index 0000000..28de481
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  linux/arch/m32r/boot/compressed/head.S
+ *
+ *  Copyright (c) 2001-2003    Hiroyuki Kondo, Hirokazu Takata,
+ *                             Hitoshi Yamamoto, Takeo Takahashi
+ *  Copyright (c) 2004         Hirokazu Takata
+ */
+
+       .text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/assembler.h>
+
+       .global startup
+       __ALIGN
+startup:
+       ldi     r0, #0x0000                     /* SPI, disable EI */
+       mvtc    r0, psw
+
+/*
+ * Clear BSS first so that there are no surprises...
+ */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       LDIMM   (r2, __bss_start)
+       LDIMM   (r3, _end)
+       sub     r3, r2          ; BSS size in bytes
+       ; R4 = BSS size in longwords (rounded down)
+       mv      r4, r3              ||  ldi     r1, #0
+       srli    r4, #4              ||  addi    r2, #-4
+       beqz    r4, .Lendloop1
+.Lloop1:
+#ifndef CONFIG_CHIP_M32310
+       ; Touch memory for the no-write-allocating cache.
+       ld      r0, @(4,r2)
+#endif
+       st      r1, @+r2            ||  addi    r4, #-1
+       st      r1, @+r2
+       st      r1, @+r2
+       st      r1, @+r2            ||  cmpeq   r1, r4  ; R4 = 0?
+       bnc     .Lloop1
+.Lendloop1:
+       and3    r4, r3, #15
+       addi    r2, #4
+       beqz    r4, .Lendloop2
+.Lloop2:
+       stb     r1, @r2             ||  addi    r4, #-1
+       addi    r2, #1
+       bnez    r4, .Lloop2
+.Lendloop2:
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       LDIMM   (r2, __bss_start)
+       LDIMM   (r3, _end)
+       sub     r3, r2          ; BSS size in bytes
+       mv      r4, r3
+       srli    r4, #2          ; R4 = BSS size in longwords (rounded down)
+       ldi     r1, #0          ; clear R1 for longwords store
+       addi    r2, #-4         ; account for pre-inc store
+       beqz    r4, .Lendloop1  ; any more to go?
+.Lloop1:
+       st      r1, @+r2        ; yep, zero out another longword
+       addi    r4, #-1         ; decrement count
+       bnez    r4, .Lloop1     ; go do some more
+.Lendloop1:
+       and3    r4, r3, #3      ; get no. of remaining BSS bytes to clear
+       addi    r2, #4          ; account for pre-inc store
+       beqz    r4, .Lendloop2  ; any more to go?
+.Lloop2:
+       stb     r1, @r2         ; yep, zero out another byte
+       addi    r2, #1          ; bump address
+       addi    r4, #-1         ; decrement count
+       bnez    r4, .Lloop2     ; go do some more
+.Lendloop2:
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+       seth    r0, #shigh(stack_start)
+       ld      sp, @(r0, low(stack_start))     /* set stack point */
+
+/*
+ * decompress the kernel
+ */
+       bl      decompress_kernel
+
+#if defined(CONFIG_CHIP_M32700)
+       /* Cache flush */
+       ldi     r0, -1
+       ldi     r1, 0xd0        ; invalidate i-cache, copy back d-cache
+       stb     r1, @r0
+#else
+#error "put your cache flush function, please"
+#endif
+        seth   r0, #high(CONFIG_MEMORY_START)
+        or3    r0, r0, #0x2000
+        jmp    r0
+
+       .balign 512
+fake_headers_as_bzImage:
+       .short  0
+       .ascii  "HdrS"
+       .short  0x0202
+       .short  0
+       .short  0
+       .byte   0x00, 0x10
+       .short  0
+       .byte   0
+       .byte   1
+       .byte   0x00, 0x80
+       .long   0
+       .long   0
+
diff --git a/arch/m32r/boot/compressed/install.sh b/arch/m32r/boot/compressed/install.sh
new file mode 100644 (file)
index 0000000..6d72e9e
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# arch/sh/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
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+# Adapted from code in arch/i386/boot/install.sh by Russell King
+# Adapted from code in arch/arm/boot/install.sh by Stuart Menefy
+# Adapted from code in arch/sh/boot/install.sh by Takeo Takahashi
+#
+# "make install" script for sh architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x /sbin/installkernel ]; then
+  exec /sbin/installkernel "$@"
+fi
+
+if [ "$2" = "zImage" ]; then
+# Compressed install
+  echo "Installing compressed kernel"
+  if [ -f $4/vmlinuz-$1 ]; then
+    mv $4/vmlinuz-$1 $4/vmlinuz.old
+  fi
+
+  if [ -f $4/System.map-$1 ]; then
+    mv $4/System.map-$1 $4/System.old
+  fi
+
+  cat $2 > $4/vmlinuz-$1
+  cp $3 $4/System.map-$1
+else
+# Normal install
+  echo "Installing normal kernel"
+  if [ -f $4/vmlinux-$1 ]; then
+    mv $4/vmlinux-$1 $4/vmlinux.old
+  fi
+
+  if [ -f $4/System.map ]; then
+    mv $4/System.map $4/System.old
+  fi
+
+  cat $2 > $4/vmlinux-$1
+  cp $3 $4/System.map
+fi
diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c
new file mode 100644 (file)
index 0000000..469c4dc
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * arch/m32r/boot/compressed/m32r_sio.c
+ *
+ * 2003-02-12: Takeo Takahashi
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+void putc(char c);
+
+int puts(const char *s)
+{
+       char c;
+       while ((c = *s++)) putc(c);
+       return 0;
+}
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+#define USE_FPGA_MAP   0
+
+#if USE_FPGA_MAP
+/*
+ * fpga configuration program uses MMU, and define map as same as
+ * M32104 uT-Engine board.
+ */
+#define BOOT_SIO0STS   (volatile unsigned short *)(0x02c00000 + 0x20006)
+#define BOOT_SIO0TXB   (volatile unsigned short *)(0x02c00000 + 0x2000c)
+#else
+#undef PLD_BASE
+#define PLD_BASE       0xa4c00000
+#define BOOT_SIO0STS   PLD_ESIO0STS
+#define BOOT_SIO0TXB   PLD_ESIO0TXB
+#endif
+
+void putc(char c)
+{
+
+       while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
+       if (c == '\n') {
+               *BOOT_SIO0TXB = '\r';
+               while ((*BOOT_SIO0STS & 0x3) != 0x3) ;
+       }
+       *BOOT_SIO0TXB = c;
+}
+#else
+void putc(char c)
+{
+       /* do nothing */
+}
+#endif
diff --git a/arch/m32r/boot/compressed/misc.c b/arch/m32r/boot/compressed/misc.c
new file mode 100644 (file)
index 0000000..4661d38
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * arch/m32r/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for SH by Stuart Menefy, Aug 1999
+ *
+ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000
+ *
+ * 2003-02-12: Support M32R by Takeo Takahashi
+ *             This is based on arch/sh/boot/compressed/misc.c.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000           /* Window size must be at least 32k, */
+                               /* and a power of two */
+
+static uch *inbuf;          /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+static unsigned insize;  /* valid bytes in inbuf */
+static unsigned inptr;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out;
+static uch *output_data;
+static unsigned long output_ptr;
+
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern int puts(const char *);
+
+extern int _text;              /* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#define HEAP_SIZE             0x10000
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+       void *p;
+
+       if (size <0) error("Malloc error\n");
+       if (free_mem_ptr == 0) error("Memory error\n");
+
+       free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+       p = (void *)free_mem_ptr;
+       free_mem_ptr += size;
+
+       if (free_mem_ptr >= free_mem_end_ptr)
+               error("\nOut of memory\n");
+
+       return p;
+}
+
+static void free(void *where)
+{      /* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+       *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+       free_mem_ptr = (long) *ptr;
+}
+
+void* memset(void* s, int c, size_t n)
+{
+       int i;
+       char *ss = (char*)s;
+
+       for (i=0;i<n;i++) ss[i] = c;
+       return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+                           size_t __n)
+{
+       int i;
+       char *d = (char *)__dest, *s = (char *)__src;
+
+       for (i=0;i<__n;i++) d[i] = s[i];
+       return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+       if (insize != 0) {
+               error("ran out of input data\n");
+       }
+
+       inbuf = input_data;
+       insize = input_len;
+       inptr = 1;
+       return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+
+    in = window;
+    out = &output_data[output_ptr];
+    for (n = 0; n < outcnt; n++) {
+           ch = *out++ = *in++;
+           c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void error(char *x)
+{
+       puts("\n\n");
+       puts(x);
+       puts("\n\n -- System halted");
+
+       while(1);       /* Halt */
+}
+
+#define STACK_SIZE (4096)
+long user_stack [STACK_SIZE];
+long* stack_start = &user_stack[STACK_SIZE];
+
+/* return decompressed size */
+long decompress_kernel(void)
+{
+       insize = 0;
+       inptr = 0;
+       bytes_out = 0;
+       outcnt = 0;
+       output_data = 0;
+       output_ptr = CONFIG_MEMORY_START + 0x2000;
+       free_mem_ptr = (unsigned long)&_end;
+       free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+       makecrc();
+       puts("Uncompressing Linux... ");
+       gunzip();
+       puts("Ok, booting the kernel.\n");
+       return bytes_out;
+}
diff --git a/arch/m32r/boot/compressed/vmlinux.lds.S b/arch/m32r/boot/compressed/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..20a9e94
--- /dev/null
@@ -0,0 +1,23 @@
+#include <linux/config.h>
+
+OUTPUT_ARCH(m32r)
+ENTRY(startup)
+SECTIONS
+{
+  . = CONFIG_MEMORY_START + 0x00400000;
+
+  _text = .;
+  .text : { *(.text) } = 0
+  .rodata : { *(.rodata) }
+  _etext = .;
+
+  . = ALIGN(32) + (. & (32 - 1));
+  .data : { *(.data) }
+  _edata  =  .;
+
+  . = ALIGN(32 / 8);
+  __bss_start = .;
+  .bss : { *(.bss) }
+  . = ALIGN(32 / 8);
+  _end = . ;
+}
diff --git a/arch/m32r/boot/compressed/vmlinux.scr b/arch/m32r/boot/compressed/vmlinux.scr
new file mode 100644 (file)
index 0000000..a084903
--- /dev/null
@@ -0,0 +1,9 @@
+SECTIONS
+{
+  .data : {
+       input_len = .;
+       LONG(input_data_end - input_data) input_data = .;
+       *(.data)
+       input_data_end = .;
+       }
+}
diff --git a/arch/m32r/boot/setup.S b/arch/m32r/boot/setup.S
new file mode 100644 (file)
index 0000000..9be5917
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *  linux/arch/m32r/boot/setup.S -- A setup code.
+ *
+ *  Copyright (C) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *  and Hitoshi Yamamoto
+ *
+ */
+/* $Id$ */
+
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <linux/config.h>
+#include <asm/assembler.h>
+#include <asm/mmu_context.h>
+#include <asm/m32r.h>
+
+/*
+ * References to members of the boot_cpu_data structure.
+ */
+
+#define CPU_PARAMS     boot_cpu_data
+#define M32R_MCICAR     0xfffffff0
+#define M32R_MCDCAR     0xfffffff4
+#define        M32R_MCCR        0xfffffffc
+#define M32R_BSCR0      0xffffffd2
+
+;BSEL
+#define BSEL0CR0        0x00ef5000
+#define        BSEL0CR1         0x00ef5004
+#define BSEL1CR0        0x00ef5100
+#define BSEL1CR1        0x00ef5104
+#define BSEL0CR0_VAL    0x00000000
+#define BSEL0CR1_VAL    0x01200100
+#define BSEL1CR0_VAL    0x01018000
+#define BSEL1CR1_VAL    0x00200001
+
+;SDRAMC
+#define SDRAMC_SDRF0    0x00ef6000
+#define SDRAMC_SDRF1    0x00ef6004
+#define SDRAMC_SDIR0    0x00ef6008
+#define SDRAMC_SDIR1    0x00ef600c
+#define SDRAMC_SD0ADR   0x00ef6020
+#define SDRAMC_SD0ER    0x00ef6024
+#define SDRAMC_SD0TR    0x00ef6028
+#define SDRAMC_SD0MOD   0x00ef602c
+#define SDRAMC_SD1ADR   0x00ef6040
+#define SDRAMC_SD1ER    0x00ef6044
+#define SDRAMC_SD1TR    0x00ef6048
+#define SDRAMC_SD1MOD   0x00ef604c
+#define SDRAM0          0x18000000
+#define SDRAM1          0x1c000000
+
+/*------------------------------------------------------------------------
+ * start up
+ */
+
+/*------------------------------------------------------------------------
+ * Kernel entry
+ */
+       .section .boot, "ax"
+ENTRY(boot)
+
+/* Set cache mode */
+#if defined(CONFIG_CHIP_XNUX2)
+       ldi     r0, #-2              ;LDIMM     (r0, M32R_MCCR)
+       ldi     r1, #0x0101             ; cache on (with invalidation)
+;      ldi     r1, #0x00               ; cache off
+       sth     r1, @r0
+#elif defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_VDEC2) \
+    || defined(CONFIG_CHIP_OPSP)
+       ldi     r0, #-4              ;LDIMM     (r0, M32R_MCCR)
+       ldi     r1, #0x73               ; cache on (with invalidation)
+;      ldi     r1, #0x00               ; cache off
+       st      r1, @r0
+#else
+#error unknown chip configuration
+#endif
+
+#ifdef CONFIG_SMP
+       ;; if not BSP (CPU#0) goto AP_loop
+       seth    r5, #shigh(M32R_CPUID_PORTL)
+       ld      r5, @(low(M32R_CPUID_PORTL), r5)
+       bnez    r5, AP_loop
+#if !defined(CONFIG_PLAT_USRV)
+       ;; boot AP
+       ld24    r5, #0xeff2f8           ; IPICR7
+       ldi     r6, #0x2                ; IPI to CPU1
+       st      r6, @r5
+#endif
+#endif
+
+/*
+ *  Now, Jump to stext
+ *        if with MMU,    TLB on.
+ *        if with no MMU, only jump.
+ */
+       .global eit_vector
+mmu_on:
+       LDIMM   (r13, stext)
+#ifdef CONFIG_MMU
+       bl      init_tlb
+       LDIMM   (r2, eit_vector)                ; set EVB(cr5)
+       mvtc    r2, cr5
+       seth    r0, #high(MMU_REG_BASE)         ; Set MMU_REG_BASE higher
+       or3     r0, r0, #low(MMU_REG_BASE)      ; Set MMU_REG_BASE lower
+       ldi     r1, #0x01
+       st      r1, @(MATM_offset,r0)           ; Set MATM (T bit ON)
+       ld      r0, @(MATM_offset,r0)           ; Check
+#else
+       seth    r0,#high(M32R_MCDCAR)
+       or3     r0,r0,#low(M32R_MCDCAR)
+       ld24    r1,#0x8080
+       st      r1,@r0
+#endif /* CONFIG_MMU */
+       jmp     r13
+       nop
+       nop
+
+#ifdef CONFIG_SMP
+/*
+ * AP wait loop
+ */
+ENTRY(AP_loop)
+       ;; disable interrupt
+       clrpsw  #0x40
+       ;; reset EVB
+       LDIMM   (r4, _AP_RE)
+       seth    r5, #high(__PAGE_OFFSET)
+       or3     r5, r5, #low(__PAGE_OFFSET)
+       not     r5, r5
+       and     r4, r5
+       mvtc    r4, cr5
+       ;; disable maskable interrupt
+       seth    r4, #high(M32R_ICU_IMASK_PORTL)
+       or3     r4, r4, #low(M32R_ICU_IMASK_PORTL)
+       ldi     r5, #0
+       st      r5, @r4
+       ld      r5, @r4
+       ;; enable only IPI
+       setpsw  #0x40
+       ;; LOOOOOOOOOOOOOOP!!!
+       .fillinsn
+2:
+       nop
+       nop
+       bra     2b
+       nop
+       nop
+
+#ifdef CONFIG_CHIP_M32700_TS1
+       .global dcache_dummy
+       .balign 16, 0
+dcache_dummy:
+       .byte   16
+#endif /* CONFIG_CHIP_M32700_TS1 */
+#endif /* CONFIG_SMP */
+
+       .end
+
diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig
new file mode 100644 (file)
index 0000000..984701b
--- /dev/null
@@ -0,0 +1,635 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+CONFIG_PLAT_M32700UT=y
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+# CONFIG_M32RPCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32700UT_CFC=y
+CONFIG_CFC_NUM=1
+# CONFIG_MTD_M32R is not set
+CONFIG_M32R_SMC91111=y
+CONFIG_M32700UT_DS1302=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_PLDSIO=y
+CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+CONFIG_M32R_AR=y
+CONFIG_M32R_AR_VGA=y
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR 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_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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_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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/kernel/Makefile b/arch/m32r/kernel/Makefile
new file mode 100644 (file)
index 0000000..cfd690b
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Makefile for the Linux/M32R kernel.
+#
+
+extra-y        := head.o init_task.o vmlinux.lds
+
+obj-y  := process.o entry.o traps.o align.o irq.o setup.o time.o \
+       m32r_ksyms.o sys_m32r.o semaphore.o signal.o ptrace.o
+
+obj-$(CONFIG_SMP)              += smp.o smpboot.o
+obj-$(CONFIG_PLAT_MAPPI)       += setup_mappi.o io_mappi.o
+obj-$(CONFIG_PLAT_MAPPI2)      += setup_mappi2.o io_mappi2.o
+obj-$(CONFIG_PLAT_USRV)                += setup_usrv.o io_usrv.o
+obj-$(CONFIG_PLAT_M32700UT)    += setup_m32700ut.o io_m32700ut.o
+obj-$(CONFIG_PLAT_OPSPUT)      += setup_opsput.o io_opsput.o
+obj-$(CONFIG_MODULES)          += module.o
+obj-$(CONFIG_PLAT_OAKS32R)     += setup_oaks32r.o io_oaks32r.o
+
+EXTRA_AFLAGS   := -traditional
+
diff --git a/arch/m32r/kernel/align.c b/arch/m32r/kernel/align.c
new file mode 100644 (file)
index 0000000..48ec297
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * align.c - address exception handler for M32R
+ *
+ * Copyright (c) 2003 Hitoshi Yamamoto
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+static int get_reg(struct pt_regs *regs, int nr)
+{
+       int val;
+
+       if (nr < 4)
+               val = *(unsigned long *)(&regs->r0 + nr);
+       else if (nr < 7)
+               val = *(unsigned long *)(&regs->r4 + (nr - 4));
+       else if (nr < 13)
+               val = *(unsigned long *)(&regs->r7 + (nr - 7));
+       else
+               val = *(unsigned long *)(&regs->fp + (nr - 13));
+
+       return val;
+}
+
+static void set_reg(struct pt_regs *regs, int nr, int val)
+{
+       if (nr < 4)
+               *(unsigned long *)(&regs->r0 + nr) = val;
+       else if (nr < 7)
+               *(unsigned long *)(&regs->r4 + (nr - 4)) = val;
+       else if (nr < 13)
+               *(unsigned long *)(&regs->r7 + (nr - 7)) = val;
+       else
+               *(unsigned long *)(&regs->fp + (nr - 13)) = val;
+}
+
+#define REG1(insn)     (((insn) & 0x0f00) >> 8)
+#define REG2(insn)     ((insn) & 0x000f)
+#define PSW_BC         0x100
+
+/* O- instruction */
+#define ISA_LD1                0x20c0  /* ld Rdest, @Rsrc */
+#define ISA_LD2                0x20e0  /* ld Rdest, @Rsrc+ */
+#define ISA_LDH                0x20a0  /* ldh Rdest, @Rsrc */
+#define ISA_LDUH       0x20b0  /* lduh Rdest, @Rsrc */
+#define ISA_ST1                0x2040  /* st Rsrc1, @Rsrc2 */
+#define ISA_ST2                0x2060  /* st Rsrc1, @+Rsrc2 */
+#define ISA_ST3                0x2070  /* st Rsrc1, @-Rsrc2 */
+#define ISA_STH1       0x2020  /* sth Rsrc1, @Rsrc2 */
+#define ISA_STH2       0x2030  /* sth Rsrc1, @Rsrc2+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+/* OS instruction */
+#define ISA_ADD                0x00a0  /* add Rdest, Rsrc */
+#define ISA_ADDI       0x4000  /* addi Rdest, #imm8 */
+#define ISA_ADDX       0x0090  /* addx Rdest, Rsrc */
+#define ISA_AND                0x00c0  /* and Rdest, Rsrc */
+#define ISA_CMP                0x0040  /* cmp Rsrc1, Rsrc2 */
+#define ISA_CMPEQ      0x0060  /* cmpeq Rsrc1, Rsrc2 */
+#define ISA_CMPU       0x0050  /* cmpu Rsrc1, Rsrc2 */
+#define ISA_CMPZ       0x0070  /* cmpz Rsrc */
+#define ISA_LDI                0x6000  /* ldi Rdest, #imm8 */
+#define ISA_MV         0x1080  /* mv Rdest, Rsrc */
+#define ISA_NEG                0x0030  /* neg Rdest, Rsrc */
+#define ISA_NOP                0x7000  /* nop */
+#define ISA_NOT                0x00b0  /* not Rdest, Rsrc */
+#define ISA_OR         0x00e0  /* or Rdest, Rsrc */
+#define ISA_SUB                0x0020  /* sub Rdest, Rsrc */
+#define ISA_SUBX       0x0010  /* subx Rdest, Rsrc */
+#define ISA_XOR                0x00d0  /* xor Rdest, Rsrc */
+
+/* -S instruction */
+#define ISA_MUL                0x1060  /* mul Rdest, Rsrc */
+#define ISA_MULLO_A0   0x3010  /* mullo Rsrc1, Rsrc2, A0 */
+#define ISA_MULLO_A1   0x3090  /* mullo Rsrc1, Rsrc2, A1 */
+#define ISA_MVFACMI_A0 0x50f2  /* mvfacmi Rdest, A0 */
+#define ISA_MVFACMI_A1 0x50f6  /* mvfacmi Rdest, A1 */
+
+static int emu_addi(unsigned short insn, struct pt_regs *regs)
+{
+       char imm = (char)(insn & 0xff);
+       int dest = REG1(insn);
+       int val;
+
+       val = get_reg(regs, dest);
+       val += imm;
+       set_reg(regs, dest, val);
+
+       return 0;
+}
+
+static int emu_ldi(unsigned short insn, struct pt_regs *regs)
+{
+       char imm = (char)(insn & 0xff);
+
+       set_reg(regs, REG1(insn), (int)imm);
+
+       return 0;
+}
+
+static int emu_add(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       int src = REG2(insn);
+       int val;
+
+       val = get_reg(regs, dest);
+       val += get_reg(regs, src);
+       set_reg(regs, dest, val);
+
+       return 0;
+}
+
+static int emu_addx(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       unsigned int val, tmp;
+
+       val = regs->psw & PSW_BC ? 1 : 0;
+       tmp = get_reg(regs, dest);
+       val += tmp;
+       val += (unsigned int)get_reg(regs, REG2(insn));
+       set_reg(regs, dest, val);
+
+       /* C bit set */
+       if (val < tmp)
+               regs->psw |= PSW_BC;
+       else
+               regs->psw &= ~(PSW_BC);
+
+       return 0;
+}
+
+static int emu_and(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       int val;
+
+       val = get_reg(regs, dest);
+       val &= get_reg(regs, REG2(insn));
+       set_reg(regs, dest, val);
+
+       return 0;
+}
+
+static int emu_cmp(unsigned short insn, struct pt_regs *regs)
+{
+       if (get_reg(regs, REG1(insn)) < get_reg(regs, REG2(insn)))
+               regs->psw |= PSW_BC;
+       else
+               regs->psw &= ~(PSW_BC);
+
+       return 0;
+}
+
+static int emu_cmpeq(unsigned short insn, struct pt_regs *regs)
+{
+       if (get_reg(regs, REG1(insn)) == get_reg(regs, REG2(insn)))
+               regs->psw |= PSW_BC;
+       else
+               regs->psw &= ~(PSW_BC);
+
+       return 0;
+}
+
+static int emu_cmpu(unsigned short insn, struct pt_regs *regs)
+{
+       if ((unsigned int)get_reg(regs, REG1(insn))
+               < (unsigned int)get_reg(regs, REG2(insn)))
+               regs->psw |= PSW_BC;
+       else
+               regs->psw &= ~(PSW_BC);
+
+       return 0;
+}
+
+static int emu_cmpz(unsigned short insn, struct pt_regs *regs)
+{
+       if (!get_reg(regs, REG2(insn)))
+               regs->psw |= PSW_BC;
+       else
+               regs->psw &= ~(PSW_BC);
+
+       return 0;
+}
+
+static int emu_mv(unsigned short insn, struct pt_regs *regs)
+{
+       int val;
+
+       val = get_reg(regs, REG2(insn));
+       set_reg(regs, REG1(insn), val);
+
+       return 0;
+}
+
+static int emu_neg(unsigned short insn, struct pt_regs *regs)
+{
+       int val;
+
+       val = get_reg(regs, REG2(insn));
+       set_reg(regs, REG1(insn), 0 - val);
+
+       return 0;
+}
+
+static int emu_not(unsigned short insn, struct pt_regs *regs)
+{
+       int val;
+
+       val = get_reg(regs, REG2(insn));
+       set_reg(regs, REG1(insn), ~val);
+
+       return 0;
+}
+
+static int emu_or(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       int val;
+
+       val = get_reg(regs, dest);
+       val |= get_reg(regs, REG2(insn));
+       set_reg(regs, dest, val);
+
+       return 0;
+}
+
+static int emu_sub(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       int val;
+
+       val = get_reg(regs, dest);
+       val -= get_reg(regs, REG2(insn));
+       set_reg(regs, dest, val);
+
+       return 0;
+}
+
+static int emu_subx(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       unsigned int val, tmp;
+
+       val = tmp = get_reg(regs, dest);
+       val -= (unsigned int)get_reg(regs, REG2(insn));
+       val -= regs->psw & PSW_BC ? 1 : 0;
+       set_reg(regs, dest, val);
+
+       /* C bit set */
+       if (val > tmp)
+               regs->psw |= PSW_BC;
+       else
+               regs->psw &= ~(PSW_BC);
+
+       return 0;
+}
+
+static int emu_xor(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       unsigned int val;
+
+       val = (unsigned int)get_reg(regs, dest);
+       val ^= (unsigned int)get_reg(regs, REG2(insn));
+       set_reg(regs, dest, val);
+
+       return 0;
+}
+
+static int emu_mul(unsigned short insn, struct pt_regs *regs)
+{
+       int dest = REG1(insn);
+       int reg1, reg2;
+
+       reg1 = get_reg(regs, dest);
+       reg2 = get_reg(regs, REG2(insn));
+
+       __asm__ __volatile__ (
+               "mul    %0, %1;         \n\t"
+               : "+r" (reg1) : "r" (reg2)
+       );
+
+       set_reg(regs, dest, reg1);
+
+       return 0;
+}
+
+static int emu_mullo_a0(unsigned short insn, struct pt_regs *regs)
+{
+       int reg1, reg2;
+
+       reg1 = get_reg(regs, REG1(insn));
+       reg2 = get_reg(regs, REG2(insn));
+
+       __asm__ __volatile__ (
+               "mullo          %0, %1, a0;     \n\t"
+               "mvfachi        %0, a0;         \n\t"
+               "mvfaclo        %1, a0;         \n\t"
+               : "+r" (reg1), "+r" (reg2)
+       );
+
+       regs->acc0h = reg1;
+       regs->acc0l = reg2;
+
+       return 0;
+}
+
+static int emu_mullo_a1(unsigned short insn, struct pt_regs *regs)
+{
+       int reg1, reg2;
+
+       reg1 = get_reg(regs, REG1(insn));
+       reg2 = get_reg(regs, REG2(insn));
+
+       __asm__ __volatile__ (
+               "mullo          %0, %1, a0;     \n\t"
+               "mvfachi        %0, a0;         \n\t"
+               "mvfaclo        %1, a0;         \n\t"
+               : "+r" (reg1), "+r" (reg2)
+       );
+
+       regs->acc1h = reg1;
+       regs->acc1l = reg2;
+
+       return 0;
+}
+
+static int emu_mvfacmi_a0(unsigned short insn, struct pt_regs *regs)
+{
+       unsigned long val;
+
+       val = (regs->acc0h << 16) | (regs->acc0l >> 16);
+       set_reg(regs, REG1(insn), (int)val);
+
+       return 0;
+}
+
+static int emu_mvfacmi_a1(unsigned short insn, struct pt_regs *regs)
+{
+       unsigned long val;
+
+       val = (regs->acc1h << 16) | (regs->acc1l >> 16);
+       set_reg(regs, REG1(insn), (int)val);
+
+       return 0;
+}
+
+static int emu_m32r2(unsigned short insn, struct pt_regs *regs)
+{
+       int res = -1;
+
+       if ((insn & 0x7fff) == ISA_NOP) /* nop */
+               return 0;
+
+       switch(insn & 0x7000) {
+       case ISA_ADDI:          /* addi Rdest, #imm8 */
+               res = emu_addi(insn, regs);
+               break;
+       case ISA_LDI:           /* ldi Rdest, #imm8 */
+               res = emu_ldi(insn, regs);
+               break;
+       default:
+               break;
+       }
+
+       if (!res)
+               return 0;
+
+       switch(insn & 0x70f0) {
+       case ISA_ADD:           /* add Rdest, Rsrc */
+               res = emu_add(insn, regs);
+               break;
+       case ISA_ADDX:          /* addx Rdest, Rsrc */
+               res = emu_addx(insn, regs);
+               break;
+       case ISA_AND:           /* and Rdest, Rsrc */
+               res = emu_and(insn, regs);
+               break;
+       case ISA_CMP:           /* cmp Rsrc1, Rsrc2 */
+               res = emu_cmp(insn, regs);
+               break;
+       case ISA_CMPEQ:         /* cmpeq Rsrc1, Rsrc2 */
+               res = emu_cmpeq(insn, regs);
+               break;
+       case ISA_CMPU:          /* cmpu Rsrc1, Rsrc2 */
+               res = emu_cmpu(insn, regs);
+               break;
+       case ISA_CMPZ:          /* cmpz Rsrc */
+               res = emu_cmpz(insn, regs);
+               break;
+       case ISA_MV:            /* mv Rdest, Rsrc */
+               res = emu_mv(insn, regs);
+               break;
+       case ISA_NEG:           /* neg Rdest, Rsrc */
+               res = emu_neg(insn, regs);
+               break;
+       case ISA_NOT:           /* not Rdest, Rsrc */
+               res = emu_not(insn, regs);
+               break;
+       case ISA_OR:            /* or Rdest, Rsrc */
+               res = emu_or(insn, regs);
+               break;
+       case ISA_SUB:           /* sub Rdest, Rsrc */
+               res = emu_sub(insn, regs);
+               break;
+       case ISA_SUBX:          /* subx Rdest, Rsrc */
+               res = emu_subx(insn, regs);
+               break;
+       case ISA_XOR:           /* xor Rdest, Rsrc */
+               res = emu_xor(insn, regs);
+               break;
+       case ISA_MUL:           /* mul Rdest, Rsrc */
+               res = emu_mul(insn, regs);
+               break;
+       case ISA_MULLO_A0:      /* mullo Rsrc1, Rsrc2 */
+               res = emu_mullo_a0(insn, regs);
+               break;
+       case ISA_MULLO_A1:      /* mullo Rsrc1, Rsrc2 */
+               res = emu_mullo_a1(insn, regs);
+               break;
+       default:
+               break;
+       }
+
+       if (!res)
+               return 0;
+
+       switch(insn & 0x70ff) {
+       case ISA_MVFACMI_A0:    /* mvfacmi Rdest */
+               res = emu_mvfacmi_a0(insn, regs);
+               break;
+       case ISA_MVFACMI_A1:    /* mvfacmi Rdest */
+               res = emu_mvfacmi_a1(insn, regs);
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
+#endif /* CONFIG_ISA_DUAL_ISSUE */
+
+/*
+ * ld   : ?010 dest 1100 src
+ *        0010 dest 1110 src : ld Rdest, @Rsrc+
+ * ldh  : ?010 dest 1010 src
+ * lduh : ?010 dest 1011 src
+ * st   : ?010 src1 0100 src2
+ *        0010 src1 0110 src2 : st Rsrc1, @+Rsrc2
+ *        0010 src1 0111 src2 : st Rsrc1, @-Rsrc2
+ * sth  : ?010 src1 0010 src2
+ */
+
+static int insn_check(unsigned long insn, struct pt_regs *regs,
+       unsigned char **ucp)
+{
+       int res = 0;
+
+       /*
+        * 32bit insn
+        *  ld Rdest, @(disp16, Rsrc)
+        *  st Rdest, @(disp16, Rsrc)
+        */
+       if (insn & 0x80000000) {        /* 32bit insn */
+               *ucp += (short)(insn & 0x0000ffff);
+               regs->bpc += 4;
+       } else {                        /* 16bit insn */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+               /* parallel exec check */
+               if (!(regs->bpc & 0x2) && insn & 0x8000) {
+                       res = emu_m32r2((unsigned short)insn, regs);
+                       regs->bpc += 4;
+               } else
+#endif /* CONFIG_ISA_DUAL_ISSUE */
+                       regs->bpc += 2;
+       }
+
+       return res;
+}
+
+static int emu_ld(unsigned long insn32, struct pt_regs *regs)
+{
+       unsigned char *ucp;
+       unsigned long val;
+       unsigned short insn16;
+       int size, src;
+
+       insn16 = insn32 >> 16;
+       src = REG2(insn16);
+       ucp = (unsigned char *)get_reg(regs, src);
+
+       if (insn_check(insn32, regs, &ucp))
+               return -1;
+
+       size = insn16 & 0x0040 ? 4 : 2;
+       if (copy_from_user(&val, ucp, size))
+               return -1;
+
+       if (size == 2)
+               val >>= 16;
+
+       /* ldh sign check */
+       if ((insn16 & 0x00f0) == 0x00a0 && (val & 0x8000))
+               val |= 0xffff0000;
+
+       set_reg(regs, REG1(insn16), val);
+
+       /* ld increment check */
+       if ((insn16 & 0xf0f0) == ISA_LD2)       /* ld Rdest, @Rsrc+ */
+               set_reg(regs, src, (unsigned long)(ucp + 4));
+
+       return 0;
+}
+
+static int emu_st(unsigned long insn32, struct pt_regs *regs)
+{
+       unsigned char *ucp;
+       unsigned long val;
+       unsigned short insn16;
+       int size, src2;
+
+       insn16 = insn32 >> 16;
+       src2 = REG2(insn16);
+
+       ucp = (unsigned char *)get_reg(regs, src2);
+
+       if (insn_check(insn32, regs, &ucp))
+               return -1;
+
+       size = insn16 & 0x0040 ? 4 : 2;
+       val = get_reg(regs, REG1(insn16));
+       if (size == 2)
+               val <<= 16;
+
+       /* st inc/dec check */
+       if ((insn16 & 0xf0e0) == 0x2060) {
+               if (insn16 & 0x0010)
+                       ucp -= 4;
+               else
+                       ucp += 4;
+
+               set_reg(regs, src2, (unsigned long)ucp);
+       }
+
+       if (copy_to_user(ucp, &val, size))
+               return -1;
+
+       /* sth inc check */
+       if ((insn16 & 0xf0f0) == ISA_STH2) {
+               ucp += 2;
+               set_reg(regs, src2, (unsigned long)ucp);
+       }
+
+       return 0;
+}
+
+int handle_unaligned_access(unsigned long insn32, struct pt_regs *regs)
+{
+       unsigned short insn16;
+       int res;
+
+       insn16 = insn32 >> 16;
+
+       /* ld or st check */
+       if ((insn16 & 0x7000) != 0x2000)
+               return -1;
+
+       /* insn alignment check */
+       if ((insn16 & 0x8000) && (regs->bpc & 3))
+               return -1;
+
+       if (insn16 & 0x0080)    /* ld */
+               res = emu_ld(insn32, regs);
+       else                    /* st */
+               res = emu_st(insn32, regs);
+
+       return res;
+}
+
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S
new file mode 100644 (file)
index 0000000..29b0d8d
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ *  linux/arch/m32r/kernel/entry.S
+ *
+ *  Copyright (c) 2001, 2002  Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
+ *  Copyright (c) 2003  Hitoshi Yamamoto
+ *  Copyright (c) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ *  Taken from i386 version.
+ *    Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ *     ptrace needs to have all regs on the stack.
+ *     if the order here is changed, it needs to be
+ *     updated in fork.c:copy_process, signal.c:do_signal,
+ *     ptrace.c and ptrace.h
+ *
+ * M32Rx/M32R2                         M32R
+ *       @(sp)      - r4               ditto
+ *       @(0x04,sp) - r5               ditto
+ *       @(0x08,sp) - r6               ditto
+ *       @(0x0c,sp) - *pt_regs         ditto
+ *       @(0x10,sp) - r0               ditto
+ *       @(0x14,sp) - r1               ditto
+ *       @(0x18,sp) - r2               ditto
+ *       @(0x1c,sp) - r3               ditto
+ *       @(0x20,sp) - r7               ditto
+ *       @(0x24,sp) - r8               ditto
+ *       @(0x28,sp) - r9               ditto
+ *       @(0x2c,sp) - r10              ditto
+ *       @(0x30,sp) - r11              ditto
+ *       @(0x34,sp) - r12              ditto
+ *       @(0x38,sp) - syscall_nr       ditto
+ *       @(0x3c,sp) - acc0h            @(0x3c,sp) - acch
+ *       @(0x40,sp) - acc0l            @(0x40,sp) - accl
+ *       @(0x44,sp) - acc1h            @(0x44,sp) - psw
+ *       @(0x48,sp) - acc1l            @(0x48,sp) - bpc
+ *       @(0x4c,sp) - psw              @(0x4c,sp) - bbpsw
+ *       @(0x50,sp) - bpc              @(0x50,sp) - bbpc
+ *       @(0x54,sp) - bbpsw            @(0x54,sp) - spu (cr3)
+ *       @(0x58,sp) - bbpc             @(0x58,sp) - fp (r13)
+ *       @(0x5c,sp) - spu (cr3)                @(0x5c,sp) - lr (r14)
+ *       @(0x60,sp) - fp (r13)         @(0x60,sp) - spi (cr12)
+ *       @(0x64,sp) - lr (r14)         @(0x64,sp) - orig_r0
+ *       @(0x68,sp) - spi (cr2)
+ *       @(0x6c,sp) - orig_r0
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/irq.h>
+#include <asm/unistd.h>
+#include <asm/assembler.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/m32r.h>
+#include <asm/mmu_context.h>
+
+#if !defined(CONFIG_MMU)
+#define sys_madvise             sys_ni_syscall
+#define sys_readahead           sys_ni_syscall
+#define sys_mprotect            sys_ni_syscall
+#define sys_msync               sys_ni_syscall
+#define sys_mlock               sys_ni_syscall
+#define sys_munlock             sys_ni_syscall
+#define sys_mlockall            sys_ni_syscall
+#define sys_munlockall          sys_ni_syscall
+#define sys_mremap              sys_ni_syscall
+#define sys_mincore             sys_ni_syscall
+#endif /* CONFIG_MMU */
+
+#define R4(reg)                        @reg
+#define R5(reg)                        @(0x04,reg)
+#define R6(reg)                        @(0x08,reg)
+#define PTREGS(reg)            @(0x0C,reg)
+#define R0(reg)                        @(0x10,reg)
+#define R1(reg)                        @(0x14,reg)
+#define R2(reg)                        @(0x18,reg)
+#define R3(reg)                        @(0x1C,reg)
+#define R7(reg)                        @(0x20,reg)
+#define R8(reg)                        @(0x24,reg)
+#define R9(reg)                        @(0x28,reg)
+#define R10(reg)               @(0x2C,reg)
+#define R11(reg)               @(0x30,reg)
+#define R12(reg)               @(0x34,reg)
+#define SYSCALL_NR(reg)                @(0x38,reg)
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+#define ACC0H(reg)             @(0x3C,reg)
+#define ACC0L(reg)             @(0x40,reg)
+#define ACC1H(reg)             @(0x44,reg)
+#define ACC1L(reg)             @(0x48,reg)
+#define PSW(reg)               @(0x4C,reg)
+#define BPC(reg)               @(0x50,reg)
+#define BBPSW(reg)             @(0x54,reg)
+#define BBPC(reg)              @(0x58,reg)
+#define SPU(reg)               @(0x5C,reg)
+#define FP(reg)                        @(0x60,reg)  /* FP = R13 */
+#define LR(reg)                        @(0x64,reg)
+#define SP(reg)                        @(0x68,reg)
+#define ORIG_R0(reg)           @(0x6C,reg)
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+#define ACCH(reg)              @(0x3C,reg)
+#define ACCL(reg)              @(0x40,reg)
+#define PSW(reg)               @(0x44,reg)
+#define BPC(reg)               @(0x48,reg)
+#define BBPSW(reg)             @(0x4C,reg)
+#define BBPC(reg)              @(0x50,reg)
+#define SPU(reg)               @(0x54,reg)
+#define FP(reg)                        @(0x58,reg)  /* FP = R13 */
+#define LR(reg)                        @(0x5C,reg)
+#define SP(reg)                        @(0x60,reg)
+#define ORIG_R0(reg)           @(0x64,reg)
+#else
+#error unknown isa configuration
+#endif
+
+CF_MASK                = 0x00000001
+TF_MASK                = 0x00000100
+IF_MASK                = 0x00000200
+DF_MASK                = 0x00000400
+NT_MASK                = 0x00004000
+VM_MASK                = 0x00020000
+
+#ifdef CONFIG_PREEMPT
+#define preempt_stop(x)                CLI(x)
+#else
+#define preempt_stop(x)
+#define resume_kernel          restore_all
+#endif
+
+ENTRY(ret_from_fork)
+       ld      r0, @sp+
+       bl      schedule_tail
+       GET_THREAD_INFO(r8)
+       bra     syscall_exit
+
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
+
+       ; userspace resumption stub bypassing syscall exit tracing
+       ALIGN
+ret_from_exception:
+       preempt_stop(r4)
+ret_from_intr:
+       ld      r4, PSW(sp)
+#ifdef CONFIG_ISA_M32R2
+       and3    r4, r4, #0x8800         ; check BSM and BPM bits
+#else
+       and3    r4, r4, #0x8000         ; check BSM bit
+#endif
+       beqz    r4, resume_kernel
+ENTRY(resume_userspace)
+       CLI(r4)                         ; make sure we don't miss an interrupt
+                                       ; setting need_resched or sigpending
+                                       ; between sampling and the iret
+       GET_THREAD_INFO(r8)
+       ld      r9, @(TI_FLAGS, r8)
+       and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
+                                       ; int/exception return?
+       bnez    r4, work_pending
+       bra     restore_all
+
+#ifdef CONFIG_PREEMPT
+ENTRY(resume_kernel)
+       GET_THREAD_INFO(r8)
+       ld      r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
+       bnez    r9, restore_all
+need_resched:
+       ld      r9, @(TI_FLAGS, r8)     ; need_resched set ?
+       and3    r4, r9, #_TIF_NEED_RESCHED
+       beqz    r4, restore_all
+       ld      r4, PSW(sp)             ; interrupts off (exception path) ?
+       and3    r4, r4, #0x4000
+       beqz    r4, restore_all
+       LDIMM   (r4, PREEMPT_ACTIVE)
+       st      r4, @(TI_PRE_COUNT, r8)
+       STI(r4)
+       bl      schedule
+       ldi     r4, #0
+       st      r4, @(TI_PRE_COUNT, r8)
+       CLI(r4)
+       bra     need_resched
+#endif
+
+       ; system call handler stub
+ENTRY(system_call)
+       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL
+       STI(r4)                         ; Enable interrupt
+       st      sp, PTREGS(sp)          ; implicit pt_regs parameter
+       cmpui   r7, #NR_syscalls
+       bnc     syscall_badsys
+       st      r7, SYSCALL_NR(sp)      ; syscall_nr
+                                       ; system call tracing in operation
+       GET_THREAD_INFO(r8)
+       ld      r9, @(TI_FLAGS, r8)
+       and3    r4, r9, #_TIF_SYSCALL_TRACE
+       bnez    r4, syscall_trace_entry
+syscall_call:
+       slli    r7, #2                  ; table jump for the system call
+       LDIMM   (r4, sys_call_table)
+       add     r7, r4
+       ld      r7, @r7
+       jl      r7                      ; execute system call
+       st      r0, R0(sp)              ; save the return value
+syscall_exit:
+       CLI(r4)                         ; make sure we don't miss an interrupt
+                                       ; setting need_resched or sigpending
+                                       ; between sampling and the iret
+       ld      r9, @(TI_FLAGS, r8)
+       and3    r4, r9, #_TIF_ALLWORK_MASK      ; current->work
+       bnez    r4, syscall_exit_work
+restore_all:
+       RESTORE_ALL
+
+       # perform work that needs to be done immediately before resumption
+       # r9 : frags
+       ALIGN
+work_pending:
+       and3    r4, r9, #_TIF_NEED_RESCHED
+       beqz    r4, work_notifysig
+work_resched:
+       bl      schedule
+       CLI(r4)                         ; make sure we don't miss an interrupt
+                                       ; setting need_resched or sigpending
+                                       ; between sampling and the iret
+       ld      r9, @(TI_FLAGS, r8)
+       and3    r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
+                                       ; than syscall tracing?
+       beqz    r4, restore_all
+       and3    r4, r4, #_TIF_NEED_RESCHED
+       bnez    r4, work_resched
+
+work_notifysig:                                ; deal with pending signals and
+                                       ; notify-resume requests
+       mv      r0, sp                  ; arg1 : struct pt_regs *regs
+       ldi     r1, #0                  ; arg2 : sigset_t *oldset
+       mv      r2, r9                  ; arg3 : __u32 thread_info_flags
+       bl      do_notify_resume
+       bra     restore_all
+
+       ; perform syscall exit tracing
+       ALIGN
+syscall_trace_entry:
+       ldi     r4, #-ENOSYS
+       st      r4, R0(sp)
+       bl      do_syscall_trace
+       ld      r0, ORIG_R0(sp)
+       ld      r1, R1(sp)
+       ld      r2, R2(sp)
+       ld      r3, R3(sp)
+       ld      r4, R4(sp)
+       ld      r5, R5(sp)
+       ld      r6, R6(sp)
+       ld      r7, SYSCALL_NR(sp)
+       cmpui   r7, #NR_syscalls
+       bc      syscall_call
+       bra     syscall_exit
+
+       ; perform syscall exit tracing
+       ALIGN
+syscall_exit_work:
+       ld      r9, @(TI_FLAGS, r8)
+       and3    r4, r9, #_TIF_SYSCALL_TRACE
+       beqz    r4, work_pending
+       STI(r4)                         ; could let do_syscall_trace() call
+                                       ; schedule() instead
+       bl      do_syscall_trace
+       bra     resume_userspace
+
+       ALIGN
+syscall_fault:
+       SAVE_ALL
+       GET_THREAD_INFO(r8)
+       ldi     r4, #-EFAULT
+       st      r4, R0(sp)
+       bra     resume_userspace
+
+       ALIGN
+syscall_badsys:
+       ldi     r4, #-ENOSYS
+       st      r4, R0(sp)
+       bra     resume_userspace
+
+       .global eit_vector
+
+       .equ ei_vec_table, eit_vector + 0x0200
+
+/*
+ * EI handler routine
+ */
+ENTRY(ei_handler)
+#if defined(CONFIG_CHIP_M32700)
+       SWITCH_TO_KERNEL_STACK
+       ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
+#endif
+       SAVE_ALL
+       mv      r1, sp                  ; arg1(regs)
+#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \
+       || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \
+       || defined(CONFIG_CHIP_OPSP)
+
+;    GET_ICU_STATUS;
+       seth    r0, #shigh(M32R_ICU_ISTS_ADDR)
+       ld      r0, @(low(M32R_ICU_ISTS_ADDR),r0)
+       st      r0, @-sp
+#if defined(CONFIG_SMP)
+       /*
+        * If IRQ == 0      --> Nothing to do,  Not write IMASK
+        * If IRQ == IPI    --> Do IPI handler, Not write IMASK
+        * If IRQ != 0, IPI --> Do do_IRQ(),    Write IMASK
+        */
+       slli    r0, #4
+       srli    r0, #24                 ; r0(irq_num<<2)
+       ;; IRQ exist check
+#if defined(CONFIG_CHIP_M32700)
+       /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
+       beqz    r0, 3f                  ; if (!irq_num) goto exit
+#else
+       beqz    r0, 1f                  ; if (!irq_num) goto exit
+#endif /* WORKAROUND */
+       ;; IPI check
+       cmpi    r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
+       bc      2f
+       cmpi    r0, #((M32R_IRQ_IPI7+1)<<2)     ; ISN > IPI7 check
+       bnc     2f
+       LDIMM   (r2, ei_vec_table)
+       add     r2, r0
+       ld      r2, @r2
+       beqz    r2, 1f                  ; if (no IPI handler) goto exit
+       mv      r0, r1                  ; arg0(regs)
+       jl      r2
+       .fillinsn
+1:
+       addi    sp, #4
+       bra     ret_to_intr
+#if defined(CONFIG_CHIP_M32700)
+       /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
+       .fillinsn
+3:
+       ld24    r14, #0x00070000
+       seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
+       st      r14, @(low(M32R_ICU_IMASK_ADDR), r0)
+       addi    sp, #4
+       bra     ret_to_intr
+#endif /* WORKAROUND */
+       ;; do_IRQ
+       .fillinsn
+2:
+       srli    r0, #2
+#if defined(CONFIG_PLAT_USRV)
+       add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+       bnez    r2, 9f
+       ; read ICU status register of PLD
+       seth    r0, #high(PLD_ICUISTS)
+       or3     r0, r0, #low(PLD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       addi    r0, #(M32700UT_PLD_IRQ_BASE)
+       .fillinsn
+9:
+#elif defined(CONFIG_PLAT_M32700UT)
+       add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+       bnez    r2, check_int0
+       ; read ICU status register of PLD
+       seth    r0, #high(PLD_ICUISTS)
+       or3     r0, r0, #low(PLD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       addi    r0, #(M32700UT_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int0:
+       add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+       bnez    r2, check_int2
+       ; read ICU status of LAN-board
+       seth    r0, #high(M32700UT_LAN_ICUISTS)
+       or3     r0, r0, #low(M32700UT_LAN_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int2:
+       add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+       bnez    r2, check_end
+       ; read ICU status of LCD-board
+       seth    r0, #high(M32700UT_LCD_ICUISTS)
+       or3     r0, r0, #low(M32700UT_LCD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_end:
+#elif defined(CONFIG_PLAT_OPSPUT)
+       add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+       bnez    r2, check_int0
+       ; read ICU status register of PLD
+       seth    r0, #high(PLD_ICUISTS)
+       or3     r0, r0, #low(PLD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       addi    r0, #(OPSPUT_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int0:
+       add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+       bnez    r2, check_int2
+       ; read ICU status of LAN-board
+       seth    r0, #high(OPSPUT_LAN_ICUISTS)
+       or3     r0, r0, #low(OPSPUT_LAN_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int2:
+       add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+       bnez    r2, check_end
+       ; read ICU status of LCD-board
+       seth    r0, #high(OPSPUT_LCD_ICUISTS)
+       or3     r0, r0, #low(OPSPUT_LCD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_end:
+#endif  /* CONFIG_PLAT_OPSPUT */
+       bl      do_IRQ                  ; r0(irq), r1(regs)
+#else  /* not CONFIG_SMP */
+       srli    r0, #22                 ; r0(irq)
+#if defined(CONFIG_PLAT_USRV)
+       add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+       bnez    r2, 1f
+       ; read ICU status register of PLD
+       seth    r0, #high(PLD_ICUISTS)
+       or3     r0, r0, #low(PLD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       addi    r0, #(M32700UT_PLD_IRQ_BASE)
+       .fillinsn
+1:
+#elif defined(CONFIG_PLAT_M32700UT)
+       add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+       bnez    r2, check_int0
+       ; read ICU status register of PLD
+       seth    r0, #high(PLD_ICUISTS)
+       or3     r0, r0, #low(PLD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       addi    r0, #(M32700UT_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int0:
+       add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+       bnez    r2, check_int2
+       ; read ICU status of LAN-board
+       seth    r0, #high(M32700UT_LAN_ICUISTS)
+       or3     r0, r0, #low(M32700UT_LAN_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(M32700UT_LAN_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int2:
+       add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+       bnez    r2, check_end
+       ; read ICU status of LCD-board
+       seth    r0, #high(M32700UT_LCD_ICUISTS)
+       or3     r0, r0, #low(M32700UT_LCD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(M32700UT_LCD_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_end:
+#elif defined(CONFIG_PLAT_OPSPUT)
+       add3    r2, r0, #-(M32R_IRQ_INT1)       ; INT1# interrupt
+       bnez    r2, check_int0
+       ; read ICU status register of PLD
+       seth    r0, #high(PLD_ICUISTS)
+       or3     r0, r0, #low(PLD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       addi    r0, #(OPSPUT_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int0:
+       add3    r2, r0, #-(M32R_IRQ_INT0)       ; INT0# interrupt
+       bnez    r2, check_int2
+       ; read ICU status of LAN-board
+       seth    r0, #high(OPSPUT_LAN_ICUISTS)
+       or3     r0, r0, #low(OPSPUT_LAN_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(OPSPUT_LAN_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_int2:
+       add3    r2, r0, #-(M32R_IRQ_INT2)       ; INT2# interrupt
+       bnez    r2, check_end
+       ; read ICU status of LCD-board
+       seth    r0, #high(OPSPUT_LCD_ICUISTS)
+       or3     r0, r0, #low(OPSPUT_LCD_ICUISTS)
+       lduh    r0, @r0
+       slli    r0, #21
+       srli    r0, #27                         ; ISN
+       add3    r0, r0, #(OPSPUT_LCD_PLD_IRQ_BASE)
+       bra     check_end
+       .fillinsn
+check_end:
+#endif  /* CONFIG_PLAT_OPSPUT */
+       bl      do_IRQ
+#endif  /* CONFIG_SMP */
+       ld      r14, @sp+
+       seth    r0, #shigh(M32R_ICU_IMASK_ADDR)
+       st      r14, @(low(M32R_ICU_IMASK_ADDR),r0)
+#else
+#error no chip configuration
+#endif
+ret_to_intr:
+       bra  ret_from_intr
+
+/*
+ * Default EIT handler
+ */
+       ALIGN
+int_msg:
+       .asciz  "Unknown interrupt\n"
+       .byte   0
+
+ENTRY(default_eit_handler)
+       push    r0
+       mvfc    r0, psw
+       push    r1
+       push    r2
+       push    r3
+       push    r0
+       LDIMM   (r0, __KERNEL_DS)
+       mv      r0, r1
+       mv      r0, r2
+       LDIMM   (r0, int_msg)
+       bl      printk
+       pop     r0
+       pop     r3
+       pop     r2
+       pop     r1
+       mvtc    r0, psw
+       pop     r0
+infinit:
+       bra     infinit
+
+#ifdef CONFIG_MMU
+/*
+ * Access Exception handler
+ */
+ENTRY(ace_handler)
+       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL
+
+       seth    r2, #shigh(MMU_REG_BASE)        /* Check status register */
+       ld      r4, @(low(MESTS_offset),r2)
+       st      r4, @(low(MESTS_offset),r2)
+       srl3    r1, r4, #4
+#ifdef CONFIG_CHIP_M32700
+       and3    r1, r1, #0x0000ffff
+       ; WORKAROUND: ignore TME bit for the M32700(TS1).
+#endif /* CONFIG_CHIP_M32700 */
+       beqz    r1, inst
+oprand:
+       ld      r2, @(low(MDEVA_offset),r2)     ; set address
+       srli    r2, #12
+       slli    r2, #12
+       srli    r1, #1
+       bra     1f
+inst:
+       and3    r1, r4, #2
+       srli    r1, #1
+       or3     r1, r1, #8
+       mvfc    r2, bpc                         ; set address
+       .fillinsn
+1:
+       mvfc    r3, psw
+       mv      r0, sp
+       and3    r3, r3, 0x800
+       srli    r3, #9
+       or      r1, r3
+       /*
+        * do_page_fault():
+        *    r0 : struct pt_regs *regs
+        *    r1 : unsigned long error-code
+        *    r2 : unsigned long address
+        * error-code:
+        *    +------+------+------+------+
+        *    | bit3 | bit2 | bit1 | bit0 |
+        *    +------+------+------+------+
+        *    bit 3 == 0:means data,          1:means instruction
+        *    bit 2 == 0:means kernel,        1:means user-mode
+        *    bit 1 == 0:means read,          1:means write
+        *    bit 0 == 0:means no page found  1:means protection fault
+        *
+        */
+       bl      do_page_fault
+       bra     ret_from_intr
+#endif  /* CONFIG_MMU */
+
+
+ENTRY(alignment_check)
+/* void alignment_check(int error_code) */
+       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL
+       ldi     r1, #0x30                       ; error_code
+       mv      r0, sp                          ; pt_regs
+       bl      do_alignment_check
+error_code:
+       bra     ret_from_exception
+
+ENTRY(rie_handler)
+/* void rie_handler(int error_code) */
+       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL
+       mvfc    r0, bpc
+       ld      r1, @r0
+       seth    r0, #0xa0f0
+       st      r1, @r0
+       ldi     r1, #0x20                       ; error_code
+       mv      r0, sp                          ; pt_regs
+       bl      do_rie_handler
+       bra     error_code
+
+ENTRY(pie_handler)
+/* void pie_handler(int error_code) */
+       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL
+       ldi     r1, #0                          ; error_code ; FIXME
+       mv      r0, sp                          ; pt_regs
+       bl      do_pie_handler
+       bra     error_code
+
+ENTRY(debug_trap)
+       .global withdraw_debug_trap
+       /* void debug_trap(void) */
+       SWITCH_TO_KERNEL_STACK
+       SAVE_ALL
+       mv      r0, sp                          ; pt_regs
+       bl      withdraw_debug_trap
+       ldi     r1, #0                          ; error_code
+       mv      r0, sp                          ; pt_regs
+       bl      do_debug_trap
+       bra     error_code
+
+
+/* Cache flushing handler */
+ENTRY(cache_flushing_handler)
+       .global _flush_cache_all
+       /* void _flush_cache_all(void); */
+       SWITCH_TO_KERNEL_STACK
+       push    r0
+       push    r1
+       push    r2
+       push    r3
+       push    r4
+       push    r5
+       push    r6
+       push    r7
+       push    lr
+       bl      _flush_cache_all
+       pop     lr
+       pop     r7
+       pop     r6
+       pop     r5
+       pop     r4
+       pop     r3
+       pop     r2
+       pop     r1
+       pop     r0
+       rte
+
+.data
+ENTRY(sys_call_table)
+       .long sys_restart_syscall       /* 0  -  old "setup()" system call*/
+       .long sys_exit
+       .long sys_fork
+       .long sys_read
+       .long sys_write
+       .long sys_open                  /* 5 */
+       .long sys_close
+       .long sys_waitpid
+       .long sys_creat
+       .long sys_link
+       .long sys_unlink                /* 10 */
+       .long sys_execve
+       .long sys_chdir
+       .long sys_time
+       .long sys_mknod
+       .long sys_chmod                 /* 15 */
+       .long sys_lchown
+       .long sys_ni_syscall            /* old break syscall holder */
+       .long sys_stat
+       .long sys_lseek
+       .long sys_getpid                /* 20 */
+       .long sys_mount
+       .long sys_oldumount
+       .long sys_setuid
+       .long sys_getuid
+       .long sys_stime                 /* 25 */
+       .long sys_ptrace
+       .long sys_alarm
+       .long sys_fstat
+       .long sys_pause
+       .long sys_utime                 /* 30 */
+       .long sys_cacheflush            /* for M32R */ /* old stty syscall holder */
+       .long sys_cachectl              /* for M32R */ /* old gtty syscall holder */
+       .long sys_access
+       .long sys_nice
+       .long sys_ni_syscall            /* 35  -  old ftime syscall holder */
+       .long sys_sync
+       .long sys_kill
+       .long sys_rename
+       .long sys_mkdir
+       .long sys_rmdir                 /* 40 */
+       .long sys_dup
+       .long sys_pipe
+       .long sys_times
+       .long sys_ni_syscall            /* old prof syscall holder */
+       .long sys_brk                   /* 45 */
+       .long sys_setgid
+       .long sys_getgid
+       .long sys_signal
+       .long sys_geteuid
+       .long sys_getegid               /* 50 */
+       .long sys_acct
+       .long sys_umount                /* recycled never used phys() */
+       .long sys_ni_syscall            /* old lock syscall holder */
+       .long sys_ioctl
+       .long sys_fcntl                 /* 55 */
+       .long sys_ni_syscall            /* old mpx syscall holder */
+       .long sys_setpgid
+       .long sys_ni_syscall            /* old ulimit syscall holder */
+       .long sys_ni_syscall            /* sys_olduname */
+       .long sys_umask                 /* 60 */
+       .long sys_chroot
+       .long sys_ustat
+       .long sys_dup2
+       .long sys_getppid
+       .long sys_getpgrp               /* 65 */
+       .long sys_setsid
+       .long sys_sigaction
+       .long sys_sgetmask
+       .long sys_ssetmask
+       .long sys_setreuid              /* 70 */
+       .long sys_setregid
+       .long sys_sigsuspend
+       .long sys_sigpending
+       .long sys_sethostname
+       .long sys_setrlimit             /* 75 */
+       .long sys_getrlimit
+       .long sys_getrusage
+       .long sys_gettimeofday
+       .long sys_settimeofday
+       .long sys_getgroups             /* 80 */
+       .long sys_setgroups
+       .long sys_ni_syscall            /* sys_oldselect */
+       .long sys_symlink
+       .long sys_lstat
+       .long sys_readlink              /* 85 */
+       .long sys_uselib
+       .long sys_swapon
+       .long sys_reboot
+       .long old_readdir
+       .long sys_ni_syscall            /* 90 - old_mmap syscall holder */
+       .long sys_munmap
+       .long sys_truncate
+       .long sys_ftruncate
+       .long sys_fchmod
+       .long sys_fchown                /* 95 */
+       .long sys_getpriority
+       .long sys_setpriority
+       .long sys_ni_syscall            /* old profil syscall holder */
+       .long sys_statfs
+       .long sys_fstatfs               /* 100 */
+       .long sys_ni_syscall            /* ioperm */
+       .long sys_socketcall
+       .long sys_syslog
+       .long sys_setitimer
+       .long sys_getitimer             /* 105 */
+       .long sys_newstat
+       .long sys_newlstat
+       .long sys_newfstat
+       .long sys_uname
+       .long sys_ni_syscall            /* 110  -  iopl */
+       .long sys_vhangup
+       .long sys_ni_syscall            /* for idle */
+       .long sys_ni_syscall            /* for vm86old */
+       .long sys_wait4
+       .long sys_swapoff               /* 115 */
+       .long sys_sysinfo
+       .long sys_ipc
+       .long sys_fsync
+       .long sys_sigreturn
+       .long sys_clone                 /* 120 */
+       .long sys_setdomainname
+       .long sys_newuname
+       .long sys_ni_syscall            /* sys_modify_ldt */
+       .long sys_adjtimex
+       .long sys_mprotect              /* 125 */
+       .long sys_sigprocmask
+       .long sys_ni_syscall            /* sys_create_module */
+       .long sys_init_module
+       .long sys_delete_module
+       .long sys_ni_syscall            /* 130 sys_get_kernel_syms */
+       .long sys_quotactl
+       .long sys_getpgid
+       .long sys_fchdir
+       .long sys_bdflush
+       .long sys_sysfs                 /* 135 */
+       .long sys_personality
+       .long sys_ni_syscall            /* for afs_syscall */
+       .long sys_setfsuid
+       .long sys_setfsgid
+       .long sys_llseek                /* 140 */
+       .long sys_getdents
+       .long sys_select
+       .long sys_flock
+       .long sys_msync
+       .long sys_readv                 /* 145 */
+       .long sys_writev
+       .long sys_getsid
+       .long sys_fdatasync
+       .long sys_sysctl
+       .long sys_mlock                 /* 150 */
+       .long sys_munlock
+       .long sys_mlockall
+       .long sys_munlockall
+       .long sys_sched_setparam
+       .long sys_sched_getparam        /* 155 */
+       .long sys_sched_setscheduler
+       .long sys_sched_getscheduler
+       .long sys_sched_yield
+       .long sys_sched_get_priority_max
+       .long sys_sched_get_priority_min        /* 160 */
+       .long sys_sched_rr_get_interval
+       .long sys_nanosleep
+       .long sys_mremap
+       .long sys_setresuid
+       .long sys_getresuid             /* 165 */
+       .long sys_tas                   /* vm86 */
+       .long sys_ni_syscall            /* sys_query_module */
+       .long sys_poll
+       .long sys_nfsservctl
+       .long sys_setresgid             /* 170 */
+       .long sys_getresgid
+       .long sys_prctl
+       .long sys_rt_sigreturn
+       .long sys_rt_sigaction
+       .long sys_rt_sigprocmask        /* 175 */
+       .long sys_rt_sigpending
+       .long sys_rt_sigtimedwait
+       .long sys_rt_sigqueueinfo
+       .long sys_rt_sigsuspend
+       .long sys_pread64               /* 180 */
+       .long sys_pwrite64
+       .long sys_chown
+       .long sys_getcwd
+       .long sys_capget
+       .long sys_capset                /* 185 */
+       .long sys_sigaltstack
+       .long sys_sendfile
+       .long sys_ni_syscall            /* streams1 */
+       .long sys_ni_syscall            /* streams2 */
+       .long sys_vfork                 /* 190 */
+       .long sys_getrlimit
+       .long sys_mmap2
+       .long sys_truncate64
+       .long sys_ftruncate64
+       .long sys_stat64                /* 195 */
+       .long sys_lstat64
+       .long sys_fstat64
+       .long sys_lchown
+       .long sys_getuid
+       .long sys_getgid                /* 200 */
+       .long sys_geteuid
+       .long sys_getegid
+       .long sys_setreuid
+       .long sys_setregid
+       .long sys_getgroups             /* 205 */
+       .long sys_setgroups
+       .long sys_fchown
+       .long sys_setresuid
+       .long sys_getresuid
+       .long sys_setresgid             /* 210 */
+       .long sys_getresgid
+       .long sys_chown
+       .long sys_setuid
+       .long sys_setgid
+       .long sys_setfsuid              /* 215 */
+       .long sys_setfsgid
+       .long sys_pivot_root
+       .long sys_mincore
+       .long sys_madvise
+       .long sys_getdents64            /* 220 */
+       .long sys_fcntl64
+       .long sys_ni_syscall            /* reserved for TUX */
+       .long sys_ni_syscall            /* Reserved for Security */
+       .long sys_gettid
+       .long sys_readahead             /* 225 */
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr
+       .long sys_getxattr
+       .long sys_lgetxattr             /* 230 */
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr
+       .long sys_flistxattr
+       .long sys_removexattr           /* 235 */
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_tkill
+       .long sys_sendfile64
+       .long sys_futex                 /* 240 */
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_ni_syscall            /* reserved for "set_thread_area" system call */
+       .long sys_ni_syscall            /* reserved for "get_thread_area" system call */
+       .long sys_io_setup              /* 245 */
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit
+       .long sys_io_cancel
+       .long sys_fadvise64             /* 250 */
+       .long sys_ni_syscall
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl             /* 255 */
+       .long sys_epoll_wait
+       .long sys_remap_file_pages
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime         /* 260 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime         /* 265 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill                /* 270 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_ni_syscall            /* Reserved for sys_vserver */
+        .long sys_ni_syscall           /* Reserved for sys_mbind */
+        .long sys_ni_syscall           /* Reserved for sys_get_mempolicy */
+        .long sys_ni_syscall           /* Reserved for sys_set_mempolicy */
+        .long sys_mq_open
+        .long sys_mq_unlink
+        .long sys_mq_timedsend
+        .long sys_mq_timedreceive       /* 280 */
+        .long sys_mq_notify
+        .long sys_mq_getsetattr
+        .long sys_ni_syscall            /* reserved for kexec */
+       .long sys_waitid
+
+syscall_table_size=(.-sys_call_table)
+
diff --git a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S
new file mode 100644 (file)
index 0000000..3e83173
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ *  linux/arch/m32r/kernel/head.S
+ *
+ *  M32R startup code.
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto
+ */
+
+/* $Id$ */
+
+#include <linux/init.h>
+__INIT
+__INITDATA
+
+       .text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/assembler.h>
+#include <asm/m32r.h>
+#include <asm/mmu_context.h>
+
+/*
+ * References to members of the boot_cpu_data structure.
+ */
+       .text
+       .global start_kernel
+       .global __bss_start
+       .global _end
+ENTRY(stext)
+ENTRY(_stext)
+ENTRY(startup_32)
+       /* Setup up the stack pointer */
+       LDIMM   (r0, spi_stack_top)
+       LDIMM   (r1, spu_stack_top)
+       mvtc    r0, spi
+       mvtc    r1, spu
+
+       /* Initilalize PSW */
+       ldi     r0, #0x0000             /* use SPI, disable EI */
+       mvtc    r0, psw
+
+       /* Set up the stack pointer */
+       LDIMM   (r0, stack_start)
+       ld      r0, @r0
+       mvtc    r0, spi
+
+/*
+ * Clear BSS first so that there are no surprises...
+ */
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       LDIMM   (r2, __bss_start)
+       LDIMM   (r3, _end)
+       sub     r3, r2          ; BSS size in bytes
+       ; R4 = BSS size in longwords (rounded down)
+       mv      r4, r3              ||  ldi     r1, #0
+       srli    r4, #4              ||  addi    r2, #-4
+       beqz    r4, .Lendloop1
+.Lloop1:
+#ifndef CONFIG_CHIP_M32310
+       ; Touch memory for the no-write-allocating cache.
+       ld      r0, @(4,r2)
+#endif
+       st      r1, @+r2            ||  addi    r4, #-1
+       st      r1, @+r2
+       st      r1, @+r2
+       st      r1, @+r2            ||  cmpeq   r1, r4  ; R4 = 0?
+       bnc     .Lloop1
+.Lendloop1:
+       and3    r4, r3, #15
+       addi    r2, #4
+       beqz    r4, .Lendloop2
+.Lloop2:
+       stb     r1, @r2             ||  addi    r4, #-1
+       addi    r2, #1
+       bnez    r4, .Lloop2
+.Lendloop2:
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       LDIMM   (r2, __bss_start)
+       LDIMM   (r3, _end)
+       sub     r3, r2          ; BSS size in bytes
+       mv      r4, r3
+       srli    r4, #2          ; R4 = BSS size in longwords (rounded down)
+       ldi     r1, #0          ; clear R1 for longwords store
+       addi    r2, #-4         ; account for pre-inc store
+       beqz    r4, .Lendloop1  ; any more to go?
+.Lloop1:
+       st      r1, @+r2        ; yep, zero out another longword
+       addi    r4, #-1         ; decrement count
+       bnez    r4, .Lloop1     ; go do some more
+.Lendloop1:
+       and3    r4, r3, #3      ; get no. of remaining BSS bytes to clear
+       addi    r2, #4          ; account for pre-inc store
+       beqz    r4, .Lendloop2  ; any more to go?
+.Lloop2:
+       stb     r1, @r2         ; yep, zero out another byte
+       addi    r2, #1          ; bump address
+       addi    r4, #-1         ; decrement count
+       bnez    r4, .Lloop2     ; go do some more
+.Lendloop2:
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+#if 0  /* M32R_FIXME */
+/*
+ * Copy data segment from ROM to RAM.
+ */
+       .global ROM_D, TOP_DATA, END_DATA
+
+       LDIMM   (r1, ROM_D)
+       LDIMM   (r2, TOP_DATA)
+       LDIMM   (r3, END_DATA)
+       addi    r2, #-4
+       addi    r3, #-4
+loop1:
+       ld      r0, @r1+
+       st      r0, @+r2
+       cmp     r2, r3
+       bc      loop1
+#endif /* 0 */
+
+/* Jump to kernel */
+       LDIMM   (r2, start_kernel)
+       jl      r2
+       .fillinsn
+1:
+       bra     1b              ; main should never return here, but
+                               ; just in case, we know what happens.
+
+#ifdef CONFIG_SMP
+/*
+ * AP startup routine
+ */
+       .text
+       .global eit_vector
+ENTRY(startup_AP)
+;; setup EVB
+       LDIMM  (r4, eit_vector)
+       mvtc   r4, cr5
+
+;; enable MMU
+       LDIMM   (r2, init_tlb)
+       jl      r2
+       seth  r4, #high(MATM)
+       or3   r4, r4, #low(MATM)
+       ldi   r5, #0x01
+       st    r5, @r4            ; Set MATM Reg(T bit ON)
+       ld    r6, @r4            ; MATM Check
+       LDIMM (r5, 1f)
+       jmp   r5                 ; enable MMU
+       nop
+       .fillinsn
+1:
+;; ISN check
+       ld    r6, @r4            ; MATM Check
+       seth  r4, #high(M32R_ICU_ISTS_ADDR)
+       or3   r4, r4, #low(M32R_ICU_ISTS_ADDR)
+       ld    r5, @r4           ; Read ISTSi reg.
+       mv    r6, r5
+       slli  r5, #13  ; PIML check
+       srli  r5, #13  ;
+       seth  r4, #high(M32R_ICU_IMASK_ADDR)
+       or3   r4, r4, #low(M32R_ICU_IMASK_ADDR)
+       st    r5, @r4           ; Write IMASKi reg.
+       slli  r6, #4   ; ISN check
+       srli  r6, #26  ;
+       seth  r4, #high(M32R_IRQ_IPI5)
+       or3   r4, r4, #low(M32R_IRQ_IPI5)
+       bne   r4, r6, 2f  ; if (ISN != CPU_BOOT_IPI) goto sleep;
+
+;; check cpu_bootout_map and set cpu_bootin_map
+       LDIMM (r4, cpu_bootout_map)
+       ld    r4, @r4
+       seth  r5, #high(M32R_CPUID_PORTL)
+       or3   r5, r5, #low(M32R_CPUID_PORTL)
+       ld    r5, @r5
+       ldi   r6, #1
+       sll   r6, r5
+       and   r4, r6
+       beqz  r4, 2f
+       LDIMM (r4, cpu_bootin_map)
+       ld    r5, @r4
+       or    r5, r6
+       st    r6, @r4
+
+;; clear PSW
+       ldi   r4, #0
+       mvtc  r4, psw
+
+;; setup SPI
+       LDIMM (r4, stack_start)
+       ld    r4, @r4
+       mvtc  r4, spi
+
+;; setup BPC (start_secondary)
+       LDIMM (r4, start_secondary)
+       mvtc  r4, bpc
+
+       rte  ; goto startup_secondary
+       nop
+       nop
+
+       .fillinsn
+2:
+       ;; disable MMU
+       seth  r4, #high(MATM)
+       or3   r4, r4, #low(MATM)
+       ldi   r5, #0
+       st    r5, @r4            ; Set MATM Reg(T bit OFF)
+       ld    r6, @r4            ; MATM Check
+       LDIMM (r4, 3f)
+       seth  r5, #high(__PAGE_OFFSET)
+       or3   r5, r5, #low(__PAGE_OFFSET)
+       not   r5, r5
+       and   r4, r5
+       jmp   r4                 ; disable MMU
+       nop
+       .fillinsn
+3:
+       ;; SLEEP and wait IPI
+       LDIMM (r4, AP_loop)
+       seth  r5, #high(__PAGE_OFFSET)
+       or3   r5, r5, #low(__PAGE_OFFSET)
+       not   r5, r5
+       and   r4, r5
+       jmp   r4
+       nop
+       nop
+#endif  /* CONFIG_SMP */
+
+ENTRY(stack_start)
+       .long   init_thread_union+8192
+       .long   __KERNEL_DS
+
+/*
+ * This is initialized to create a identity-mapping at 0-4M (for bootup
+ * purposes) and another mapping of the 0-4M area at virtual address
+ * PAGE_OFFSET.
+ */
+       .text
+
+#define  MOUNT_ROOT_RDONLY    1
+#define  RAMDISK_FLAGS        0                ; 1024KB
+#define  ORIG_ROOT_DEV        0x0100   ; /dev/ram0 (major:01, minor:00)
+#define  LOADER_TYPE          1                ; (??? - non-zero value seems
+                                       ; to be needed to boot from initrd)
+
+#define  COMMAND_LINE ""
+
+       .section        .empty_zero_page, "aw"
+ENTRY(empty_zero_page)
+       .long   MOUNT_ROOT_RDONLY               /* offset: +0x00 */
+       .long   RAMDISK_FLAGS
+       .long   ORIG_ROOT_DEV
+       .long   LOADER_TYPE
+       .long   0       /* INITRD_START */      /* +0x10 */
+       .long   0       /* INITRD_SIZE */
+       .long   0       /* CPU_CLOCK */
+       .long   0       /* BUS_CLOCK */
+       .long   0       /* TIMER_DIVIDE */      /* +0x20 */
+       .balign 256,0
+       .asciz  COMMAND_LINE
+       .byte   0
+       .balign 4096,0,4096
+
+/*------------------------------------------------------------------------
+ * Stack area
+ */
+       .section .spi
+       ALIGN
+       .global spi_stack_top
+       .zero   1024
+spi_stack_top:
+
+       .section .spu
+       ALIGN
+       .global spu_stack_top
+       .zero   1024
+spu_stack_top:
+
+       .end
diff --git a/arch/m32r/kernel/init_task.c b/arch/m32r/kernel/init_task.c
new file mode 100644 (file)
index 0000000..9e508fd
--- /dev/null
@@ -0,0 +1,41 @@
+/* orig : i386 init_task.c */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+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);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union
+       __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
+
diff --git a/arch/m32r/kernel/io_m32700ut.c b/arch/m32r/kernel/io_m32700ut.c
new file mode 100644 (file)
index 0000000..501b755
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ *  linux/arch/m32r/kernel/io_mappi.c
+ *
+ *  Typical I/O routines for M32700UT board.
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto, Takeo Takahashi
+ *
+ *  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/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
+
+#define PORT2ADDR(port)  _port2addr(port)
+#define PORT2ADDR_USB(port) _port2addr_usb(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET);
+}
+
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+static __inline__ void *__port2addr_ata(unsigned long port)
+{
+       static int      dummy_reg;
+
+       switch (port) {
+       case 0x1f0:     return (void *)0xac002000;
+       case 0x1f1:     return (void *)0xac012800;
+       case 0x1f2:     return (void *)0xac012002;
+       case 0x1f3:     return (void *)0xac012802;
+       case 0x1f4:     return (void *)0xac012004;
+       case 0x1f5:     return (void *)0xac012804;
+       case 0x1f6:     return (void *)0xac012006;
+       case 0x1f7:     return (void *)0xac012806;
+       case 0x3f6:     return (void *)0xac01200e;
+       default:        return (void *)&dummy_reg;
+       }
+}
+#endif
+
+/*
+ * M32700UT-LAN is located in the extended bus space
+ * from 0x10000000 to 0x13ffffff on physical address.
+ * The base address of LAN controller(LAN91C111) is 0x300.
+ */
+#define LAN_IOSTART    0x300
+#define LAN_IOEND      0x320
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET + 0x10000000);
+}
+static __inline__ void *_port2addr_usb(unsigned long port)
+{
+  return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
+}
+
+static __inline__ void delay(void)
+{
+       __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+/*
+ * NIC I/O function
+ */
+
+#define PORT2ADDR_NE(port)  _port2addr_ne(port)
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+       return *(volatile unsigned char *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+       return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp);
+}
+
+static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count)
+{
+       unsigned char *buf = (unsigned char *)addr;
+
+       while (count--) *buf++ = _ne_inb(portp);
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+       *(volatile unsigned char *)portp = b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+       *(volatile unsigned short *)portp = cpu_to_le16(w);
+}
+
+unsigned char _inb(unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               return _ne_inb(PORT2ADDR_NE(port));
+
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               return *(volatile unsigned char *)__port2addr_ata(port);
+       }
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+
+       return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               return *(volatile unsigned short *)__port2addr_ata(port);
+       }
+#endif
+#if defined(CONFIG_USB)
+       else if(port >= 0x340 && port < 0x3a0)
+         return *(volatile unsigned short *)PORT2ADDR_USB(port);
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+       return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned long l;
+          pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+          return l;
+       } else
+#endif
+       return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+       unsigned char  v;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               v = _ne_inb(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               return *(volatile unsigned char *)__port2addr_ata(port);
+       } else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+               v = *(volatile unsigned char *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+       unsigned short  v;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               v = _ne_inw(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               return *(volatile unsigned short *)__port2addr_ata(port);
+       } else
+#endif
+#if defined(CONFIG_USB)
+         if(port >= 0x340 && port < 0x3a0)
+           return *(volatile unsigned short *)PORT2ADDR_USB(port);
+       else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+               v = *(volatile unsigned short *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+       unsigned long  v;
+
+       v = *(volatile unsigned long *)PORT2ADDR(port);
+       delay();
+       return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               *(volatile unsigned char *)__port2addr_ata(port) = b;
+       } else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               *(volatile unsigned short *)__port2addr_ata(port) = w;
+       } else
+#endif
+#if defined(CONFIG_USB)
+       if(port >= 0x340 && port < 0x3a0)
+         *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
+       } else
+#endif
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               *(volatile unsigned char *)__port2addr_ata(port) = b;
+       } else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+
+       delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               *(volatile unsigned short *)__port2addr_ata(port) = w;
+       } else
+#endif
+#if defined(CONFIG_USB)
+         if(port >= 0x340 && port < 0x3a0)
+           *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+
+       delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+       delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               unsigned char *buf = addr;
+               unsigned char *portp = __port2addr_ata(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+         else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+       }
+#endif
+       else {
+               unsigned char *buf = addr;
+               unsigned char *portp = PORT2ADDR(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
+               /*
+                * This portion is only used by smc91111.c to read data
+                * from the DATA_REG. Do not swap the data.
+                */
+               portp = PORT2ADDR_NE(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               portp = __port2addr_ata(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+       }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned long *buf = addr;
+       unsigned long *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned char *buf = addr;
+       unsigned char *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outb(*buf++, portp);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               portp = __port2addr_ata(port);
+               while(count--) *(volatile unsigned char *)portp = *buf++;
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned char *)portp = *buf++;
+       }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
+               /*
+                * This portion is only used by smc91111.c to write data
+                * into the DATA_REG. Do not swap the data.
+                */
+               portp = PORT2ADDR_NE(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+       } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+               portp = __port2addr_ata(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+       }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned long *buf = addr;
+       unsigned char *portp;
+
+       portp = PORT2ADDR(port);
+       while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff --git a/arch/m32r/kernel/io_mappi.c b/arch/m32r/kernel/io_mappi.c
new file mode 100644 (file)
index 0000000..74aeca6
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ *  linux/arch/m32r/kernel/io_mappi.c
+ *
+ *  Typical I/O routines for Mappi board.
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto
+ */
+
+/* $Id: io_mappi.c,v 1.9 2003/12/02 07:18:08 fujiwara Exp $ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+#define M32R_PCC_IOSTART1 0x2000
+#define M32R_PCC_IOEND1   (M32R_PCC_IOSTART1 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32RPCC */
+
+#define PORT2ADDR(port)  _port2addr(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET);
+}
+
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+       return (void *)((port<<1) + NONCACHE_OFFSET + 0x0C000000);
+}
+
+static __inline__ void delay(void)
+{
+       __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+/*
+ * NIC I/O function
+ */
+
+#define PORT2ADDR_NE(port)  _port2addr_ne(port)
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+       return (unsigned char) *(volatile unsigned short *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+       unsigned short tmp;
+
+       tmp = *(volatile unsigned short *)portp;
+       return le16_to_cpu(tmp);
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+       *(volatile unsigned short *)portp = (unsigned short)b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+       *(volatile unsigned short *)portp = cpu_to_le16(w);
+}
+
+unsigned char _inb(unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               return _ne_inb(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+        if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+         unsigned char b;
+          pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+
+       return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               return _ne_inw(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          unsigned short w;
+          pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+       return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned long l;
+          pcc_ioread(0, port, &l, sizeof(l), 1, 0);
+          return l;
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          unsigned short l;
+          pcc_ioread(1, port, &l, sizeof(l), 1, 0);
+          return l;
+       } else
+#endif
+       return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+       unsigned char  v;
+
+       if (port >= 0x300 && port < 0x320)
+               v = _ne_inb(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+         unsigned char b;
+          pcc_ioread(1, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+               v = *(volatile unsigned char *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+       unsigned short  v;
+
+       if (port >= 0x300 && port < 0x320)
+               v = _ne_inw(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          unsigned short w;
+          pcc_ioread(1, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+               v = *(volatile unsigned short *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+       unsigned long  v;
+
+       v = *(volatile unsigned long *)PORT2ADDR(port);
+       delay();
+       return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, &l, sizeof(l), 1, 0);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, &l, sizeof(l), 1, 0);
+       } else
+#endif
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, &b, sizeof(b), 1, 0);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+
+       delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, &w, sizeof(w), 1, 0);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+
+       delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+       delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= 0x300 && port < 0x320){
+               portp = PORT2ADDR_NE(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_ioread(1, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= 0x300 && port < 0x320) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) *buf++ = _ne_inw(portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_ioread(1, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+       }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned long *buf = addr;
+       unsigned long *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned char *buf = addr;
+       unsigned char *portp;
+
+       if (port >= 0x300 && port < 0x320) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outb(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+       } else if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned char *)portp = *buf++;
+       }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= 0x300 && port < 0x320) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outw(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32RPCC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite(0, port, (void *)addr, sizeof(unsigned short), count, 1);
+       } else  if (port >= M32R_PCC_IOSTART1 && port <= M32R_PCC_IOEND1) {
+          pcc_iowrite(1, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+       }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned long *buf = addr;
+       unsigned char *portp;
+
+       portp = PORT2ADDR(port);
+       while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff --git a/arch/m32r/kernel/io_mappi2.c b/arch/m32r/kernel/io_mappi2.c
new file mode 100644 (file)
index 0000000..7705fb0
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ *  linux/arch/m32r/kernel/io_mappi2.c
+ *
+ *  Typical I/O routines for Mappi2 board.
+ *
+ *  Copyright (c) 2001-2003  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+/* $Id:$ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_MAPPI2_CFC */
+
+#define PORT2ADDR(port)      _port2addr(port)
+#define PORT2ADDR_NE(port)   _port2addr_ne(port)
+#define PORT2ADDR_USB(port)  _port2addr_usb(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET);
+}
+
+#define LAN_IOSTART    0x300
+#define LAN_IOEND      0x320
+#ifdef CONFIG_CHIP_OPSP
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET + 0x10000000);
+}
+#else
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET + 0x04000000);
+}
+#endif
+static __inline__ void *_port2addr_usb(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET + 0x14000000);
+}
+static __inline__ void delay(void)
+{
+       __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+/*
+ * NIC I/O function
+ */
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+       return (unsigned char) *(volatile unsigned char *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+#if 1  /* byte swap */
+       unsigned short tmp,tmp2;
+       tmp = *(volatile unsigned short *)portp;
+       tmp2 = (tmp>>8|tmp<<8);
+       return tmp2;
+#else
+       return *(volatile unsigned short *)portp;
+#endif
+}
+
+static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count)
+{
+       unsigned short tmp;
+       unsigned char *buf = addr;
+
+       tmp = *(volatile unsigned char *)portp;
+       while (count--) *buf++ = *(volatile unsigned char *)portp;
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+       *(volatile unsigned char *)portp = (unsigned char)b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+       *(volatile unsigned short *)portp = (w>>8|w<<8);
+}
+
+unsigned char _inb(unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               return _ne_inb(PORT2ADDR_NE(port));
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+
+       return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_USB)
+        else if (port >= 0x340 && port < 0x3a0)
+         return *(volatile unsigned short *)PORT2ADDR_USB(port);
+#endif
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+         else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+       return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned long l;
+          pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+          return l;
+       } else
+#endif
+       return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+       unsigned char  v;
+
+       if (port >= 0x300 && port < 0x320)
+               v = _ne_inb(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+               v = *(volatile unsigned char *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+       unsigned short  v;
+
+       if (port >= 0x300 && port < 0x320)
+               v = _ne_inw(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_USB)
+         if (port >= 0x340 && port < 0x3a0)
+               v = *(volatile unsigned short *)PORT2ADDR_USB(port);
+         else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+               v = *(volatile unsigned short *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+       unsigned long  v;
+
+       v = *(volatile unsigned long *)PORT2ADDR(port);
+       delay();
+       return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_USB)
+         if (port >= 0x340 && port < 0x3a0)
+           *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
+       } else
+#endif
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+
+       delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_USB)
+         if (port >= 0x340 && port < 0x3a0)
+               *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       else
+#endif
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+
+       delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+       delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+         else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+       }
+#endif
+       else {
+               unsigned char *buf = addr;
+               unsigned char *portp = PORT2ADDR(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               portp = PORT2ADDR_NE(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+       }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned long *buf = addr;
+       unsigned long *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned char *buf = addr;
+       unsigned char *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outb(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned char *)portp = *buf++;
+       }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               portp = PORT2ADDR_NE(port);
+               while (count--) *(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+       }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned long *buf = addr;
+       unsigned char *portp;
+
+       portp = PORT2ADDR(port);
+       while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff --git a/arch/m32r/kernel/io_oaks32r.c b/arch/m32r/kernel/io_oaks32r.c
new file mode 100644 (file)
index 0000000..7fcbf20
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ *  linux/arch/m32r/kernel/io_oaks32r.c
+ *
+ *  Typical I/O routines for OAKS32R board.
+ *
+ *  Copyright (c) 2001-2004  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#define PORT2ADDR(port)  _port2addr(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET);
+}
+
+static __inline__  void *_port2addr_ne(unsigned long port)
+{
+       return (void *)((port<<1) + NONCACHE_OFFSET + 0x02000000);
+}
+
+static __inline__ void delay(void)
+{
+       __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+/*
+ * NIC I/O function
+ */
+
+#define PORT2ADDR_NE(port)  _port2addr_ne(port)
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+       return *(volatile unsigned char *)(portp+1);
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+       unsigned short tmp;
+
+       tmp = *(unsigned short *)(portp) & 0xff;
+       tmp |= *(unsigned short *)(portp+2) << 8;
+       return tmp;
+}
+
+static __inline__  void _ne_insb(void *portp, void * addr, unsigned long count)
+{
+       unsigned char *buf = addr;
+       while (count--) *buf++ = *(volatile unsigned char *)(portp+1);
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+       *(volatile unsigned char *)(portp+1) = b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+  *(volatile unsigned short *)portp =  (w >> 8);
+  *(volatile unsigned short *)(portp+2) =  (w & 0xff);
+}
+
+unsigned char _inb(unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               return _ne_inb(PORT2ADDR_NE(port));
+
+       return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               return _ne_inw(PORT2ADDR_NE(port));
+
+       return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+       return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+       unsigned char  v;
+
+       if (port >= 0x300 && port < 0x320)
+               v = _ne_inb(PORT2ADDR_NE(port));
+       else
+               v = *(volatile unsigned char *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+       unsigned short  v;
+
+       if (port >= 0x300 && port < 0x320)
+               v = _ne_inw(PORT2ADDR_NE(port));
+       else
+               v = *(volatile unsigned short *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+       unsigned long  v;
+
+       v = *(volatile unsigned long *)PORT2ADDR(port);
+       delay();
+       return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+
+       delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+
+       delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+       delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+       if (port >= 0x300 && port < 0x320)
+               _ne_insb(PORT2ADDR_NE(port), addr, count);
+       else {
+               unsigned char *buf = addr;
+               unsigned char *portp = PORT2ADDR(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= 0x300 && port < 0x320) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) *buf++ = _ne_inw(portp);
+       } else {
+               portp = PORT2ADDR(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+       }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned long *buf = addr;
+       unsigned long *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned char *buf = addr;
+       unsigned char *portp;
+
+       if (port >= 0x300 && port < 0x320) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outb(*buf++, portp);
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned char *)portp = *buf++;
+       }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= 0x300 && port < 0x320) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outw(*buf++, portp);
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+       }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned long *buf = addr;
+       unsigned char *portp;
+
+       portp = PORT2ADDR(port);
+       while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff --git a/arch/m32r/kernel/io_opsput.c b/arch/m32r/kernel/io_opsput.c
new file mode 100644 (file)
index 0000000..642376e
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ *  linux/arch/m32r/kernel/io_mappi.c
+ *
+ *  Typical I/O routines for OPSPUT board.
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto, Takeo Takahashi
+ *
+ *  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/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+#include <linux/types.h>
+
+#define M32R_PCC_IOMAP_SIZE 0x1000
+
+#define M32R_PCC_IOSTART0 0x1000
+#define M32R_PCC_IOEND0   (M32R_PCC_IOSTART0 + M32R_PCC_IOMAP_SIZE - 1)
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
+
+#define PORT2ADDR(port)  _port2addr(port)
+#define PORT2ADDR_USB(port) _port2addr_usb(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET);
+}
+
+/*
+ * OPSPUT-LAN is located in the extended bus space
+ * from 0x10000000 to 0x13ffffff on physical address.
+ * The base address of LAN controller(LAN91C111) is 0x300.
+ */
+#define LAN_IOSTART    0x300
+#define LAN_IOEND      0x320
+static __inline__ void *_port2addr_ne(unsigned long port)
+{
+       return (void *)(port + NONCACHE_OFFSET + 0x10000000);
+}
+static __inline__ void *_port2addr_usb(unsigned long port)
+{
+  return (void *)((port & 0x0f) + NONCACHE_OFFSET + 0x10303000);
+}
+
+static __inline__ void delay(void)
+{
+       __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+/*
+ * NIC I/O function
+ */
+
+#define PORT2ADDR_NE(port)  _port2addr_ne(port)
+
+static __inline__ unsigned char _ne_inb(void *portp)
+{
+       return *(volatile unsigned char *)portp;
+}
+
+static __inline__ unsigned short _ne_inw(void *portp)
+{
+       return (unsigned short)le16_to_cpu(*(volatile unsigned short *)portp);
+}
+
+static __inline__ void _ne_insb(void *portp, void * addr, unsigned long count)
+{
+       unsigned char *buf = (unsigned char *)addr;
+
+       while (count--) *buf++ = _ne_inb(portp);
+}
+
+static __inline__ void _ne_outb(unsigned char b, void *portp)
+{
+       *(volatile unsigned char *)portp = b;
+}
+
+static __inline__ void _ne_outw(unsigned short w, void *portp)
+{
+       *(volatile unsigned short *)portp = cpu_to_le16(w);
+}
+
+unsigned char _inb(unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               return _ne_inb(PORT2ADDR_NE(port));
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+
+       return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_USB)
+       else if(port >= 0x340 && port < 0x3a0)
+         return *(volatile unsigned short *)PORT2ADDR_USB(port);
+#endif
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+         else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+       return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned long l;
+          pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+          return l;
+       } else
+#endif
+       return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+       unsigned char  v;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               v = _ne_inb(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned char b;
+          pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+          return b;
+       } else
+#endif
+               v = *(volatile unsigned char *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+       unsigned short  v;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               v = _ne_inw(PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_USB)
+         if(port >= 0x340 && port < 0x3a0)
+           return *(volatile unsigned short *)PORT2ADDR_USB(port);
+       else
+#endif
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          unsigned short w;
+          pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+          return w;
+       } else
+#endif
+               v = *(volatile unsigned short *)PORT2ADDR(port);
+
+       delay();
+       return (v);
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+       unsigned long  v;
+
+       v = *(volatile unsigned long *)PORT2ADDR(port);
+       delay();
+       return (v);
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_USB)
+       if(port >= 0x340 && port < 0x3a0)
+         *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       else
+#endif
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
+       } else
+#endif
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outb(b, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       } else
+#endif
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+
+       delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_outw(w, PORT2ADDR_NE(port));
+       else
+#if defined(CONFIG_USB)
+         if(port >= 0x340 && port < 0x3a0)
+           *(volatile unsigned short *)PORT2ADDR_USB(port) = w;
+       else
+#endif
+
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       } else
+#endif
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+
+       delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+       delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+       if (port >= LAN_IOSTART && port < LAN_IOEND)
+               _ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+         else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+       }
+#endif
+       else {
+               unsigned char *buf = addr;
+               unsigned char *portp = PORT2ADDR(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
+               /*
+                * This portion is only used by smc91111.c to read data
+                * from the DATA_REG. Do not swap the data.
+                */
+               portp = PORT2ADDR_NE(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+       }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned long *buf = addr;
+       unsigned long *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--) *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned char *buf = addr;
+       unsigned char *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
+               portp = PORT2ADDR_NE(port);
+               while (count--) _ne_outb(*buf++, portp);
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned char *)portp = *buf++;
+       }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= LAN_IOSTART && port < LAN_IOEND) {
+               /*
+                * This portion is only used by smc91111.c to write data
+                * into the DATA_REG. Do not swap the data.
+                */
+               portp = PORT2ADDR_NE(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
+       } else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
+          pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short), count, 1);
+#endif
+       } else {
+               portp = PORT2ADDR(port);
+               while(count--) *(volatile unsigned short *)portp = *buf++;
+       }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned long *buf = addr;
+       unsigned char *portp;
+
+       portp = PORT2ADDR(port);
+       while(count--) *(volatile unsigned long *)portp = *buf++;
+}
diff --git a/arch/m32r/kernel/io_usrv.c b/arch/m32r/kernel/io_usrv.c
new file mode 100644 (file)
index 0000000..cc77ced
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ *  linux/arch/m32r/kernel/io_usrv.c
+ *
+ *  Typical I/O routines for uServer board.
+ *
+ *  Copyright (c) 2001 - 2003  Hiroyuki Kondo, Hirokazu Takata,
+ *                             Hitoshi Yamamoto, Takeo Takahashi
+ *
+ *  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/config.h>
+#include <asm/m32r.h>
+#include <asm/page.h>
+#include <asm/io.h>
+
+#include <linux/types.h>
+#include "../drivers/m32r_cfc.h"
+
+extern void pcc_ioread_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_ioread_word(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_byte(int, unsigned long, void *, size_t, size_t, int);
+extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
+#define CFC_IOSTART    CFC_IOPORT_BASE
+#define CFC_IOEND      (CFC_IOSTART + (M32R_PCC_MAPSIZE * M32R_MAX_PCC) - 1)
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+#define UART0_REGSTART         0x04c20000
+#define UART1_REGSTART         0x04c20100
+#define UART_IOMAP_SIZE                8
+#define UART0_IOSTART          0x3f8
+#define UART0_IOEND            (UART0_IOSTART + UART_IOMAP_SIZE - 1)
+#define UART1_IOSTART          0x2f8
+#define UART1_IOEND            (UART1_IOSTART + UART_IOMAP_SIZE - 1)
+#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */
+
+#define PORT2ADDR(port)        _port2addr(port)
+
+static __inline__ void *_port2addr(unsigned long port)
+{
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+       if (port >= UART0_IOSTART && port <= UART0_IOEND)
+               port = ((port - UART0_IOSTART) << 1) + UART0_REGSTART;
+       else if (port >= UART1_IOSTART && port <= UART1_IOEND)
+               port = ((port - UART1_IOSTART) << 1) + UART1_REGSTART;
+#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */
+       return (void *)(port + NONCACHE_OFFSET);
+}
+
+static __inline__ void delay(void)
+{
+       __asm__ __volatile__ ("push r0; \n\t pop r0;" : : :"memory");
+}
+
+unsigned char _inb(unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND) {
+               unsigned char b;
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
+       } else
+               return *(volatile unsigned char *)PORT2ADDR(port);
+}
+
+unsigned short _inw(unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND) {
+               unsigned short w;
+               pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+               return w;
+       } else
+               return *(volatile unsigned short *)PORT2ADDR(port);
+}
+
+unsigned long _inl(unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND) {
+               unsigned long l;
+               pcc_ioread_word(0, port, &l, sizeof(l), 1, 0);
+               return l;
+       } else
+               return *(volatile unsigned long *)PORT2ADDR(port);
+}
+
+unsigned char _inb_p(unsigned long port)
+{
+       unsigned char b;
+
+       if (port >= CFC_IOSTART && port <= CFC_IOEND) {
+               pcc_ioread_byte(0, port, &b, sizeof(b), 1, 0);
+               return b;
+       } else {
+               b = *(volatile unsigned char *)PORT2ADDR(port);
+               delay();
+               return b;
+       }
+}
+
+unsigned short _inw_p(unsigned long port)
+{
+       unsigned short w;
+
+       if (port >= CFC_IOSTART && port <= CFC_IOEND) {
+               pcc_ioread_word(0, port, &w, sizeof(w), 1, 0);
+               return w;
+       } else {
+               w = *(volatile unsigned short *)PORT2ADDR(port);
+               delay();
+               return w;
+       }
+}
+
+unsigned long _inl_p(unsigned long port)
+{
+       unsigned long v;
+
+       v = *(volatile unsigned long *)PORT2ADDR(port);
+       delay();
+
+       return v;
+}
+
+void _outb(unsigned char b, unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       else
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+}
+
+void _outw(unsigned short w, unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       else
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+}
+
+void _outl(unsigned long l, unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_word(0, port, &l, sizeof(l), 1, 0);
+       else
+               *(volatile unsigned long *)PORT2ADDR(port) = l;
+}
+
+void _outb_p(unsigned char b, unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
+       else
+               *(volatile unsigned char *)PORT2ADDR(port) = b;
+       delay();
+}
+
+void _outw_p(unsigned short w, unsigned long port)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_word(0, port, &w, sizeof(w), 1, 0);
+       else
+               *(volatile unsigned short *)PORT2ADDR(port) = w;
+       delay();
+}
+
+void _outl_p(unsigned long l, unsigned long port)
+{
+       *(volatile unsigned long *)PORT2ADDR(port) = l;
+       delay();
+}
+
+void _insb(unsigned int port, void * addr, unsigned long count)
+{
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_ioread_byte(0, port, addr, sizeof(unsigned char), count, 1);
+       else {
+               unsigned char *buf = addr;
+               unsigned char *portp = PORT2ADDR(port);
+               while(count--) *buf++ = *(volatile unsigned char *)portp;
+       }
+}
+
+void _insw(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_ioread_word(0, port, addr, sizeof(unsigned short), count,
+                       1);
+       else {
+               portp = PORT2ADDR(port);
+               while (count--) *buf++ = *(volatile unsigned short *)portp;
+       }
+}
+
+void _insl(unsigned int port, void * addr, unsigned long count)
+{
+       unsigned long *buf = addr;
+       unsigned long *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--)
+               *buf++ = *(volatile unsigned long *)portp;
+}
+
+void _outsb(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned char *buf = addr;
+       unsigned char *portp;
+
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
+                       count, 1);
+       else {
+               portp = PORT2ADDR(port);
+               while (count--)
+                       *(volatile unsigned char *)portp = *buf++;
+       }
+}
+
+void _outsw(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned short *buf = addr;
+       unsigned short *portp;
+
+       if (port >= CFC_IOSTART && port <= CFC_IOEND)
+               pcc_iowrite_word(0, port, (void *)addr, sizeof(unsigned short),
+                       count, 1);
+       else {
+               portp = PORT2ADDR(port);
+               while (count--)
+                       *(volatile unsigned short *)portp = *buf++;
+       }
+}
+
+void _outsl(unsigned int port, const void * addr, unsigned long count)
+{
+       const unsigned long *buf = addr;
+       unsigned char *portp;
+
+       portp = PORT2ADDR(port);
+       while (count--)
+               *(volatile unsigned long *)portp = *buf++;
+}
diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c
new file mode 100644 (file)
index 0000000..ba13577
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+ * linux/arch/m32r/kernel/irq.c
+ *
+ *  Copyright (c) 2003, 2004 Hitoshi Yamamoto
+ *
+ *  Taken from i386 2.6.4 version.
+ */
+
+/*
+ *     linux/arch/i386/kernel/irq.c
+ *
+ *     Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+/*
+ * (mostly architecture independent, will move to kernel/irq.c in 2.5.)
+ *
+ * IRQs are in fact implemented a bit like signal handlers for the kernel.
+ * Naturally it's not a 1:1 relation, but there are similarities.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+       [0 ... NR_IRQS-1] = {
+               .handler = &no_irq_type,
+               .lock = SPIN_LOCK_UNLOCKED
+       }
+};
+
+static void register_irq_proc (unsigned int irq);
+
+/*
+ * Special irq handlers.
+ */
+
+irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{ return IRQ_NONE; }
+
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesn't deserve
+ * a generic callback i think.
+ */
+       printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none  disable_none
+#define end_none       enable_none
+
+struct hw_interrupt_type no_irq_type = {
+       "none",
+       startup_none,
+       shutdown_none,
+       enable_none,
+       disable_none,
+       ack_none,
+       end_none
+};
+
+atomic_t irq_err_count;
+atomic_t irq_mis_count;
+
+/*
+ * 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, "ERR: %10u\n", atomic_read(&irq_err_count));
+               seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+       }
+       return 0;
+}
+
+#ifdef CONFIG_SMP
+inline void synchronize_irq(unsigned int irq)
+{
+       while (irq_desc[irq].status & IRQ_INPROGRESS)
+               cpu_relax();
+}
+#endif
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq,
+               struct pt_regs *regs, struct irqaction *action)
+{
+       int status = 1; /* Force the "do bottom halves" bit */
+       int ret, retval = 0;
+
+       if (!(action->flags & SA_INTERRUPT))
+               local_irq_enable();
+
+       do {
+               ret = action->handler(irq, action->dev_id, regs);
+               if (ret == IRQ_HANDLED)
+                       status |= action->flags;
+               action = action->next;
+               retval |= ret;
+       } while (action);
+       if (status & SA_SAMPLE_RANDOM)
+               add_interrupt_randomness(irq);
+       local_irq_disable();
+       return retval;
+}
+
+static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+       struct irqaction *action;
+
+       if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+               printk(KERN_ERR "irq event %d: bogus return value %x\n",
+                               irq, action_ret);
+       } else {
+               printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+       }
+       dump_stack();
+       printk(KERN_ERR "handlers:\n");
+       action = desc->action;
+       do {
+               printk(KERN_ERR "[<%p>]", action->handler);
+               print_symbol(" (%s)",
+                       (unsigned long)action->handler);
+               printk("\n");
+               action = action->next;
+       } while (action);
+}
+
+static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+       static int count = 100;
+
+       if (count) {
+               count--;
+               __report_bad_irq(irq, desc, action_ret);
+       }
+}
+
+static int noirqdebug;
+
+static int __init noirqdebug_setup(char *str)
+{
+       noirqdebug = 1;
+       printk("IRQ lockup detection disabled\n");
+       return 1;
+}
+
+__setup("noirqdebug", noirqdebug_setup);
+
+/*
+ * 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 and try to
+ * turn the IRQ off.
+ *
+ * (The other 100-of-100,000 interrupts may have been a correctly-functioning
+ *  device sharing an IRQ with the failing one)
+ *
+ * Called under desc->lock
+ */
+static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+       if (action_ret != IRQ_HANDLED) {
+               desc->irqs_unhandled++;
+               if (action_ret != IRQ_NONE)
+                       report_bad_irq(irq, desc, action_ret);
+       }
+
+       desc->irq_count++;
+       if (desc->irq_count < 100000)
+               return;
+
+       desc->irq_count = 0;
+       if (desc->irqs_unhandled > 99900) {
+               /*
+                * The interrupt is stuck
+                */
+               __report_bad_irq(irq, desc, action_ret);
+               /*
+                * Now kill the IRQ
+                */
+               printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
+               desc->status |= IRQ_DISABLED;
+               desc->handler->disable(irq);
+       }
+       desc->irqs_unhandled = 0;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+
+/**
+ *     disable_irq_nosync - disable an irq without waiting
+ *     @irq: Interrupt to disable
+ *
+ *     Disable the selected interrupt line.  Disables and Enables are
+ *     nested.
+ *     Unlike disable_irq(), this function does not ensure existing
+ *     instances of the IRQ handler have completed before returning.
+ *
+ *     This function may be called from IRQ context.
+ */
+
+inline void disable_irq_nosync(unsigned int irq)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       if (!desc->depth++) {
+               desc->status |= IRQ_DISABLED;
+               desc->handler->disable(irq);
+       }
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ *     disable_irq - disable an irq and wait for completion
+ *     @irq: Interrupt to disable
+ *
+ *     Disable the selected interrupt line.  Enables and Disables are
+ *     nested.
+ *     This function waits for any pending IRQ handlers for this interrupt
+ *     to complete before returning. If you use this function while
+ *     holding a resource the IRQ handler may need you will deadlock.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+
+void disable_irq(unsigned int irq)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       disable_irq_nosync(irq);
+       if (desc->action)
+               synchronize_irq(irq);
+}
+
+/**
+ *     enable_irq - enable handling of an irq
+ *     @irq: Interrupt to enable
+ *
+ *     Undoes the effect of one call to disable_irq().  If this
+ *     matches the last disable, processing of interrupts on this
+ *     IRQ line is re-enabled.
+ *
+ *     This function may be called from IRQ context.
+ */
+
+void enable_irq(unsigned int irq)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       switch (desc->depth) {
+       case 1: {
+               unsigned int status = desc->status & ~IRQ_DISABLED;
+               desc->status = status;
+               if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+                       desc->status = status | IRQ_REPLAY;
+                       hw_resend_irq(desc->handler,irq);
+               }
+               desc->handler->enable(irq);
+               /* fall-through */
+       }
+       default:
+               desc->depth--;
+               break;
+       case 0:
+               printk("enable_irq(%u) unbalanced from %p\n", irq,
+                      __builtin_return_address(0));
+       }
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
+{
+       /*
+        * We ack quickly, we don't want the irq controller
+        * thinking we're snobs just because some other CPU has
+        * disabled global interrupts (we have already done the
+        * INT_ACK cycles, it's too late to try to pretend to the
+        * controller that we aren't taking the interrupt).
+        *
+        * 0 return value means that this irq is already being
+        * handled by some other CPU. (or is disabled)
+        */
+       irq_desc_t *desc = irq_desc + irq;
+       struct irqaction * action;
+       unsigned int status;
+
+       irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+       /* FIXME M32R */
+#endif
+       kstat_this_cpu.irqs[irq]++;
+       spin_lock(&desc->lock);
+       desc->handler->ack(irq);
+       /*
+          REPLAY is when Linux resends an IRQ that was dropped earlier
+          WAITING is used by probe to mark irqs that are being tested
+          */
+       status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+       status |= IRQ_PENDING; /* we _want_ to handle it */
+
+       /*
+        * If the IRQ is disabled for whatever reason, we cannot
+        * use the action we have.
+        */
+       action = NULL;
+       if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
+               action = desc->action;
+               status &= ~IRQ_PENDING; /* we commit to handling */
+               status |= IRQ_INPROGRESS; /* we are handling it */
+       }
+       desc->status = status;
+
+       /*
+        * If there is no IRQ handler or it was disabled, exit early.
+          Since we set PENDING, if another processor is handling
+          a different instance of this same irq, the other processor
+          will take care of it.
+        */
+       if (unlikely(!action))
+               goto out;
+
+       /*
+        * Edge triggered interrupts need to remember
+        * pending events.
+        * This applies to any hw interrupts that allow a second
+        * instance of the same irq to arrive while we are in do_IRQ
+        * or in the handler. But the code here only handles the _second_
+        * instance of the irq, not the third or fourth. So it is mostly
+        * useful for irq hardware that does not mask cleanly in an
+        * SMP environment.
+        */
+       for (;;) {
+               irqreturn_t action_ret;
+
+               spin_unlock(&desc->lock);
+               action_ret = handle_IRQ_event(irq, regs, action);
+               spin_lock(&desc->lock);
+               if (!noirqdebug)
+                       note_interrupt(irq, desc, action_ret);
+               if (likely(!(desc->status & IRQ_PENDING)))
+                       break;
+               desc->status &= ~IRQ_PENDING;
+       }
+       desc->status &= ~IRQ_INPROGRESS;
+
+out:
+       /*
+        * The ->end() handler has to deal with interrupts which got
+        * disabled while the handler was running.
+        */
+       desc->handler->end(irq);
+       spin_unlock(&desc->lock);
+
+       irq_exit();
+
+#if defined(CONFIG_SMP)
+       if (irq == M32R_IRQ_MFT2)
+               smp_send_timer();
+#endif /* CONFIG_SMP */
+
+       return 1;
+}
+
+int can_request_irq(unsigned int irq, unsigned long irqflags)
+{
+       struct irqaction *action;
+
+       if (irq >= NR_IRQS)
+               return 0;
+       action = irq_desc[irq].action;
+       if (action) {
+               if (irqflags & action->flags & SA_SHIRQ)
+                       action = NULL;
+       }
+       return !action;
+}
+
+/**
+ *     request_irq - allocate an interrupt line
+ *     @irq: Interrupt line to allocate
+ *     @handler: Function to be called when the IRQ occurs
+ *     @irqflags: Interrupt type flags
+ *     @devname: An ascii name for the claiming device
+ *     @dev_id: A cookie passed back to the handler function
+ *
+ *     This call allocates interrupt resources and enables the
+ *     interrupt line and IRQ handling. From the point this
+ *     call is made your handler function may be invoked. Since
+ *     your handler function must clear any interrupt the board
+ *     raises, you must take care both to initialise your hardware
+ *     and to set up the interrupt handler in the right order.
+ *
+ *     Dev_id must be globally unique. Normally the address of the
+ *     device data structure is used as the cookie. Since the handler
+ *     receives this value it makes sense to use it.
+ *
+ *     If your interrupt is shared you must pass a non NULL dev_id
+ *     as this is required when freeing the interrupt.
+ *
+ *     Flags:
+ *
+ *     SA_SHIRQ                Interrupt is shared
+ *
+ *     SA_INTERRUPT            Disable local interrupts while processing
+ *
+ *     SA_SAMPLE_RANDOM        The interrupt can be used for entropy
+ *
+ */
+
+int request_irq(unsigned int irq,
+               irqreturn_t (*handler)(int, void *, struct pt_regs *),
+               unsigned long irqflags,
+               const char * devname,
+               void *dev_id)
+{
+       int retval;
+       struct irqaction * action;
+
+#if 1
+       /*
+        * Sanity-check: shared interrupts should REALLY pass in
+        * a real dev-ID, otherwise we'll have trouble later trying
+        * to figure out which interrupt is which (messes up the
+        * interrupt freeing logic etc).
+        */
+       if (irqflags & SA_SHIRQ) {
+               if (!dev_id)
+                       printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
+       }
+#endif
+
+       if (irq >= NR_IRQS)
+               return -EINVAL;
+       if (!handler)
+               return -EINVAL;
+
+       action = (struct irqaction *)
+                       kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
+       if (!action)
+               return -ENOMEM;
+
+       action->handler = handler;
+       action->flags = irqflags;
+       cpus_clear(action->mask);
+       action->name = devname;
+       action->next = NULL;
+       action->dev_id = dev_id;
+
+       retval = setup_irq(irq, action);
+       if (retval)
+               kfree(action);
+       return retval;
+}
+
+EXPORT_SYMBOL(request_irq);
+
+/**
+ *     free_irq - free an interrupt
+ *     @irq: Interrupt line to free
+ *     @dev_id: Device identity to free
+ *
+ *     Remove an interrupt handler. The handler is removed and if the
+ *     interrupt line is no longer in use by any driver it is disabled.
+ *     On a shared IRQ the caller must ensure the interrupt is disabled
+ *     on the card it drives before calling this function. The function
+ *     does not return until any executing interrupts for this IRQ
+ *     have completed.
+ *
+ *     This function must not be called from interrupt context.
+ */
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+       irq_desc_t *desc;
+       struct irqaction **p;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS)
+               return;
+
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
+       for (;;) {
+               struct irqaction * action = *p;
+               if (action) {
+                       struct irqaction **pp = p;
+                       p = &action->next;
+                       if (action->dev_id != dev_id)
+                               continue;
+
+                       /* Found it - now remove it from the list of entries */
+                       *pp = action->next;
+                       if (!desc->action) {
+                               desc->status |= IRQ_DISABLED;
+                               desc->handler->shutdown(irq);
+                       }
+                       spin_unlock_irqrestore(&desc->lock,flags);
+
+                       /* Wait to make sure it's not being used on another CPU */
+                       synchronize_irq(irq);
+                       kfree(action);
+                       return;
+               }
+               printk("Trying to free free IRQ%d\n",irq);
+               spin_unlock_irqrestore(&desc->lock,flags);
+               return;
+       }
+}
+
+EXPORT_SYMBOL(free_irq);
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *     probe_irq_on    - begin an interrupt autodetect
+ *
+ *     Commence probing for an interrupt. The interrupts are scanned
+ *     and a mask of potential interrupt lines is returned.
+ *
+ */
+
+unsigned long probe_irq_on(void)
+{
+       unsigned int i;
+       irq_desc_t *desc;
+       unsigned long val;
+       unsigned long delay;
+
+       down(&probe_sem);
+       /*
+        * something may have generated an irq long ago and we want to
+        * flush such a longstanding irq before considering it as spurious.
+        */
+       for (i = NR_IRQS-1; i > 0; i--)  {
+               desc = irq_desc + i;
+
+               spin_lock_irq(&desc->lock);
+               if (!irq_desc[i].action)
+                       irq_desc[i].handler->startup(i);
+               spin_unlock_irq(&desc->lock);
+       }
+
+       /* Wait for longstanding interrupts to trigger. */
+       for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+               /* about 20ms delay */ barrier();
+
+       /*
+        * enable any unassigned irqs
+        * (we must startup again here because if a longstanding irq
+        * happened in the previous stage, it may have masked itself)
+        */
+       for (i = NR_IRQS-1; i > 0; i--) {
+               desc = irq_desc + i;
+
+               spin_lock_irq(&desc->lock);
+               if (!desc->action) {
+                       desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+                       if (desc->handler->startup(i))
+                               desc->status |= IRQ_PENDING;
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+
+       /*
+        * Wait for spurious interrupts to trigger
+        */
+       for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+               /* about 100ms delay */ barrier();
+
+       /*
+        * Now filter out any obviously spurious interrupts
+        */
+       val = 0;
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       /* It triggered already - consider it spurious. */
+                       if (!(status & IRQ_WAITING)) {
+                               desc->status = status & ~IRQ_AUTODETECT;
+                               desc->handler->shutdown(i);
+                       } else
+                               if (i < 32)
+                                       val |= 1 << i;
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+
+       return val;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+
+/**
+ *     probe_irq_mask - scan a bitmap of interrupt lines
+ *     @val:   mask of interrupts to consider
+ *
+ *     Scan the ISA bus interrupt lines and return a bitmap of
+ *     active interrupts. The interrupt probe logic state is then
+ *     returned to its previous value.
+ *
+ *     Note: we need to scan all the irq's even though we will
+ *     only return ISA irq numbers - just so that we reset them
+ *     all to a known state.
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+       int i;
+       unsigned int mask;
+
+       mask = 0;
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       if (i < 16 && !(status & IRQ_WAITING))
+                               mask |= 1 << i;
+
+                       desc->status = status & ~IRQ_AUTODETECT;
+                       desc->handler->shutdown(i);
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+       up(&probe_sem);
+
+       return mask & val;
+}
+
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ *     probe_irq_off   - end an interrupt autodetect
+ *     @val: mask of potential interrupts (unused)
+ *
+ *     Scans the unused interrupt lines and returns the line which
+ *     appears to have triggered the interrupt. If no interrupt was
+ *     found then zero is returned. If more than one interrupt is
+ *     found then minus the first candidate is returned to indicate
+ *     their is doubt.
+ *
+ *     The interrupt probe logic state is returned to its previous
+ *     value.
+ *
+ *     BUGS: When used in a module (which arguably shouldnt happen)
+ *     nothing prevents two IRQ probe callers from overlapping. The
+ *     results of this are non-optimal.
+ */
+
+int probe_irq_off(unsigned long val)
+{
+       int i, irq_found, nr_irqs;
+
+       nr_irqs = 0;
+       irq_found = 0;
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       if (!(status & IRQ_WAITING)) {
+                               if (!nr_irqs)
+                                       irq_found = i;
+                               nr_irqs++;
+                       }
+                       desc->status = status & ~IRQ_AUTODETECT;
+                       desc->handler->shutdown(i);
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+       up(&probe_sem);
+
+       if (nr_irqs > 1)
+               irq_found = -irq_found;
+       return irq_found;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+       int shared = 0;
+       unsigned long flags;
+       struct irqaction *old, **p;
+       irq_desc_t *desc = irq_desc + irq;
+
+       if (desc->handler == &no_irq_type)
+               return -ENOSYS;
+       /*
+        * Some drivers like serial.c use request_irq() heavily,
+        * so we have to be careful not to interfere with a
+        * running system.
+        */
+       if (new->flags & SA_SAMPLE_RANDOM) {
+               /*
+                * This function might sleep, we want to call it first,
+                * outside of the atomic block.
+                * Yes, this might clear the entropy pool if the wrong
+                * driver is attempted to be loaded, without actually
+                * installing a new handler, but is this really a problem,
+                * only the sysadmin is able to do this.
+                */
+               rand_initialize_irq(irq);
+       }
+
+       /*
+        * The following block of code has to be executed atomically
+        */
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
+       if ((old = *p) != NULL) {
+               /* Can't share interrupts unless both agree to */
+               if (!(old->flags & new->flags & SA_SHIRQ)) {
+                       spin_unlock_irqrestore(&desc->lock,flags);
+                       return -EBUSY;
+               }
+
+               /* add new interrupt at end of irq queue */
+               do {
+                       p = &old->next;
+                       old = *p;
+               } while (old);
+               shared = 1;
+       }
+
+       *p = new;
+
+       if (!shared) {
+               desc->depth = 0;
+               desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+               desc->handler->startup(irq);
+       }
+       spin_unlock_irqrestore(&desc->lock,flags);
+
+       register_irq_proc(irq);
+       return 0;
+}
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+
+#ifdef CONFIG_SMP
+
+static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static int irq_affinity_read_proc(char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+       int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+       if (count - len < 2)
+               return -EINVAL;
+       len += sprintf(page + len, "\n");
+       return len;
+}
+
+static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
+                                       unsigned long count, void *data)
+{
+       int irq = (long)data, full_count = count, err;
+       cpumask_t new_value, tmp;
+
+       if (!irq_desc[irq].handler->set_affinity)
+               return -EIO;
+
+       err = cpumask_parse(buffer, count, new_value);
+       if (err)
+               return err;
+
+       /*
+        * Do not allow disabling IRQs completely - it's a too easy
+        * way to make the system unusable accidentally :-) At least
+        * one online CPU still has to be targeted.
+        */
+       cpus_and(tmp, new_value, cpu_online_map);
+       if (cpus_empty(tmp))
+               return -EINVAL;
+
+       irq_affinity[irq] = new_value;
+       irq_desc[irq].handler->set_affinity(irq,
+                                       cpumask_of_cpu(first_cpu(new_value)));
+
+       return full_count;
+}
+
+#endif
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+                       int count, int *eof, void *data)
+{
+       int len = cpumask_scnprintf(page, count, *(cpumask_t *)data);
+       if (count - len < 2)
+               return -EINVAL;
+       len += sprintf(page + len, "\n");
+       return len;
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
+                                       unsigned long count, void *data)
+{
+       cpumask_t *mask = (cpumask_t *)data;
+       unsigned long full_count = count, err;
+       cpumask_t new_value;
+
+       err = cpumask_parse(buffer, count, new_value);
+       if (err)
+               return err;
+
+       *mask = new_value;
+       return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+       char name [MAX_NAMELEN];
+
+       if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+                       irq_dir[irq])
+               return;
+
+       memset(name, 0, MAX_NAMELEN);
+       sprintf(name, "%d", irq);
+
+       /* create /proc/irq/1234 */
+       irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+       {
+               struct proc_dir_entry *entry;
+
+               /* create /proc/irq/1234/smp_affinity */
+               entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+               if (entry) {
+                       entry->nlink = 1;
+                       entry->data = (void *)(long)irq;
+                       entry->read_proc = irq_affinity_read_proc;
+                       entry->write_proc = irq_affinity_write_proc;
+               }
+
+               smp_affinity_entry[irq] = entry;
+       }
+#endif
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+       struct proc_dir_entry *entry;
+       int i;
+
+       /* create /proc/irq */
+       root_irq_dir = proc_mkdir("irq", NULL);
+
+       /* create /proc/irq/prof_cpu_mask */
+       entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+       if (!entry)
+           return;
+
+       entry->nlink = 1;
+       entry->data = (void *)&prof_cpu_mask;
+       entry->read_proc = prof_cpu_mask_read_proc;
+       entry->write_proc = prof_cpu_mask_write_proc;
+
+       /*
+        * Create entries for all existing IRQs.
+        */
+       for (i = 0; i < NR_IRQS; i++)
+               register_irq_proc(i);
+}
+
diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c
new file mode 100644 (file)
index 0000000..f5aa076
--- /dev/null
@@ -0,0 +1,141 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/string.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/tlbflush.h>
+
+extern void dump_thread(struct pt_regs *, struct user *);
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
+extern struct drive_info_struct drive_info;
+EXPORT_SYMBOL(drive_info);
+#endif
+
+/* platform dependent support */
+EXPORT_SYMBOL(boot_cpu_data);
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down_trylock);
+
+/* Networking helper routines. */
+/* Delay loops */
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__delay);
+EXPORT_SYMBOL(__const_udelay);
+
+EXPORT_SYMBOL(__get_user_1);
+EXPORT_SYMBOL(__get_user_2);
+EXPORT_SYMBOL(__get_user_4);
+
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(strncpy_from_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(clear_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__generic_copy_from_user);
+EXPORT_SYMBOL(__generic_copy_to_user);
+EXPORT_SYMBOL(strnlen_user);
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_CHIP_M32700_TS1
+extern void *dcache_dummy;
+EXPORT_SYMBOL(dcache_dummy);
+#endif
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(cpu_callout_map);
+
+/* Global SMP stuff */
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(smp_call_function);
+
+/* TLB flushing */
+EXPORT_SYMBOL(smp_flush_tlb_page);
+EXPORT_SYMBOL_GPL(smp_flush_tlb_all);
+#endif
+
+/* compiler generated symbol */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __lshldi3(void);
+extern void __lshrdi3(void);
+extern void __muldi3(void);
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshldi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+
+/* memory and string operations */
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(memcpy);
+/* EXPORT_SYMBOL(memcpy_fromio); // not implement yet */
+/* EXPORT_SYMBOL(memcpy_toio); // not implement yet */
+EXPORT_SYMBOL(memset);
+/* EXPORT_SYMBOL(memset_io); // not implement yet */
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(clear_page);
+
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strncpy);
+
+EXPORT_SYMBOL(_inb);
+EXPORT_SYMBOL(_inw);
+EXPORT_SYMBOL(_inl);
+EXPORT_SYMBOL(_outb);
+EXPORT_SYMBOL(_outw);
+EXPORT_SYMBOL(_outl);
+EXPORT_SYMBOL(_inb_p);
+EXPORT_SYMBOL(_inw_p);
+EXPORT_SYMBOL(_inl_p);
+EXPORT_SYMBOL(_outb_p);
+EXPORT_SYMBOL(_outw_p);
+EXPORT_SYMBOL(_outl_p);
+EXPORT_SYMBOL(_insb);
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsb);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(_readb);
+EXPORT_SYMBOL(_readw);
+EXPORT_SYMBOL(_readl);
+EXPORT_SYMBOL(_writeb);
+EXPORT_SYMBOL(_writew);
+EXPORT_SYMBOL(_writel);
+
diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c
new file mode 100644 (file)
index 0000000..2d5c384
--- /dev/null
@@ -0,0 +1,253 @@
+/*  Kernel module help for M32R.
+
+    This 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/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+       if (size == 0)
+               return NULL;
+       return vmalloc_exec(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+       /* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       return 0;
+}
+
+#define COPY_UNALIGNED_WORD(sw, tw, align) \
+{ \
+       void *__s = &(sw), *__t = &(tw); \
+       unsigned short *__s2 = __s, *__t2 =__t; \
+       unsigned char *__s1 = __s, *__t1 =__t; \
+       switch ((align)) \
+       { \
+       case 0: \
+               *(unsigned long *) __t = *(unsigned long *) __s; \
+               break; \
+       case 2: \
+               *__t2++ = *__s2++; \
+               *__t2 = *__s2; \
+               break; \
+       default: \
+               *__t1++ = *__s1++; \
+               *__t1++ = *__s1++; \
+               *__t1++ = *__s1++; \
+               *__t1 = *__s1; \
+               break; \
+       } \
+}
+
+#define COPY_UNALIGNED_HWORD(sw, tw, align) \
+  { \
+    void *__s = &(sw), *__t = &(tw); \
+    unsigned short *__s2 = __s, *__t2 =__t; \
+    unsigned char *__s1 = __s, *__t1 =__t; \
+    switch ((align)) \
+    { \
+    case 0: \
+      *__t2 = *__s2; \
+      break; \
+    default: \
+      *__t1++ = *__s1++; \
+      *__t1 = *__s1; \
+      break; \
+    } \
+  }
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       unsigned int i;
+       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       Elf32_Addr relocation;
+       uint32_t *location;
+       uint32_t value;
+       unsigned short *hlocation;
+       unsigned short hvalue;
+       int svalue;
+       int align;
+
+       DEBUGP("Applying relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+               relocation = sym->st_value + rel[i].r_addend;
+               align = (int)location & 3;
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_M32R_32_RELA:
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               case R_M32R_HI16_ULO_RELA:
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                        relocation = (relocation >>16) & 0xffff;
+                       /* RELA must has 0 at relocation field. */
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               case R_M32R_HI16_SLO_RELA:
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                       if (relocation & 0x8000) relocation += 0x10000;
+                        relocation = (relocation >>16) & 0xffff;
+                       /* RELA must has 0 at relocation field. */
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               case R_M32R_16_RELA:
+                       hlocation = (unsigned short *)location;
+                        relocation = relocation & 0xffff;
+                       /* RELA must has 0 at relocation field. */
+                       hvalue = relocation;
+                       COPY_UNALIGNED_WORD (hvalue, *hlocation, align);
+                       break;
+               case R_M32R_SDA16_RELA:
+               case R_M32R_LO16_RELA:
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                        relocation = relocation & 0xffff;
+                       /* RELA must has 0 at relocation field. */
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               case R_M32R_24_RELA:
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                        relocation = relocation & 0xffffff;
+                       /* RELA must has 0 at relocation field. */
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               case R_M32R_18_PCREL_RELA:
+                       relocation = (relocation - (Elf32_Addr) location);
+                       if (relocation < -0x20000 || 0x1fffc < relocation)
+                               {
+                                       printk(KERN_ERR "module %s: relocation overflow: %u\n",
+                                       me->name, relocation);
+                                       return -ENOEXEC;
+                               }
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                       if (value & 0xffff)
+                               {
+                                       /* RELA must has 0 at relocation field. */
+                                       printk(KERN_ERR "module %s: illegal relocation field: %u\n",
+                                       me->name, value);
+                                       return -ENOEXEC;
+                               }
+                        relocation = (relocation >> 2) & 0xffff;
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               case R_M32R_10_PCREL_RELA:
+                       hlocation = (unsigned short *)location;
+                       relocation = (relocation - (Elf32_Addr) location);
+                       COPY_UNALIGNED_HWORD (*hlocation, hvalue, align);
+                       svalue = (int)hvalue;
+                       svalue = (signed char)svalue << 2;
+                       relocation += svalue;
+                        relocation = (relocation >> 2) & 0xff;
+                       hvalue = hvalue & 0xff00;
+                       hvalue += relocation;
+                       COPY_UNALIGNED_HWORD (hvalue, *hlocation, align);
+                       break;
+               case R_M32R_26_PCREL_RELA:
+                       relocation = (relocation - (Elf32_Addr) location);
+                       if (relocation < -0x2000000 || 0x1fffffc < relocation)
+                               {
+                                       printk(KERN_ERR "module %s: relocation overflow: %u\n",
+                                       me->name, relocation);
+                                       return -ENOEXEC;
+                               }
+                       COPY_UNALIGNED_WORD (*location, value, align);
+                       if (value & 0xffffff)
+                               {
+                                       /* RELA must has 0 at relocation field. */
+                                       printk(KERN_ERR "module %s: illegal relocation field: %u\n",
+                                       me->name, value);
+                                       return -ENOEXEC;
+                               }
+                        relocation = (relocation >> 2) & 0xffffff;
+                       value += relocation;
+                       COPY_UNALIGNED_WORD (value, *location, align);
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+#if 0
+       printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+              me->name);
+       return -ENOEXEC;
+#endif
+       return 0;
+
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+{
+       return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
new file mode 100644 (file)
index 0000000..9e7de27
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ *  linux/arch/m32r/kernel/process.c
+ *    orig : sh
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto
+ *  Taken from sh version.
+ *    Copyright (C) 1995  Linus Torvalds
+ *    SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+ */
+
+#undef DEBUG_PROCESS
+#ifdef DEBUG_PROCESS
+#define DPRINTK(fmt, args...)  printk("%s:%d:%s: " fmt, __FILE__, __LINE__, \
+  __FUNCTION__, ##args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/fs.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/elf.h>
+#include <asm/m32r.h>
+
+#include <linux/err.h>
+
+static int hlt_counter=0;
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+       return tsk->thread.lr;
+}
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void) = NULL;
+
+void disable_hlt(void)
+{
+       hlt_counter++;
+}
+
+EXPORT_SYMBOL(disable_hlt);
+
+void enable_hlt(void)
+{
+       hlt_counter--;
+}
+
+EXPORT_SYMBOL(enable_hlt);
+
+/*
+ * We use this is we don't have any better
+ * idle routine..
+ */
+void default_idle(void)
+{
+       /* M32R_FIXME: Please use "cpu_sleep" mode.  */
+       cpu_relax();
+}
+
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle (void)
+{
+       /* M32R_FIXME */
+       cpu_relax();
+}
+
+/*
+ * 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)
+{
+       /* endless idle loop with no priority at all */
+       while (1) {
+               while (!need_resched()) {
+                       void (*idle)(void) = pm_idle;
+
+                       if (!idle)
+                               idle = default_idle;
+
+                       idle();
+               }
+               schedule();
+       }
+}
+
+void machine_restart(char *__unused)
+{
+       printk("Please push reset button!\n");
+       while (1)
+               cpu_relax();
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_halt(void)
+{
+       printk("Please push reset button!\n");
+       while (1)
+               cpu_relax();
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off(void)
+{
+       /* M32R_FIXME */
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+static int __init idle_setup (char *str)
+{
+       if (!strncmp(str, "poll", 4)) {
+               printk("using poll in idle threads.\n");
+               pm_idle = poll_idle;
+       } else if (!strncmp(str, "sleep", 4)) {
+               printk("using sleep in idle threads.\n");
+               pm_idle = default_idle;
+       }
+
+       return 1;
+}
+
+__setup("idle=", idle_setup);
+
+void show_regs(struct pt_regs * regs)
+{
+       printk("\n");
+       printk("BPC[%08lx]:PSW[%08lx]:LR [%08lx]:FP [%08lx]\n", \
+         regs->bpc, regs->psw, regs->lr, regs->fp);
+       printk("BBPC[%08lx]:BBPSW[%08lx]:SPU[%08lx]:SPI[%08lx]\n", \
+         regs->bbpc, regs->bbpsw, regs->spu, regs->spi);
+       printk("R0 [%08lx]:R1 [%08lx]:R2 [%08lx]:R3 [%08lx]\n", \
+         regs->r0, regs->r1, regs->r2, regs->r3);
+       printk("R4 [%08lx]:R5 [%08lx]:R6 [%08lx]:R7 [%08lx]\n", \
+         regs->r4, regs->r5, regs->r6, regs->r7);
+       printk("R8 [%08lx]:R9 [%08lx]:R10[%08lx]:R11[%08lx]\n", \
+         regs->r8, regs->r9, regs->r10, regs->r11);
+       printk("R12[%08lx]\n", \
+         regs->r12);
+
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       printk("ACC0H[%08lx]:ACC0L[%08lx]\n", \
+         regs->acc0h, regs->acc0l);
+       printk("ACC1H[%08lx]:ACC1L[%08lx]\n", \
+         regs->acc1h, regs->acc1l);
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       printk("ACCH[%08lx]:ACCL[%08lx]\n", \
+         regs->acch, regs->accl);
+#else
+#error unknown isa configuration
+#endif
+}
+
+/*
+ * Create a kernel thread
+ */
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg)
+{
+       fn(arg);
+       do_exit(-1);
+}
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+       struct pt_regs regs;
+
+       memset(&regs, 0, sizeof (regs));
+       regs.r1 = (unsigned long)fn;
+       regs.r2 = (unsigned long)arg;
+
+       regs.bpc = (unsigned long)kernel_thread_helper;
+
+       regs.psw = M32R_PSW_BIE;
+
+       /* Ok, create the new process. */
+       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
+               NULL);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+       /* Nothing to do. */
+       DPRINTK("pid = %d\n", current->pid);
+}
+
+void flush_thread(void)
+{
+       DPRINTK("pid = %d\n", current->pid);
+       memset(&current->thread.debug_trap, 0, sizeof(struct debug_trap));
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+       /* do nothing */
+       DPRINTK("pid = %d\n", dead_task->pid);
+}
+
+/* Fill in the fpu structure for a core dump.. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+       return 0; /* Task didn't use the fpu at all. */
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long spu,
+       unsigned long unused, struct task_struct *tsk, struct pt_regs *regs)
+{
+       struct pt_regs *childregs;
+       unsigned long sp = (unsigned long)tsk->thread_info + THREAD_SIZE;
+       extern void ret_from_fork(void);
+
+       tsk->set_child_tid = tsk->clear_child_tid = NULL;
+
+       /* Copy registers */
+       sp -= sizeof (struct pt_regs);
+       childregs = (struct pt_regs *)sp;
+       *childregs = *regs;
+
+       childregs->spu = spu;
+       childregs->r0 = 0;      /* Child gets zero as return value */
+       regs->r0 = tsk->pid;
+       tsk->thread.sp = (unsigned long)childregs;
+       tsk->thread.lr = (unsigned long)ret_from_fork;
+
+       return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+       /* M32R_FIXME */
+}
+
+/*
+ * Capture the user space registers if the task is not running (in user space)
+ */
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+       /* M32R_FIXME */
+       return 1;
+}
+
+asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2,
+       unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
+       struct pt_regs regs)
+{
+#ifdef CONFIG_MMU
+       return do_fork(SIGCHLD, regs.spu, &regs, 0, NULL, NULL);
+#else
+       return -EINVAL;
+#endif /* CONFIG_MMU */
+}
+
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+       unsigned long r2, unsigned long r3, unsigned long r4, unsigned long r5,
+       unsigned long r6, struct pt_regs regs)
+{
+       if (!newsp)
+               newsp = regs.spu;
+
+       return do_fork(clone_flags, newsp, &regs, 0, NULL, NULL);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2,
+       unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
+       struct pt_regs regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, &regs, 0,
+                       NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, char __user * __user *uenvp,
+  unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
+  struct pt_regs regs)
+{
+       int error;
+       char *filename;
+
+       filename = getname(ufilename);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+
+       error = do_execve(filename, uargv, uenvp, &regs);
+       if (error == 0)
+               current->ptrace &= ~PT_DTRACE;
+       putname(filename);
+out:
+       return error;
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+#define first_sched    ((unsigned long) scheduling_functions_start_here)
+#define last_sched     ((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       /* M32R_FIXME */
+       return (0);
+}
+
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..ab4137a
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * linux/arch/m32r/kernel/ptrace.c
+ *
+ * Copyright (C) 2002  Hirokazu Takata, Takeo Takahashi
+ * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * Original x86 implementation:
+ *     By Ross Biro 1/23/92
+ *     edited by Linus Torvalds
+ *
+ * Some code taken from sh version:
+ *   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+ * Some code taken from arm version:
+ *   Copyright (C) 2000 Russell King
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/string.h>
+
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
+ */
+static inline struct pt_regs *
+get_user_regs(struct task_struct *task)
+{
+        return (struct pt_regs *)
+                ((unsigned long)task->thread_info + THREAD_SIZE
+                 - sizeof(struct pt_regs));
+}
+
+/*
+ * This routine will get a word off of the process kernel stack.
+ */
+static inline unsigned long int
+get_stack_long(struct task_struct *task, int offset)
+{
+       unsigned long *stack;
+
+       stack = (unsigned long *)get_user_regs(task);
+
+       return stack[offset];
+}
+
+/*
+ * This routine will put a word on the process kernel stack.
+ */
+static inline int
+put_stack_long(struct task_struct *task, int offset, unsigned long data)
+{
+       unsigned long *stack;
+
+       stack = (unsigned long *)get_user_regs(task);
+       stack[offset] = data;
+
+       return 0;
+}
+
+static int reg_offset[] = {
+       PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
+       PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_FP, PT_LR, PT_SPU,
+};
+
+/*
+ * Read the word at offset "off" into the "struct user".  We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
+                           unsigned long __user *data)
+{
+       unsigned long tmp;
+#ifndef NO_FPU
+       struct user * dummy = NULL;
+#endif
+
+       if ((off & 3) || (off < 0) || (off > sizeof(struct user) - 3))
+               return -EIO;
+
+       off >>= 2;
+       switch (off) {
+       case PT_EVB:
+               __asm__ __volatile__ (
+                       "mvfc   %0, cr5 \n\t"
+                       : "=r" (tmp)
+               );
+               break;
+       case PT_CBR: {
+                       unsigned long psw;
+                       psw = get_stack_long(tsk, PT_PSW);
+                       tmp = ((psw >> 8) & 1);
+               }
+               break;
+       case PT_PSW: {
+                       unsigned long psw, bbpsw;
+                       psw = get_stack_long(tsk, PT_PSW);
+                       bbpsw = get_stack_long(tsk, PT_BBPSW);
+                       tmp = ((psw >> 8) & 0xff) | ((bbpsw & 0xff) << 8);
+               }
+               break;
+       case PT_PC:
+               tmp = get_stack_long(tsk, PT_BPC);
+               break;
+       case PT_BPC:
+               off = PT_BBPC;
+               /* fall through */
+       default:
+               if (off < (sizeof(struct pt_regs) >> 2))
+                       tmp = get_stack_long(tsk, off);
+#ifndef NO_FPU
+               else if (off >= (long)(&dummy->fpu >> 2) &&
+                        off < (long)(&dummy->u_fpvalid >> 2)) {
+                       if (!tsk->used_math) {
+                               if (off == (long)(&dummy->fpu.fpscr >> 2))
+                                       tmp = FPSCR_INIT;
+                               else
+                                       tmp = 0;
+                       } else
+                               tmp = ((long *)(&tsk->thread.fpu >> 2))
+                                       [off - (long)&dummy->fpu];
+               } else if (off == (long)(&dummy->u_fpvalid >> 2))
+                       tmp = tsk->used_math;
+#endif /* not NO_FPU */
+               else
+                       tmp = 0;
+       }
+
+       return put_user(tmp, data);
+}
+
+static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
+                            unsigned long data)
+{
+       int ret = -EIO;
+#ifndef NO_FPU
+       struct user * dummy = NULL;
+#endif
+
+       if ((off & 3) || off < 0 ||
+           off > sizeof(struct user) - 3)
+               return -EIO;
+
+       off >>= 2;
+       switch (off) {
+       case PT_EVB:
+       case PT_BPC:
+       case PT_SPI:
+               /* We don't allow to modify evb. */
+               ret = 0;
+               break;
+       case PT_PSW:
+       case PT_CBR: {
+                       /* We allow to modify only cbr in psw */
+                       unsigned long psw;
+                       psw = get_stack_long(tsk, PT_PSW);
+                       psw = (psw & ~0x100) | ((data & 1) << 8);
+                       ret = put_stack_long(tsk, PT_PSW, psw);
+               }
+               break;
+       case PT_PC:
+               off = PT_BPC;
+               data &= ~1;
+               /* fall through */
+       default:
+               if (off < (sizeof(struct pt_regs) >> 2))
+                       ret = put_stack_long(tsk, off, data);
+#ifndef NO_FPU
+               else if (off >= (long)(&dummy->fpu >> 2) &&
+                        off < (long)(&dummy->u_fpvalid >> 2)) {
+                       tsk->used_math = 1;
+                       ((long *)&tsk->thread.fpu)
+                               [off - (long)&dummy->fpu] = data;
+                       ret = 0;
+               } else if (off == (long)(&dummy->u_fpvalid >> 2)) {
+                       tsk->used_math = data ? 1 : 0;
+                       ret = 0;
+               }
+#endif /* not NO_FPU */
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Get all user integer registers.
+ */
+static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
+{
+       struct pt_regs *regs = get_user_regs(tsk);
+
+       return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/*
+ * Set all user integer registers.
+ */
+static int ptrace_setregs(struct task_struct *tsk, void __user *uregs)
+{
+       struct pt_regs newregs;
+       int ret;
+
+       ret = -EFAULT;
+       if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
+               struct pt_regs *regs = get_user_regs(tsk);
+               *regs = newregs;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+
+static inline int
+check_condition_bit(struct task_struct *child)
+{
+       return (int)((get_stack_long(child, PT_PSW) >> 8) & 1);
+}
+
+static int
+check_condition_src(unsigned long op, unsigned long regno1,
+                   unsigned long regno2, struct task_struct *child)
+{
+       unsigned long reg1, reg2;
+
+       reg2 = get_stack_long(child, reg_offset[regno2]);
+
+       switch (op) {
+       case 0x0: /* BEQ */
+               reg1 = get_stack_long(child, reg_offset[regno1]);
+               return reg1 == reg2;
+       case 0x1: /* BNE */
+               reg1 = get_stack_long(child, reg_offset[regno1]);
+               return reg1 != reg2;
+       case 0x8: /* BEQZ */
+               return reg2 == 0;
+       case 0x9: /* BNEZ */
+               return reg2 != 0;
+       case 0xa: /* BLTZ */
+               return (int)reg2 < 0;
+       case 0xb: /* BGEZ */
+               return (int)reg2 >= 0;
+       case 0xc: /* BLEZ */
+               return (int)reg2 <= 0;
+       case 0xd: /* BGTZ */
+               return (int)reg2 > 0;
+       default:
+               /* never reached */
+               return 0;
+       }
+}
+
+static void
+compute_next_pc_for_16bit_insn(unsigned long insn, unsigned long pc,
+                              unsigned long *next_pc,
+                              struct task_struct *child)
+{
+       unsigned long op, op2, op3;
+       unsigned long disp;
+       unsigned long regno;
+       int parallel = 0;
+
+       if (insn & 0x00008000)
+               parallel = 1;
+       if (pc & 3)
+               insn &= 0x7fff; /* right slot */
+       else
+               insn >>= 16;    /* left slot */
+
+       op = (insn >> 12) & 0xf;
+       op2 = (insn >> 8) & 0xf;
+       op3 = (insn >> 4) & 0xf;
+
+       if (op == 0x7) {
+               switch (op2) {
+               case 0xd: /* BNC */
+               case 0x9: /* BNCL */
+                       if (!check_condition_bit(child)) {
+                               disp = (long)(insn << 24) >> 22;
+                               *next_pc = (pc & ~0x3) + disp;
+                               return;
+                       }
+                       break;
+               case 0x8: /* BCL */
+               case 0xc: /* BC */
+                       if (check_condition_bit(child)) {
+                               disp = (long)(insn << 24) >> 22;
+                               *next_pc = (pc & ~0x3) + disp;
+                               return;
+                       }
+                       break;
+               case 0xe: /* BL */
+               case 0xf: /* BRA */
+                       disp = (long)(insn << 24) >> 22;
+                       *next_pc = (pc & ~0x3) + disp;
+                       return;
+                       break;
+               }
+       } else if (op == 0x1) {
+               switch (op2) {
+               case 0x0:
+                       if (op3 == 0xf) { /* TRAP */
+#if 1
+                               /* pass through */
+#else
+                               /* kernel space is not allowed as next_pc */
+                               unsigned long evb;
+                               unsigned long trapno;
+                               trapno = insn & 0xf;
+                               __asm__ __volatile__ (
+                                       "mvfc %0, cr5\n"
+                                       :"=r"(evb)
+                                       :
+                               );
+                               *next_pc = evb + (trapno << 2);
+                               return;
+#endif
+                       } else if (op3 == 0xd) { /* RTE */
+                               *next_pc = get_stack_long(child, PT_BPC);
+                               return;
+                       }
+                       break;
+               case 0xc: /* JC */
+                       if (op3 == 0xc && check_condition_bit(child)) {
+                               regno = insn & 0xf;
+                               *next_pc = get_stack_long(child,
+                                                         reg_offset[regno]);
+                               return;
+                       }
+                       break;
+               case 0xd: /* JNC */
+                       if (op3 == 0xc && !check_condition_bit(child)) {
+                               regno = insn & 0xf;
+                               *next_pc = get_stack_long(child,
+                                                         reg_offset[regno]);
+                               return;
+                       }
+                       break;
+               case 0xe: /* JL */
+               case 0xf: /* JMP */
+                       if (op3 == 0xc) { /* JMP */
+                               regno = insn & 0xf;
+                               *next_pc = get_stack_long(child,
+                                                         reg_offset[regno]);
+                               return;
+                       }
+                       break;
+               }
+       }
+       if (parallel)
+               *next_pc = pc + 4;
+       else
+               *next_pc = pc + 2;
+}
+
+static void
+compute_next_pc_for_32bit_insn(unsigned long insn, unsigned long pc,
+                              unsigned long *next_pc,
+                              struct task_struct *child)
+{
+       unsigned long op;
+       unsigned long op2;
+       unsigned long disp;
+       unsigned long regno1, regno2;
+
+       op = (insn >> 28) & 0xf;
+       if (op == 0xf) {        /* branch 24-bit relative */
+               op2 = (insn >> 24) & 0xf;
+               switch (op2) {
+               case 0xd:       /* BNC */
+               case 0x9:       /* BNCL */
+                       if (!check_condition_bit(child)) {
+                               disp = (long)(insn << 8) >> 6;
+                               *next_pc = (pc & ~0x3) + disp;
+                               return;
+                       }
+                       break;
+               case 0x8:       /* BCL */
+               case 0xc:       /* BC */
+                       if (check_condition_bit(child)) {
+                               disp = (long)(insn << 8) >> 6;
+                               *next_pc = (pc & ~0x3) + disp;
+                               return;
+                       }
+                       break;
+               case 0xe:       /* BL */
+               case 0xf:       /* BRA */
+                       disp = (long)(insn << 8) >> 6;
+                       *next_pc = (pc & ~0x3) + disp;
+                       return;
+               }
+       } else if (op == 0xb) { /* branch 16-bit relative */
+               op2 = (insn >> 20) & 0xf;
+               switch (op2) {
+               case 0x0: /* BEQ */
+               case 0x1: /* BNE */
+               case 0x8: /* BEQZ */
+               case 0x9: /* BNEZ */
+               case 0xa: /* BLTZ */
+               case 0xb: /* BGEZ */
+               case 0xc: /* BLEZ */
+               case 0xd: /* BGTZ */
+                       regno1 = ((insn >> 24) & 0xf);
+                       regno2 = ((insn >> 16) & 0xf);
+                       if (check_condition_src(op2, regno1, regno2, child)) {
+                               disp = (long)(insn << 16) >> 14;
+                               *next_pc = (pc & ~0x3) + disp;
+                               return;
+                       }
+                       break;
+               }
+       }
+       *next_pc = pc + 4;
+}
+
+static inline void
+compute_next_pc(unsigned long insn, unsigned long pc,
+               unsigned long *next_pc, struct task_struct *child)
+{
+       if (insn & 0x80000000)
+               compute_next_pc_for_32bit_insn(insn, pc, next_pc, child);
+       else
+               compute_next_pc_for_16bit_insn(insn, pc, next_pc, child);
+}
+
+static int
+register_debug_trap(struct task_struct *child, unsigned long next_pc,
+       unsigned long next_insn, unsigned long *code)
+{
+       struct debug_trap *p = &child->thread.debug_trap;
+       unsigned long addr = next_pc & ~3;
+
+       if (p->nr_trap != 0) {
+               printk("kernel BUG at %s %d: p->nr_trap = %d\n",
+                                       __FILE__, __LINE__, p->nr_trap);
+               return -1;
+       }
+       p->addr = addr;
+       p->insn = next_insn;
+       p->nr_trap++;
+       if (next_pc & 3) {
+               *code = (next_insn & 0xffff0000) | 0x10f1;
+               /* xxx --> TRAP1 */
+       } else {
+               if ((next_insn & 0x80000000) || (next_insn & 0x8000)) {
+                       *code = 0x10f17000;
+                       /* TRAP1 --> NOP */
+               } else {
+                       *code = (next_insn & 0xffff) | 0x10f10000;
+                       /* TRAP1 --> xxx */
+               }
+       }
+       return 0;
+}
+
+int withdraw_debug_trap_for_signal(struct task_struct *child)
+{
+       struct debug_trap *p = &child->thread.debug_trap;
+       int nr_trap = p->nr_trap;
+
+       if (nr_trap) {
+               access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1);
+               p->nr_trap = 0;
+               p->addr = 0;
+               p->insn = 0;
+       }
+       return nr_trap;
+}
+
+static int
+unregister_debug_trap(struct task_struct *child, unsigned long addr,
+                     unsigned long *code)
+{
+       struct debug_trap *p = &child->thread.debug_trap;
+
+       if (p->nr_trap != 1 || p->addr != addr) {
+               /* The trap may be requested from debugger.
+                * ptrace should do nothing in this case.
+                */
+               return 0;
+       }
+       *code = p->insn;
+       p->insn = 0;
+       p->addr = 0;
+       p->nr_trap--;
+       return 1;
+}
+
+static void
+unregister_all_debug_traps(struct task_struct *child)
+{
+       struct debug_trap *p = &child->thread.debug_trap;
+
+       if (p->nr_trap) {
+               access_process_vm(child, p->addr, &p->insn, sizeof(p->insn), 1);
+               p->addr = 0;
+               p->insn = 0;
+               p->nr_trap = 0;
+       }
+}
+
+static inline void
+invalidate_cache(void)
+{
+#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP)
+
+       _flush_cache_copyback_all();
+
+#else  /* ! CONFIG_CHIP_M32700 */
+
+       /* Invalidate cache */
+       __asm__ __volatile__ (
+                "ldi    r0, #-1                                        \n\t"
+                "ldi    r1, #0                                 \n\t"
+                "stb    r1, @r0                ; cache off             \n\t"
+                ";                                             \n\t"
+                "ldi    r0, #-2                                        \n\t"
+                "ldi    r1, #1                                 \n\t"
+                "stb    r1, @r0                ; cache invalidate      \n\t"
+                ".fillinsn                                     \n"
+                "0:                                            \n\t"
+                "ldb    r1, @r0                ; invalidate check      \n\t"
+                "bnez   r1, 0b                                 \n\t"
+                ";                                             \n\t"
+                "ldi    r0, #-1                                        \n\t"
+                "ldi    r1, #1                                 \n\t"
+                "stb    r1, @r0                ; cache on              \n\t"
+               : : : "r0", "r1", "memory"
+       );
+       /* FIXME: copying-back d-cache and invalidating i-cache are needed.
+        */
+#endif /* CONFIG_CHIP_M32700 */
+}
+
+/* Embed a debug trap (TRAP1) code */
+static int
+embed_debug_trap(struct task_struct *child, unsigned long next_pc)
+{
+       unsigned long next_insn, code;
+       unsigned long addr = next_pc & ~3;
+
+       if (access_process_vm(child, addr, &next_insn, sizeof(next_insn), 0)
+           != sizeof(next_insn)) {
+               return -1; /* error */
+       }
+
+       /* Set a trap code. */
+       if (register_debug_trap(child, next_pc, next_insn, &code)) {
+               return -1; /* error */
+       }
+       if (access_process_vm(child, addr, &code, sizeof(code), 1)
+           != sizeof(code)) {
+               return -1; /* error */
+       }
+       return 0; /* success */
+}
+
+void
+embed_debug_trap_for_signal(struct task_struct *child)
+{
+       unsigned long next_pc;
+       unsigned long pc, insn;
+       int ret;
+
+       pc = get_stack_long(child, PT_BPC);
+       ret = access_process_vm(child, pc&~3, &insn, sizeof(insn), 0);
+       if (ret != sizeof(insn)) {
+               printk("kernel BUG at %s %d: access_process_vm returns %d\n",
+                      __FILE__, __LINE__, ret);
+               return;
+       }
+       compute_next_pc(insn, pc, &next_pc, child);
+       if (next_pc & 0x80000000) {
+               printk("kernel BUG at %s %d: next_pc = 0x%08x\n",
+                      __FILE__, __LINE__, (int)next_pc);
+               return;
+       }
+       if (embed_debug_trap(child, next_pc)) {
+               printk("kernel BUG at %s %d: embed_debug_trap error\n",
+                      __FILE__, __LINE__);
+               return;
+       }
+       invalidate_cache();
+}
+
+void
+withdraw_debug_trap(struct pt_regs *regs)
+{
+       unsigned long addr;
+       unsigned long code;
+
+       addr = (regs->bpc - 2) & ~3;
+       regs->bpc -= 2;
+       if (unregister_debug_trap(current, addr, &code)) {
+           access_process_vm(current, addr, &code, sizeof(code), 1);
+           invalidate_cache();
+       }
+}
+
+static void
+init_debug_traps(struct task_struct *child)
+{
+       struct debug_trap *p = &child->thread.debug_trap;
+       p->nr_trap = 0;
+       p->addr = 0;
+       p->insn = 0;
+}
+
+
+/*
+ * 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.. */
+}
+
+static int
+do_ptrace(long request, struct task_struct *child, long addr, long data)
+{
+       unsigned long tmp;
+       int ret;
+
+       switch (request) {
+       /*
+        * read word at location "addr" in the child process.
+        */
+       case PTRACE_PEEKTEXT:
+       case PTRACE_PEEKDATA:
+               ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+               if (ret == sizeof(tmp))
+                       ret = put_user(tmp,(unsigned long __user *) data);
+               else
+                       ret = -EIO;
+               break;
+
+       /*
+        * read the word at location addr in the USER area.
+        */
+       case PTRACE_PEEKUSR:
+               ret = ptrace_read_user(child, addr,
+                                      (unsigned long __user *)data);
+               break;
+
+       /*
+        * write the word at location addr.
+        */
+       case PTRACE_POKETEXT:
+       case PTRACE_POKEDATA:
+               ret = access_process_vm(child, addr, &data, sizeof(data), 1);
+               if (ret == sizeof(data)) {
+                       ret = 0;
+                       if (request == PTRACE_POKETEXT) {
+                               invalidate_cache();
+                       }
+               } else {
+                       ret = -EIO;
+               }
+               break;
+
+       /*
+        * write the word at location addr in the USER area.
+        */
+       case PTRACE_POKEUSR:
+               ret = ptrace_write_user(child, addr, data);
+               break;
+
+       /*
+        * continue/restart and stop at next (return from) syscall
+        */
+       case PTRACE_SYSCALL:
+       case PTRACE_CONT:
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       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;
+               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;
+               unregister_all_debug_traps(child);
+               invalidate_cache();
+               if (child->state == TASK_ZOMBIE)        /* already dead */
+                       break;
+               child->exit_code = SIGKILL;
+               wake_up_process(child);
+               break;
+       }
+
+       /*
+        * execute single instruction.
+        */
+       case PTRACE_SINGLESTEP: {
+               unsigned long next_pc;
+               unsigned long pc, insn;
+
+               ret = -EIO;
+               if ((unsigned long) data > _NSIG)
+                       break;
+               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               if ((child->ptrace & PT_DTRACE) == 0) {
+                       /* Spurious delayed TF traps may occur */
+                       child->ptrace |= PT_DTRACE;
+               }
+
+               /* Compute next pc.  */
+               pc = get_stack_long(child, PT_BPC);
+
+               if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
+                   != sizeof(insn))
+                       break;
+
+               compute_next_pc(insn, pc, &next_pc, child);
+               if (next_pc & 0x80000000)
+                       break;
+
+               if (embed_debug_trap(child, next_pc))
+                       break;
+
+               invalidate_cache();
+               child->exit_code = data;
+
+               /* give it a chance to run. */
+               wake_up_process(child);
+               ret = 0;
+               break;
+       }
+
+       /*
+        * detach a process that was attached.
+        */
+       case PTRACE_DETACH:
+               ret = 0;
+               ret = ptrace_detach(child, data);
+               break;
+
+       case PTRACE_GETREGS:
+               ret = ptrace_getregs(child, (void __user *)data);
+               break;
+
+       case PTRACE_SETREGS:
+               ret = ptrace_setregs(child, (void __user *)data);
+               break;
+
+       default:
+               ret = ptrace_request(child, request, addr, data);
+               break;
+       }
+
+       return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+       struct task_struct *child;
+       int ret;
+
+       lock_kernel();
+       ret = -EPERM;
+       if (request == PTRACE_TRACEME) {
+               /* are we already being traced? */
+               if (current->ptrace & PT_PTRACED)
+                       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);
+               if (ret == 0)
+                       init_debug_traps(child);
+               goto out_tsk;
+       }
+
+       ret = ptrace_check_attach(child, request == PTRACE_KILL);
+       if (ret == 0)
+               ret = do_ptrace(request, child, addr, data);
+
+out_tsk:
+       put_task_struct(child);
+out:
+       unlock_kernel();
+
+       return ret;
+}
+
+/* notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
+ */
+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/m32r/kernel/semaphore.c b/arch/m32r/kernel/semaphore.c
new file mode 100644 (file)
index 0000000..358f217
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ *  linux/arch/m32r/semaphore.c
+ *    orig : i386 2.6.4
+ *
+ *  M32R semaphore implementation.
+ *
+ *     Copyright (c) 2002 - 2004 Hitoshi Yamamoto
+ */
+
+/*
+ * i386 semaphore implementation.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Portions Copyright 1999 Red Hat, 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.
+ *
+ * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@redhat.com>
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to acquire the semaphore, while the "sleeping"
+ * variable is a count of such acquires.
+ *
+ * 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.
+ *
+ * "sleeping" and the contention routine ordering is protected
+ * by the spinlock in the semaphore's waitqueue head.
+ *
+ * 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.
+ */
+
+/*
+ * Logic:
+ *  - only on a boundary condition do we need to care. When we go
+ *    from a negative count to a non-negative, we wake people up.
+ *  - when we go from a non-negative count to a negative do we
+ *    (a) synchronize with the "sleeper" count and (b) make sure
+ *    that we're on the wakeup list before we synchronize so that
+ *    we cannot lose wakeup events.
+ */
+
+asmlinkage void __up(struct semaphore *sem)
+{
+       wake_up(&sem->wait);
+}
+
+asmlinkage void __sched __down(struct semaphore * sem)
+{
+       struct task_struct *tsk = current;
+       DECLARE_WAITQUEUE(wait, tsk);
+       unsigned long flags;
+
+       tsk->state = TASK_UNINTERRUPTIBLE;
+       spin_lock_irqsave(&sem->wait.lock, flags);
+       add_wait_queue_exclusive_locked(&sem->wait, &wait);
+
+       sem->sleepers++;
+       for (;;) {
+               int sleepers = sem->sleepers;
+
+               /*
+                * Add "everybody else" into it. They aren't
+                * playing, because we own the spinlock in
+                * the wait_queue_head.
+                */
+               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+                       sem->sleepers = 0;
+                       break;
+               }
+               sem->sleepers = 1;      /* us - see -1 above */
+               spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+               schedule();
+
+               spin_lock_irqsave(&sem->wait.lock, flags);
+               tsk->state = TASK_UNINTERRUPTIBLE;
+       }
+       remove_wait_queue_locked(&sem->wait, &wait);
+       wake_up_locked(&sem->wait);
+       spin_unlock_irqrestore(&sem->wait.lock, flags);
+       tsk->state = TASK_RUNNING;
+}
+
+asmlinkage int __sched __down_interruptible(struct semaphore * sem)
+{
+       int retval = 0;
+       struct task_struct *tsk = current;
+       DECLARE_WAITQUEUE(wait, tsk);
+       unsigned long flags;
+
+       tsk->state = TASK_INTERRUPTIBLE;
+       spin_lock_irqsave(&sem->wait.lock, flags);
+       add_wait_queue_exclusive_locked(&sem->wait, &wait);
+
+       sem->sleepers++;
+       for (;;) {
+               int sleepers = sem->sleepers;
+
+               /*
+                * With signals pending, this turns into
+                * the trylock failure case - we won't be
+                * sleeping, and we* can't get the lock as
+                * it has contention. Just correct the count
+                * and exit.
+                */
+               if (signal_pending(current)) {
+                       retval = -EINTR;
+                       sem->sleepers = 0;
+                       atomic_add(sleepers, &sem->count);
+                       break;
+               }
+
+               /*
+                * Add "everybody else" into it. They aren't
+                * playing, because we own the spinlock in
+                * wait_queue_head. The "-1" is because we're
+                * still hoping to get the semaphore.
+                */
+               if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+                       sem->sleepers = 0;
+                       break;
+               }
+               sem->sleepers = 1;      /* us - see -1 above */
+               spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+               schedule();
+
+               spin_lock_irqsave(&sem->wait.lock, flags);
+               tsk->state = TASK_INTERRUPTIBLE;
+       }
+       remove_wait_queue_locked(&sem->wait, &wait);
+       wake_up_locked(&sem->wait);
+       spin_unlock_irqrestore(&sem->wait.lock, flags);
+
+       tsk->state = TASK_RUNNING;
+       return retval;
+}
+
+/*
+ * Trylock failed - make sure we correct for
+ * having decremented the count.
+ *
+ * We could have done the trylock with a
+ * single "cmpxchg" without failure cases,
+ * but then it wouldn't work on a 386.
+ */
+asmlinkage int __down_trylock(struct semaphore * sem)
+{
+       int sleepers;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sem->wait.lock, flags);
+       sleepers = sem->sleepers + 1;
+       sem->sleepers = 0;
+
+       /*
+        * Add "everybody else" and us into it. They aren't
+        * playing, because we own the spinlock in the
+        * wait_queue_head.
+        */
+       if (!atomic_add_negative(sleepers, &sem->count)) {
+               wake_up_locked(&sem->wait);
+       }
+
+       spin_unlock_irqrestore(&sem->wait.lock, flags);
+       return 1;
+}
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c
new file mode 100644 (file)
index 0000000..db9589c
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ *  linux/arch/m32r/kernel/setup.c
+ *
+ *  Setup routines for Renesas M32R
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto
+ */
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <linux/initrd.h>
+#include <linux/major.h>
+#include <linux/root_dev.h>
+#include <linux/seq_file.h>
+#include <linux/timex.h>
+#include <linux/tty.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/m32r.h>
+#include <asm/setup.h>
+#include <asm/sections.h>
+
+#ifdef CONFIG_MMU
+extern void init_mmu(void);
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)  \
+       || defined(CONFIG_BLK_DEV_IDE_MODULE)                   \
+       || defined(CONFIG_BLK_DEV_HD_MODULE)
+struct drive_info_struct { char dummy[32]; } drive_info;
+#endif
+
+extern char _end[];
+
+/*
+ * Machine setup..
+ */
+struct cpuinfo_m32r boot_cpu_data;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload;  /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;  /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;  /* starting block # of image */
+#endif
+
+#if defined(CONFIG_VGA_CONSOLE)
+struct screen_info screen_info = {
+       .orig_video_lines      = 25,
+       .orig_video_cols       = 80,
+       .orig_video_mode       = 0,
+       .orig_video_ega_bx     = 0,
+       .orig_video_isVGA      = 1,
+       .orig_video_points     = 8
+};
+#endif
+
+extern int root_mountflags;
+
+static char command_line[COMMAND_LINE_SIZE];
+
+static struct resource data_resource = {
+       .name   = "Kernel data",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource code_resource = {
+       .name   = "Kernel code",
+       .start  = 0,
+       .end    = 0,
+       .flags  = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+unsigned long memory_start;
+unsigned long memory_end;
+
+void __init setup_arch(char **);
+int get_cpuinfo(char *);
+
+static __inline__ void parse_mem_cmdline(char ** cmdline_p)
+{
+       char c = ' ';
+       char *to = command_line;
+       char *from = COMMAND_LINE;
+       int len = 0;
+       int usermem = 0;
+
+       /* Save unparsed command line copy for /proc/cmdline */
+       memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+       saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+       memory_start = (unsigned long)CONFIG_MEMORY_START+PAGE_OFFSET;
+       memory_end = memory_start+(unsigned long)CONFIG_MEMORY_SIZE;
+
+       for ( ; ; ) {
+               if (c == ' ' && !memcmp(from, "mem=", 4)) {
+                       if (to != command_line)
+                               to--;
+
+                       {
+                               unsigned long mem_size;
+
+                               usermem = 1;
+                               mem_size = memparse(from+4, &from);
+                               memory_end = memory_start + mem_size;
+                       }
+               }
+               c = *(from++);
+               if (!c)
+                       break;
+
+               if (COMMAND_LINE_SIZE <= ++len)
+                       break;
+
+               *(to++) = c;
+       }
+       *to = '\0';
+       *cmdline_p = command_line;
+       if (usermem)
+               printk(KERN_INFO "user-defined physical RAM map:\n");
+}
+
+#ifndef CONFIG_DISCONTIGMEM
+static unsigned long __init setup_memory(void)
+{
+       unsigned long start_pfn, max_low_pfn, bootmap_size;
+
+       start_pfn = PFN_UP( __pa(_end) );
+       max_low_pfn = PFN_DOWN( __pa(memory_end) );
+
+       /*
+        * Initialize the boot-time allocator (with low memory only):
+        */
+       bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
+               CONFIG_MEMORY_START>>PAGE_SHIFT, max_low_pfn);
+
+       /*
+        * Register fully available low RAM pages with the bootmem allocator.
+        */
+       {
+               unsigned long curr_pfn;
+               unsigned long last_pfn;
+               unsigned long pages;
+
+               /*
+                * We are rounding up the start address of usable memory:
+                */
+               curr_pfn = PFN_UP(__pa(memory_start));
+
+               /*
+                * ... and at the end of the usable range downwards:
+                */
+               last_pfn = PFN_DOWN(__pa(memory_end));
+
+               if (last_pfn > max_low_pfn)
+                       last_pfn = max_low_pfn;
+
+               pages = last_pfn - curr_pfn;
+               free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
+       }
+
+       /*
+        * Reserve the kernel text and
+        * Reserve the bootmem bitmap. We do this in two steps (first step
+        * was init_bootmem()), because this catches the (definitely buggy)
+        * case of us accidentally initializing the bootmem allocator with
+        * an invalid RAM area.
+        */
+       reserve_bootmem(CONFIG_MEMORY_START + PAGE_SIZE,
+               (PFN_PHYS(start_pfn) + bootmap_size + PAGE_SIZE - 1)
+               - CONFIG_MEMORY_START);
+
+       /*
+        * reserve physical page 0 - it's a special BIOS page on many boxes,
+        * enabling clean reboots, SMP operation, laptop functions.
+        */
+       reserve_bootmem(CONFIG_MEMORY_START, PAGE_SIZE);
+
+       /*
+        * reserve memory hole
+        */
+#ifdef CONFIG_MEMHOLE
+       reserve_bootmem(CONFIG_MEMHOLE_START, CONFIG_MEMHOLE_SIZE);
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (LOADER_TYPE && INITRD_START) {
+               if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
+                       reserve_bootmem(INITRD_START, INITRD_SIZE);
+                       initrd_start = INITRD_START ?
+                               INITRD_START + PAGE_OFFSET : 0;
+
+                       initrd_end = initrd_start + INITRD_SIZE;
+                       printk("initrd:start[%08lx],size[%08lx]\n",
+                               initrd_start, INITRD_SIZE);
+               } else {
+                       printk("initrd extends beyond end of memory "
+                               "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                               INITRD_START + INITRD_SIZE,
+                               max_low_pfn << PAGE_SHIFT);
+
+                       initrd_start = 0;
+               }
+       }
+#endif
+
+       return max_low_pfn;
+}
+#else  /* CONFIG_DISCONTIGMEM */
+extern unsigned long setup_memory(void);
+#endif /* CONFIG_DISCONTIGMEM */
+
+#define M32R_PCC_PCATCR        0x00ef7014      /* will move to m32r.h */
+
+void __init setup_arch(char **cmdline_p)
+{
+       ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+
+       boot_cpu_data.cpu_clock = M32R_CPUCLK;
+       boot_cpu_data.bus_clock = M32R_BUSCLK;
+       boot_cpu_data.timer_divide = M32R_TIMER_DIVIDE;
+
+#ifdef CONFIG_BLK_DEV_RAM
+       rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+       rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+       rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+
+       if (!MOUNT_ROOT_RDONLY)
+               root_mountflags &= ~MS_RDONLY;
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+       conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+#endif
+#endif
+
+#ifdef CONFIG_DISCONTIGMEM
+       numnodes = 2;
+#endif /* CONFIG_DISCONTIGMEM */
+
+       init_mm.start_code = (unsigned long) _text;
+       init_mm.end_code = (unsigned long) _etext;
+       init_mm.end_data = (unsigned long) _edata;
+       init_mm.brk = (unsigned long) _end;
+
+       code_resource.start = virt_to_phys(_text);
+       code_resource.end = virt_to_phys(_etext)-1;
+       data_resource.start = virt_to_phys(_etext);
+       data_resource.end = virt_to_phys(_edata)-1;
+
+       parse_mem_cmdline(cmdline_p);
+
+       setup_memory();
+
+       paging_init();
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ *     Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+       struct cpuinfo_m32r *c = v;
+       unsigned long cpu = c - cpu_data;
+
+#ifdef CONFIG_SMP
+       if (!cpu_online(cpu))
+               return 0;
+#endif  /* CONFIG_SMP */
+
+       seq_printf(m, "processor\t: %ld\n", cpu);
+
+#ifdef CONFIG_CHIP_VDEC2
+       seq_printf(m, "cpu family\t: VDEC2\n"
+               "cache size\t: Unknown\n");
+#elif  CONFIG_CHIP_M32700
+       seq_printf(m,"cpu family\t: M32700\n"
+               "cache size\t: I-8KB/D-8KB\n");
+#elif  CONFIG_CHIP_M32102
+       seq_printf(m,"cpu family\t: M32102\n"
+               "cache size\t: I-8KB\n");
+#elif  CONFIG_CHIP_OPSP
+       seq_printf(m,"cpu family\t: OPSP\n"
+               "cache size\t: I-8KB/D-8KB\n");
+#elif  CONFIG_CHIP_MP
+       seq_printf(m, "cpu family\t: M32R-MP\n"
+               "cache size\t: I-xxKB/D-xxKB\n");
+#else
+       seq_printf(m, "cpu family\t: Unknown\n");
+#endif
+       seq_printf(m, "bogomips\t: %lu.%02lu\n",
+               c->loops_per_jiffy/(500000/HZ),
+               (c->loops_per_jiffy/(5000/HZ)) % 100);
+#ifdef CONFIG_PLAT_MAPPI
+       seq_printf(m, "Machine\t\t: Mappi Evaluation board\n");
+#elif CONFIG_PLAT_MAPPI2
+       seq_printf(m, "Machine\t\t: Mappi-II Evaluation board\n");
+#elif  CONFIG_PLAT_M32700UT
+       seq_printf(m, "Machine\t\t: M32700UT Evaluation board\n");
+#elif  CONFIG_PLAT_OPSPUT
+       seq_printf(m, "Machine\t\t: OPSPUT Evaluation board\n");
+#elif  CONFIG_PLAT_USRV
+       seq_printf(m, "Machine\t\t: uServer\n");
+#elif  CONFIG_PLAT_OAKS32R
+       seq_printf(m, "Machine\t\t: OAKS32R\n");
+#else
+       seq_printf(m, "Machine\t\t: Unknown\n");
+#endif
+
+#define PRINT_CLOCK(name, value)                               \
+       seq_printf(m, name " clock\t: %d.%02dMHz\n",            \
+               ((value) / 1000000), ((value) % 1000000)/10000)
+
+       PRINT_CLOCK("CPU", (int)c->cpu_clock);
+       PRINT_CLOCK("Bus", (int)c->bus_clock);
+
+       seq_printf(m, "\n");
+
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+       start:  c_start,
+       next:   c_next,
+       stop:   c_stop,
+       show:   show_cpuinfo,
+};
+#endif  /* CONFIG_PROC_FS */
+
+unsigned long cpu_initialized __initdata = 0;
+
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process.
+ * We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ */
+#if defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2)   \
+       || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \
+       || defined(CONFIG_CHIP_OPSP)
+void __init cpu_init (void)
+{
+       int cpu_id = smp_processor_id();
+
+       if (test_and_set_bit(cpu_id, &cpu_initialized)) {
+               printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id);
+               for ( ; ; )
+                       local_irq_enable();
+       }
+       printk(KERN_INFO "Initializing CPU#%d\n", cpu_id);
+
+       /* Set up and load the per-CPU TSS and LDT */
+       atomic_inc(&init_mm.mm_count);
+       current->active_mm = &init_mm;
+       if (current->mm)
+               BUG();
+
+       /* Force FPU initialization */
+       current_thread_info()->status = 0;
+       current->used_math = 0;
+
+#ifdef CONFIG_MMU
+       /* Set up MMU */
+       init_mmu();
+#endif
+
+       /* Set up ICUIMASK */
+       outl(0x00070000, M32R_ICU_IMASK_PORTL);   /* imask=111 */
+}
+#endif  /* defined(CONFIG_CHIP_VDEC2) ... */
+
diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c
new file mode 100644 (file)
index 0000000..5d0780b
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ *  linux/arch/m32r/kernel/setup_m32700ut.c
+ *
+ *  Setup routines for Renesas M32700UT Board
+ *
+ *  Copyright (c) 2002         Hiroyuki Kondo, Hirokazu Takata,
+ *                      Hitoshi Yamamoto, Takeo Takahashi
+ *
+ *  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/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+/*
+ * M32700 Interrupt Control Unit (Level 1)
+ */
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#ifndef CONFIG_SMP
+typedef struct {
+       unsigned long icucr;  /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+static icu_data_t icu_data[M32700UT_NUM_CPU_IRQ];
+
+static void disable_m32700ut_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+       outl(data, port);
+}
+
+static void enable_m32700ut_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+       outl(data, port);
+}
+
+static void mask_and_ack_m32700ut(unsigned int irq)
+{
+       disable_m32700ut_irq(irq);
+}
+
+static void end_m32700ut_irq(unsigned int irq)
+{
+       enable_m32700ut_irq(irq);
+}
+
+static unsigned int startup_m32700ut_irq(unsigned int irq)
+{
+       enable_m32700ut_irq(irq);
+       return (0);
+}
+
+static void shutdown_m32700ut_irq(unsigned int irq)
+{
+       unsigned long port;
+
+       port = irq2port(irq);
+       outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type m32700ut_irq_type =
+{
+       "M32700UT-IRQ",
+       startup_m32700ut_irq,
+       shutdown_m32700ut_irq,
+       enable_m32700ut_irq,
+       disable_m32700ut_irq,
+       mask_and_ack_m32700ut,
+       end_m32700ut_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on M32700UT (Level 2)
+ */
+#define irq2pldirq(x)          ((x) - M32700UT_PLD_IRQ_BASE)
+#define pldirq2port(x)         (unsigned long)((int)PLD_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+typedef struct {
+       unsigned short icucr;  /* ICU Control Register */
+} pld_icu_data_t;
+
+static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ];
+
+static void disable_m32700ut_pld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+//     disable_m32700ut_irq(M32R_IRQ_INT1);
+       port = pldirq2port(pldirq);
+       data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_m32700ut_pld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+//     enable_m32700ut_irq(M32R_IRQ_INT1);
+       port = pldirq2port(pldirq);
+       data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_m32700ut_pld(unsigned int irq)
+{
+       disable_m32700ut_pld_irq(irq);
+//     mask_and_ack_m32700ut(M32R_IRQ_INT1);
+}
+
+static void end_m32700ut_pld_irq(unsigned int irq)
+{
+       enable_m32700ut_pld_irq(irq);
+       end_m32700ut_irq(M32R_IRQ_INT1);
+}
+
+static unsigned int startup_m32700ut_pld_irq(unsigned int irq)
+{
+       enable_m32700ut_pld_irq(irq);
+       return (0);
+}
+
+static void shutdown_m32700ut_pld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+//     shutdown_m32700ut_irq(M32R_IRQ_INT1);
+       port = pldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type m32700ut_pld_irq_type =
+{
+       "M32700UT-PLD-IRQ",
+       startup_m32700ut_pld_irq,
+       shutdown_m32700ut_pld_irq,
+       enable_m32700ut_pld_irq,
+       disable_m32700ut_pld_irq,
+       mask_and_ack_m32700ut_pld,
+       end_m32700ut_pld_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on M32700UT-LAN (Level 2)
+ */
+#define irq2lanpldirq(x)       ((x) - M32700UT_LAN_PLD_IRQ_BASE)
+#define lanpldirq2port(x)      (unsigned long)((int)M32700UT_LAN_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+static pld_icu_data_t lanpld_icu_data[M32700UT_NUM_LAN_PLD_IRQ];
+
+static void disable_m32700ut_lanpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lanpldirq(irq);
+       port = lanpldirq2port(pldirq);
+       data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_m32700ut_lanpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lanpldirq(irq);
+       port = lanpldirq2port(pldirq);
+       data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_m32700ut_lanpld(unsigned int irq)
+{
+       disable_m32700ut_lanpld_irq(irq);
+}
+
+static void end_m32700ut_lanpld_irq(unsigned int irq)
+{
+       enable_m32700ut_lanpld_irq(irq);
+       end_m32700ut_irq(M32R_IRQ_INT0);
+}
+
+static unsigned int startup_m32700ut_lanpld_irq(unsigned int irq)
+{
+       enable_m32700ut_lanpld_irq(irq);
+       return (0);
+}
+
+static void shutdown_m32700ut_lanpld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2lanpldirq(irq);
+       port = lanpldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type m32700ut_lanpld_irq_type =
+{
+       "M32700UT-PLD-LAN-IRQ",
+       startup_m32700ut_lanpld_irq,
+       shutdown_m32700ut_lanpld_irq,
+       enable_m32700ut_lanpld_irq,
+       disable_m32700ut_lanpld_irq,
+       mask_and_ack_m32700ut_lanpld,
+       end_m32700ut_lanpld_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on M32700UT-LCD (Level 2)
+ */
+#define irq2lcdpldirq(x)       ((x) - M32700UT_LCD_PLD_IRQ_BASE)
+#define lcdpldirq2port(x)      (unsigned long)((int)M32700UT_LCD_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+static pld_icu_data_t lcdpld_icu_data[M32700UT_NUM_LCD_PLD_IRQ];
+
+static void disable_m32700ut_lcdpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lcdpldirq(irq);
+       port = lcdpldirq2port(pldirq);
+       data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_m32700ut_lcdpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lcdpldirq(irq);
+       port = lcdpldirq2port(pldirq);
+       data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_m32700ut_lcdpld(unsigned int irq)
+{
+       disable_m32700ut_lcdpld_irq(irq);
+}
+
+static void end_m32700ut_lcdpld_irq(unsigned int irq)
+{
+       enable_m32700ut_lcdpld_irq(irq);
+       end_m32700ut_irq(M32R_IRQ_INT2);
+}
+
+static unsigned int startup_m32700ut_lcdpld_irq(unsigned int irq)
+{
+       enable_m32700ut_lcdpld_irq(irq);
+       return (0);
+}
+
+static void shutdown_m32700ut_lcdpld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2lcdpldirq(irq);
+       port = lcdpldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type m32700ut_lcdpld_irq_type =
+{
+       "M32700UT-PLD-LCD-IRQ",
+       startup_m32700ut_lcdpld_irq,
+       shutdown_m32700ut_lcdpld_irq,
+       enable_m32700ut_lcdpld_irq,
+       disable_m32700ut_lcdpld_irq,
+       mask_and_ack_m32700ut_lcdpld,
+       end_m32700ut_lcdpld_irq
+};
+
+void __init init_IRQ(void)
+{
+#if defined(CONFIG_SMC91X)
+       /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/
+       irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED;
+       irq_desc[M32700UT_LAN_IRQ_LAN].handler = &m32700ut_lanpld_irq_type;
+       irq_desc[M32700UT_LAN_IRQ_LAN].action = 0;
+       irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1;       /* disable nested irq */
+       lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;   /* "H" edge sense */
+       disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN);
+#endif  /* CONFIG_SMC91X */
+
+       /* MFT2 : system timer */
+       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_MFT2].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_MFT2].action = 0;
+       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+       disable_m32700ut_irq(M32R_IRQ_MFT2);
+
+       /* SIO0 : receive */
+       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_R].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].action = 0;
+       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+       disable_m32700ut_irq(M32R_IRQ_SIO0_R);
+
+       /* SIO0 : send */
+       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_S].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].action = 0;
+       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+       disable_m32700ut_irq(M32R_IRQ_SIO0_S);
+
+       /* SIO1 : receive */
+       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_R].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].action = 0;
+       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+       disable_m32700ut_irq(M32R_IRQ_SIO1_R);
+
+       /* SIO1 : send */
+       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_S].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].action = 0;
+       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+       disable_m32700ut_irq(M32R_IRQ_SIO1_S);
+
+       /* DMA1 : */
+       irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_DMA1].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_DMA1].action = 0;
+       irq_desc[M32R_IRQ_DMA1].depth = 1;
+       icu_data[M32R_IRQ_DMA1].icucr = 0;
+       disable_m32700ut_irq(M32R_IRQ_DMA1);
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       /* INT#1: SIO0 Receive on PLD */
+       irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_SIO0_RCV].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
+       irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
+       disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV);
+
+       /* INT#1: SIO0 Send on PLD */
+       irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_SIO0_SND].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_SND].action = 0;
+       irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
+       disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND);
+#endif  /* CONFIG_SERIAL_M32R_PLDSIO */
+
+       /* INT#1: CFC IREQ on PLD */
+       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFIREQ].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].action = 0;
+       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
+       disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ);
+
+       /* INT#1: CFC Insert on PLD */
+       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFC_INSERT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
+       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
+       disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT);
+
+       /* INT#1: CFC Eject on PLD */
+       irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFC_EJECT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
+       irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
+       disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT);
+
+       /*
+        * INT0# is used for LAN, DIO
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
+       enable_m32700ut_irq(M32R_IRQ_INT0);
+
+       /*
+        * INT1# is used for UART, MMC, CF Controller in FPGA.
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
+       enable_m32700ut_irq(M32R_IRQ_INT1);
+
+#if defined(CONFIG_USB)
+       outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
+
+    irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
+    irq_desc[M32700UT_LCD_IRQ_USB_INT1].handler = &m32700ut_lcdpld_irq_type;
+    irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0;
+    irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1;
+    lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
+    disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1);
+#endif
+       /*
+        * INT2# is used for BAT, USB, AUDIO
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
+       enable_m32700ut_irq(M32R_IRQ_INT2);
+
+//#if defined(CONFIG_M32R_AR_VGA)
+       /*
+        * INT3# is used for AR
+        */
+       irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT3].handler = &m32700ut_irq_type;
+       irq_desc[M32R_IRQ_INT3].action = 0;
+       irq_desc[M32R_IRQ_INT3].depth = 1;
+       icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+       disable_m32700ut_irq(M32R_IRQ_INT3);
+//#endif       /* CONFIG_M32R_ARV */
+}
+
+#define LAN_IOSTART     0x300
+#define LAN_IOEND       0x320
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .start  = (LAN_IOSTART),
+               .end    = (LAN_IOEND),
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = M32700UT_LAN_IRQ_LAN,
+               .end    = M32700UT_LAN_IRQ_LAN,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
+};
+
+static int __init platform_init(void)
+{
+       platform_device_register(&smc91x_device);
+       return 0;
+}
+arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c
new file mode 100644 (file)
index 0000000..523cee3
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ *  linux/arch/m32r/kernel/setup_mappi.c
+ *
+ *  Setup routines for Renesas MAPPI Board
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto
+ */
+
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#ifndef CONFIG_SMP
+typedef struct {
+       unsigned long icucr;  /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+icu_data_t icu_data[NR_IRQS];
+
+static void disable_mappi_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+       outl(data, port);
+}
+
+static void enable_mappi_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+       outl(data, port);
+}
+
+static void mask_and_ack_mappi(unsigned int irq)
+{
+       disable_mappi_irq(irq);
+}
+
+static void end_mappi_irq(unsigned int irq)
+{
+       enable_mappi_irq(irq);
+}
+
+static unsigned int startup_mappi_irq(unsigned int irq)
+{
+       enable_mappi_irq(irq);
+       return (0);
+}
+
+static void shutdown_mappi_irq(unsigned int irq)
+{
+       unsigned long port;
+
+       port = irq2port(irq);
+       outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type mappi_irq_type =
+{
+       "MAPPI-IRQ",
+       startup_mappi_irq,
+       shutdown_mappi_irq,
+       enable_mappi_irq,
+       disable_mappi_irq,
+       mask_and_ack_mappi,
+       end_mappi_irq
+};
+
+void __init init_IRQ(void)
+{
+       static int once = 0;
+
+       if (once)
+               return;
+       else
+               once++;
+
+#ifdef CONFIG_NE2000
+       /* INT0 : LAN controller (RTL8019AS) */
+       irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT0].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT0].action = 0;
+       irq_desc[M32R_IRQ_INT0].depth = 1;
+       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+       disable_mappi_irq(M32R_IRQ_INT0);
+#endif /* CONFIG_M32R_NE2000 */
+
+       /* MFT2 : system timer */
+       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_MFT2].action = 0;
+       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+       disable_mappi_irq(M32R_IRQ_MFT2);
+
+#ifdef CONFIG_SERIAL_M32R_SIO
+       /* SIO0_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].action = 0;
+       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO0_R);
+
+       /* SIO0_S : uart send data */
+       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].action = 0;
+       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO0_S);
+
+       /* SIO1_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].action = 0;
+       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO1_R);
+
+       /* SIO1_S : uart send data */
+       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].action = 0;
+       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO1_S);
+#endif /* CONFIG_SERIAL_M32R_SIO */
+
+#if defined(CONFIG_M32RPCC)
+       /* INT1 : pccard0 interrupt */
+       irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT1].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT1].action = 0;
+       irq_desc[M32R_IRQ_INT1].depth = 1;
+       icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
+       disable_mappi_irq(M32R_IRQ_INT1);
+
+       /* INT2 : pccard1 interrupt */
+       irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_INT2].action = 0;
+       irq_desc[M32R_IRQ_INT2].depth = 1;
+       icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
+       disable_mappi_irq(M32R_IRQ_INT2);
+#endif /* CONFIG_M32RPCC */
+}
diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c
new file mode 100644 (file)
index 0000000..92eb06e
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ *  linux/arch/m32r/kernel/setup_mappi.c
+ *
+ *  Setup routines for Renesas MAPPI-II(M3A-ZA36) Board
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#ifndef CONFIG_SMP
+typedef struct {
+       unsigned long icucr;  /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+icu_data_t icu_data[NR_IRQS];
+
+static void disable_mappi2_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       if ((irq == 0) ||(irq >= NR_IRQS))  {
+               printk("bad irq 0x%08x\n", irq);
+               return;
+       }
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+       outl(data, port);
+}
+
+static void enable_mappi2_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       if ((irq == 0) ||(irq >= NR_IRQS))  {
+               printk("bad irq 0x%08x\n", irq);
+               return;
+       }
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+       outl(data, port);
+}
+
+static void mask_and_ack_mappi2(unsigned int irq)
+{
+       disable_mappi2_irq(irq);
+}
+
+static void end_mappi2_irq(unsigned int irq)
+{
+       enable_mappi2_irq(irq);
+}
+
+static unsigned int startup_mappi2_irq(unsigned int irq)
+{
+       enable_mappi2_irq(irq);
+       return (0);
+}
+
+static void shutdown_mappi2_irq(unsigned int irq)
+{
+       unsigned long port;
+
+       port = irq2port(irq);
+       outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type mappi2_irq_type =
+{
+       "MAPPI2-IRQ",
+       startup_mappi2_irq,
+       shutdown_mappi2_irq,
+       enable_mappi2_irq,
+       disable_mappi2_irq,
+       mask_and_ack_mappi2,
+       end_mappi2_irq
+};
+
+void __init init_IRQ(void)
+{
+#if defined(CONFIG_SMC91X)
+       /* INT0 : LAN controller (SMC91111) */
+       irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT0].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_INT0].action = 0;
+       irq_desc[M32R_IRQ_INT0].depth = 1;
+       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+       disable_mappi2_irq(M32R_IRQ_INT0);
+#endif  /* CONFIG_SMC91X */
+
+       /* MFT2 : system timer */
+       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_MFT2].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_MFT2].action = 0;
+       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+       disable_mappi2_irq(M32R_IRQ_MFT2);
+
+#ifdef CONFIG_SERIAL_M32R_SIO
+       /* SIO0_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].action = 0;
+       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+       disable_mappi2_irq(M32R_IRQ_SIO0_R);
+
+       /* SIO0_S : uart send data */
+       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].action = 0;
+       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+       disable_mappi2_irq(M32R_IRQ_SIO0_S);
+       /* SIO1_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].action = 0;
+       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+       disable_mappi2_irq(M32R_IRQ_SIO1_R);
+
+       /* SIO1_S : uart send data */
+       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].action = 0;
+       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+       disable_mappi2_irq(M32R_IRQ_SIO1_S);
+#endif  /* CONFIG_M32R_USE_DBG_CONSOLE */
+
+#if defined(CONFIG_USB)
+       /* INT1 : USB Host controller interrupt */
+       irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT1].handler = &mappi2_irq_type;
+       irq_desc[M32R_IRQ_INT1].action = 0;
+       irq_desc[M32R_IRQ_INT1].depth = 1;
+       icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
+       disable_mappi2_irq(M32R_IRQ_INT1);
+#endif /* CONFIG_USB */
+
+#if defined(CONFIG_M32R_CFC)
+       /* ICUCR40: CFC IREQ */
+       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFIREQ].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].action = 0;
+       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+//     icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
+       icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
+       disable_mappi2_irq(PLD_IRQ_CFIREQ);
+
+       /* ICUCR41: CFC Insert */
+       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFC_INSERT].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
+       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
+//     icu_data[PLD_IRQ_CFC_INSERT].icucr = 0;
+       disable_mappi2_irq(PLD_IRQ_CFC_INSERT);
+
+       /* ICUCR42: CFC Eject */
+       irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFC_EJECT].handler = &mappi2_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
+       irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
+       icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+//     icu_data[PLD_IRQ_CFC_EJECT].icucr = 0;
+       disable_mappi2_irq(PLD_IRQ_CFC_EJECT);
+
+#endif /* CONFIG_MAPPI2_CFC */
+}
+
+#define LAN_IOSTART     0x300
+#define LAN_IOEND       0x320
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .start  = (LAN_IOSTART),
+               .end    = (LAN_IOEND),
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = M32R_IRQ_INT0,
+               .end    = M32R_IRQ_INT0,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
+};
+
+static int __init platform_init(void)
+{
+       platform_device_register(&smc91x_device);
+       return 0;
+}
+arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c
new file mode 100644 (file)
index 0000000..b048345
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *  linux/arch/m32r/kernel/setup_oaks32r.c
+ *
+ *  Setup routines for OAKS32R Board
+ *
+ *  Copyright (c) 2002-2004   Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto, Mamoru Sakugawa
+ */
+
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#ifndef CONFIG_SMP
+typedef struct {
+       unsigned long icucr;  /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+icu_data_t icu_data[NR_IRQS];
+
+static void disable_oaks32r_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+       outl(data, port);
+}
+
+static void enable_oaks32r_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+       outl(data, port);
+}
+
+static void mask_and_ack_mappi(unsigned int irq)
+{
+       disable_oaks32r_irq(irq);
+}
+
+static void end_oaks32r_irq(unsigned int irq)
+{
+       enable_oaks32r_irq(irq);
+}
+
+static unsigned int startup_oaks32r_irq(unsigned int irq)
+{
+       enable_oaks32r_irq(irq);
+       return (0);
+}
+
+static void shutdown_oaks32r_irq(unsigned int irq)
+{
+       unsigned long port;
+
+       port = irq2port(irq);
+       outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type oaks32r_irq_type =
+{
+       "OAKS32R-IRQ",
+       startup_oaks32r_irq,
+       shutdown_oaks32r_irq,
+       enable_oaks32r_irq,
+       disable_oaks32r_irq,
+       mask_and_ack_mappi,
+       end_oaks32r_irq
+};
+
+void __init init_IRQ(void)
+{
+       static int once = 0;
+
+       if (once)
+               return;
+       else
+               once++;
+
+#ifdef CONFIG_NE2000
+       /* INT3 : LAN controller (RTL8019AS) */
+       irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT3].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_INT3].action = 0;
+       irq_desc[M32R_IRQ_INT3].depth = 1;
+       icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+       disable_oaks32r_irq(M32R_IRQ_INT3);
+#endif /* CONFIG_M32R_NE2000 */
+
+       /* MFT2 : system timer */
+       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_MFT2].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_MFT2].action = 0;
+       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+       disable_oaks32r_irq(M32R_IRQ_MFT2);
+
+#ifdef CONFIG_SERIAL_M32R_SIO
+       /* SIO0_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_R].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].action = 0;
+       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+       disable_oaks32r_irq(M32R_IRQ_SIO0_R);
+
+       /* SIO0_S : uart send data */
+       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_S].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].action = 0;
+       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+       disable_oaks32r_irq(M32R_IRQ_SIO0_S);
+
+       /* SIO1_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_R].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].action = 0;
+       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+       disable_oaks32r_irq(M32R_IRQ_SIO1_R);
+
+       /* SIO1_S : uart send data */
+       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_S].handler = &oaks32r_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].action = 0;
+       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+       disable_oaks32r_irq(M32R_IRQ_SIO1_S);
+#endif /* CONFIG_SERIAL_M32R_SIO */
+
+}
diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c
new file mode 100644 (file)
index 0000000..17a4d3e
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ *  linux/arch/m32r/kernel/setup_opsput.c
+ *
+ *  Setup routines for Renesas OPSPUT Board
+ *
+ *  Copyright (c) 2002-2004
+ *     Hiroyuki Kondo, Hirokazu Takata,
+ *      Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa
+ *
+ *  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/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+/*
+ * OPSP Interrupt Control Unit (Level 1)
+ */
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#ifndef CONFIG_SMP
+typedef struct {
+       unsigned long icucr;  /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+static icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ];
+
+static void disable_opsput_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+       outl(data, port);
+}
+
+static void enable_opsput_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+       outl(data, port);
+}
+
+static void mask_and_ack_opsput(unsigned int irq)
+{
+       disable_opsput_irq(irq);
+}
+
+static void end_opsput_irq(unsigned int irq)
+{
+       enable_opsput_irq(irq);
+}
+
+static unsigned int startup_opsput_irq(unsigned int irq)
+{
+       enable_opsput_irq(irq);
+       return (0);
+}
+
+static void shutdown_opsput_irq(unsigned int irq)
+{
+       unsigned long port;
+
+       port = irq2port(irq);
+       outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type opsput_irq_type =
+{
+       "OPSPUT-IRQ",
+       startup_opsput_irq,
+       shutdown_opsput_irq,
+       enable_opsput_irq,
+       disable_opsput_irq,
+       mask_and_ack_opsput,
+       end_opsput_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on OPSPUT (Level 2)
+ */
+#define irq2pldirq(x)          ((x) - OPSPUT_PLD_IRQ_BASE)
+#define pldirq2port(x)         (unsigned long)((int)PLD_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+typedef struct {
+       unsigned short icucr;  /* ICU Control Register */
+} pld_icu_data_t;
+
+static pld_icu_data_t pld_icu_data[OPSPUT_NUM_PLD_IRQ];
+
+static void disable_opsput_pld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+//     disable_opsput_irq(M32R_IRQ_INT1);
+       port = pldirq2port(pldirq);
+       data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_opsput_pld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+//     enable_opsput_irq(M32R_IRQ_INT1);
+       port = pldirq2port(pldirq);
+       data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_opsput_pld(unsigned int irq)
+{
+       disable_opsput_pld_irq(irq);
+//     mask_and_ack_opsput(M32R_IRQ_INT1);
+}
+
+static void end_opsput_pld_irq(unsigned int irq)
+{
+       enable_opsput_pld_irq(irq);
+       end_opsput_irq(M32R_IRQ_INT1);
+}
+
+static unsigned int startup_opsput_pld_irq(unsigned int irq)
+{
+       enable_opsput_pld_irq(irq);
+       return (0);
+}
+
+static void shutdown_opsput_pld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+//     shutdown_opsput_irq(M32R_IRQ_INT1);
+       port = pldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type opsput_pld_irq_type =
+{
+       "OPSPUT-PLD-IRQ",
+       startup_opsput_pld_irq,
+       shutdown_opsput_pld_irq,
+       enable_opsput_pld_irq,
+       disable_opsput_pld_irq,
+       mask_and_ack_opsput_pld,
+       end_opsput_pld_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on OPSPUT-LAN (Level 2)
+ */
+#define irq2lanpldirq(x)       ((x) - OPSPUT_LAN_PLD_IRQ_BASE)
+#define lanpldirq2port(x)      (unsigned long)((int)OPSPUT_LAN_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+static pld_icu_data_t lanpld_icu_data[OPSPUT_NUM_LAN_PLD_IRQ];
+
+static void disable_opsput_lanpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lanpldirq(irq);
+       port = lanpldirq2port(pldirq);
+       data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_opsput_lanpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lanpldirq(irq);
+       port = lanpldirq2port(pldirq);
+       data = lanpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_opsput_lanpld(unsigned int irq)
+{
+       disable_opsput_lanpld_irq(irq);
+}
+
+static void end_opsput_lanpld_irq(unsigned int irq)
+{
+       enable_opsput_lanpld_irq(irq);
+       end_opsput_irq(M32R_IRQ_INT0);
+}
+
+static unsigned int startup_opsput_lanpld_irq(unsigned int irq)
+{
+       enable_opsput_lanpld_irq(irq);
+       return (0);
+}
+
+static void shutdown_opsput_lanpld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2lanpldirq(irq);
+       port = lanpldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type opsput_lanpld_irq_type =
+{
+       "OPSPUT-PLD-LAN-IRQ",
+       startup_opsput_lanpld_irq,
+       shutdown_opsput_lanpld_irq,
+       enable_opsput_lanpld_irq,
+       disable_opsput_lanpld_irq,
+       mask_and_ack_opsput_lanpld,
+       end_opsput_lanpld_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on OPSPUT-LCD (Level 2)
+ */
+#define irq2lcdpldirq(x)       ((x) - OPSPUT_LCD_PLD_IRQ_BASE)
+#define lcdpldirq2port(x)      (unsigned long)((int)OPSPUT_LCD_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+static pld_icu_data_t lcdpld_icu_data[OPSPUT_NUM_LCD_PLD_IRQ];
+
+static void disable_opsput_lcdpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lcdpldirq(irq);
+       port = lcdpldirq2port(pldirq);
+       data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_opsput_lcdpld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2lcdpldirq(irq);
+       port = lcdpldirq2port(pldirq);
+       data = lcdpld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_opsput_lcdpld(unsigned int irq)
+{
+       disable_opsput_lcdpld_irq(irq);
+}
+
+static void end_opsput_lcdpld_irq(unsigned int irq)
+{
+       enable_opsput_lcdpld_irq(irq);
+       end_opsput_irq(M32R_IRQ_INT2);
+}
+
+static unsigned int startup_opsput_lcdpld_irq(unsigned int irq)
+{
+       enable_opsput_lcdpld_irq(irq);
+       return (0);
+}
+
+static void shutdown_opsput_lcdpld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2lcdpldirq(irq);
+       port = lcdpldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type opsput_lcdpld_irq_type =
+{
+       "OPSPUT-PLD-LCD-IRQ",
+       startup_opsput_lcdpld_irq,
+       shutdown_opsput_lcdpld_irq,
+       enable_opsput_lcdpld_irq,
+       disable_opsput_lcdpld_irq,
+       mask_and_ack_opsput_lcdpld,
+       end_opsput_lcdpld_irq
+};
+
+void __init init_IRQ(void)
+{
+#if defined(CONFIG_SMC91X)
+       /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/
+       irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED;
+       irq_desc[OPSPUT_LAN_IRQ_LAN].handler = &opsput_lanpld_irq_type;
+       irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0;
+       irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */
+       lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;     /* "H" edge sense */
+       disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN);
+#endif  /* CONFIG_SMC91X */
+
+       /* MFT2 : system timer */
+       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_MFT2].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_MFT2].action = 0;
+       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+       disable_opsput_irq(M32R_IRQ_MFT2);
+
+       /* SIO0 : receive */
+       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_R].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].action = 0;
+       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+       disable_opsput_irq(M32R_IRQ_SIO0_R);
+
+       /* SIO0 : send */
+       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_S].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].action = 0;
+       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+       disable_opsput_irq(M32R_IRQ_SIO0_S);
+
+       /* SIO1 : receive */
+       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_R].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].action = 0;
+       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+       disable_opsput_irq(M32R_IRQ_SIO1_R);
+
+       /* SIO1 : send */
+       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_S].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].action = 0;
+       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+       disable_opsput_irq(M32R_IRQ_SIO1_S);
+
+       /* DMA1 : */
+       irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_DMA1].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_DMA1].action = 0;
+       irq_desc[M32R_IRQ_DMA1].depth = 1;
+       icu_data[M32R_IRQ_DMA1].icucr = 0;
+       disable_opsput_irq(M32R_IRQ_DMA1);
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       /* INT#1: SIO0 Receive on PLD */
+       irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_SIO0_RCV].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
+       irq_desc[PLD_IRQ_SIO0_RCV].depth = 1;   /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
+       disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV);
+
+       /* INT#1: SIO0 Send on PLD */
+       irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_SIO0_SND].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_SIO0_SND].action = 0;
+       irq_desc[PLD_IRQ_SIO0_SND].depth = 1;   /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
+       disable_opsput_pld_irq(PLD_IRQ_SIO0_SND);
+#endif  /* CONFIG_SERIAL_M32R_PLDSIO */
+
+#if defined(CONFIG_M32R_CFC)
+       /* INT#1: CFC IREQ on PLD */
+       irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFIREQ].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFIREQ].action = 0;
+       irq_desc[PLD_IRQ_CFIREQ].depth = 1;     /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
+       disable_opsput_pld_irq(PLD_IRQ_CFIREQ);
+
+       /* INT#1: CFC Insert on PLD */
+       irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFC_INSERT].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
+       irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
+       disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT);
+
+       /* INT#1: CFC Eject on PLD */
+       irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_CFC_EJECT].handler = &opsput_pld_irq_type;
+       irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
+       irq_desc[PLD_IRQ_CFC_EJECT].depth = 1;  /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
+       disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT);
+#endif /* CONFIG_M32R_CFC */
+
+
+       /*
+        * INT0# is used for LAN, DIO
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
+       enable_opsput_irq(M32R_IRQ_INT0);
+
+       /*
+        * INT1# is used for UART, MMC, CF Controller in FPGA.
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
+       enable_opsput_irq(M32R_IRQ_INT1);
+
+#if defined(CONFIG_USB)
+       outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
+
+    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
+    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].handler = &opsput_lcdpld_irq_type;
+    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0;
+    irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1;
+    lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;   /* "L" level sense */
+    disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1);
+#endif
+       /*
+        * INT2# is used for BAT, USB, AUDIO
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
+       enable_opsput_irq(M32R_IRQ_INT2);
+
+//#if defined(CONFIG_M32R_AR_VGA)
+       /*
+        * INT3# is used for AR
+        */
+       irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_INT3].handler = &opsput_irq_type;
+       irq_desc[M32R_IRQ_INT3].action = 0;
+       irq_desc[M32R_IRQ_INT3].depth = 1;
+       icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+       disable_opsput_irq(M32R_IRQ_INT3);
+//#endif       /* CONFIG_M32R_ARV */
+}
+
+#define LAN_IOSTART     0x300
+#define LAN_IOEND       0x320
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .start  = (LAN_IOSTART),
+               .end    = (LAN_IOEND),
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = OPSPUT_LAN_IRQ_LAN,
+               .end    = OPSPUT_LAN_IRQ_LAN,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
+};
+
+static int __init platform_init(void)
+{
+       platform_device_register(&smc91x_device);
+       return 0;
+}
+arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_usrv.c b/arch/m32r/kernel/setup_usrv.c
new file mode 100644 (file)
index 0000000..fe417be
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *  linux/arch/m32r/kernel/setup_usrv.c
+ *
+ *  Setup routines for MITSUBISHI uServer
+ *
+ *  Copyright (c) 2001, 2002, 2003  Hiroyuki Kondo, Hirokazu Takata,
+ *                                  Hitoshi Yamamoto
+ */
+
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+
+#define irq2port(x) (M32R_ICU_CR1_PORTL + ((x - 1) * sizeof(unsigned long)))
+
+#if !defined(CONFIG_SMP)
+typedef struct {
+       unsigned long icucr;    /* ICU Control Register */
+} icu_data_t;
+#endif /* CONFIG_SMP */
+
+icu_data_t icu_data[M32700UT_NUM_CPU_IRQ];
+
+static void disable_mappi_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_ILEVEL7;
+       outl(data, port);
+}
+
+static void enable_mappi_irq(unsigned int irq)
+{
+       unsigned long port, data;
+
+       port = irq2port(irq);
+       data = icu_data[irq].icucr|M32R_ICUCR_IEN|M32R_ICUCR_ILEVEL6;
+       outl(data, port);
+}
+
+static void mask_and_ack_mappi(unsigned int irq)
+{
+       disable_mappi_irq(irq);
+}
+
+static void end_mappi_irq(unsigned int irq)
+{
+       enable_mappi_irq(irq);
+}
+
+static unsigned int startup_mappi_irq(unsigned int irq)
+{
+       enable_mappi_irq(irq);
+       return 0;
+}
+
+static void shutdown_mappi_irq(unsigned int irq)
+{
+       unsigned long port;
+
+       port = irq2port(irq);
+       outl(M32R_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type mappi_irq_type =
+{
+       "M32700-IRQ",
+       startup_mappi_irq,
+       shutdown_mappi_irq,
+       enable_mappi_irq,
+       disable_mappi_irq,
+       mask_and_ack_mappi,
+       end_mappi_irq
+};
+
+/*
+ * Interrupt Control Unit of PLD on M32700UT (Level 2)
+ */
+#define irq2pldirq(x)          ((x) - M32700UT_PLD_IRQ_BASE)
+#define pldirq2port(x)         (unsigned long)((int)PLD_ICUCR1 + \
+                                (((x) - 1) * sizeof(unsigned short)))
+
+typedef struct {
+       unsigned short icucr;  /* ICU Control Register */
+} pld_icu_data_t;
+
+static pld_icu_data_t pld_icu_data[M32700UT_NUM_PLD_IRQ];
+
+static void disable_m32700ut_pld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+       port = pldirq2port(pldirq);
+       data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
+       outw(data, port);
+}
+
+static void enable_m32700ut_pld_irq(unsigned int irq)
+{
+       unsigned long port, data;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+       port = pldirq2port(pldirq);
+       data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
+       outw(data, port);
+}
+
+static void mask_and_ack_m32700ut_pld(unsigned int irq)
+{
+       disable_m32700ut_pld_irq(irq);
+}
+
+static void end_m32700ut_pld_irq(unsigned int irq)
+{
+       enable_m32700ut_pld_irq(irq);
+       end_mappi_irq(M32R_IRQ_INT1);
+}
+
+static unsigned int startup_m32700ut_pld_irq(unsigned int irq)
+{
+       enable_m32700ut_pld_irq(irq);
+       return 0;
+}
+
+static void shutdown_m32700ut_pld_irq(unsigned int irq)
+{
+       unsigned long port;
+       unsigned int pldirq;
+
+       pldirq = irq2pldirq(irq);
+       port = pldirq2port(pldirq);
+       outw(PLD_ICUCR_ILEVEL7, port);
+}
+
+static struct hw_interrupt_type m32700ut_pld_irq_type =
+{
+       "USRV-PLD-IRQ",
+       startup_m32700ut_pld_irq,
+       shutdown_m32700ut_pld_irq,
+       enable_m32700ut_pld_irq,
+       disable_m32700ut_pld_irq,
+       mask_and_ack_m32700ut_pld,
+       end_m32700ut_pld_irq
+};
+
+void __init init_IRQ(void)
+{
+       static int once = 0;
+       int i;
+
+       if (once)
+               return;
+       else
+               once++;
+
+       /* MFT2 : system timer */
+       irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_MFT2].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_MFT2].action = 0;
+       irq_desc[M32R_IRQ_MFT2].depth = 1;
+       icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
+       disable_mappi_irq(M32R_IRQ_MFT2);
+
+#if defined(CONFIG_SERIAL_M32R_SIO)
+       /* SIO0_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_R].action = 0;
+       irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+       icu_data[M32R_IRQ_SIO0_R].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO0_R);
+
+       /* SIO0_S : uart send data */
+       irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO0_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO0_S].action = 0;
+       irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+       icu_data[M32R_IRQ_SIO0_S].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO0_S);
+
+       /* SIO1_R : uart receive data */
+       irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_R].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_R].action = 0;
+       irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+       icu_data[M32R_IRQ_SIO1_R].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO1_R);
+
+       /* SIO1_S : uart send data */
+       irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
+       irq_desc[M32R_IRQ_SIO1_S].handler = &mappi_irq_type;
+       irq_desc[M32R_IRQ_SIO1_S].action = 0;
+       irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+       icu_data[M32R_IRQ_SIO1_S].icucr = 0;
+       disable_mappi_irq(M32R_IRQ_SIO1_S);
+#endif  /* CONFIG_SERIAL_M32R_SIO */
+
+       /* INT#67-#71: CFC#0 IREQ on PLD */
+       for (i = 0 ; i < CONFIG_CFC_NUM ; i++ ) {
+               irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED;
+               irq_desc[PLD_IRQ_CF0 + i].handler = &m32700ut_pld_irq_type;
+               irq_desc[PLD_IRQ_CF0 + i].action = 0;
+               irq_desc[PLD_IRQ_CF0 + i].depth = 1;    /* disable nested irq */
+               pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr
+                       = PLD_ICUCR_ISMOD01;    /* 'L' level sense */
+               disable_m32700ut_pld_irq(PLD_IRQ_CF0 + i);
+       }
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+       /* INT#76: 16552D#0 IREQ on PLD */
+       irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_UART0].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_UART0].action = 0;
+       irq_desc[PLD_IRQ_UART0].depth = 1;      /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr
+               = PLD_ICUCR_ISMOD03;    /* 'H' level sense */
+       disable_m32700ut_pld_irq(PLD_IRQ_UART0);
+
+       /* INT#77: 16552D#1 IREQ on PLD */
+       irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_UART1].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_UART1].action = 0;
+       irq_desc[PLD_IRQ_UART1].depth = 1;      /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr
+               = PLD_ICUCR_ISMOD03;    /* 'H' level sense */
+       disable_m32700ut_pld_irq(PLD_IRQ_UART1);
+#endif /* CONFIG_SERIAL_8250 || CONFIG_SERIAL_8250_MODULE */
+
+#if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE)
+       /* INT#80: AK4524 IREQ on PLD */
+       irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED;
+       irq_desc[PLD_IRQ_SNDINT].handler = &m32700ut_pld_irq_type;
+       irq_desc[PLD_IRQ_SNDINT].action = 0;
+       irq_desc[PLD_IRQ_SNDINT].depth = 1;     /* disable nested irq */
+       pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr
+               = PLD_ICUCR_ISMOD01;    /* 'L' level sense */
+       disable_m32700ut_pld_irq(PLD_IRQ_SNDINT);
+#endif /* CONFIG_IDC_AK4524 || CONFIG_IDC_AK4524_MODULE */
+
+       /*
+        * INT1# is used for UART, MMC, CF Controller in FPGA.
+        * We enable it here.
+        */
+       icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD11;
+       enable_mappi_irq(M32R_IRQ_INT1);
+}
+
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
new file mode 100644 (file)
index 0000000..cbfa674
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ *  linux/arch/m32r/kernel/signal.c
+ *
+ *  Copyright (c) 2003  Hitoshi Yamamoto
+ *
+ *  Taken from i386 version.
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
+ */
+
+#include <linux/config.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/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <linux/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+int do_signal(struct pt_regs *, sigset_t *);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(old_sigset_t mask, unsigned long r1,
+              unsigned long r2, unsigned long r3, unsigned long r4,
+              unsigned long r5, unsigned long r6, struct pt_regs regs)
+{
+       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.r0 = -EINTR;
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+               if (do_signal(&regs, &saveset))
+                       return regs.r0;
+       }
+}
+
+asmlinkage int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+                 unsigned long r2, unsigned long r3, unsigned long r4,
+                 unsigned long r5, unsigned long r6, struct pt_regs regs)
+{
+       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.r0 = -EINTR;
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+               if (do_signal(&regs, &saveset))
+                       return regs.r0;
+       }
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+             struct old_sigaction __user *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(const stack_t __user *uss, stack_t __user *uoss,
+               unsigned long r2, unsigned long r3, unsigned long r4,
+               unsigned long r5, unsigned long r6, struct pt_regs regs)
+{
+       return do_sigaltstack(uss, uoss, regs.spu);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+//     char *pretcode;
+       int sig;
+       struct sigcontext sc;
+//     struct _fpstate fpstate;
+       unsigned long extramask[_NSIG_WORDS-1];
+       char retcode[4];
+};
+
+struct rt_sigframe
+{
+//     char *pretcode;
+       int sig;
+       struct siginfo *pinfo;
+       void *puc;
+       struct siginfo info;
+       struct ucontext uc;
+//     struct _fpstate fpstate;
+       char retcode[8];
+};
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
+                  int *r0_p)
+{
+       unsigned int err = 0;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+#define COPY(x)                err |= __get_user(regs->x, &sc->sc_##x)
+       COPY(r4);
+       COPY(r5);
+       COPY(r6);
+       COPY(pt_regs);
+       /* COPY(r0); Skip r0 */
+       COPY(r1);
+       COPY(r2);
+       COPY(r3);
+       COPY(r7);
+       COPY(r8);
+       COPY(r9);
+       COPY(r10);
+       COPY(r11);
+       COPY(r12);
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       COPY(acc0h);
+       COPY(acc0l);
+       COPY(acc1h);
+       COPY(acc1l);
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       COPY(acch);
+       COPY(accl);
+#else
+#error unknown isa configuration
+#endif
+       COPY(psw);
+       COPY(bpc);
+       COPY(bbpsw);
+       COPY(bbpc);
+       COPY(spu);
+       COPY(fp);
+       COPY(lr);
+       COPY(spi);
+#undef COPY
+
+       regs->syscall_nr = -1;  /* disable syscall checks */
+       err |= __get_user(*r0_p, &sc->sc_r0);
+
+       return err;
+}
+
+asmlinkage int
+sys_sigreturn(unsigned long r0, unsigned long r1,
+             unsigned long r2, unsigned long r3, unsigned long r4,
+             unsigned long r5, unsigned long r6, struct pt_regs regs)
+{
+       struct sigframe __user *frame = (struct sigframe __user *)regs.spu;
+       sigset_t set;
+       int result;
+
+       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, &result))
+               goto badframe;
+       return result;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+asmlinkage int
+sys_rt_sigreturn(unsigned long r0, unsigned long r1,
+                unsigned long r2, unsigned long r3, unsigned long r4,
+                unsigned long r5, unsigned long r6, struct pt_regs regs)
+{
+       struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.spu;
+       sigset_t set;
+       stack_t st;
+       int result;
+
+       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, &result))
+               goto badframe;
+
+       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.spu);
+
+       return result;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+                unsigned long mask)
+{
+       int err = 0;
+
+#define COPY(x)        err |= __put_user(regs->x, &sc->sc_##x)
+       COPY(r4);
+       COPY(r5);
+       COPY(r6);
+       COPY(pt_regs);
+       COPY(r0);
+       COPY(r1);
+       COPY(r2);
+       COPY(r3);
+       COPY(r7);
+       COPY(r8);
+       COPY(r9);
+       COPY(r10);
+       COPY(r11);
+       COPY(r12);
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       COPY(acc0h);
+       COPY(acc0l);
+       COPY(acc1h);
+       COPY(acc1l);
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       COPY(acch);
+       COPY(accl);
+#else
+#error unknown isa configuration
+#endif
+       COPY(psw);
+       COPY(bpc);
+       COPY(bbpsw);
+       COPY(bbpc);
+       COPY(spu);
+       COPY(fp);
+       COPY(lr);
+       COPY(spi);
+#undef COPY
+
+       err |= __put_user(mask, &sc->oldmask);
+
+       return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+       /* This is the X/Open sanctioned signal stack switching.  */
+       if (ka->sa.sa_flags & SA_ONSTACK) {
+               if (sas_ss_flags(sp) == 0)
+                       sp = current->sas_ss_sp + current->sas_ss_size;
+       }
+
+       return (void __user *)((sp - frame_size) & -8ul);
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+                       sigset_t *set, struct pt_regs *regs)
+{
+       struct sigframe __user *frame;
+       int err = 0;
+       int signal;
+
+       frame = get_sigframe(ka, regs->spu, sizeof(*frame));
+
+       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 |= __put_user(signal, &frame->sig);
+       if (err)
+               goto give_sigsegv;
+
+       err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+       if (err)
+               goto give_sigsegv;
+
+       if (_NSIG_WORDS > 1) {
+               err |= __copy_to_user(frame->extramask, &set->sig[1],
+                                     sizeof(frame->extramask));
+               if (err)
+                       goto give_sigsegv;
+       }
+
+       if (ka->sa.sa_flags & SA_RESTORER)
+               regs->lr = (unsigned long)ka->sa.sa_restorer;
+       else {
+               /* This is : ldi r7, #__NR_sigreturn ; trap #2 */
+               unsigned long code = 0x670010f2 | (__NR_sigreturn << 16);
+
+               regs->lr = (unsigned long)frame->retcode;
+               err |= __put_user(code, (long __user *)(frame->retcode+0));
+               if (err)
+                       goto give_sigsegv;
+               flush_cache_sigtramp((unsigned long)frame->retcode);
+       }
+
+       /* Set up registers for signal handler */
+       regs->spu = (unsigned long)frame;
+       regs->r0 = signal;      /* Arg for signal handler */
+       regs->r1 = (unsigned long)&frame->sc;
+       regs->bpc = (unsigned long)ka->sa.sa_handler;
+
+       set_fs(USER_DS);
+
+#if DEBUG_SIG
+       printk("SIG deliver (%s:%d): sp=%p pc=%p\n",
+               current->comm, current->pid, frame, regs->pc);
+#endif
+
+       return;
+
+give_sigsegv:
+       force_sigsegv(sig, 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 __user *frame;
+       int err = 0;
+       int signal;
+
+       frame = get_sigframe(ka, regs->spu, sizeof(*frame));
+
+       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 |= __put_user(signal, &frame->sig);
+       if (err)
+               goto give_sigsegv;
+
+       err |= __put_user(&frame->info, &frame->pinfo);
+       err |= __put_user(&frame->uc, &frame->puc);
+       err |= copy_siginfo_to_user(&frame->info, info);
+       if (err)
+               goto give_sigsegv;
+
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->uc.uc_flags);
+       err |= __put_user(0, &frame->uc.uc_link);
+       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->spu),
+                         &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, regs, set->sig[0]);
+       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+       if (err)
+               goto give_sigsegv;
+
+       /* Set up to return from userspace.  */
+       if (ka->sa.sa_flags & SA_RESTORER)
+               regs->lr = (unsigned long)ka->sa.sa_restorer;
+       else {
+               /* This is : ldi r7, #__NR_rt_sigreturn ; trap #2 */
+               unsigned long code1 = 0x97f00000 | (__NR_rt_sigreturn);
+               unsigned long code2 = 0x10f2f000;
+
+               regs->lr = (unsigned long)frame->retcode;
+               err |= __put_user(code1, (long __user *)(frame->retcode+0));
+               err |= __put_user(code2, (long __user *)(frame->retcode+4));
+               if (err)
+                       goto give_sigsegv;
+               flush_cache_sigtramp((unsigned long)frame->retcode);
+       }
+
+       /* Set up registers for signal handler */
+       regs->spu = (unsigned long)frame;
+       regs->r0 = signal;      /* Arg for signal handler */
+       regs->r1 = (unsigned long)&frame->info;
+       regs->r2 = (unsigned long)&frame->uc;
+       regs->bpc = (unsigned long)ka->sa.sa_handler;
+
+       set_fs(USER_DS);
+
+#if DEBUG_SIG
+       printk("SIG deliver (%s:%d): sp=%p pc=%p\n",
+               current->comm, current->pid, frame, regs->pc);
+#endif
+
+       return;
+
+give_sigsegv:
+       force_sigsegv(sig, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
+             sigset_t *oldset, struct pt_regs *regs)
+{
+       unsigned short inst;
+
+       /* Are we from a system call? */
+       if (regs->syscall_nr >= 0) {
+               /* If so, check system call restarting.. */
+               switch (regs->r0) {
+                       case -ERESTART_RESTARTBLOCK:
+                       case -ERESTARTNOHAND:
+                               regs->r0 = -EINTR;
+                               break;
+
+                       case -ERESTARTSYS:
+                               if (!(ka->sa.sa_flags & SA_RESTART)) {
+                                       regs->r0 = -EINTR;
+                                       break;
+                               }
+                       /* fallthrough */
+                       case -ERESTARTNOINTR:
+                               regs->r0 = regs->orig_r0;
+                               inst = *(unsigned short *)(regs->bpc - 2);
+                               if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
+                                       regs->bpc -= 2;
+                               else
+                                       regs->bpc -= 4;
+               }
+       }
+
+       /* Set up the stack frame */
+       if (ka->sa.sa_flags & SA_SIGINFO)
+               setup_rt_frame(sig, ka, info, oldset, regs);
+       else
+               setup_frame(sig, ka, oldset, regs);
+
+       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,sig);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+}
+
+/*
+ * 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.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+       siginfo_t info;
+       int signr;
+       struct k_sigaction ka;
+       unsigned short inst;
+
+       /*
+        * We want the common case to go fast, which
+        * is why we may in certain cases get here from
+        * kernel mode. Just return without doing anything
+        * if so.
+        */
+       if (!user_mode(regs))
+               return 1;
+
+       if (current->flags & PF_FREEZE) {
+               refrigerator(0);
+               goto no_signal;
+       }
+
+       if (!oldset)
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
+               /* Reenable any watchpoints before delivering the
+                * signal to user space. The processor register will
+                * have been cleared if the watchpoint triggered
+                * inside the kernel.
+                */
+
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &ka, &info, oldset, regs);
+               return 1;
+       }
+
+ no_signal:
+       /* Did we come from a system call? */
+       if (regs->syscall_nr >= 0) {
+               /* Restart the system call - no handlers present */
+               if (regs->r0 == -ERESTARTNOHAND ||
+                   regs->r0 == -ERESTARTSYS ||
+                   regs->r0 == -ERESTARTNOINTR) {
+                       regs->r0 = regs->orig_r0;
+                       inst = *(unsigned short *)(regs->bpc - 2);
+                       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
+                               regs->bpc -= 2;
+                       else
+                               regs->bpc -= 4;
+               }
+               if (regs->r0 == -ERESTART_RESTARTBLOCK){
+                       regs->r0 = regs->orig_r0;
+                       regs->r7 = __NR_restart_syscall;
+                       inst = *(unsigned short *)(regs->bpc - 2);
+                       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
+                               regs->bpc -= 2;
+                       else
+                               regs->bpc -= 4;
+               }
+       }
+       return 0;
+}
+
+/*
+ * notification of userspace execution resumption
+ * - triggered by current->work.notify_resume
+ */
+void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+                     __u32 thread_info_flags)
+{
+       /* Pending single-step? */
+       if (thread_info_flags & _TIF_SINGLESTEP)
+               clear_thread_flag(TIF_SINGLESTEP);
+
+       /* deal with pending signal delivery */
+       if (thread_info_flags & _TIF_SIGPENDING)
+               do_signal(regs,oldset);
+
+       clear_thread_flag(TIF_IRET);
+}
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
new file mode 100644 (file)
index 0000000..2dc542e
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ *  linux/arch/m32r/kernel/smp.c
+ *
+ *  M32R SMP support routines.
+ *
+ *  Copyright (c) 2001, 2002  Hitoshi Yamamoto
+ *
+ *  Taken from i386 version.
+ *    (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *    (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ *  This code is released under the GNU General Public License version 2 or
+ *  later.
+ */
+
+#undef DEBUG_SMP
+
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/profile.h>
+#include <linux/cpu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgalloc.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/m32r.h>
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Data structures and variables                                             */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+
+struct call_data_struct {
+       void (*func) (void *info);
+       void *info;
+       atomic_t started;
+       atomic_t finished;
+       int wait;
+} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+
+static struct call_data_struct *call_data;
+
+/*
+ * For flush_cache_all()
+ */
+static spinlock_t flushcache_lock = SPIN_LOCK_UNLOCKED;
+static volatile unsigned long flushcache_cpumask = 0;
+
+/*
+ * For flush_tlb_others()
+ */
+static volatile cpumask_t flush_cpumask;
+static struct mm_struct *flush_mm;
+static struct vm_area_struct *flush_vma;
+static volatile unsigned long flush_va;
+static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED;
+#define FLUSH_ALL 0xffffffff
+
+DECLARE_PER_CPU(int, prof_multiplier);
+DECLARE_PER_CPU(int, prof_old_multiplier);
+DECLARE_PER_CPU(int, prof_counter);
+
+extern spinlock_t ipi_lock[];
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Function Prototypes                                                       */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+void smp_send_reschedule(int);
+void smp_reschedule_interrupt(void);
+
+void smp_flush_cache_all(void);
+void smp_flush_cache_all_interrupt(void);
+
+void smp_flush_tlb_all(void);
+static void flush_tlb_all_ipi(void *);
+
+void smp_flush_tlb_mm(struct mm_struct *);
+void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \
+       unsigned long);
+void smp_flush_tlb_page(struct vm_area_struct *, unsigned long);
+static void flush_tlb_others(cpumask_t, struct mm_struct *,
+       struct vm_area_struct *, unsigned long);
+void smp_invalidate_interrupt(void);
+
+void smp_send_stop(void);
+static void stop_this_cpu(void *);
+
+int smp_call_function(void (*) (void *), void *, int, int);
+void smp_call_function_interrupt(void);
+
+void smp_send_timer(void);
+void smp_ipi_timer_interrupt(struct pt_regs *);
+void smp_local_timer_interrupt(struct pt_regs *);
+
+void send_IPI_allbutself(int, int);
+static void send_IPI_mask(cpumask_t, int, int);
+unsigned long send_IPI_mask_phys(cpumask_t, int, int);
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Rescheduling request Routines                                             */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         smp_send_reschedule
+ *
+ * Description:  This routine requests other CPU to execute rescheduling.
+ *               1.Send 'RESCHEDULE_IPI' to other CPU.
+ *                 Request other CPU to execute 'smp_reschedule_interrupt()'.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    cpu_id - Target CPU ID
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_send_reschedule(int cpu_id)
+{
+       WARN_ON(cpu_is_offline(cpu_id));
+       send_IPI_mask(cpumask_of_cpu(cpu_id), RESCHEDULE_IPI, 1);
+}
+
+/*==========================================================================*
+ * Name:         smp_reschedule_interrupt
+ *
+ * Description:  This routine executes on CPU which received
+ *               'RESCHEDULE_IPI'.
+ *               Rescheduling is processed at the exit of interrupt
+ *               operation.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_reschedule_interrupt(void)
+{
+       /* nothing to do */
+}
+
+/*==========================================================================*
+ * Name:         smp_flush_cache_all
+ *
+ * Description:  This routine sends a 'INVALIDATE_CACHE_IPI' to all other
+ *               CPUs in the system.
+ *
+ * Born on Date: 2003-05-28
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_flush_cache_all(void)
+{
+       cpumask_t cpumask;
+       unsigned long *mask;
+
+       preempt_disable();
+       cpumask = cpu_online_map;
+       cpu_clear(smp_processor_id(), cpumask);
+       spin_lock(&flushcache_lock);
+       mask=cpus_addr(cpumask);
+       atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask);
+       send_IPI_mask(cpumask, INVALIDATE_CACHE_IPI, 0);
+       _flush_cache_copyback_all();
+       while (flushcache_cpumask)
+               mb();
+       spin_unlock(&flushcache_lock);
+       preempt_enable();
+}
+
+void smp_flush_cache_all_interrupt(void)
+{
+       _flush_cache_copyback_all();
+       clear_bit(smp_processor_id(), &flushcache_cpumask);
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* TLB flush request Routins                                                 */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         smp_flush_tlb_all
+ *
+ * Description:  This routine flushes all processes TLBs.
+ *               1.Request other CPU to execute 'flush_tlb_all_ipi()'.
+ *               2.Execute 'do_flush_tlb_all_local()'.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_flush_tlb_all(void)
+{
+       unsigned long flags;
+
+       preempt_disable();
+       local_irq_save(flags);
+       __flush_tlb_all();
+       local_irq_restore(flags);
+       smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
+       preempt_enable();
+}
+
+/*==========================================================================*
+ * Name:         flush_tlb_all_ipi
+ *
+ * Description:  This routine flushes all local TLBs.
+ *               1.Execute 'do_flush_tlb_all_local()'.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *info - not used
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+static void flush_tlb_all_ipi(void *info)
+{
+       __flush_tlb_all();
+}
+
+/*==========================================================================*
+ * Name:         smp_flush_tlb_mm
+ *
+ * Description:  This routine flushes the specified mm context TLB's.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *mm - a pointer to the mm struct for flush TLB
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_flush_tlb_mm(struct mm_struct *mm)
+{
+       int cpu_id = smp_processor_id();
+       cpumask_t cpu_mask;
+       unsigned long *mmc = &mm->context[cpu_id];
+       unsigned long flags;
+
+       preempt_disable();
+       cpu_mask = mm->cpu_vm_mask;
+       cpu_clear(cpu_id, cpu_mask);
+
+       if (*mmc != NO_CONTEXT) {
+               local_irq_save(flags);
+               *mmc = NO_CONTEXT;
+               if (mm == current->mm)
+                       activate_context(mm);
+               else
+                       cpu_clear(cpu_id, mm->cpu_vm_mask);
+               local_irq_restore(flags);
+       }
+       if (!cpus_empty(cpu_mask))
+               flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL);
+
+       preempt_enable();
+}
+
+/*==========================================================================*
+ * Name:         smp_flush_tlb_range
+ *
+ * Description:  This routine flushes a range of pages.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *mm - a pointer to the mm struct for flush TLB
+ *               start - not used
+ *               end - not used
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+       unsigned long end)
+{
+       smp_flush_tlb_mm(vma->vm_mm);
+}
+
+/*==========================================================================*
+ * Name:         smp_flush_tlb_page
+ *
+ * Description:  This routine flushes one page.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *vma - a pointer to the vma struct include va
+ *               va - virtual address for flush TLB
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
+{
+       struct mm_struct *mm = vma->vm_mm;
+       int cpu_id = smp_processor_id();
+       cpumask_t cpu_mask;
+       unsigned long *mmc = &mm->context[cpu_id];
+       unsigned long flags;
+
+       preempt_disable();
+       cpu_mask = mm->cpu_vm_mask;
+       cpu_clear(cpu_id, cpu_mask);
+
+#ifdef DEBUG_SMP
+       if (!mm)
+               BUG();
+#endif
+
+       if (*mmc != NO_CONTEXT) {
+               local_irq_save(flags);
+               va &= PAGE_MASK;
+               va |= (*mmc & MMU_CONTEXT_ASID_MASK);
+               __flush_tlb_page(va);
+               local_irq_restore(flags);
+       }
+       if (!cpus_empty(cpu_mask))
+               flush_tlb_others(cpu_mask, mm, vma, va);
+
+       preempt_enable();
+}
+
+/*==========================================================================*
+ * Name:         flush_tlb_others
+ *
+ * Description:  This routine requests other CPU to execute flush TLB.
+ *               1.Setup parmeters.
+ *               2.Send 'INVALIDATE_TLB_IPI' to other CPU.
+ *                 Request other CPU to execute 'smp_invalidate_interrupt()'.
+ *               3.Wait for other CPUs operation finished.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    cpumask - bitmap of target CPUs
+ *               *mm -  a pointer to the mm struct for flush TLB
+ *               *vma -  a pointer to the vma struct include va
+ *               va - virtual address for flush TLB
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+       struct vm_area_struct *vma, unsigned long va)
+{
+       unsigned long *mask;
+#ifdef DEBUG_SMP
+       unsigned long flags;
+       __save_flags(flags);
+       if (!(flags & 0x0040))  /* Interrupt Disable NONONO */
+               BUG();
+#endif /* DEBUG_SMP */
+
+       /*
+        * 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));
+
+       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.
+        * Temporarily this turns IRQs off, so that lockups are
+        * detected by the NMI watchdog.
+        */
+       spin_lock(&tlbstate_lock);
+
+       flush_mm = mm;
+       flush_vma = vma;
+       flush_va = va;
+       mask=cpus_addr(cpumask);
+       atomic_set_mask(*mask, (atomic_t *)&flush_cpumask);
+
+       /*
+        * We have to send the IPI only to
+        * CPUs affected.
+        */
+       send_IPI_mask(cpumask, INVALIDATE_TLB_IPI, 0);
+
+       while (!cpus_empty(flush_cpumask)) {
+               /* nothing. lockup detection does not belong here */
+               mb();
+       }
+
+       flush_mm = NULL;
+       flush_vma = NULL;
+       flush_va = 0;
+       spin_unlock(&tlbstate_lock);
+}
+
+/*==========================================================================*
+ * Name:         smp_invalidate_interrupt
+ *
+ * Description:  This routine executes on CPU which received
+ *               'INVALIDATE_TLB_IPI'.
+ *               1.Flush local TLB.
+ *               2.Report flush TLB process was finished.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_invalidate_interrupt(void)
+{
+       int cpu_id = smp_processor_id();
+       unsigned long *mmc = &flush_mm->context[cpu_id];
+
+       if (!cpu_isset(cpu_id, flush_cpumask))
+               return;
+
+       if (flush_va == FLUSH_ALL) {
+               *mmc = NO_CONTEXT;
+               if (flush_mm == current->active_mm)
+                       activate_context(flush_mm);
+               else
+                       cpu_clear(cpu_id, flush_mm->cpu_vm_mask);
+       } else {
+               unsigned long va = flush_va;
+
+               if (*mmc != NO_CONTEXT) {
+                       va &= PAGE_MASK;
+                       va |= (*mmc & MMU_CONTEXT_ASID_MASK);
+                       __flush_tlb_page(va);
+               }
+       }
+       cpu_clear(cpu_id, flush_cpumask);
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Stop CPU request Routins                                                 */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         smp_send_stop
+ *
+ * Description:  This routine requests stop all CPUs.
+ *               1.Request other CPU to execute 'stop_this_cpu()'.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_send_stop(void)
+{
+       smp_call_function(stop_this_cpu, NULL, 1, 0);
+}
+
+/*==========================================================================*
+ * Name:         stop_this_cpu
+ *
+ * Description:  This routine halt CPU.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+static void stop_this_cpu(void *dummy)
+{
+       int cpu_id = smp_processor_id();
+
+       /*
+        * Remove this CPU:
+        */
+       cpu_clear(cpu_id, cpu_online_map);
+
+       /*
+        * PSW IE = 1;
+        * IMASK = 0;
+        * goto SLEEP
+        */
+       local_irq_disable();
+       outl(0, M32R_ICU_IMASK_PORTL);
+       inl(M32R_ICU_IMASK_PORTL);      /* dummy read */
+       local_irq_enable();
+
+       for ( ; ; );
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Call function Routins                                                     */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         smp_call_function
+ *
+ * Description:  This routine sends a 'CALL_FUNCTION_IPI' to all other CPUs
+ *               in the system.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *func - The function to run. This must be fast and
+ *                       non-blocking.
+ *               *info - An arbitrary pointer to pass to the function.
+ *               nonatomic - currently unused.
+ *               wait - If true, wait (atomically) until function has
+ *                      completed on other CPUs.
+ *
+ * Returns:      0 on success, else a negative status code. Does not return
+ *               until remote CPUs are nearly ready to execute <<func>> or
+ *               are or have executed.
+ *
+ * Cautions:     You must not call this function with disabled interrupts or
+ *               from a hardware interrupt handler, you may call it from a
+ *               bottom half handler.
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
+       int wait)
+{
+       struct call_data_struct data;
+       int cpus;
+
+#ifdef DEBUG_SMP
+       unsigned long flags;
+       __save_flags(flags);
+       if (!(flags & 0x0040))  /* Interrupt Disable NONONO */
+               BUG();
+#endif /* DEBUG_SMP */
+
+       /* 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());
+
+       data.func = func;
+       data.info = info;
+       atomic_set(&data.started, 0);
+       data.wait = wait;
+       if (wait)
+               atomic_set(&data.finished, 0);
+
+       call_data = &data;
+       mb();
+
+       /* Send a message to all other CPUs and wait for them to respond */
+       send_IPI_allbutself(CALL_FUNCTION_IPI, 0);
+
+       /* Wait for response */
+       while (atomic_read(&data.started) != cpus)
+               barrier();
+
+       if (wait)
+               while (atomic_read(&data.finished) != cpus)
+                       barrier();
+       spin_unlock(&call_lock);
+
+       return 0;
+}
+
+/*==========================================================================*
+ * Name:         smp_call_function_interrupt
+ *
+ * Description:  This routine executes on CPU which received
+ *               'CALL_FUNCTION_IPI'.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_call_function_interrupt(void)
+{
+       void (*func) (void *info) = call_data->func;
+       void *info = call_data->info;
+       int wait = call_data->wait;
+
+       /*
+        * Notify initiating CPU that I've grabbed the data and am
+        * about to execute the function
+        */
+       mb();
+       atomic_inc(&call_data->started);
+       /*
+        * At this point the info structure may be out of scope unless wait==1
+        */
+       irq_enter();
+       (*func)(info);
+       irq_exit();
+
+       if (wait) {
+               mb();
+               atomic_inc(&call_data->finished);
+       }
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Timer Routins                                                             */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         smp_send_timer
+ *
+ * Description:  This routine sends a 'LOCAL_TIMER_IPI' to all other CPUs
+ *               in the system.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_send_timer(void)
+{
+       send_IPI_allbutself(LOCAL_TIMER_IPI, 1);
+}
+
+/*==========================================================================*
+ * Name:         smp_send_timer
+ *
+ * Description:  This routine executes on CPU which received
+ *               'LOCAL_TIMER_IPI'.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *regs - a pointer to the saved regster info
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void smp_ipi_timer_interrupt(struct pt_regs *regs)
+{
+       irq_enter();
+       smp_local_timer_interrupt(regs);
+       irq_exit();
+}
+
+/*==========================================================================*
+ * Name:         smp_local_timer_interrupt
+ *
+ * Description:  Local timer interrupt handler. It does both profiling and
+ *               process statistics/rescheduling.
+ *               We do profiling in every local tick, statistics/rescheduling
+ *               happen only every 'profiling multiplier' ticks. The default
+ *               multiplier is 1 and it can be changed by writing the new
+ *               multiplier value into /proc/profile.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *regs - a pointer to the saved regster info
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Original:     arch/i386/kernel/apic.c
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ * 2003-06-24 hy  use per_cpu structure.
+ *==========================================================================*/
+void smp_local_timer_interrupt(struct pt_regs *regs)
+{
+       int user = user_mode(regs);
+       int cpu_id = smp_processor_id();
+
+       /*
+        * The profiling function is SMP safe. (nothing can mess
+        * around with "current", and the profiling counters are
+        * updated with atomic operations). This is especially
+        * useful with a profiling multiplier != 1
+        */
+
+       profile_tick(CPU_PROFILING, regs);
+
+       if (--per_cpu(prof_counter, cpu_id) <= 0) {
+               /*
+                * The multiplier may have changed since the last time we got
+                * to this point as a result of the user writing to
+                * /proc/profile. In this case we need to adjust the APIC
+                * timer accordingly.
+                *
+                * Interrupts are already masked off at this point.
+                */
+               per_cpu(prof_counter, cpu_id)
+                       = per_cpu(prof_multiplier, cpu_id);
+               if (per_cpu(prof_counter, cpu_id)
+                       != per_cpu(prof_old_multiplier, cpu_id))
+               {
+                       per_cpu(prof_old_multiplier, cpu_id)
+                               = per_cpu(prof_counter, cpu_id);
+               }
+
+               update_process_times(user);
+       }
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Send IPI Routins                                                          */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         send_IPI_allbutself
+ *
+ * Description:  This routine sends a IPI to all other CPUs in the system.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    ipi_num - Number of IPI
+ *               try -  0 : Send IPI certainly.
+ *                     !0 : The following IPI is not sended when Target CPU
+ *                          has not received the before IPI.
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+void send_IPI_allbutself(int ipi_num, int try)
+{
+       cpumask_t cpumask;
+
+       cpumask = cpu_online_map;
+       cpu_clear(smp_processor_id(), cpumask);
+
+       send_IPI_mask(cpumask, ipi_num, try);
+}
+
+/*==========================================================================*
+ * Name:         send_IPI_mask
+ *
+ * Description:  This routine sends a IPI to CPUs in the system.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    cpu_mask - Bitmap of target CPUs logical ID
+ *               ipi_num - Number of IPI
+ *               try -  0 : Send IPI certainly.
+ *                     !0 : The following IPI is not sended when Target CPU
+ *                          has not received the before IPI.
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+static void send_IPI_mask(cpumask_t cpumask, int ipi_num, int try)
+{
+       cpumask_t physid_mask, tmp;
+       int cpu_id, phys_id;
+       int num_cpus = num_online_cpus();
+
+       if (num_cpus <= 1)      /* NO MP */
+               return;
+
+       cpus_and(tmp, cpumask, cpu_online_map);
+       BUG_ON(!cpus_equal(cpumask, tmp));
+
+       physid_mask = CPU_MASK_NONE;
+       for_each_cpu_mask(cpu_id, cpumask){
+               if ((phys_id = cpu_to_physid(cpu_id)) != -1)
+                       cpu_set(phys_id, physid_mask);
+       }
+
+       send_IPI_mask_phys(physid_mask, ipi_num, try);
+}
+
+/*==========================================================================*
+ * Name:         send_IPI_mask_phys
+ *
+ * Description:  This routine sends a IPI to other CPUs in the system.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    cpu_mask - Bitmap of target CPUs physical ID
+ *               ipi_num - Number of IPI
+ *               try -  0 : Send IPI certainly.
+ *                     !0 : The following IPI is not sended when Target CPU
+ *                          has not received the before IPI.
+ *
+ * Returns:      IPICRi regster value.
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ *
+ *==========================================================================*/
+unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num,
+       int try)
+{
+       spinlock_t *ipilock;
+       unsigned long flags = 0;
+       volatile unsigned long *ipicr_addr;
+       unsigned long ipicr_val;
+       unsigned long my_physid_mask;
+       unsigned long mask = cpus_addr(physid_mask)[0];
+
+
+       if (mask & ~physids_coerce(phys_cpu_present_map))
+               BUG();
+       if (ipi_num >= NR_IPIS)
+               BUG();
+
+       mask <<= IPI_SHIFT;
+       ipilock = &ipi_lock[ipi_num];
+       ipicr_addr = (volatile unsigned long *)(M32R_ICU_IPICR_ADDR
+               + (ipi_num << 2));
+       my_physid_mask = ~(1 << smp_processor_id());
+
+       /*
+        * lock ipi_lock[i]
+        * check IPICRi == 0
+        * write IPICRi (send IPIi)
+        * unlock ipi_lock[i]
+        */
+       __asm__ __volatile__ (
+               ";; LOCK ipi_lock[i]            \n\t"
+               ".fillinsn                      \n"
+               "1:                             \n\t"
+               "mvfc   %1, psw                 \n\t"
+               "clrpsw #0x40 -> nop            \n\t"
+               DCACHE_CLEAR("r4", "r5", "%2")
+               "lock   r4, @%2                 \n\t"
+               "addi   r4, #-1                 \n\t"
+               "unlock r4, @%2                 \n\t"
+               "mvtc   %1, psw                 \n\t"
+               "bnez   r4, 2f                  \n\t"
+               LOCK_SECTION_START(".balign 4 \n\t")
+               ".fillinsn                      \n"
+               "2:                             \n\t"
+               "ld     r4, @%2                 \n\t"
+               "blez   r4, 2b                  \n\t"
+               "bra    1b                      \n\t"
+               LOCK_SECTION_END
+               ";; CHECK IPICRi == 0           \n\t"
+               ".fillinsn                      \n"
+               "3:                             \n\t"
+               "ld     %0, @%3                 \n\t"
+               "and    %0, %6                  \n\t"
+               "beqz   %0, 4f                  \n\t"
+               "bnez   %5, 5f                  \n\t"
+               "bra    3b                      \n\t"
+               ";; WRITE IPICRi (send IPIi)    \n\t"
+               ".fillinsn                      \n"
+               "4:                             \n\t"
+               "st     %4, @%3                 \n\t"
+               ";; UNLOCK ipi_lock[i]          \n\t"
+               ".fillinsn                      \n"
+               "5:                             \n\t"
+               "ldi    r4, #1                  \n\t"
+               "st     r4, @%2                 \n\t"
+               : "=&r"(ipicr_val)
+               : "r"(flags), "r"(&ipilock->lock), "r"(ipicr_addr),
+                 "r"(mask), "r"(try), "r"(my_physid_mask)
+               : "memory", "r4"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r5"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+
+       return ipicr_val;
+}
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
new file mode 100644 (file)
index 0000000..6ac4f70
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ *  linux/arch/m32r/kernel/smpboot.c
+ *    orig : i386 2.4.10
+ *
+ *  M32R SMP booting functions
+ *
+ *  Copyright (c) 2001, 2002, 2003  Hitoshi Yamamoto
+ *
+ *  Taken from i386 version.
+ *       (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ *       (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ *     Much of the core SMP work is based on previous work by Thomas Radke, to
+ *     whom a great many thanks are extended.
+ *
+ *     Thanks to Intel for making available several different Pentium,
+ *     Pentium Pro and Pentium-II/Xeon MP machines.
+ *     Original development of Linux SMP code supported by Caldera.
+ *
+ *     This code is released under the GNU General Public License version 2 or
+ *     later.
+ *
+ *     Fixes
+ *             Felix Koop      :       NR_CPUS used properly
+ *             Jose Renau      :       Handle single CPU case.
+ *             Alan Cox        :       By repeated request
+ *                                     8) - Total BogoMIP report.
+ *             Greg Wright     :       Fix for kernel stacks panic.
+ *             Erich Boleyn    :       MP v1.4 and additional changes.
+ *     Matthias Sattler        :       Changes for 2.1 kernel map.
+ *     Michel Lespinasse       :       Changes for 2.1 kernel map.
+ *     Michael Chastain        :       Change trampoline.S to gnu as.
+ *             Alan Cox        :       Dumb bug: 'B' step PPro's are fine
+ *             Ingo Molnar     :       Added APIC timers, based on code
+ *                                     from Jose Renau
+ *             Ingo Molnar     :       various cleanups and rewrites
+ *             Tigran Aivazian :       fixed "0.00 in /proc/uptime on SMP" bug.
+ *     Maciej W. Rozycki       :       Bits for genuine 82489DX APICs
+ *             Martin J. Bligh :       Added support for multi-quad systems
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+#define DEBUG_SMP
+#ifdef DEBUG_SMP
+#define Dprintk(x...) printk(x)
+#else
+#define Dprintk(x...)
+#endif
+
+extern int cpu_idle(void);
+extern cpumask_t cpu_initialized;
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Data structures and variables                                             */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/* Processor that is doing the boot up */
+static unsigned int bsp_phys_id = -1;
+
+/* Bitmask of physically existing CPUs */
+physid_mask_t phys_cpu_present_map;
+
+/* Bitmask of currently online CPUs */
+cpumask_t cpu_online_map;
+
+cpumask_t cpu_bootout_map;
+cpumask_t cpu_bootin_map;
+cpumask_t cpu_callout_map;
+static cpumask_t cpu_callin_map;
+
+/* Per CPU bogomips and other parameters */
+struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned;
+
+/* Set when the idlers are all forked */
+int smp_threads_ready;
+
+static int cpucount;
+static cpumask_t smp_commenced_mask;
+
+extern struct {
+       void * spi;
+       unsigned short ss;
+} stack_start;
+
+/* which physical physical ID maps to which logical CPU number */
+static volatile int physid_2_cpu[NR_CPUS];
+
+/* which logical CPU number maps to which physical ID */
+volatile int cpu_2_physid[NR_CPUS];
+
+DEFINE_PER_CPU(int, prof_multiplier) = 1;
+DEFINE_PER_CPU(int, prof_old_multiplier) = 1;
+DEFINE_PER_CPU(int, prof_counter) = 1;
+
+spinlock_t ipi_lock[NR_IPIS];
+
+static unsigned int calibration_result;
+
+unsigned long cache_decay_ticks = HZ / 100;
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Function Prototypes                                                       */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+void smp_prepare_boot_cpu(void);
+void smp_prepare_cpus(unsigned int);
+static void smp_tune_scheduling(void);
+static void init_ipi_lock(void);
+static void do_boot_cpu(int);
+int __cpu_up(unsigned int);
+void smp_cpus_done(unsigned int);
+
+int start_secondary(void *);
+static void smp_callin(void);
+static void smp_online(void);
+
+static void show_mp_info(int);
+static void smp_store_cpu_info(int);
+static void show_cpu_info(int);
+int setup_profiling_timer(unsigned int);
+static void init_cpu_to_physid(void);
+static void map_cpu_to_physid(int, int);
+static void unmap_cpu_to_physid(int, int);
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Boot up APs Routins : BSP                                                 */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+void __devinit smp_prepare_boot_cpu(void)
+{
+       bsp_phys_id = hard_smp_processor_id();
+       physid_set(bsp_phys_id, phys_cpu_present_map);
+       cpu_set(0, cpu_online_map);     /* BSP's cpu_id == 0 */
+       cpu_set(0, cpu_callout_map);
+       cpu_set(0, cpu_callin_map);
+
+       /*
+        * Initialize the logical to physical CPU number mapping
+        */
+       init_cpu_to_physid();
+       map_cpu_to_physid(0, bsp_phys_id);
+       current_thread_info()->cpu = 0;
+}
+
+/*==========================================================================*
+ * Name:         smp_prepare_cpus (old smp_boot_cpus)
+ *
+ * Description:  This routine boot up APs.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ * 2003-06-24 hy  modify for linux-2.5.69
+ *
+ *==========================================================================*/
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       int phys_id;
+       unsigned long nr_cpu;
+
+       nr_cpu = inl(M32R_FPGA_NUM_OF_CPUS_PORTL);
+       if (nr_cpu > NR_CPUS) {
+               printk(KERN_INFO "NUM_OF_CPUS reg. value [%ld] > NR_CPU [%d]",
+                       nr_cpu, NR_CPUS);
+               goto smp_done;
+       }
+       for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++)
+               physid_set(phys_id, phys_cpu_present_map);
+
+       show_mp_info(nr_cpu);
+
+       init_ipi_lock();
+
+       /*
+        * Setup boot CPU information
+        */
+       smp_store_cpu_info(0); /* Final full version of the data */
+       smp_tune_scheduling();
+
+       /*
+        * If SMP should be disabled, then really disable it!
+        */
+       if (!max_cpus) {
+               printk(KERN_INFO "SMP mode deactivated by commandline.\n");
+               goto smp_done;
+       }
+
+       /*
+        * Now scan the CPU present map and fire up the other CPUs.
+        */
+       Dprintk("CPU present map : %lx\n", physids_coerce(phys_cpu_present_map));
+
+       for (phys_id = 0 ; phys_id < NR_CPUS ; phys_id++) {
+               /*
+                * Don't even attempt to start the boot CPU!
+                */
+               if (phys_id == bsp_phys_id)
+                       continue;
+
+               if (!physid_isset(phys_id, phys_cpu_present_map))
+                       continue;
+
+               if ((max_cpus >= 0) && (max_cpus <= cpucount + 1))
+                       continue;
+
+               do_boot_cpu(phys_id);
+
+               /*
+                * Make sure we unmap all failed CPUs
+                */
+               if (physid_to_cpu(phys_id) == -1) {
+                       physid_clear(phys_id, phys_cpu_present_map);
+                       printk("phys CPU#%d not responding - " \
+                               "cannot use it.\n", phys_id);
+               }
+       }
+
+smp_done:
+       Dprintk("Boot done.\n");
+}
+
+static void __init smp_tune_scheduling(void)
+{
+       /* Nothing to do. */
+}
+
+/*
+ * init_ipi_lock : Initialize IPI locks.
+ */
+static void __init init_ipi_lock(void)
+{
+       int ipi;
+
+       for (ipi = 0 ; ipi < NR_IPIS ; ipi++)
+               ipi_lock[ipi] = SPIN_LOCK_UNLOCKED;
+}
+
+/*==========================================================================*
+ * Name:         do_boot_cpu
+ *
+ * Description:  This routine boot up one AP.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    phys_id - Target CPU physical ID
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ * 2003-06-24 hy  modify for linux-2.5.69
+ *
+ *==========================================================================*/
+static void __init do_boot_cpu(int phys_id)
+{
+       struct task_struct *idle;
+       unsigned long send_status, boot_status;
+       int timeout, cpu_id;
+
+       cpu_id = ++cpucount;
+
+       /*
+        * We can't use kernel_thread since we must avoid to
+        * reschedule the child.
+        */
+       idle = fork_idle(cpu_id);
+       if (IS_ERR(idle))
+               panic("failed fork for CPU#%d.", cpu_id);
+
+       idle->thread.lr = (unsigned long)start_secondary;
+
+       map_cpu_to_physid(cpu_id, phys_id);
+
+       /* So we see what's up   */
+       printk("Booting processor %d/%d\n", phys_id, cpu_id);
+       stack_start.spi = (void *)idle->thread.sp;
+       idle->thread_info->cpu = cpu_id;
+
+       /*
+        * Send Startup IPI
+        *   1.IPI received by CPU#(phys_id).
+        *   2.CPU#(phys_id) enter startup_AP (arch/m32r/kernel/head.S)
+        *   3.CPU#(phys_id) enter start_secondary()
+        */
+       send_status = 0;
+       boot_status = 0;
+
+       cpu_set(phys_id, cpu_bootout_map);
+
+       /* Send Startup IPI */
+       send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0);
+
+       Dprintk("Waiting for send to finish...\n");
+       timeout = 0;
+
+       /* Wait 100[ms] */
+       do {
+               Dprintk("+");
+               udelay(1000);
+               send_status = !cpu_isset(phys_id, cpu_bootin_map);
+       } while (send_status && (timeout++ < 100));
+
+       Dprintk("After Startup.\n");
+
+       if (!send_status) {
+               /*
+                * allow APs to start initializing.
+                */
+               Dprintk("Before Callout %d.\n", cpu_id);
+               cpu_set(cpu_id, cpu_callout_map);
+               Dprintk("After Callout %d.\n", cpu_id);
+
+               /*
+                * Wait 5s total for a response
+                */
+               for (timeout = 0; timeout < 5000; timeout++) {
+                       if (cpu_isset(cpu_id, cpu_callin_map))
+                               break;  /* It has booted */
+                       udelay(1000);
+               }
+
+               if (cpu_isset(cpu_id, cpu_callin_map)) {
+                       /* number CPUs logically, starting from 1 (BSP is 0) */
+                       Dprintk("OK.\n");
+               } else {
+                       boot_status = 1;
+                       printk("Not responding.\n");
+               }
+       } else
+               printk("IPI never delivered???\n");
+
+       if (send_status || boot_status) {
+               unmap_cpu_to_physid(cpu_id, phys_id);
+               cpu_clear(cpu_id, cpu_callout_map);
+               cpu_clear(cpu_id, cpu_callin_map);
+               cpu_clear(cpu_id, cpu_initialized);
+               cpucount--;
+       }
+}
+
+int __devinit __cpu_up(unsigned int cpu_id)
+{
+       int timeout;
+
+       cpu_set(cpu_id, smp_commenced_mask);
+
+       /*
+        * Wait 5s total for a response
+        */
+       for (timeout = 0; timeout < 5000; timeout++) {
+               if (cpu_isset(cpu_id, cpu_online_map))
+                       break;
+               udelay(1000);
+       }
+       if (!cpu_isset(cpu_id, cpu_online_map))
+               BUG();
+
+       return 0;
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+       int cpu_id, timeout;
+       unsigned long bogosum = 0;
+
+       for (timeout = 0; timeout < 5000; timeout++) {
+               if (cpus_equal(cpu_callin_map, cpu_online_map))
+                       break;
+               udelay(1000);
+       }
+       if (!cpus_equal(cpu_callin_map, cpu_online_map))
+               BUG();
+
+       for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++)
+               show_cpu_info(cpu_id);
+
+       /*
+        * Allow the user to impress friends.
+        */
+       Dprintk("Before bogomips.\n");
+       if (cpucount) {
+               for_each_cpu_mask(cpu_id, cpu_online_map)
+                       bogosum += cpu_data[cpu_id].loops_per_jiffy;
+
+               printk(KERN_INFO "Total of %d processors activated " \
+                       "(%lu.%02lu BogoMIPS).\n", cpucount + 1,
+                       bogosum / (500000 / HZ),
+                       (bogosum / (5000 / HZ)) % 100);
+               Dprintk("Before bogocount - setting activated=1.\n");
+       }
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Activate a secondary processor Routins                                    */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+
+/*==========================================================================*
+ * Name:         start_secondary
+ *
+ * Description:  This routine activate a secondary processor.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    *unused - currently unused.
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ * 2003-06-24 hy  modify for linux-2.5.69
+ *
+ *==========================================================================*/
+int __init start_secondary(void *unused)
+{
+       cpu_init();
+       smp_callin();
+       while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+               rep_nop();
+
+       smp_online();
+
+       /*
+        * low-memory mappings have been cleared, flush them from
+        * the local TLBs too.
+        */
+       local_flush_tlb_all();
+
+       return cpu_idle();
+}
+
+/*==========================================================================*
+ * Name:         smp_callin
+ *
+ * Description:  This routine activate a secondary processor.
+ *
+ * Born on Date: 2002.02.05
+ *
+ * Arguments:    NONE
+ *
+ * Returns:      void (cannot fail)
+ *
+ * Modification log:
+ * Date       Who Description
+ * ---------- --- --------------------------------------------------------
+ * 2003-06-24 hy  modify for linux-2.5.69
+ *
+ *==========================================================================*/
+static void __init smp_callin(void)
+{
+       int phys_id = hard_smp_processor_id();
+       int cpu_id = smp_processor_id();
+       unsigned long timeout;
+
+       if (cpu_isset(cpu_id, cpu_callin_map)) {
+               printk("huh, phys CPU#%d, CPU#%d already present??\n",
+                       phys_id, cpu_id);
+               BUG();
+       }
+       Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpu_id, phys_id);
+
+       /* Waiting 2s total for startup (udelay is not yet working) */
+       timeout = jiffies + (2 * HZ);
+       while (time_before(jiffies, timeout)) {
+               /* Has the boot CPU finished it's STARTUP sequence ? */
+               if (cpu_isset(cpu_id, cpu_callout_map))
+                       break;
+               rep_nop();
+       }
+
+       if (!time_before(jiffies, timeout)) {
+               printk("BUG: CPU#%d started up but did not get a callout!\n",
+                       cpu_id);
+               BUG();
+       }
+
+       /* Allow the master to continue. */
+       cpu_set(cpu_id, cpu_callin_map);
+}
+
+static void __init smp_online(void)
+{
+       int cpu_id = smp_processor_id();
+
+       local_irq_enable();
+
+       /* Get our bogomips. */
+       calibrate_delay();
+
+       /* Save our processor parameters */
+       smp_store_cpu_info(cpu_id);
+
+       cpu_set(cpu_id, cpu_online_map);
+}
+
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+/* Boot up CPUs common Routins                                               */
+/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
+static void __init show_mp_info(int nr_cpu)
+{
+       int i;
+       char cpu_model0[17], cpu_model1[17], cpu_ver[9];
+
+       strncpy(cpu_model0, (char *)M32R_FPGA_CPU_NAME_ADDR, 16);
+       strncpy(cpu_model1, (char *)M32R_FPGA_MODEL_ID_ADDR, 16);
+       strncpy(cpu_ver, (char *)M32R_FPGA_VERSION_ADDR, 8);
+
+       cpu_model0[16] = '\0';
+       for (i = 15 ; i >= 0 ; i--) {
+               if (cpu_model0[i] != ' ')
+                       break;
+               cpu_model0[i] = '\0';
+       }
+       cpu_model1[16] = '\0';
+       for (i = 15 ; i >= 0 ; i--) {
+               if (cpu_model1[i] != ' ')
+                       break;
+               cpu_model1[i] = '\0';
+       }
+       cpu_ver[8] = '\0';
+       for (i = 7 ; i >= 0 ; i--) {
+               if (cpu_ver[i] != ' ')
+                       break;
+               cpu_ver[i] = '\0';
+       }
+
+       printk(KERN_INFO "M32R-mp information\n");
+       printk(KERN_INFO "  On-chip CPUs : %d\n", nr_cpu);
+       printk(KERN_INFO "  CPU model : %s/%s(%s)\n", cpu_model0,
+               cpu_model1, cpu_ver);
+}
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+static void __init smp_store_cpu_info(int cpu_id)
+{
+       struct cpuinfo_m32r *ci = cpu_data + cpu_id;
+
+       *ci = boot_cpu_data;
+       ci->loops_per_jiffy = loops_per_jiffy;
+}
+
+static void __init show_cpu_info(int cpu_id)
+{
+       struct cpuinfo_m32r *ci = &cpu_data[cpu_id];
+
+       printk("CPU#%d : ", cpu_id);
+
+#define PRINT_CLOCK(name, value) \
+       printk(name " clock %d.%02dMHz", \
+               ((value) / 1000000), ((value) % 1000000) / 10000)
+
+       PRINT_CLOCK("CPU", (int)ci->cpu_clock);
+       PRINT_CLOCK(", Bus", (int)ci->bus_clock);
+       printk(", loops_per_jiffy[%ld]\n", ci->loops_per_jiffy);
+}
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing a multiplier value into /proc/profile.
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+       int i;
+
+       /*
+        * Sanity check. [at least 500 APIC cycles should be
+        * between APIC interrupts as a rule of thumb, to avoid
+        * irqs flooding us]
+        */
+       if ( (!multiplier) || (calibration_result / multiplier < 500))
+               return -EINVAL;
+
+       /*
+        * Set the new multiplier for each CPU. CPUs don't start using the
+        * new values until the next timer interrupt in which they do process
+        * accounting. At that time they also adjust their APIC timers
+        * accordingly.
+        */
+       for (i = 0; i < NR_CPUS; ++i)
+               per_cpu(prof_multiplier, i) = multiplier;
+
+       return 0;
+}
+
+/* Initialize all maps between cpu number and apicids */
+static void __init init_cpu_to_physid(void)
+{
+       int  i;
+
+       for (i = 0 ; i < NR_CPUS ; i++) {
+               cpu_2_physid[i] = -1;
+               physid_2_cpu[i] = -1;
+       }
+}
+
+/*
+ * set up a mapping between cpu and apicid. Uses logical apicids for multiquad,
+ * else physical apic ids
+ */
+static void __init map_cpu_to_physid(int cpu_id, int phys_id)
+{
+       physid_2_cpu[phys_id] = cpu_id;
+       cpu_2_physid[cpu_id] = phys_id;
+}
+
+/*
+ * undo a mapping between cpu and apicid. Uses logical apicids for multiquad,
+ * else physical apic ids
+ */
+static void __init unmap_cpu_to_physid(int cpu_id, int phys_id)
+{
+       physid_2_cpu[phys_id] = -1;
+       cpu_2_physid[cpu_id] = -1;
+}
+
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
new file mode 100644 (file)
index 0000000..f34fa19
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * linux/arch/m32r/kernel/sys_m32r.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/M32R platform.
+ *
+ * Taken from i386 version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/cacheflush.h>
+#include <asm/ipc.h>
+
+/*
+ * sys_tas() - test-and-set
+ * linuxthreads testing version
+ */
+#ifndef CONFIG_SMP
+asmlinkage int sys_tas(int *addr)
+{
+       int oldval;
+       unsigned long flags;
+
+       if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
+               return -EFAULT;
+       local_irq_save(flags);
+       oldval = *addr;
+       *addr = 1;
+       local_irq_restore(flags);
+       return oldval;
+}
+#else /* CONFIG_SMP */
+#include <linux/spinlock.h>
+
+static spinlock_t tas_lock = SPIN_LOCK_UNLOCKED;
+
+asmlinkage int sys_tas(int *addr)
+{
+       int oldval;
+
+       if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
+               return -EFAULT;
+
+       spin_lock(&tas_lock);
+       oldval = *addr;
+       *addr = 1;
+       spin_unlock(&tas_lock);
+
+       return oldval;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage int
+sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2,
+       unsigned long r3, unsigned long r4, unsigned long r5,
+       unsigned long r6, struct pt_regs regs)
+{
+       int fd[2];
+       int error;
+
+       error = do_pipe(fd);
+       if (!error) {
+               if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int)))
+                       error = -EFAULT;
+       }
+       return error;
+}
+
+asmlinkage long sys_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;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage 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;
+
+       switch (call) {
+       case SEMOP:
+               return sys_semtimedop(first, (struct sembuf __user *)ptr,
+                                     second, NULL);
+       case SEMTIMEDOP:
+               return sys_semtimedop(first, (struct sembuf __user *)ptr,
+                                     second, (const struct timespec __user *)fifth);
+       case SEMGET:
+               return sys_semget (first, second, third);
+       case SEMCTL: {
+               union semun fourth;
+               if (!ptr)
+                       return -EINVAL;
+               if (get_user(fourth.__pad, (void __user * __user *) ptr))
+                       return -EFAULT;
+               return sys_semctl (first, second, third, fourth);
+               }
+
+       case MSGSND:
+               return sys_msgsnd (first, (struct msgbuf __user *) ptr,
+                                  second, third);
+       case MSGRCV:
+               switch (version) {
+               case 0: {
+                       struct ipc_kludge tmp;
+                       if (!ptr)
+                               return -EINVAL;
+
+                       if (copy_from_user(&tmp,
+                                          (struct ipc_kludge __user *) ptr,
+                                          sizeof (tmp)))
+                               return -EFAULT;
+                       return sys_msgrcv (first, tmp.msgp, second,
+                                          tmp.msgtyp, third);
+                       }
+               default:
+                       return sys_msgrcv (first,
+                                          (struct msgbuf __user *) ptr,
+                                          second, fifth, third);
+               }
+       case MSGGET:
+               return sys_msgget ((key_t) first, second);
+       case MSGCTL:
+               return sys_msgctl (first, second,
+                                  (struct msqid_ds __user *) ptr);
+       case SHMAT: {
+               ulong raddr;
+
+               if ((ret = verify_area(VERIFY_WRITE, (ulong __user *) third,
+                                     sizeof(ulong))))
+                       return ret;
+               ret = do_shmat (first, (char __user *) ptr, second, &raddr);
+               if (ret)
+                       return ret;
+               return put_user (raddr, (ulong __user *) third);
+               }
+       case SHMDT:
+               return sys_shmdt ((char __user *)ptr);
+       case SHMGET:
+               return sys_shmget (first, second, third);
+       case SHMCTL:
+               return sys_shmctl (first, second,
+                                  (struct shmid_ds __user *) ptr);
+       default:
+               return -ENOSYS;
+       }
+}
+
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+       int err;
+       if (!name)
+               return -EFAULT;
+       down_read(&uts_sem);
+       err=copy_to_user(name, &system_utsname, sizeof (*name));
+       up_read(&uts_sem);
+       return err?-EFAULT:0;
+}
+
+asmlinkage int sys_cacheflush(void *addr, int bytes, int cache)
+{
+       /* This should flush more selectivly ...  */
+       _flush_cache_all();
+       return 0;
+}
+
+asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
+{
+       /* Not implemented yet. */
+       return -ENOSYS;
+}
+
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c
new file mode 100644 (file)
index 0000000..25a3166
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ *  linux/arch/m32r/kernel/time.c
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata,
+ *                            Hitoshi Yamamoto
+ *  Taken from i386 version.
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *    Copyright (C) 1996, 1997, 1998  Ralf Baechle
+ *
+ *  This file contains the time handling details for PC-style clocks as
+ *  found in some MIPS systems.
+ *
+ *  Some code taken from sh version.
+ *    Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
+ *    Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
+ */
+
+#undef  DEBUG_TIMER
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/profile.h>
+
+#include <asm/io.h>
+#include <asm/m32r.h>
+
+#include <asm/hw_irq.h>
+
+#ifdef CONFIG_SMP
+extern void send_IPI_allbutself(int, int);
+extern void smp_local_timer_interrupt(struct pt_regs *);
+#endif
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+EXPORT_SYMBOL(jiffies_64);
+
+extern unsigned long wall_jiffies;
+#define TICK_SIZE      (tick_nsec / 1000)
+
+/*
+ * Change this if you have some constant time drift
+ */
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+
+static unsigned long latch;
+
+static unsigned long do_gettimeoffset(void)
+{
+       unsigned long  elapsed_time = 0;  /* [us] */
+
+#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \
+       || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \
+       || defined(CONFIG_CHIP_OPSP)
+#ifndef CONFIG_SMP
+
+       unsigned long count;
+
+       /* timer count may underflow right here */
+       count = inl(M32R_MFT2CUT_PORTL);
+
+       if (inl(M32R_ICU_CR18_PORTL) & 0x00000100)      /* underflow check */
+               count = 0;
+
+       count = (latch - count) * TICK_SIZE;
+       elapsed_time = (count + latch / 2) / latch;
+       /* NOTE: LATCH is equal to the "interval" value (= reload count). */
+
+#else /* CONFIG_SMP */
+       unsigned long count;
+       static unsigned long p_jiffies = -1;
+       static unsigned long p_count = 0;
+
+       /* timer count may underflow right here */
+       count = inl(M32R_MFT2CUT_PORTL);
+
+       if (jiffies == p_jiffies && count > p_count)
+               count = 0;
+
+       p_jiffies = jiffies;
+       p_count = count;
+
+       count = (latch - count) * TICK_SIZE;
+       elapsed_time = (count + latch / 2) / latch;
+       /* NOTE: LATCH is equal to the "interval" value (= reload count). */
+#endif /* CONFIG_SMP */
+#elif defined(CONFIG_CHIP_M32310)
+#warning do_gettimeoffse not implemented
+#else
+#error no chip configuration
+#endif
+
+       return elapsed_time;
+}
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+       unsigned long seq;
+       unsigned long usec, sec;
+       unsigned long max_ntp_tick = tick_usec - tickadj;
+
+       do {
+               unsigned long lost;
+
+               seq = read_seqbegin(&xtime_lock);
+
+               usec = do_gettimeoffset();
+               lost = jiffies - wall_jiffies;
+
+               /*
+                * If time_adjust is negative then NTP is slowing the clock
+                * so make sure not to go into next possible interval.
+                * Better to lose some accuracy than have time go backwards..
+                */
+               if (unlikely(time_adjust < 0)) {
+                       usec = min(usec, max_ntp_tick);
+                       if (lost)
+                               usec += lost * max_ntp_tick;
+               } else if (unlikely(lost))
+                       usec += lost * tick_usec;
+
+               sec = xtime.tv_sec;
+               usec += (xtime.tv_nsec / 1000);
+       } while (read_seqretry(&xtime_lock, seq));
+
+       while (usec >= 1000000) {
+               usec -= 1000000;
+               sec++;
+       }
+
+       tv->tv_sec = sec;
+       tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+       time_t wtm_sec, sec = tv->tv_sec;
+       long wtm_nsec, nsec = tv->tv_nsec;
+
+       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+               return -EINVAL;
+
+       write_seqlock_irq(&xtime_lock);
+       /*
+        * This is revolting. We need to set "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!
+        */
+       nsec -= do_gettimeoffset() * NSEC_PER_USEC;
+       nsec -= (jiffies - wall_jiffies) * TICK_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);
+       clock_was_set();
+
+       return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ *      sets the minutes. Usually you won't notice until after reboot!
+ */
+static __inline__ int set_rtc_mmss(unsigned long nowtime)
+{
+       return 0;
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static __inline__ void do_timer_interrupt(int irq, void *dev_id,
+       struct pt_regs * regs)
+{
+       do_timer(regs);
+
+       /*
+        * If we have an externally synchronized Linux clock, then update
+        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+        * called as close as possible to 500 ms before the new second starts.
+        */
+       if ((time_status & STA_UNSYNC) == 0
+               && xtime.tv_sec > last_rtc_update + 660
+               && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned)TICK_SIZE) / 2
+               && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned)TICK_SIZE) / 2)
+       {
+               if (set_rtc_mmss(xtime.tv_sec) == 0)
+                       last_rtc_update = xtime.tv_sec;
+               else    /* do it again in 60 s */
+                       last_rtc_update = xtime.tv_sec - 600;
+       }
+       /* As we return to user mode fire off the other CPU schedulers..
+          this is basically because we don't yet share IRQ's around.
+          This message is rigged to be safe on the 386 - basically it's
+          a hack, so don't look closely for now.. */
+
+#ifdef CONFIG_SMP
+       smp_local_timer_interrupt(regs);
+#endif
+}
+
+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       write_seqlock(&xtime_lock);
+       do_timer_interrupt(irq, NULL, regs);
+       write_sequnlock(&xtime_lock);
+
+#ifndef CONFIG_SMP
+       profile_tick(CPU_PROFILING, regs);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE,
+                         "MFT2", NULL, NULL };
+
+void __init time_init(void)
+{
+       unsigned int epoch, year, mon, day, hour, min, sec;
+
+       sec = min = hour = day = mon = year = 0;
+       epoch = 0;
+
+       year = 23;
+       mon = 4;
+       day = 17;
+
+       /* Attempt to guess the epoch.  This is the same heuristic as in rtc.c
+          so no stupid things will happen to timekeeping.  Who knows, maybe
+          Ultrix also uses 1952 as epoch ...  */
+       if (year > 10 && year < 44)
+               epoch = 1980;
+       else if (year < 96)
+               epoch = 1952;
+       year += epoch;
+
+       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+       wall_to_monotonic.tv_sec = -xtime.tv_sec;
+       wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
+
+#if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \
+       || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \
+       || defined(CONFIG_CHIP_OPSP)
+
+       /* M32102 MFT setup */
+       setup_irq(M32R_IRQ_MFT2, &irq0);
+       {
+               unsigned long bus_clock;
+               unsigned short divide;
+
+               bus_clock = boot_cpu_data.bus_clock;
+               divide = boot_cpu_data.timer_divide;
+               latch = (bus_clock/divide + HZ / 2) / HZ;
+
+               printk("Timer start : latch = %ld\n", latch);
+
+               outl((M32R_MFTMOD_CC_MASK | M32R_MFTMOD_TCCR \
+                       |M32R_MFTMOD_CSSEL011), M32R_MFT2MOD_PORTL);
+               outl(latch, M32R_MFT2RLD_PORTL);
+               outl(latch, M32R_MFT2CUT_PORTL);
+               outl(0, M32R_MFT2CMPRLD_PORTL);
+               outl((M32R_MFTCR_MFT2MSK|M32R_MFTCR_MFT2EN), M32R_MFTCR_PORTL);
+       }
+
+#elif defined(CONFIG_CHIP_M32310)
+#warning time_init not implemented
+#else
+#error no chip configuration
+#endif
+}
+
+/*
+ *  Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+       return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
new file mode 100644 (file)
index 0000000..87fdc4d
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ *  linux/arch/m32r/kernel/traps.c
+ *
+ *  Copyright (C) 2001, 2002  Hirokazu Takata, Hiroyuki Kondo,
+ *                            Hitoshi Yamamoto
+ */
+
+/* $Id$ */
+
+/*
+ * 'traps.c' handles hardware traps and faults after we have saved some
+ * state in 'entry.S'.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kallsyms.h>
+#include <linux/stddef.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+
+#include <asm/smp.h>
+
+#include <linux/module.h>
+
+asmlinkage void alignment_check(void);
+asmlinkage void ei_handler(void);
+asmlinkage void rie_handler(void);
+asmlinkage void debug_trap(void);
+asmlinkage void cache_flushing_handler(void);
+
+#ifdef CONFIG_SMP
+extern void smp_reschedule_interrupt(void);
+extern void smp_invalidate_interrupt(void);
+extern void smp_call_function_interrupt(void);
+extern void smp_ipi_timer_interrupt(void);
+extern void smp_flush_cache_all_interrupt(void);
+
+/*
+ * for Boot AP function
+ */
+asm (
+       "       .section .eit_vector4,\"ax\"    \n"
+       "       .global _AP_RE                  \n"
+       "       .global startup_AP              \n"
+       "_AP_RE:                                \n"
+       "       .fill 32, 4, 0                  \n"
+       "_AP_EI: bra    startup_AP              \n"
+       "       .previous                       \n"
+);
+#endif  /* CONFIG_SMP */
+
+extern unsigned long   eit_vector[];
+#define BRA_INSN(func, entry)  \
+       ((unsigned long)func - (unsigned long)eit_vector - entry*4)/4 \
+       + 0xff000000UL
+
+void   set_eit_vector_entries(void)
+{
+       extern void default_eit_handler(void);
+       extern void system_call(void);
+       extern void pie_handler(void);
+       extern void ace_handler(void);
+       extern void tme_handler(void);
+       extern void _flush_cache_copyback_all(void);
+
+       eit_vector[0] = 0xd0c00001; /* seth r0, 0x01 */
+       eit_vector[1] = BRA_INSN(default_eit_handler, 1);
+       eit_vector[4] = 0xd0c00010; /* seth r0, 0x10 */
+       eit_vector[5] = BRA_INSN(default_eit_handler, 5);
+       eit_vector[8] = BRA_INSN(rie_handler, 8);
+       eit_vector[12] = BRA_INSN(alignment_check, 12);
+       eit_vector[16] = 0xff000000UL;
+       eit_vector[17] = BRA_INSN(debug_trap, 17);
+       eit_vector[18] = BRA_INSN(system_call, 18);
+       eit_vector[19] = 0xff000000UL;
+       eit_vector[20] = 0xff000000UL;
+       eit_vector[21] = 0xff000000UL;
+       eit_vector[22] = 0xff000000UL;
+       eit_vector[23] = 0xff000000UL;
+       eit_vector[24] = 0xff000000UL;
+       eit_vector[25] = 0xff000000UL;
+       eit_vector[26] = 0xff000000UL;
+       eit_vector[27] = 0xff000000UL;
+       eit_vector[28] = BRA_INSN(cache_flushing_handler, 28);
+       eit_vector[29] = 0xff000000UL;
+       eit_vector[30] = 0xff000000UL;
+       eit_vector[31] = 0xff000000UL;
+       eit_vector[32] = BRA_INSN(ei_handler, 32);
+       eit_vector[64] = BRA_INSN(pie_handler, 64);
+       eit_vector[68] = BRA_INSN(ace_handler, 68);
+       eit_vector[72] = BRA_INSN(tme_handler, 72);
+#ifdef CONFIG_SMP
+       eit_vector[184] = (unsigned long)smp_reschedule_interrupt;
+       eit_vector[185] = (unsigned long)smp_invalidate_interrupt;
+       eit_vector[186] = (unsigned long)smp_call_function_interrupt;
+       eit_vector[187] = (unsigned long)smp_ipi_timer_interrupt;
+       eit_vector[188] = (unsigned long)smp_flush_cache_all_interrupt;
+       eit_vector[189] = 0;
+       eit_vector[190] = 0;
+       eit_vector[191] = 0;
+#endif
+       _flush_cache_copyback_all();
+}
+
+void __init trap_init(void)
+{
+       set_eit_vector_entries();
+
+       /*
+        * Should be a barrier for any external CPU state.
+        */
+       cpu_init();
+}
+
+int kstack_depth_to_print = 24;
+
+void show_trace(struct task_struct *task, unsigned long *stack)
+{
+       unsigned long addr;
+
+       if (!stack)
+               stack = (unsigned long*)&stack;
+
+       printk("Call Trace: ");
+       while (!kstack_end(stack)) {
+               addr = *stack++;
+               if (__kernel_text_address(addr)) {
+                       printk("[<%08lx>] ", addr);
+                       print_symbol("%s\n", addr);
+               }
+       }
+       printk("\n");
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       unsigned long  *stack;
+       int  i;
+
+       /*
+        * debugging aid: "show_stack(NULL);" prints the
+        * back trace for this cpu.
+        */
+
+       if(sp==NULL) {
+               if (task)
+                       sp = (unsigned long *)task->thread.sp;
+               else
+                       sp=(unsigned long*)&sp;
+       }
+
+       stack = sp;
+       for(i=0; i < kstack_depth_to_print; i++) {
+               if (kstack_end(stack))
+                       break;
+               if (i && ((i % 4) == 0))
+                       printk("\n       ");
+               printk("%08lx ", *stack++);
+       }
+       printk("\n");
+       show_trace(task, sp);
+}
+
+void dump_stack(void)
+{
+       unsigned long stack;
+
+       show_trace(current, &stack);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+static void show_registers(struct pt_regs *regs)
+{
+       int i = 0;
+       int in_kernel = 1;
+       unsigned long sp;
+
+       printk("CPU:    %d\n", smp_processor_id());
+       show_regs(regs);
+
+       sp = (unsigned long) (1+regs);
+       if (user_mode(regs)) {
+               in_kernel = 0;
+               sp = regs->spu;
+               printk("SPU: %08lx\n", sp);
+       } else {
+               printk("SPI: %08lx\n", sp);
+       }
+       printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)",
+               current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current);
+
+       /*
+        * When in-kernel, we also print out the stack and code at the
+        * time of the fault..
+        */
+       if (in_kernel) {
+               printk("\nStack: ");
+               show_stack(current, (unsigned long*) sp);
+
+               printk("\nCode: ");
+               if (regs->bpc < PAGE_OFFSET)
+                       goto bad;
+
+               for(i=0;i<20;i++) {
+                       unsigned char c;
+                       if (__get_user(c, &((unsigned char*)regs->bpc)[i])) {
+bad:
+                               printk(" Bad PC value.");
+                               break;
+                       }
+                       printk("%02x ", c);
+               }
+       }
+       printk("\n");
+}
+
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+       console_verbose();
+       spin_lock_irq(&die_lock);
+       bust_spinlocks(1);
+       printk("%s: %04lx\n", str, err & 0xffff);
+       show_registers(regs);
+       bust_spinlocks(0);
+       spin_unlock_irq(&die_lock);
+       do_exit(SIGSEGV);
+}
+
+static __inline__ void die_if_kernel(const char * str,
+       struct pt_regs * regs, long err)
+{
+       if (!user_mode(regs))
+               die(str, regs, err);
+}
+
+static __inline__ void do_trap(int trapnr, int signr, const char * str,
+       struct pt_regs * regs, long error_code, siginfo_t *info)
+{
+       if (user_mode(regs)) {
+               /* 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
+                       force_sig(signr, tsk);
+               return;
+       } else {
+               /* kernel_trap */
+               if (!fixup_exception(regs))
+                       die(str, regs, error_code);
+               return;
+       }
+}
+
+#define DO_ERROR(trapnr, signr, str, name) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+       do_trap(trapnr, signr, 0, regs, error_code, NULL); \
+}
+
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+       siginfo_t info; \
+       info.si_signo = signr; \
+       info.si_errno = 0; \
+       info.si_code = sicode; \
+       info.si_addr = (void __user *)siaddr; \
+       do_trap(trapnr, signr, str, regs, error_code, &info); \
+}
+
+DO_ERROR( 1, SIGTRAP, "debug trap", debug_trap)
+DO_ERROR_INFO(0x20, SIGILL,  "reserved instruction ", rie_handler, ILL_ILLOPC, regs->bpc)
+DO_ERROR_INFO(0x100, SIGILL,  "privilege instruction", pie_handler, ILL_PRVOPC, regs->bpc)
+
+extern int handle_unaligned_access(unsigned long, struct pt_regs *);
+
+/* This code taken from arch/sh/kernel/traps.c */
+asmlinkage void do_alignment_check(struct pt_regs *regs, long error_code)
+{
+       mm_segment_t oldfs;
+       unsigned long insn;
+       int tmp;
+
+       oldfs = get_fs();
+
+       if (user_mode(regs)) {
+               local_irq_enable();
+               current->thread.error_code = error_code;
+               current->thread.trap_no = 0x17;
+
+               set_fs(USER_DS);
+               if (copy_from_user(&insn, (void *)regs->bpc, 4)) {
+                       set_fs(oldfs);
+                       goto uspace_segv;
+               }
+               tmp = handle_unaligned_access(insn, regs);
+               set_fs(oldfs);
+
+               if (!tmp)
+                       return;
+
+       uspace_segv:
+               printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
+                       "access\n", current->comm);
+               force_sig(SIGSEGV, current);
+       } else {
+               set_fs(KERNEL_DS);
+               if (copy_from_user(&insn, (void *)regs->bpc, 4)) {
+                       set_fs(oldfs);
+                       die("insn faulting in do_address_error", regs, 0);
+               }
+               handle_unaligned_access(insn, regs);
+               set_fs(oldfs);
+       }
+}
+
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..729a264
--- /dev/null
@@ -0,0 +1,143 @@
+/* ld script to make M32R Linux kernel
+ */
+
+#include <linux/config.h>
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+
+OUTPUT_ARCH(m32r)
+ENTRY(startup_32)
+#if defined(__LITTLE_ENDIAN__)
+       jiffies = jiffies_64;
+#else
+       jiffies = jiffies_64 + 4;
+#endif
+SECTIONS
+{
+  . = CONFIG_MEMORY_START + __PAGE_OFFSET;
+  eit_vector = .;
+
+  . = . + 0x1000;
+  .empty_zero_page : { *(.empty_zero_page) } = 0
+
+  /* read-only */
+  _text = .;                   /* Text and read-only data */
+  .boot : { *(.boot) } = 0
+  .text : {
+       *(.text)
+       SCHED_TEXT
+       LOCK_TEXT
+       *(.fixup)
+       *(.gnu.warning)
+       } = 0x9090
+#ifdef CONFIG_SMP
+  . = ALIGN(65536);
+  .eit_vector4 : { *(.eit_vector4) }
+#endif
+  _etext = .;                  /* End of text section */
+
+  . = ALIGN(16);               /* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  RODATA
+
+  /* writeable */
+  .data : {                    /* Data */
+       *(.spu)
+       *(.spi)
+       *(.data)
+       CONSTRUCTORS
+       }
+
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
+
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  _edata = .;                  /* End of data section */
+
+  . = ALIGN(8192);             /* init_task */
+  .data.init_task : { *(.data.init_task) }
+
+  /* will be freed after init */
+  . = ALIGN(4096);             /* Init code and data */
+  __init_begin = .;
+  .init.text : {
+       _sinittext = .;
+       *(.init.text)
+       _einittext = .;
+  }
+  .init.data : { *(.init.data) }
+  . = ALIGN(16);
+  __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);
+  __alt_instructions = .;
+  .altinstructions : { *(.altinstructions) }
+  __alt_instructions_end = .;
+  .altinstr_replacement : { *(.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) }
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+  /* freed after init ends here */
+
+  __bss_start = .;             /* BSS */
+  .bss : { *(.bss) }
+  . = ALIGN(4);
+  __bss_stop = .;
+
+  _end = . ;
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+       *(.exit.text)
+       *(.exit.data)
+       *(.exitcall.exit)
+       }
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff --git a/arch/m32r/lib/Makefile b/arch/m32r/lib/Makefile
new file mode 100644 (file)
index 0000000..e632d10
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for M32R-specific library files..
+#
+
+lib-y  := checksum.o ashxdi3.o memset.o memcpy.o getuser.o \
+         putuser.o delay.o strlen.o usercopy.o csum_partial_copy.o
+
diff --git a/arch/m32r/lib/ashxdi3.S b/arch/m32r/lib/ashxdi3.S
new file mode 100644 (file)
index 0000000..78effca
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * linux/arch/m32r/lib/ashxdi3.S
+ *
+ * Copyright (C) 2001,2002  Hiroyuki Kondo, and Hirokazu Takata
+ *
+ */
+/* $Id$ */
+
+#include <linux/config.h>
+
+;
+;      input   (r0,r1)  src
+;      input    r2      shift val
+;               r3      scratch
+;      output  (r0,r1)
+;
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+#ifndef __LITTLE_ENDIAN__
+
+       .text
+       .align  4
+       .globl __ashrdi3
+__ashrdi3:
+       cmpz    r2                  ||  ldi     r3, #32
+       jc      r14                 ||  cmpu    r2, r3
+       bc      1f
+    ;   case 32 =< shift
+       mv      r1, r0              ||  srai    r0, #31
+       addi    r2, #-32
+       sra     r1, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r0              ||  srl     r1, r2
+       sra     r0, r2              ||  neg     r2, r2
+       sll     r3, r2
+       or      r1, r3              ||  jmp     r14
+
+        .align  4
+        .globl __ashldi3
+        .globl __lshldi3
+__ashldi3:
+__lshldi3:
+       cmpz    r2                  ||  ldi     r3, #32
+       jc      r14                 ||  cmpu    r2, r3
+       bc      1f
+    ;   case 32 =< shift
+       mv      r0, r1              ||  addi    r2, #-32
+       sll     r0, r2              ||  ldi     r1, #0
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r1              ||  sll     r0, r2
+       sll     r1, r2              ||  neg     r2, r2
+       srl     r3, r2
+       or      r0, r3              ||  jmp     r14
+
+       .align  4
+       .globl __lshrdi3
+__lshrdi3:
+       cmpz    r2                  ||  ldi     r3, #32
+       jc      r14                 ||  cmpu    r2, r3
+       bc      1f
+    ;   case 32 =< shift
+       mv      r1, r0              ||  addi    r2, #-32
+       ldi     r0, #0              ||  srl     r1, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r0              ||  srl     r1, r2
+       srl     r0, r2              ||  neg     r2, r2
+       sll     r3, r2
+       or      r1, r3              ||  jmp     r14
+
+#else /* LITTLE_ENDIAN */
+
+       .text
+       .align  4
+       .globl __ashrdi3
+__ashrdi3:
+       cmpz    r2                  ||  ldi     r3, #32
+       jc      r14                 ||  cmpu    r2, r3
+       bc      1f
+    ;   case 32 =< shift
+       mv      r0, r1              ||  srai    r1, #31
+       addi    r2, #-32
+       sra     r0, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r1              ||  srl     r0, r2
+       sra     r1, r2              ||  neg     r2, r2
+       sll     r3, r2
+       or      r0, r3              ||  jmp     r14
+
+        .align  4
+        .globl __ashldi3
+        .globl __lshldi3
+__ashldi3:
+__lshldi3:
+       cmpz    r2                  ||  ldi     r3, #32
+       jc      r14                 ||  cmpu    r2, r3
+       bc      1f
+    ;   case 32 =< shift
+       mv      r1, r0              ||  addi    r2, #-32
+       sll     r1, r2              ||  ldi     r0, #0
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r0              ||  sll     r1, r2
+       sll     r0, r2              ||  neg     r2, r2
+       srl     r3, r2
+       or      r1, r3              ||  jmp     r14
+
+       .align  4
+       .globl __lshrdi3
+__lshrdi3:
+       cmpz    r2                  ||  ldi     r3, #32
+       jc      r14                 ||  cmpu    r2, r3
+       bc      1f
+    ;   case 32 =< shift
+       mv      r0, r1              ||  addi    r2, #-32
+       ldi     r1, #0              ||  srl     r0, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r1              ||  srl     r0, r2
+       srl     r1, r2              ||  neg     r2, r2
+       sll     r3, r2
+       or      r0, r3              ||  jmp     r14
+
+#endif
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+#ifndef __LITTLE_ENDIAN__
+
+       .text
+       .align  4
+       .globl __ashrdi3
+__ashrdi3:
+       beqz    r2, 2f
+       cmpui   r2, #32
+       bc      1f
+    ;   case 32 =< shift
+       mv      r1, r0
+       srai    r0, #31
+       addi    r2, #-32
+       sra     r1, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r0
+       srl     r1, r2
+       sra     r0, r2
+       neg     r2, r2
+       sll     r3, r2
+       or      r1, r3
+       .fillinsn
+2:
+       jmp     r14
+
+        .align  4
+        .globl __ashldi3
+        .globl __lshldi3
+__ashldi3:
+__lshldi3:
+       beqz    r2, 2f
+       cmpui   r2, #32
+       bc      1f
+    ;   case 32 =< shift
+       mv      r0, r1
+       addi    r2, #-32
+       sll     r0, r2
+       ldi     r1, #0
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r1
+       sll     r0, r2
+       sll     r1, r2
+       neg     r2, r2
+       srl     r3, r2
+       or      r0, r3
+       .fillinsn
+2:
+       jmp     r14
+
+       .align  4
+       .globl __lshrdi3
+__lshrdi3:
+       beqz    r2, 2f
+       cmpui   r2, #32
+       bc      1f
+    ;   case 32 =< shift
+       mv      r1, r0
+       ldi     r0, #0
+       addi    r2, #-32
+       srl     r1, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r0
+       srl     r1, r2
+       srl     r0, r2
+       neg     r2, r2
+       sll     r3, r2
+       or      r1, r3
+       .fillinsn
+2:
+       jmp     r14
+
+#else
+
+       .text
+       .align  4
+       .globl __ashrdi3
+__ashrdi3:
+       beqz    r2, 2f
+       cmpui   r2, #32
+       bc      1f
+    ;   case 32 =< shift
+       mv      r0, r1
+       srai    r1, #31
+       addi    r2, #-32
+       sra     r0, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r1
+       srl     r0, r2
+       sra     r1, r2
+       neg     r2, r2
+       sll     r3, r2
+       or      r0, r3
+       .fillinsn
+2:
+       jmp     r14
+
+        .align  4
+        .globl __ashldi3
+        .globl __lshldi3
+__ashldi3:
+__lshldi3:
+       beqz    r2, 2f
+       cmpui   r2, #32
+       bc      1f
+    ;   case 32 =< shift
+       mv      r1, r0
+       addi    r2, #-32
+       sll     r1, r2
+       ldi     r0, #0
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r0
+       sll     r1, r2
+       sll     r0, r2
+       neg     r2, r2
+       srl     r3, r2
+       or      r1, r3
+       .fillinsn
+2:
+       jmp     r14
+
+       .align  4
+       .globl __lshrdi3
+__lshrdi3:
+       beqz    r2, 2f
+       cmpui   r2, #32
+       bc      1f
+    ;   case 32 =< shift
+       mv      r0, r1
+       ldi     r1, #0
+       addi    r2, #-32
+       srl     r0, r2
+       jmp     r14
+       .fillinsn
+1:  ;   case shift <32
+       mv      r3, r1
+       srl     r0, r2
+       srl     r1, r2
+       neg     r2, r2
+       sll     r3, r2
+       or      r0, r3
+       .fillinsn
+2:
+       jmp     r14
+
+#endif
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .end
+
diff --git a/arch/m32r/lib/checksum.S b/arch/m32r/lib/checksum.S
new file mode 100644 (file)
index 0000000..f6fc1bd
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * 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
+ *
+ * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
+ *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *             Tom May, <ftom@netcom.com>
+ *              Pentium Pro/II routines:
+ *              Alexander Kjeldaas <astor@guardian.no>
+ *              Finn Arne Gangstad <finnag@guardian.no>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ *                          handling.
+ *             Andi Kleen,  add zeroing on error
+ *                   converted to pure assembler
+ *             Hirokazu Takata,Hiroyuki Kondo rewrite for the m32r architecture.
+ *
+ *             This 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.
+ */
+/* $Id$ */
+
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       /*
+        * Experiments with Ethernet and SLIP connections show that buff
+        * is aligned on either a 2-byte or 4-byte boundary.  We get at
+        * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+        * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+        * alignment for the unrolled loop.
+        */
+
+       .text
+ENTRY(csum_partial)
+       ; Function args
+       ;  r0: unsigned char *buff
+       ;  r1: int len
+       ;  r2: unsigned int sum
+
+       push    r2                  ||  ldi     r2, #0
+       and3    r7, r0, #1              ; Check alignment.
+       beqz    r7, 1f                  ; Jump if alignment is ok.
+       ; 1-byte mis aligned
+       ldub    r4, @r0             ||  addi    r0, #1
+       ; clear c-bit || Alignment uses up bytes.
+       cmp     r0, r0              ||  addi    r1, #-1
+       ldi     r3, #0              ||  addx    r2, r4
+       addx    r2, r3
+       .fillinsn
+1:
+       and3    r4, r0, #2              ; Check alignment.
+       beqz    r4, 2f                  ; Jump if alignment is ok.
+       ; clear c-bit || Alignment uses up two bytes.
+       cmp     r0, r0              ||  addi    r1, #-2
+       bgtz    r1, 1f                  ; Jump if we had at least two bytes.
+       bra     4f                  ||  addi    r1, #2
+       .fillinsn                       ; len(r1) was < 2.  Deal with it.
+1:
+       ; 2-byte aligned
+       lduh    r4, @r0             ||  ldi     r3, #0
+       addx    r2, r4              ||  addi    r0, #2
+       addx    r2, r3
+       .fillinsn
+2:
+       ; 4-byte aligned
+       cmp     r0, r0                  ; clear c-bit
+       srl3    r6, r1, #5
+       beqz    r6, 2f
+       .fillinsn
+
+1:     ld      r3, @r0+
+       ld      r4, @r0+                                        ; +4
+       ld      r5, @r0+                                        ; +8
+       ld      r3, @r0+            ||  addx    r2, r3          ; +12
+       ld      r4, @r0+            ||  addx    r2, r4          ; +16
+       ld      r5, @r0+            ||  addx    r2, r5          ; +20
+       ld      r3, @r0+            ||  addx    r2, r3          ; +24
+       ld      r4, @r0+            ||  addx    r2, r4          ; +28
+       addx    r2, r5              ||  addi    r6, #-1
+       addx    r2, r3
+       addx    r2, r4
+       bnez    r6, 1b
+
+       addx    r2, r6                  ; r6=0
+       cmp     r0, r0                  ; This clears c-bit
+       .fillinsn
+2:     and3    r6, r1, #0x1c           ; withdraw len
+       beqz    r6, 4f
+       srli    r6, #2
+       .fillinsn
+
+3:     ld      r4, @r0+            ||  addi    r6, #-1
+       addx    r2, r4
+       bnez    r6, 3b
+
+       addx    r2, r6                  ; r6=0
+       cmp     r0, r0                  ; This clears c-bit
+       .fillinsn
+4:     and3    r1, r1, #3
+       beqz    r1, 7f                  ; if len == 0 goto end
+       and3    r6, r1, #2
+       beqz    r6, 5f                  ; if len < 2  goto 5f(1byte)
+       lduh    r4, @r0             ||  addi    r0, #2
+       addi    r1, #-2             ||  slli    r4, #16
+       addx    r2, r4
+       beqz    r1, 6f
+       .fillinsn
+5:     ldub    r4, @r0             ||  ldi     r1, #0
+#ifndef __LITTLE_ENDIAN__
+       slli    r4, #8
+#endif
+       addx    r2, r4
+       .fillinsn
+6:     addx    r2, r1
+       .fillinsn
+7:
+       and3    r0, r2, #0xffff
+       srli    r2, #16
+       add     r0, r2
+       srl3    r2, r0, #16
+       beqz    r2, 1f
+       addi    r0, #1
+       and3    r0, r0, #0xffff
+       .fillinsn
+1:
+       beqz    r7, 1f                  ; swap the upper byte for the lower
+       and3    r2, r0, #0xff
+       srl3    r0, r0, #8
+       slli    r2, #8
+       or      r0, r2
+       .fillinsn
+1:
+       pop     r2                  ||  cmp     r0, r0
+       addx    r0, r2              ||  ldi     r2, #0
+       addx    r0, r2
+       jmp     r14
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       /*
+        * Experiments with Ethernet and SLIP connections show that buff
+        * is aligned on either a 2-byte or 4-byte boundary.  We get at
+        * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+        * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+        * alignment for the unrolled loop.
+        */
+
+       .text
+ENTRY(csum_partial)
+       ; Function args
+       ;  r0: unsigned char *buff
+       ;  r1: int len
+       ;  r2: unsigned int sum
+
+       push    r2
+       ldi     r2, #0
+       and3    r7, r0, #1              ; Check alignment.
+       beqz    r7, 1f                  ; Jump if alignment is ok.
+       ; 1-byte mis aligned
+       ldub    r4, @r0
+       addi    r0, #1
+       addi    r1, #-1                 ; Alignment uses up bytes.
+       cmp     r0, r0                  ; clear c-bit
+       ldi     r3, #0
+       addx    r2, r4
+       addx    r2, r3
+       .fillinsn
+1:
+       and3    r4, r0, #2              ; Check alignment.
+       beqz    r4, 2f                  ; Jump if alignment is ok.
+       addi    r1, #-2                 ; Alignment uses up two bytes.
+       cmp             r0, r0                  ; clear c-bit
+       bgtz    r1, 1f                  ; Jump if we had at least two bytes.
+       addi    r1, #2                  ; len(r1) was < 2.  Deal with it.
+       bra     4f
+       .fillinsn
+1:
+       ; 2-byte aligned
+       lduh    r4, @r0
+       addi    r0, #2
+       ldi             r3, #0
+       addx    r2, r4
+       addx    r2, r3
+       .fillinsn
+2:
+       ; 4-byte aligned
+       cmp     r0, r0                  ; clear c-bit
+       srl3    r6, r1, #5
+       beqz    r6, 2f
+       .fillinsn
+
+1:     ld      r3, @r0+
+       ld      r4, @r0+                ; +4
+       ld      r5, @r0+                ; +8
+       addx    r2, r3
+       addx    r2, r4
+       addx    r2, r5
+       ld      r3, @r0+                ; +12
+       ld      r4, @r0+                ; +16
+       ld      r5, @r0+                ; +20
+       addx    r2, r3
+       addx    r2, r4
+       addx    r2, r5
+       ld      r3, @r0+                ; +24
+       ld      r4, @r0+                ; +28
+       addi    r6, #-1
+       addx    r2, r3
+       addx    r2, r4
+       bnez    r6, 1b
+       addx    r2, r6                  ; r6=0
+       cmp     r0, r0                  ; This clears c-bit
+       .fillinsn
+
+2:     and3    r6, r1, #0x1c           ; withdraw len
+       beqz    r6, 4f
+       srli    r6, #2
+       .fillinsn
+
+3:     ld      r4, @r0+
+       addi    r6, #-1
+       addx    r2, r4
+       bnez    r6, 3b
+       addx    r2, r6                  ; r6=0
+       cmp     r0, r0                  ; This clears c-bit
+       .fillinsn
+
+4:     and3    r1, r1, #3
+       beqz    r1, 7f                  ; if len == 0 goto end
+       and3    r6, r1, #2
+       beqz    r6, 5f                  ; if len < 2  goto 5f(1byte)
+
+       lduh    r4, @r0
+       addi    r0, #2
+       addi    r1, #-2
+       slli    r4, #16
+       addx    r2, r4
+       beqz    r1, 6f
+       .fillinsn
+5:     ldub    r4, @r0
+#ifndef __LITTLE_ENDIAN__
+       slli    r4, #8
+#endif
+       addx    r2, r4
+       .fillinsn
+6:     ldi     r5, #0
+       addx    r2, r5
+       .fillinsn
+7:
+       and3    r0, r2, #0xffff
+       srli    r2, #16
+       add     r0, r2
+       srl3    r2, r0, #16
+       beqz    r2, 1f
+       addi    r0, #1
+       and3    r0, r0, #0xffff
+       .fillinsn
+1:
+       beqz    r7, 1f
+       mv      r2, r0
+       srl3    r0, r2, #8
+       and3    r2, r2, #0xff
+       slli    r2, #8
+       or      r0, r2
+       .fillinsn
+1:
+       pop     r2
+       cmp     r0, r0
+       addx    r0, r2
+       ldi     r2, #0
+       addx    r0, r2
+       jmp     r14
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+                                 int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+ */
+
+/*
+ * 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 all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ *       DST definitions? It's damn hard to trigger all cases.  I hope I got
+ *       them all but there's no guarantee.
+ */
+
+ENTRY(csum_partial_copy_generic)
+       nop
+       nop
+       nop
+       nop
+       jmp r14
+       nop
+       nop
+       nop
+
diff --git a/arch/m32r/lib/csum_partial_copy.c b/arch/m32r/lib/csum_partial_copy.c
new file mode 100644 (file)
index 0000000..22600fc
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ *             MIPS specific IP/TCP/UDP checksumming routines
+ *
+ * Authors:    Ralf Baechle, <ralf@waldorf-gmbh.de>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ *             This 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/types.h>
+
+#include <net/checksum.h>
+#include <asm/byteorder.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+/*
+ * Copy while checksumming, otherwise like csum_partial
+ */
+unsigned int csum_partial_copy_nocheck (const char *src, char *dst,
+                                        int len, unsigned int sum)
+{
+       sum = csum_partial(src, len, sum);
+       memcpy(dst, src, len);
+
+       return sum;
+}
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
+/*
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user (const char __user *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
+{
+       int missing;
+
+       missing = copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *err_ptr = -EFAULT;
+       }
+
+       return csum_partial(dst, len-missing, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
diff --git a/arch/m32r/lib/delay.c b/arch/m32r/lib/delay.c
new file mode 100644 (file)
index 0000000..7afe66e
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * linux/arch/m32r/lib/delay.c
+ *
+ * Copyright (c) 2002  Hitoshi Yamamoto, Hirokazu Takata
+ * Copyright (c) 2004  Hirokazu Takata
+ */
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <linux/param.h>
+#ifdef CONFIG_SMP
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <asm/smp.h>
+#endif  /* CONFIG_SMP */
+#include <asm/processor.h>
+
+void __delay(unsigned long loops)
+{
+#ifdef CONFIG_ISA_DUAL_ISSUE
+       __asm__ __volatile__ (
+               "beqz   %0, 2f                  \n\t"
+               "addi   %0, #-1                 \n\t"
+
+               " .fillinsn                     \n\t"
+               "1:                             \n\t"
+               "cmpz   %0  ||  addi  %0, #-1   \n\t"
+               "bc     2f  ||  cmpz  %0        \n\t"
+               "bc     2f  ||  addi  %0, #-1   \n\t"
+               "cmpz   %0  ||  addi  %0, #-1   \n\t"
+               "bc     2f  ||  cmpz  %0        \n\t"
+               "bnc    1b  ||  addi  %0, #-1   \n\t"
+               " .fillinsn                     \n\t"
+               "2:                             \n\t"
+               : "+r" (loops)
+               : "r" (0)
+               : "cbit"
+       );
+#else
+       __asm__ __volatile__ (
+               "beqz   %0, 2f                  \n\t"
+               " .fillinsn                     \n\t"
+               "1:                             \n\t"
+               "addi   %0, #-1                 \n\t"
+               "blez   %0, 2f                  \n\t"
+               "addi   %0, #-1                 \n\t"
+               "blez   %0, 2f                  \n\t"
+               "addi   %0, #-1                 \n\t"
+               "blez   %0, 2f                  \n\t"
+               "addi   %0, #-1                 \n\t"
+               "bgtz   %0, 1b                  \n\t"
+               " .fillinsn                     \n\t"
+               "2:i                            \n\t"
+               : "+r" (loops)
+               : "r" (0)
+       );
+#endif
+}
+
+void __const_udelay(unsigned long xloops)
+{
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       /*
+        * loops [1] = (xloops >> 32) [sec] * loops_per_jiffy [1/jiffy]
+        *            * HZ [jiffy/sec]
+        *          = (xloops >> 32) [sec] * (loops_per_jiffy * HZ) [1/sec]
+        *          = (((xloops * loops_per_jiffy) >> 32) * HZ) [1]
+        *
+        * NOTE:
+        *   - '[]' depicts variable's dimension in the above equation.
+        *   - "rac" instruction rounds the accumulator in word size.
+        */
+       __asm__ __volatile__ (
+               "srli   %0, #1                          \n\t"
+               "mulwhi %0, %1  ; a0                    \n\t"
+               "mulwu1 %0, %1  ; a1                    \n\t"
+               "sadd           ; a0 += (a1 >> 16)      \n\t"
+               "rac    a0, a0, #1                      \n\t"
+               "mvfacmi %0, a0                         \n\t"
+               : "+r" (xloops)
+               : "r" (current_cpu_data.loops_per_jiffy)
+               : "a0", "a1"
+       );
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       /*
+        * u64 ull;
+        * ull = (u64)xloops * (u64)current_cpu_data.loops_per_jiffy;
+        * xloops = (ull >> 32);
+        */
+       __asm__ __volatile__ (
+               "and3   r4, %0, #0xffff         \n\t"
+               "and3   r5, %1, #0xffff         \n\t"
+               "mul    r4, r5                  \n\t"
+               "srl3   r6, %0, #16             \n\t"
+               "srli   r4, #16                 \n\t"
+               "mul    r5, r6                  \n\t"
+               "add    r4, r5                  \n\t"
+               "and3   r5, %0, #0xffff         \n\t"
+               "srl3   r6, %1, #16             \n\t"
+               "mul    r5, r6                  \n\t"
+               "add    r4, r5                  \n\t"
+               "srl3   r5, %0, #16             \n\t"
+               "srli   r4, #16                 \n\t"
+               "mul    r5, r6                  \n\t"
+               "add    r4, r5                  \n\t"
+               "mv     %0, r4                  \n\t"
+               : "+r" (xloops)
+               : "r" (current_cpu_data.loops_per_jiffy)
+               : "r4", "r5", "r6"
+       );
+#else
+#error unknown isa configuration
+#endif
+       __delay(xloops * HZ);
+}
+
+void __udelay(unsigned long usecs)
+{
+       __const_udelay(usecs * 0x000010c7);  /* 2**32 / 1000000 (rounded up) */
+}
+
+void __ndelay(unsigned long nsecs)
+{
+       __const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+}
diff --git a/arch/m32r/lib/getuser.S b/arch/m32r/lib/getuser.S
new file mode 100644 (file)
index 0000000..58a0db0
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * __get_user functions.
+ *
+ * (C) Copyright 2001 Hirokazu Takata
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient, especially as they
+ * return an error value in addition to the "real"
+ * return value.
+ */
+
+#include <linux/config.h>
+
+/*
+ * __get_user_X
+ *
+ * Inputs:     r0 contains the address
+ *
+ * Outputs:    r0 is error code (0 or -EFAULT)
+ *             r1 contains zero-extended value
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       .text
+       .balign 4
+       .globl __get_user_1
+__get_user_1:
+1:     ldub    r1, @r0             ||  ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __get_user_2
+__get_user_2:
+2:     lduh    r1, @r0             ||  ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __get_user_4
+__get_user_4:
+3:     ld      r1, @r0             ||  ldi     r0, #0
+       jmp     r14
+
+bad_get_user:
+       ldi     r1, #0              ||  ldi     r0, #-14
+       jmp     r14
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .text
+       .balign 4
+       .globl __get_user_1
+__get_user_1:
+1:     ldub    r1, @r0
+       ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __get_user_2
+__get_user_2:
+2:     lduh    r1, @r0
+       ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __get_user_4
+__get_user_4:
+3:     ld      r1, @r0
+       ldi     r0, #0
+       jmp     r14
+
+bad_get_user:
+       ldi     r1, #0
+       ldi     r0, #-14
+       jmp     r14
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+.section __ex_table,"a"
+       .long 1b,bad_get_user
+       .long 2b,bad_get_user
+       .long 3b,bad_get_user
+.previous
+
+       .end
diff --git a/arch/m32r/lib/memcpy.S b/arch/m32r/lib/memcpy.S
new file mode 100644 (file)
index 0000000..800898a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  linux/arch/m32r/lib/memcpy.S
+ *
+ *  Copyright (C) 2001  Hiroyuki Kondo, and Hirokazu Takata
+ *  Copyright (C) 2004  Hirokazu Takata
+ *
+ *  void *memcopy(void *dst, const void *src, int n);
+ *
+ *        dst: r0
+ *        src: r1
+ *        n  : r2
+ */
+/* $Id$ */
+
+
+       .text
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       .text
+ENTRY(memcpy)
+memcopy:
+       mv      r4, r0              ||  mv      r7, r0
+       or      r7, r1              ||  cmpz    r2
+       jc      r14                 ||  cmpeq   r0, r1  ; return if r2=0
+       jc      r14                                     ; return if r0=r1
+
+       and3    r7, r7, #3
+       bnez    r7, byte_copy
+       srl3    r3, r2, #2
+       and3    r2, r2, #3
+       beqz    r3, byte_copy
+       addi    r4, #-4
+word_copy:
+       ld      r7, @r1+            ||  addi    r3, #-1
+       st      r7, @+r4            ||  cmpz    r2
+       bnez    r3, word_copy
+       addi    r4, #4              ||  jc      r14     ; return if r2=0
+#if defined(CONFIG_ISA_M32R2)
+byte_copy:
+       ldb     r7, @r1             ||  addi    r1, #1
+       addi    r2, #-1             ||  stb     r7, @r4+
+       bnez    r2, byte_copy
+#elif defined(CONFIG_ISA_M32R)
+byte_copy:
+       ldb     r7, @r1             ||  addi    r1, #1
+       addi    r2, #-1             ||  stb     r7, @r4
+       addi    r4, #1
+       bnez    r2, byte_copy
+#else
+#error unknown isa configuration
+#endif
+end_memcopy:
+       jmp     r14
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .text
+ENTRY(memcpy)
+memcopy:
+       mv      r4, r0
+       mv      r7, r0
+       or      r7, r1
+       beq     r0, r1, end_memcopy
+       beqz    r2, end_memcopy
+
+       and3    r7, r7, #3
+       bnez    r7, byte_copy
+       srl3    r3, r2, #2
+       and3    r2, r2, #3
+       beqz    r3, byte_copy
+       addi    r4, #-4
+word_copy:
+       ld      r7, @r1+
+       addi    r3, #-1
+       st      r7, @+r4
+       bnez    r3, word_copy
+       beqz    r2, end_memcopy
+       addi    r4, #4
+byte_copy:
+       ldb     r7, @r1
+       addi    r1, #1
+       addi    r2, #-1
+       stb     r7, @r4
+       addi    r4, #1
+       bnez    r2, byte_copy
+end_memcopy:
+       jmp     r14
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .end
diff --git a/arch/m32r/lib/memset.S b/arch/m32r/lib/memset.S
new file mode 100644 (file)
index 0000000..7fe94b6
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  linux/arch/m32r/lib/memset.S
+ *
+ *  Copyright (C) 2001,2002  Hiroyuki Kondo, and Hirokazu Takata
+ *  Copyright (C) 2004  Hirokazu Takata
+ *
+ *  void *memset(void *dst, int val, int len);
+ *
+ *        dst: r0
+ *        val: r1
+ *        len: r2
+ *        ret: r0
+ *
+ */
+/* $Id$ */
+
+#include <linux/config.h>
+
+       .text
+       .global memset
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       .align 4
+memset:
+       mv      r4, r0              ||  cmpz    r2
+       jc      r14
+       cmpui   r2, #16
+       bnc     qword_align_check
+       cmpui   r2, #4
+       bc      byte_set
+word_align_check:                      /* len >= 4 */
+       and3    r3, r4, #3
+       beqz    r3, word_set
+       addi    r3, #-4
+       neg     r3, r3                  /* r3 = -(r3 - 4) */
+align_word:
+       stb     r1, @r4             ||  addi    r4, #1
+       addi    r2, #-1             ||  addi    r3, #-1
+       bnez    r3, align_word
+       cmpui   r2, #4
+       bc      byte_set
+word_set:
+       and3    r1, r1, #0x00ff         /* r1: abababab <-- ??????ab */
+       sll3    r3, r1, #8
+       or      r1, r3              ||  addi    r4, #-4
+       sll3    r3, r1, #16
+       or      r1, r3              ||  addi    r2, #-4
+word_set_loop:
+       st      r1, @+r4            ||  addi    r2, #-4
+       bgtz    r2, word_set_loop
+       bnez    r2, byte_set_wrap
+       st      r1, @+r4
+       jmp     r14
+
+qword_align_check:                     /* len >= 16 */
+       and3    r3, r4, #15
+       bnez    r3, word_align_check
+qword_set:
+       and3    r1, r1, #0x00ff         /* r1: abababab <-- ??????ab */
+       sll3    r3, r1, #8
+       or      r1, r3              ||  addi    r4, #-4
+       sll3    r3, r1, #16
+       or      r1, r3              ||  ldi     r5, #16
+qword_set_loop:
+       ld      r3, @(4,r4)             /* cache line allocate */
+       st      r1, @+r4            ||  addi    r2, #-16
+       st      r1, @+r4            ||  cmpu    r2, r5
+       st      r1, @+r4
+       st      r1, @+r4
+       bnc     qword_set_loop      ||  cmpz    r2
+       jc      r14
+word_set_wrap:
+       cmpui   r2, #4
+       bc      byte_set
+       addi    r2, #-4
+       bra     word_set_loop
+
+byte_set_wrap:
+       addi    r2, #4
+       addi    r4, #4              ||  cmpz    r2
+       jc      r14
+#if defined(CONFIG_ISA_M32R2)
+byte_set:
+       addi    r2, #-1             ||  stb     r1, @r4+
+       bnez    r2, byte_set
+#elif defined(CONFIG_ISA_M32R)
+byte_set:
+       addi    r2, #-1             ||  stb     r1, @r4
+       addi    r4, #1
+       bnez    r2, byte_set
+#else
+#error unknown isa configuration
+#endif
+end_memset:
+       jmp     r14
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .align 4
+memset:
+       mv      r4, r0
+       beqz    r2, end_memset
+       cmpui   r2, #16
+       bnc     qword_align_check
+       cmpui   r2, #4
+       bc      byte_set
+word_align_check:                      /* len >= 4 */
+       and3    r3, r4, #3
+       beqz    r3, word_set
+       addi    r3, #-4
+       neg     r3, r3                  /* r3 = -(r3 - 4) */
+align_word:
+       stb     r1, @r4
+       addi    r4, #1
+       addi    r2, #-1
+       addi    r3, #-1
+       bnez    r3, align_word
+       cmpui   r2, #4
+       bc      byte_set
+word_set:
+       and3    r1, r1, #0x00ff         /* r1: abababab <-- ??????ab */
+       sll3    r3, r1, #8
+       or      r1, r3
+       sll3    r3, r1, #16
+       or      r1, r3
+       addi    r2, #-4
+       addi    r4, #-4
+word_set_loop:
+       st      r1, @+r4
+       addi    r2, #-4
+       bgtz    r2, word_set_loop
+       bnez    r2, byte_set_wrap
+       st      r1, @+r4
+       jmp     r14
+
+qword_align_check:                     /* len >= 16 */
+       and3    r3, r4, #15
+       bnez    r3, word_align_check
+qword_set:
+       and3    r1, r1, #0x00ff         /* r1: abababab <-- ??????ab */
+       sll3    r3, r1, #8
+       or      r1, r3
+       sll3    r3, r1, #16
+       or      r1, r3
+       addi    r4, #-4
+qword_set_loop:
+       ld      r3, @(4,r4)             /* cache line allocate */
+       addi    r2, #-16
+       st      r1, @+r4
+       st      r1, @+r4
+       cmpui   r2, #16
+       st      r1, @+r4
+       st      r1, @+r4
+       bnc     qword_set_loop
+       bnez    r2, word_set_wrap
+       jmp     r14
+word_set_wrap:
+       cmpui   r2, #4
+       bc      byte_set
+       addi    r2, #-4
+       bra     word_set_loop
+
+byte_set_wrap:
+       addi    r2, #4
+       addi    r4, #4
+       beqz    r2, end_memset
+byte_set:
+       addi    r2, #-1
+       stb     r1, @r4
+       addi    r4, #1
+       bnez    r2, byte_set
+end_memset:
+       jmp     r14
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .end
diff --git a/arch/m32r/lib/putuser.S b/arch/m32r/lib/putuser.S
new file mode 100644 (file)
index 0000000..218154c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * __put_user functions.
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ * (C) Copyright 2001 Hirokazu Takata
+ *
+ * These functions have a non-standard call interface
+ * to make them more efficient.
+ */
+
+#include <linux/config.h>
+
+/*
+ * __put_user_X
+ *
+ * Inputs:     r0 contains the address
+ *             r1 contains the value
+ *
+ * Outputs:    r0 is error code (0 or -EFAULT)
+ *             r1 is corrupted (will contain "current_task").
+ *
+ * These functions should not modify any other registers,
+ * as they get called from within inline assembly.
+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       .text
+       .balign 4
+       .globl __put_user_1
+__put_user_1:
+1:     stb     r1, @r0             ||  ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __put_user_2
+__put_user_2:
+2:     sth     r1, @r0             ||  ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __put_user_4
+__put_user_4:
+3:     st      r1, @r0             ||  ldi     r0, #0
+       jmp     r14
+
+bad_put_user:
+       ldi     r0, #-14            ||  jmp     r14
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .text
+       .balign 4
+       .globl __put_user_1
+__put_user_1:
+1:     stb     r1, @r0
+       ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __put_user_2
+__put_user_2:
+2:     sth     r1, @r0
+       ldi     r0, #0
+       jmp     r14
+
+       .balign 4
+       .globl __put_user_4
+__put_user_4:
+3:     st      r1, @r0
+       ldi     r0, #0
+       jmp     r14
+
+bad_put_user:
+       ldi     r0, #-14
+       jmp     r14
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+.section __ex_table,"a"
+       .long 1b,bad_put_user
+       .long 2b,bad_put_user
+       .long 3b,bad_put_user
+.previous
diff --git a/arch/m32r/lib/strlen.S b/arch/m32r/lib/strlen.S
new file mode 100644 (file)
index 0000000..8d23cfb
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  linux/arch/m32r/strlen.S --  strlen code.
+ *
+ *  Copyright (C) 2001  Hirokazu Takata
+ *
+ *  size_t strlen(const char *s);
+ *
+ */
+/* $Id$ */
+
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+       .text
+ENTRY(strlen)
+       mv      r6, r0              ||  ldi     r2, #0
+       and3    r0, r0, #3
+       bnez    r0, strlen_byte
+;
+strlen_word:
+       ld      r0, @r6+
+;
+       seth    r5, #high(0x01010101)
+       or3     r5, r5, #low(0x01010101)
+       sll3    r7, r5, #7
+strlen_word_loop:
+       ld      r1, @r6+            ||  not     r4, r0
+       sub     r0, r5              ||  and     r4, r7
+       and     r4, r0
+       bnez    r4, strlen_last_bytes
+       ld      r0, @r6+            ||  not     r4, r1
+       sub     r1, r5              ||  and     r4, r7
+       and     r4, r1              ||  addi    r2, #4
+       bnez    r4, strlen_last_bytes
+       addi    r2, #4              ||  bra.s   strlen_word_loop
+
+       ; NOTE: If a null char. exists, return 0.
+       ; if ((x - 0x01010101) & ~x & 0x80808080)
+       ;     return 0;
+;
+strlen_byte:
+       ldb     r1, @r6             ||  addi    r6, #1
+       beqz    r1, strlen_exit
+       addi    r2, #1              ||  bra.s   strlen_byte
+;
+strlen_last_bytes:
+       ldi     r0, #4              ||  addi    r6, #-8
+;
+strlen_byte_loop:
+       ldb     r1, @r6             ||  addi    r6, #1
+       addi    r0, #-1             ||  cmpz    r1
+       bc.s    strlen_exit         ||  cmpz    r0
+       addi    r2, #1              ||  bnc.s   strlen_byte_loop
+;
+strlen_exit:
+       mv      r0, r2              ||  jmp     r14
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .text
+ENTRY(strlen)
+       mv      r6, r0
+       ldi     r2, #0
+       and3    r0, r0, #3
+       bnez    r0, strlen_byte
+;
+strlen_word:
+       ld      r0, @r6+
+;
+       seth    r5, #high(0x01010101)
+       or3     r5, r5, #low(0x01010101)
+       sll3    r7, r5, #7
+strlen_word_loop:
+       ld      r1, @r6+
+       not     r4, r0          ; NOTE: If a null char. exists, return 0.
+       sub     r0, r5          ; if ((x - 0x01010101) & ~x & 0x80808080)
+       and     r4, r7          ;     return 0;
+       and     r4, r0
+       bnez    r4, strlen_last_bytes
+       addi    r2, #4
+;
+       ld      r0, @r6+
+       not     r4, r1          ; NOTE: If a null char. exists, return 0.
+       sub     r1, r5          ; if ((x - 0x01010101) & ~x & 0x80808080)
+       and     r4, r7          ;     return 0;
+       and     r4, r1
+       bnez    r4, strlen_last_bytes
+       addi    r2, #4
+       bra     strlen_word_loop
+;
+strlen_byte:
+       ldb     r1, @r6
+       addi    r6, #1
+       beqz    r1, strlen_exit
+       addi    r2, #1
+       bra     strlen_byte
+;
+strlen_last_bytes:
+       ldi     r0, #4
+       addi    r6, #-8
+;
+strlen_byte_loop:
+       ldb     r1, @r6
+       addi    r6, #1
+       addi    r0, #-1
+       beqz    r1, strlen_exit
+       addi    r2, #1
+       bnez    r0, strlen_byte_loop
+;
+strlen_exit:
+       mv      r0, r2
+       jmp     r14
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+       .end
diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c
new file mode 100644 (file)
index 0000000..6c6855f
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * User address space access functions.
+ * The non inlined parts of asm-m32r/uaccess.h are here.
+ *
+ * Copyright 1997 Andi Kleen <ak@muc.de>
+ * Copyright 1997 Linus Torvalds
+ * Copyright 2001, 2002, 2004 Hirokazu Takata
+ */
+#include <linux/config.h>
+#include <linux/prefetch.h>
+#include <linux/string.h>
+#include <linux/thread_info.h>
+#include <asm/uaccess.h>
+
+unsigned long
+__generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+       prefetch(from);
+       if (access_ok(VERIFY_WRITE, to, n))
+               __copy_user(to,from,n);
+       return n;
+}
+
+unsigned long
+__generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+       prefetchw(to);
+       if (access_ok(VERIFY_READ, from, n))
+               __copy_user_zeroing(to,from,n);
+       else
+               memset(to, 0, n);
+       return n;
+}
+
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+#define __do_strncpy_from_user(dst,src,count,res)                      \
+do {                                                                   \
+       int __d0, __d1, __d2;                                           \
+       __asm__ __volatile__(                                           \
+               "       beqz    %1, 2f\n"                               \
+               "       .fillinsn\n"                                    \
+               "0:     ldb     r14, @%3    ||  addi    %3, #1\n"       \
+               "       stb     r14, @%4    ||  addi    %4, #1\n"       \
+               "       beqz    r14, 1f\n"                              \
+               "       addi    %1, #-1\n"                              \
+               "       bnez    %1, 0b\n"                               \
+               "       .fillinsn\n"                                    \
+               "1:     sub     %0, %1\n"                               \
+               "       .fillinsn\n"                                    \
+               "2:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "3:     seth    r14, #high(2b)\n"                       \
+               "       or3     r14, r14, #low(2b)\n"                   \
+               "       jmp     r14         ||  ldi     %0, #%5\n"      \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 0b,3b\n"                                  \
+               ".previous"                                             \
+               : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1),   \
+                 "=&r" (__d2)                                          \
+               : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),       \
+                 "4"(dst)                                              \
+               : "r14", "cbit", "memory");                             \
+} while (0)
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+#define __do_strncpy_from_user(dst,src,count,res)                      \
+do {                                                                   \
+       int __d0, __d1, __d2;                                           \
+       __asm__ __volatile__(                                           \
+               "       beqz    %1, 2f\n"                               \
+               "       .fillinsn\n"                                    \
+               "0:     ldb     r14, @%3\n"                             \
+               "       stb     r14, @%4\n"                             \
+               "       addi    %3, #1\n"                               \
+               "       addi    %4, #1\n"                               \
+               "       beqz    r14, 1f\n"                              \
+               "       addi    %1, #-1\n"                              \
+               "       bnez    %1, 0b\n"                               \
+               "       .fillinsn\n"                                    \
+               "1:     sub     %0, %1\n"                               \
+               "       .fillinsn\n"                                    \
+               "2:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "3:     ldi     %0, #%5\n"                              \
+               "       seth    r14, #high(2b)\n"                       \
+               "       or3     r14, r14, #low(2b)\n"                   \
+               "       jmp     r14\n"                                  \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 0b,3b\n"                                  \
+               ".previous"                                             \
+               : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1),   \
+                 "=&r" (__d2)                                          \
+               : "i"(-EFAULT), "0"(count), "1"(count), "3"(src),       \
+                 "4"(dst)                                              \
+               : "r14", "cbit", "memory");                             \
+} while (0)
+
+#endif /* CONFIG_ISA_DUAL_ISSUE */
+
+long
+__strncpy_from_user(char *dst, const char *src, long count)
+{
+       long res;
+       __do_strncpy_from_user(dst, src, count, res);
+       return res;
+}
+
+long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+       long res = -EFAULT;
+       if (access_ok(VERIFY_READ, src, 1))
+               __do_strncpy_from_user(dst, src, count, res);
+       return res;
+}
+
+
+/*
+ * Zero Userspace
+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+#define __do_clear_user(addr,size)                                     \
+do {                                                                   \
+       int __dst, __c;                                                 \
+       __asm__ __volatile__(                                           \
+               "       beqz    %1, 9f\n"                               \
+               "       and3    r14, %0, #3\n"                          \
+               "       bnez    r14, 2f\n"                              \
+               "       and3    r14, %1, #3\n"                          \
+               "       bnez    r14, 2f\n"                              \
+               "       and3    %1, %1, #3\n"                           \
+               "       beqz    %2, 2f\n"                               \
+               "       addi    %0, #-4\n"                              \
+               "       .fillinsn\n"                                    \
+               "0:     ; word clear \n"                                \
+               "       st      %6, @+%0    ||  addi    %2, #-1\n"      \
+               "       bnez    %2, 0b\n"                               \
+               "       beqz    %1, 9f\n"                               \
+               "       .fillinsn\n"                                    \
+               "2:     ; byte clear \n"                                \
+               "       stb     %6, @%0     ||  addi    %1, #-1\n"      \
+               "       addi    %0, #1\n"                               \
+               "       bnez    %1, 2b\n"                               \
+               "       .fillinsn\n"                                    \
+               "9:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "4:     slli    %2, #2\n"                               \
+               "       seth    r14, #high(9b)\n"                       \
+               "       or3     r14, r14, #low(9b)\n"                   \
+               "       jmp     r14         ||  add     %1, %2\n"       \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 0b,4b\n"                                  \
+               "       .long 2b,9b\n"                                  \
+               ".previous\n"                                           \
+               : "=&r"(__dst), "=&r"(size), "=&r"(__c)                 \
+               : "0"(addr), "1"(size), "2"(size / 4), "r"(0)           \
+               : "r14", "cbit", "memory");                             \
+} while (0)
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+#define __do_clear_user(addr,size)                                     \
+do {                                                                   \
+       int __dst, __c;                                                 \
+       __asm__ __volatile__(                                           \
+               "       beqz    %1, 9f\n"                               \
+               "       and3    r14, %0, #3\n"                          \
+               "       bnez    r14, 2f\n"                              \
+               "       and3    r14, %1, #3\n"                          \
+               "       bnez    r14, 2f\n"                              \
+               "       and3    %1, %1, #3\n"                           \
+               "       beqz    %2, 2f\n"                               \
+               "       addi    %0, #-4\n"                              \
+               "       .fillinsn\n"                                    \
+               "0:     st      %6, @+%0        ; word clear \n"        \
+               "       addi    %2, #-1\n"                              \
+               "       bnez    %2, 0b\n"                               \
+               "       beqz    %1, 9f\n"                               \
+               "       .fillinsn\n"                                    \
+               "2:     stb     %6, @%0         ; byte clear \n"        \
+               "       addi    %1, #-1\n"                              \
+               "       addi    %0, #1\n"                               \
+               "       bnez    %1, 2b\n"                               \
+               "       .fillinsn\n"                                    \
+               "9:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "4:     slli    %2, #2\n"                               \
+               "       add     %1, %2\n"                               \
+               "       seth    r14, #high(9b)\n"                       \
+               "       or3     r14, r14, #low(9b)\n"                   \
+               "       jmp     r14\n"                                  \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 0b,4b\n"                                  \
+               "       .long 2b,9b\n"                                  \
+               ".previous\n"                                           \
+               : "=&r"(__dst), "=&r"(size), "=&r"(__c)                 \
+               : "0"(addr), "1"(size), "2"(size / 4), "r"(0)           \
+               : "r14", "cbit", "memory");                             \
+} while (0)
+
+#endif /* not CONFIG_ISA_DUAL_ISSUE */
+
+unsigned long
+clear_user(void *to, unsigned long n)
+{
+       if (access_ok(VERIFY_WRITE, to, n))
+               __do_clear_user(to, n);
+       return n;
+}
+
+unsigned long
+__clear_user(void *to, unsigned long n)
+{
+       __do_clear_user(to, n);
+       return n;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+
+#ifdef CONFIG_ISA_DUAL_ISSUE
+
+long strnlen_user(const char *s, long n)
+{
+       unsigned long mask = -__addr_ok(s);
+       unsigned long res;
+
+       __asm__ __volatile__(
+               "       and     %0, %5      ||  mv      r1, %1\n"
+               "       beqz    %0, strnlen_exit\n"
+               "       and3    r0, %1, #3\n"
+               "       bnez    r0, strnlen_byte_loop\n"
+               "       cmpui   %0, #4\n"
+               "       bc      strnlen_byte_loop\n"
+               "strnlen_word_loop:\n"
+               "0:     ld      r0, @%1+\n"
+               "       pcmpbz  r0\n"
+               "       bc      strnlen_last_bytes_fixup\n"
+               "       addi    %0, #-4\n"
+               "       beqz    %0, strnlen_exit\n"
+               "       bgtz    %0, strnlen_word_loop\n"
+               "strnlen_last_bytes:\n"
+               "       mv      %0, %4\n"
+               "strnlen_last_bytes_fixup:\n"
+               "       addi    %1, #-4\n"
+               "strnlen_byte_loop:\n"
+               "1:     ldb     r0, @%1     ||  addi    %0, #-1\n"
+               "       beqz    r0, strnlen_exit\n"
+               "       addi    %1, #1\n"
+               "       bnez    %0, strnlen_byte_loop\n"
+               "strnlen_exit:\n"
+               "       sub     %1, r1\n"
+               "       add3    %0, %1, #1\n"
+               "       .fillinsn\n"
+               "9:\n"
+               ".section .fixup,\"ax\"\n"
+               "       .balign 4\n"
+               "4:     addi    %1, #-4\n"
+               "       .fillinsn\n"
+               "5:     seth    r1, #high(9b)\n"
+               "       or3     r1, r1, #low(9b)\n"
+               "       jmp     r1          ||  ldi     %0, #0\n"
+               ".previous\n"
+               ".section __ex_table,\"a\"\n"
+               "       .balign 4\n"
+               "       .long 0b,4b\n"
+               "       .long 1b,5b\n"
+               ".previous"
+               : "=&r" (res), "=r" (s)
+               : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
+               : "r0", "r1", "cbit");
+
+       /* NOTE: strnlen_user() algorism:
+        * {
+        *   char *p;
+        *   for (p = s; n-- && *p != '\0'; ++p)
+        *     ;
+        *   return p - s + 1;
+        * }
+        */
+
+       /* NOTE: If a null char. exists, return 0.
+        * if ((x - 0x01010101) & ~x & 0x80808080)\n"
+        *   return 0;\n"
+        */
+
+       return res & mask;
+}
+
+#else /* not CONFIG_ISA_DUAL_ISSUE */
+
+long strnlen_user(const char *s, long n)
+{
+       unsigned long mask = -__addr_ok(s);
+       unsigned long res;
+
+       __asm__ __volatile__(
+               "       and     %0, %5\n"
+               "       mv      r1, %1\n"
+               "       beqz    %0, strnlen_exit\n"
+               "       and3    r0, %1, #3\n"
+               "       bnez    r0, strnlen_byte_loop\n"
+               "       cmpui   %0, #4\n"
+               "       bc      strnlen_byte_loop\n"
+               "       sll3    r3, %6, #7\n"
+               "strnlen_word_loop:\n"
+               "0:     ld      r0, @%1+\n"
+               "       not     r2, r0\n"
+               "       sub     r0, %6\n"
+               "       and     r2, r3\n"
+               "       and     r2, r0\n"
+               "       bnez    r2, strnlen_last_bytes_fixup\n"
+               "       addi    %0, #-4\n"
+               "       beqz    %0, strnlen_exit\n"
+               "       bgtz    %0, strnlen_word_loop\n"
+               "strnlen_last_bytes:\n"
+               "       mv      %0, %4\n"
+               "strnlen_last_bytes_fixup:\n"
+               "       addi    %1, #-4\n"
+               "strnlen_byte_loop:\n"
+               "1:     ldb     r0, @%1\n"
+               "       addi    %0, #-1\n"
+               "       beqz    r0, strnlen_exit\n"
+               "       addi    %1, #1\n"
+               "       bnez    %0, strnlen_byte_loop\n"
+               "strnlen_exit:\n"
+               "       sub     %1, r1\n"
+               "       add3    %0, %1, #1\n"
+               "       .fillinsn\n"
+               "9:\n"
+               ".section .fixup,\"ax\"\n"
+               "       .balign 4\n"
+               "4:     addi    %1, #-4\n"
+               "       .fillinsn\n"
+               "5:     ldi     %0, #0\n"
+               "       seth    r1, #high(9b)\n"
+               "       or3     r1, r1, #low(9b)\n"
+               "       jmp     r1\n"
+               ".previous\n"
+               ".section __ex_table,\"a\"\n"
+               "       .balign 4\n"
+               "       .long 0b,4b\n"
+               "       .long 1b,5b\n"
+               ".previous"
+               : "=&r" (res), "=r" (s)
+               : "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
+               : "r0", "r1", "r2", "r3", "cbit");
+
+       /* NOTE: strnlen_user() algorism:
+        * {
+        *   char *p;
+        *   for (p = s; n-- && *p != '\0'; ++p)
+        *     ;
+        *   return p - s + 1;
+        * }
+        */
+
+       /* NOTE: If a null char. exists, return 0.
+        * if ((x - 0x01010101) & ~x & 0x80808080)\n"
+        *   return 0;\n"
+        */
+
+       return res & mask;
+}
+
+#endif /* CONFIG_ISA_DUAL_ISSUE */
+
diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.smp b/arch/m32r/m32700ut/defconfig.m32700ut.smp
new file mode 100644 (file)
index 0000000..df7f9d0
--- /dev/null
@@ -0,0 +1,662 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+
+#
+# General setup
+#
+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=15
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+CONFIG_PLAT_M32700UT=y
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+CONFIG_SMP=y
+CONFIG_CHIP_M32700_TS1=y
+CONFIG_NR_CPUS=2
+# CONFIG_NUMA is not set
+
+#
+# M32R drivers
+#
+# CONFIG_M32RPCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32700UT_CFC=y
+CONFIG_CFC_NUM=1
+# CONFIG_MTD_M32R is not set
+CONFIG_M32R_SMC91111=y
+CONFIG_M32700UT_DS1302=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_PLDSIO=y
+CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+CONFIG_M32R_AR=y
+CONFIG_M32R_AR_VGA=y
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_EPSON_S1D13806=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_M32R_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR 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_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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_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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/m32700ut/defconfig.m32700ut.up b/arch/m32r/m32700ut/defconfig.m32700ut.up
new file mode 100644 (file)
index 0000000..5a9da73
--- /dev/null
@@ -0,0 +1,659 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+CONFIG_PLAT_M32700UT=y
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+# CONFIG_M32RPCC is not set
+CONFIG_M32R_CFC=y
+CONFIG_M32700UT_CFC=y
+CONFIG_CFC_NUM=1
+# CONFIG_MTD_M32R is not set
+CONFIG_M32R_SMC91111=y
+CONFIG_M32700UT_DS1302=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_PLDSIO=y
+CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+CONFIG_M32R_AR=y
+CONFIG_M32R_AR_VGA=y
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_EPSON_S1D13806=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_M32R_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR 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_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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_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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB b/arch/m32r/m32700ut/dot.gdbinit_200MHz_16MB
new file mode 100644 (file)
index 0000000..fa79cd9
--- /dev/null
@@ -0,0 +1,249 @@
+# .gdbinit file
+# $Id: dot.gdbinit_200MHz_16MB,v 1.1 2004/08/17 02:58:11 takata Exp $
+#-----
+# NOTE: this file is generated by a script, "gen_gdbinit.pl".
+# (Please type "gen_gdbinit.pl --help" and check the help message).
+# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $
+#-----
+# target platform: m32700ut
+
+# setting
+set width 0d70
+set radix 0d16
+
+debug_chaos
+
+# clk xin:cpu:bif:bus=25:200:50:50
+define clock_init
+  set *(unsigned long *)0x00ef4008 = 0x00000000
+  set *(unsigned long *)0x00ef4004 = 0
+  shell sleep 0.1
+  # NOTE: Please change the master clock source from PLL-clock to Xin-clock
+  # and switch off PLL, before resetting the clock gear ratio.
+
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 3
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x00000200
+end
+
+# Initialize SDRAM controller
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  # Initialize wait
+  shell sleep 0.1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c = 0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028 = 0x00041302
+  # Ch0-ADR (size:16MB)
+  set *(unsigned long *)0x00ef6020 = 0x08000002
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004 = 0x00010517
+  # Access enable
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  SDRAM controller initialization
+  0x08000000 - 0x08ffffff (16MB)
+end
+
+# Initialize BSEL3 for UT-CFC
+define cfc_init
+  set $sfrbase = 0xa0ef0000
+# too fast
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f
+end
+document cfc_init
+  CF controller initialization
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb 0d32
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb 0d32
+end
+
+# Initialize TLB entries
+define init_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set *(unsigned long *)($addr + 0x4) = 0
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define tlb_init
+  set $itlb=0xfe000000
+  init_tlb_entries $itlb 0d32
+  set $dtlb=0xfe000800
+  init_tlb_entries $dtlb 0d32
+end
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set  = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+end
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+  clock_init
+  shell sleep 0.1
+  # SDRAM: 16MB
+  set *(unsigned long *)0x00ef6020 = 0x08000002
+  cfc_init
+  # USB
+  set *(unsigned short *)0xb0301000 = 0x100
+
+  set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x08002000
+  # INITRD_START
+  set *(unsigned long *)($param + 0x0010) = 0x082a0000
+  # INITRD_SIZE
+  set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d200000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d50000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x console=tty1 video=s1d13xxxfb:mode:240x320-16 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=16M \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $fp = 0
+  set $pc = 0x08001000
+  set *(unsigned char *)0xffffffff = 0x03
+  si
+  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x08000030
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  set $pc = 0
+  b *0x04001000
+  b *0x08001000
+  b *0x08002000
+  si
+  c
+  tlb_init
+  del
+  setup
+  load_modules
+  boot
+end
+
+define si
+  stepi
+  x/i $pc
+  show_reg
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+set $pc = 0
+b *0x04001000
+b *0x08001000
+b *0x08002000
+c
+tlb_init
+del
+setup
+load_modules
+boot
+
diff --git a/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB b/arch/m32r/m32700ut/dot.gdbinit_300MHz_32MB
new file mode 100644 (file)
index 0000000..4df06e1
--- /dev/null
@@ -0,0 +1,249 @@
+# .gdbinit file
+# $Id: dot.gdbinit_300MHz_32MB,v 1.1 2004/08/17 02:58:11 takata Exp $
+#-----
+# NOTE: this file is generated by a script, "gen_gdbinit.pl".
+# (Please type "gen_gdbinit.pl --help" and check the help message).
+# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $
+#-----
+# target platform: m32700ut
+
+# setting
+set width 0d70
+set radix 0d16
+
+debug_chaos
+
+# clk xin:cpu:bif:bus=25:300:75:75
+define clock_init
+  set *(unsigned long *)0x00ef4008 = 0x00000000
+  set *(unsigned long *)0x00ef4004 = 0
+  shell sleep 0.1
+  # NOTE: Please change the master clock source from PLL-clock to Xin-clock
+  # and switch off PLL, before resetting the clock gear ratio.
+
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 5
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x00000200
+end
+
+# Initialize SDRAM controller
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  # Initialize wait
+  shell sleep 0.1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c = 0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028 = 0x00051502
+  # Ch0-ADR (size:16MB)
+  set *(unsigned long *)0x00ef6020 = 0x08000002
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004 = 0x00010e24
+  # Access enable
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  SDRAM controller initialization
+  0x08000000 - 0x08ffffff (16MB)
+end
+
+# Initialize BSEL3 for UT-CFC
+define cfc_init
+  set $sfrbase = 0xa0ef0000
+# too fast
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f
+end
+document cfc_init
+  CF controller initialization
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb 0d32
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb 0d32
+end
+
+# Initialize TLB entries
+define init_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set *(unsigned long *)($addr + 0x4) = 0
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define tlb_init
+  set $itlb=0xfe000000
+  init_tlb_entries $itlb 0d32
+  set $dtlb=0xfe000800
+  init_tlb_entries $dtlb 0d32
+end
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set  = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+end
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+  clock_init
+  shell sleep 0.1
+  # SDRAM: 16MB
+  set *(unsigned long *)0x00ef6020 = 0x08000002
+  cfc_init
+  # USB
+  set *(unsigned short *)0xb0301000 = 0x100
+
+  set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x08002000
+  # INITRD_START
+  set *(unsigned long *)($param + 0x0010) = 0x082a0000
+  # INITRD_SIZE
+  set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d300000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d75000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x console=tty1 video=s1d13xxxfb:mode:240x320-16 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=16M \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $fp = 0
+  set $pc = 0x08001000
+  set *(unsigned char *)0xffffffff = 0x03
+  si
+  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x08000030
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  set $pc = 0
+  b *0x04001000
+  b *0x08001000
+  b *0x08002000
+  si
+  c
+  tlb_init
+  del
+  setup
+  load_modules
+  boot
+end
+
+define si
+  stepi
+  x/i $pc
+  show_reg
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+set $pc = 0
+b *0x04001000
+b *0x08001000
+b *0x08002000
+c
+tlb_init
+del
+setup
+load_modules
+boot
+
diff --git a/arch/m32r/m32700ut/dot.gdbinit_400MHz_32MB b/arch/m32r/m32700ut/dot.gdbinit_400MHz_32MB
new file mode 100644 (file)
index 0000000..adc608a
--- /dev/null
@@ -0,0 +1,249 @@
+# .gdbinit file
+# $Id: dot.gdbinit_400MHz_32MB,v 1.1 2004/10/21 01:41:27 fujiwara Exp $
+#-----
+# NOTE: this file is generated by a script, "gen_gdbinit.pl".
+# (Please type "gen_gdbinit.pl --help" and check the help message).
+# $ Id: gen_gdbinit.pl,v 1.12 2004/07/26 09:56:10 takata Exp $
+#-----
+# target platform: m32700ut
+
+# setting
+set width 0d70
+set radix 0d16
+
+debug_chaos
+
+# clk xin:cpu:bif:bus=25:400:100:50
+define clock_init
+  set *(unsigned long *)0x00ef4008 = 0x00000000
+  set *(unsigned long *)0x00ef4004 = 0
+  shell sleep 0.1
+  # NOTE: Please change the master clock source from PLL-clock to Xin-clock
+  # and switch off PLL, before resetting the clock gear ratio.
+
+  set *(unsigned long *)0x00ef4024 = 3
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 7
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x00000200
+end
+
+# Initialize SDRAM controller
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  # Initialize wait
+  shell sleep 0.1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c = 0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028 = 0x00041302
+  # Ch0-ADR (size:32MB)
+  set *(unsigned long *)0x00ef6020 = 0x08000003
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004 = 0x00010517
+  # Access enable
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  SDRAM controller initialization
+  0x08000000 - 0x09ffffff (32MB)
+end
+
+# Initialize BSEL3 for UT-CFC
+define cfc_init
+  set $sfrbase = 0xa0ef0000
+# too fast
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x0b0b8000
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x00102204
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f8000
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x1f1f1fdf
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x0013220f
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x0013330f
+end
+document cfc_init
+  CF controller initialization
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb 0d32
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb 0d32
+end
+
+# Initialize TLB entries
+define init_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set *(unsigned long *)($addr + 0x4) = 0
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define tlb_init
+  set $itlb=0xfe000000
+  init_tlb_entries $itlb 0d32
+  set $dtlb=0xfe000800
+  init_tlb_entries $dtlb 0d32
+end
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set  = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+end
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+  clock_init
+  shell sleep 0.1
+  # SDRAM: 32MB
+  set *(unsigned long *)0x00ef6020 = 0x08000003
+  cfc_init
+  # USB
+  set *(unsigned short *)0xb0301000 = 0x100
+
+  set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x08001000
+  # INITRD_START
+#  set *(unsigned long *)($param + 0x0010) = 0x08300000
+  # INITRD_SIZE
+#  set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d400000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d50000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=ttyS0,115200n8x console=tty1 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs,rsize=1024,wsize=1024 nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 mem=32M \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $fp = 0
+  set $pc = 0x08002000
+# set *(unsigned char *)0xffffffff = 0x03
+  si
+  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x08000030
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  set $pc = 0
+  b *0x04001000
+  b *0x08001000
+  b *0x08002000
+  si
+  c
+  tlb_init
+  del
+  setup
+  load_modules
+  boot
+end
+
+define si
+  stepi
+  x/i $pc
+  show_reg
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+set $pc = 0
+b *0x04001000
+b *0x08001000
+b *0x08002000
+c
+tlb_init
+del
+setup
+load_modules
+boot
+
diff --git a/arch/m32r/mappi/defconfig.nommu b/arch/m32r/mappi/defconfig.nommu
new file mode 100644 (file)
index 0000000..cae54bf
--- /dev/null
@@ -0,0 +1,529 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+# 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=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+CONFIG_PLAT_MAPPI=y
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+# CONFIG_MMU is not set
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x00000000
+CONFIG_MEMORY_SIZE=0x00E00000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+# CONFIG_M32RPCC is not set
+CONFIG_M32R_NE2000=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_FLAT=y
+# CONFIG_BINFMT_ZFLAT is not set
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
+# CONFIG_SERIAL_M32R_PLDSIO is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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=y
+CONFIG_DEVPTS_FS_SECURITY=y
+# 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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/mappi/defconfig.smp b/arch/m32r/mappi/defconfig.smp
new file mode 100644 (file)
index 0000000..b0fe571
--- /dev/null
@@ -0,0 +1,646 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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=15
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+
+#
+# Processor type and features
+#
+CONFIG_PLAT_MAPPI=y
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=10000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_NOHIGHMEM=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_IRAM_START=0x00f00000
+CONFIG_IRAM_SIZE=0x00080000
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+CONFIG_SMP=y
+CONFIG_CHIP_M32700_TS1=y
+CONFIG_NR_CPUS=2
+# CONFIG_NUMA is not set
+
+#
+# M32R drivers
+#
+CONFIG_M32RPCC=y
+CONFIG_M32R_NE2000=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+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
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD 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
+#
+
+#
+# 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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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
+
+#
+# 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
+# CONFIG_SERIAL_M32R_PLDSIO is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/m32r/mappi/defconfig.up b/arch/m32r/mappi/defconfig.up
new file mode 100644 (file)
index 0000000..b4ab5ff
--- /dev/null
@@ -0,0 +1,642 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+CONFIG_PLAT_MAPPI=y
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+CONFIG_CHIP_M32700=y
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=10000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_NOHIGHMEM=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_IRAM_START=0x00f00000
+CONFIG_IRAM_SIZE=0x00080000
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+CONFIG_M32RPCC=y
+CONFIG_M32R_NE2000=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+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
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD 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
+#
+
+#
+# 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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_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
+
+#
+# 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
+# CONFIG_SERIAL_M32R_PLDSIO is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/m32r/mappi/dot.gdbinit b/arch/m32r/mappi/dot.gdbinit
new file mode 100644 (file)
index 0000000..ea566b6
--- /dev/null
@@ -0,0 +1,242 @@
+# .gdbinit file
+# $Id$
+#-----
+# NOTE: this file is generated by a script, "gen_gdbinit.pl".
+# (Please type "gen_gdbinit.pl --help" and check the help message).
+# $ Id: gen_gdbinit.pl,v 1.8 2004/02/27 07:08:32 takata Exp $
+#-----
+# target platform: mappi
+
+# setting
+set width 0d70
+set radix 0d16
+debug_chaos
+
+# clk xin:cpu:bif:bus=30:360:180:90
+define clock_init
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 1
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 5
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x00000200
+end
+
+# Initialize programmable ports
+define port_init
+  set $sfrbase = 0x00ef0000
+  set *(unsigned short *)0x00ef1060 = 0x5555
+  set *(unsigned short *)0x00ef1062 = 0x5555
+  set *(unsigned short *)0x00ef1064 = 0x5555
+  set *(unsigned short *)0x00ef1066 = 0x5555
+  set *(unsigned short *)0x00ef1068 = 0x5555
+  set *(unsigned short *)0x00ef106a = 0x0000
+  set *(unsigned short *)0x00ef106e = 0x5555
+  set *(unsigned short *)0x00ef1070 = 0x5555
+  # LED ON
+  set *(unsigned char *)($sfrbase + 0x1015) = 0xff
+  set *(unsigned char *)($sfrbase + 0x1085) = 0xff
+  shell sleep 0.1
+  # LED OFF
+  set *(unsigned char *)($sfrbase + 0x1085) = 0x00
+end
+document port_init
+  P5=LED(output), P6.b4=LAN_RESET(output)
+end
+
+# Initialize SDRAM controller
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  # Initialize wait
+  shell sleep 0.1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c = 0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028 = 0x00051502
+  # Ch0-ADR (size:64MB)
+  set *(unsigned long *)0x00ef6020 = 0x08000004
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004 = 0x00010e2b
+  # Access enable
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  SDRAM controller initialization
+  0x08000000 - 0x0bffffff (64MB)
+end
+
+# Initialize LAN controller
+define lanc_init
+  set $sfrbase = 0x00ef0000
+  # Set BSEL3 (BSEL3 for the Chaos's bselc)
+  set *(unsigned long *)($sfrbase + 0x5300) = 0x0a0a8040
+  set *(unsigned long *)($sfrbase + 0x5304) = 0x01120203
+  set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001
+  # Reset (P5=LED,P6.b4=LAN_RESET)
+  set *(unsigned short *)($sfrbase + 0x106c) = 0x0000
+  set *(unsigned char *)($sfrbase + 0x1016) = 0xff
+  set *(unsigned char *)($sfrbase + 0x1086) = 0xff
+  shell sleep 0.1
+  # swivel: 0=normal, 4=reverse
+#  set *(unsigned char *)($sfrbase + 0x1086) = 0x00
+  set *(unsigned char *)($sfrbase + 0x1086) = 0x04
+  set *(unsigned long *)(0x0c000330) = 0xffffffff
+  # Set mac address
+  set $lanc = (void*)0x0c000300
+  set *(unsigned long *)($lanc + 0x0000) = 0x00610010
+  set *(unsigned long *)($lanc + 0x0004) = 0x00200030
+  set *(unsigned long *)($lanc + 0x0008) = 0x00400050
+  set *(unsigned long *)($lanc + 0x000c) = 0x00600007
+end
+document lanc_init
+  LAN controller initialization
+  ex.) MAC address:  10 20 30 40 50 60
+end
+
+# LCD & CRT dual-head setting (8bpp)
+define dispc_init
+  set $sfrbase = 0x00ef0000
+  # BSEL4 Dispc
+  set *(unsigned long *)($sfrbase + 0x5400) = 0x0e0e8000
+  set *(unsigned long *)($sfrbase + 0x5404) = 0x0012220a
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb 0d32
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb 0d32
+end
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set  = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+end
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+  clock_init
+  shell sleep 0.1
+  port_init
+  sdram_init
+  lanc_init
+  dispc_init
+  set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x08002000
+  # INITRD_START
+  set *(unsigned long *)($param + 0x0010) = 0x082a0000
+  # INITRD_SIZE
+  set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d360000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d90000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $fp = 0
+  set $pc=0x08001000
+  si
+  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x08000030
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  setup
+  load_modules
+  boot
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+setup
+#load_module
+#set_breakpoints
+#boot
+
diff --git a/arch/m32r/mappi/dot.gdbinit.nommu b/arch/m32r/mappi/dot.gdbinit.nommu
new file mode 100644 (file)
index 0000000..1ca03f8
--- /dev/null
@@ -0,0 +1,245 @@
+# .gdbinit file
+# $Id$
+#-----
+# NOTE: this file is generated by a script, "gen_gdbinit.pl".
+# (Please type "gen_gdbinit.pl --help" and check the help message).
+# $ Id: gen_gdbinit.pl,v 1.5 2004/01/23 08:23:25 takata Exp $
+#-----
+# target platform: mappi
+
+# setting
+set width 0d70
+set radix 0d16
+debug_chaos
+
+# clk xin:cpu:bif:bus=25:200:50:50
+define clock_init
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 3
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x00000200
+end
+
+# Initialize programmable ports
+define port_init
+  set $sfrbase = 0x00ef0000
+  set *(unsigned short *)0x00ef1060 = 0x5555
+  set *(unsigned short *)0x00ef1062 = 0x5555
+  set *(unsigned short *)0x00ef1064 = 0x5555
+  set *(unsigned short *)0x00ef1066 = 0x5555
+  set *(unsigned short *)0x00ef1068 = 0x5555
+  set *(unsigned short *)0x00ef106a = 0x0000
+  set *(unsigned short *)0x00ef106e = 0x5555
+  set *(unsigned short *)0x00ef1070 = 0x5555
+  # LED ON
+  set *(unsigned char *)($sfrbase + 0x1015) = 0xff
+  set *(unsigned char *)($sfrbase + 0x1085) = 0xff
+  shell sleep 0.1
+  # LED OFF
+  set *(unsigned char *)($sfrbase + 0x1085) = 0x00
+end
+document port_init
+  P5=LED(output), P6.b4=LAN_RESET(output)
+end
+
+# Initialize SDRAM controller
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  # Initialize wait
+  shell sleep 0.1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c = 0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028 = 0x00051502
+  # Ch0-ADR (size:64MB)
+  set *(unsigned long *)0x00ef6020 = 0x00000004
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004 = 0x00010f05
+  # Access enable
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  SDRAM controller initialization
+  0x08000000 - 0x0bffffff (64MB)
+end
+
+# Initialize LAN controller
+define lanc_init
+  set $sfrbase = 0x00ef0000
+  # Set BSEL3 (BSEL3 for the Chaos's bselc)
+  set *(unsigned long *)($sfrbase + 0x5300) = 0x07078040
+  set *(unsigned long *)($sfrbase + 0x5304) = 0x01110102
+  set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001
+  # Reset (P5=LED,P6.b4=LAN_RESET)
+  set *(unsigned short *)($sfrbase + 0x106c) = 0x0000
+  set *(unsigned char *)($sfrbase + 0x1016) = 0xff
+  set *(unsigned char *)($sfrbase + 0x1086) = 0xff
+  shell sleep 0.1
+  # swivel: 0=normal, 4=reverse
+#  set *(unsigned char *)($sfrbase + 0x1086) = 0x00
+  set *(unsigned char *)($sfrbase + 0x1086) = 0x04
+  set *(unsigned long *)(0x0c000330) = 0xffffffff
+  # Set mac address
+  set $lanc = (void*)0x0c000300
+  set *(unsigned long *)($lanc + 0x0000) = 0x00610010
+  set *(unsigned long *)($lanc + 0x0004) = 0x00200030
+  set *(unsigned long *)($lanc + 0x0008) = 0x00400050
+  set *(unsigned long *)($lanc + 0x000c) = 0x00600007
+end
+document lanc_init
+  LAN controller initialization
+  ex.) MAC address:  10 20 30 40 50 60
+end
+
+# LCD & CRT dual-head setting (8bpp)
+define dispc_init
+  set $sfrbase = 0x00ef0000
+  # BSEL4 Dispc
+  set *(unsigned long *)($sfrbase + 0x5400) = 0x06078000
+  set *(unsigned long *)($sfrbase + 0x5404) = 0x00101101
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  set $nr_entries = $arg1
+  use_mon_code
+  while ($i < $nr_entries)
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb 0d32
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb 0d32
+end
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set  = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+end
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+  clock_init
+  shell sleep 0.1
+  port_init
+  sdram_init
+  lanc_init
+  dispc_init
+  set $evb=0x00000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x00002000
+  # INITRD_START
+  #set *(unsigned long *)($param + 0x0010) = 0x082a0000
+  # INITRD_SIZE
+  #set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d200000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d50000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.bbox-httpd nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $fp = 0
+  set $pc=0x00001000
+  set *(long *)0xfffffff4=0x8080
+#  b load_flat_binary
+#  set *(unsigned char *)0x08001003=0x63
+#  set *(unsigned char *)0x08001003=0x02
+  si
+#  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x08000030
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  setup
+  load_modules
+  boot
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+setup
+load_modules
+boot
+
diff --git a/arch/m32r/mappi/dot.gdbinit.smp b/arch/m32r/mappi/dot.gdbinit.smp
new file mode 100644 (file)
index 0000000..db0274f
--- /dev/null
@@ -0,0 +1,344 @@
+# .gdbinit file
+# $Id$
+
+# setting
+set width 0d70
+set radix 0d16
+debug_chaos
+
+# clk xin:cpu:bif:bus=1:4:2:1
+define clock_init_on
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 1
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 0x1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x0200
+#  set *(unsigned long *)0x00ef4008 = 0x0201
+end
+
+# clk xin:cpu:bif:bus=1:4:1:1
+define clock_init_on_1411
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 0x1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x0200
+end
+
+# clk xin:cpu:bif:bus=1:4:2:1
+define clock_init_on_1421
+  set *(unsigned long *)0x00ef4024 = 2
+  set *(unsigned long *)0x00ef4020 = 1
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 0x1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x0200
+end
+
+# clk xin:cpu:bif:bus=1:8:2:1
+define clock_init_on_1821
+  set *(unsigned long *)0x00ef4024 = 3
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 0x3
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x0200
+end
+
+# clk xin:cpu:bif:bus=1:8:4:1
+define clock_init_on_1841
+  set *(unsigned long *)0x00ef4024 = 3
+  set *(unsigned long *)0x00ef4020 = 1
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 0x3
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x0200
+end
+
+# clk xin:cpu:bif:bus=1:16:8:1
+define clock_init_on_11681
+  set *(unsigned long *)0x00ef4024 = 4
+  set *(unsigned long *)0x00ef4020 = 2
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  set *(unsigned long *)0x00ef4004 = 0x7
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4008 = 0x0200
+end
+
+# clk xin:cpu:bif:bus=1:1:1:1
+define clock_init_off
+  # CPU
+  set *(unsigned long *)0x00ef4010 = 0
+  set *(unsigned long *)0x00ef4014 = 0
+  # BIF
+  set *(unsigned long *)0x00ef4020 = 0
+  # BUS
+  set *(unsigned long *)0x00ef4024 = 0
+  # PLL
+  set *(unsigned long *)0x00ef4008 = 0x0000
+end
+
+# Initialize programmable ports
+define port_init
+  set $sfrbase = 0x00ef0000
+  set *(unsigned short *)0x00ef1060 = 0x5555
+  set *(unsigned short *)0x00ef1062 = 0x5555
+  set *(unsigned short *)0x00ef1064 = 0x5555
+  set *(unsigned short *)0x00ef1066 = 0x5555
+  set *(unsigned short *)0x00ef1068 = 0x5555
+  set *(unsigned short *)0x00ef106a = 0x0000
+  set *(unsigned short *)0x00ef106e = 0x5555
+  set *(unsigned short *)0x00ef1070 = 0x5555
+  # LED ON
+  set *(unsigned char *)($sfrbase + 0x1015) = 0xff
+  set *(unsigned char *)($sfrbase + 0x1085) = 0xff
+  shell sleep 0.1
+  # LED OFF
+  set *(unsigned char *)($sfrbase + 0x1085) = 0x00
+end
+document port_init
+  P5=LED(output), P6.b4=LAN_RESET(output)
+end
+
+# Initialize SDRAM controller for Mappi
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  # Initialize wait
+  shell sleep 0.1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c = 0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028 = 0x00010002
+  # Ch0-ADR
+  set *(unsigned long *)0x00ef6020 = 0x08000004
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004 = 0x00010107
+  # Access enable
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  Mappi SDRAM controller initialization
+  0x08000000 - 0x0bffffff (64MB)
+end
+
+# Initialize LAN controller for Mappi
+define lanc_init
+  set $sfrbase = 0x00ef0000
+  # Set BSEL3 (BSEL3 for the Chaos's bselc)
+#  set *(unsigned long *)($sfrbase + 0x5300) = 0x01018040
+#  set *(unsigned long *)($sfrbase + 0x5304) = 0x01011101
+  set *(unsigned long *)($sfrbase + 0x5300) = 0x04048000
+  set *(unsigned long *)($sfrbase + 0x5304) = 0x01011103
+  set *(unsigned long *)($sfrbase + 0x5308) = 0x00000001
+  # Reset (P5=LED,P6.b4=LAN_RESET)
+  set *(unsigned short *)($sfrbase + 0x106c) = 0x0000
+  set *(unsigned char *)($sfrbase + 0x1016) = 0xff
+  set *(unsigned char *)($sfrbase + 0x1086) = 0xff
+  shell sleep 0.1
+#  set *(unsigned char *)($sfrbase + 0x1086) = 0x00
+  set *(unsigned char *)($sfrbase + 0x1086) = 0x04
+  set *(unsigned long *)(0x0c000330) = 0xffffffff
+  # Set mac address
+  set $lanc = (void*)0x0c000300
+  set *(unsigned long *)($lanc + 0x0000) = 0x00610010
+  set *(unsigned long *)($lanc + 0x0004) = 0x00200030
+  set *(unsigned long *)($lanc + 0x0008) = 0x00400050
+  set *(unsigned long *)($lanc + 0x000c) = 0x00600007
+end
+document lanc_init
+  Mappi LAN controller initialization
+  ex.) MAC address:  10 20 30 40 50 60
+end
+
+# LCD & CRT dual-head setting (8bpp)
+define dispc_init
+  set $sfrbase = 0x00ef0000
+  # BSEL4 Dispc
+  # 20MHz
+#  set *(unsigned long *)($sfrbase + 0x5400) = 0x02028282
+#  set *(unsigned long *)($sfrbase + 0x5404) = 0x00122202
+  # 40MHz
+  set *(unsigned long *)($sfrbase + 0x5400) = 0x04048000
+  set *(unsigned long *)($sfrbase + 0x5404) = 0x00101103
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  use_mon_code
+  while ($i < 0d32 )
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb
+end
+
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set $task = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$fp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+end
+
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+#  clock_init_on_1411
+  clock_init_on_1421
+#  clock_init_on_1821
+#  clock_init_on_1841
+#  clock_init_on_11681
+#  clock_init_off
+  shell sleep 0.1
+  port_init
+  sdram_init
+  lanc_init
+  dispc_init
+  set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+#  load ramdisk_082a0000.mot
+#  load romfs_082a0000.mot
+#  use_mon_code
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x08002000
+  # INITRD_START
+# set *(unsigned long *)($param + 0x0010) = 0x082a0000
+  # INITRD_SIZE
+  set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d160000000
+#  set *(unsigned long *)($param + 0x0018) = 0d80000000
+#  set *(unsigned long *)($param + 0x0018) = 0d40000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d40000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=tty1 console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0"
+#  set {char[0x200]}($param + 0x100) = "console=tty1 root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.x nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $pc=0x08001000
+  set *(unsigned char *)0x08001003=0x03
+  si
+  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x08000030
+end
+
+## Boot MP
+define boot_mp
+  set_kernel_parameters
+  set *(unsigned long *)0x00f00000 = boot - 0x80000000
+  set *(unsigned long *)0x00eff2f8 = 0x2
+  x 0x00eff2f8
+
+  set $pc=0x08001000
+  si
+  c
+end
+document boot_mp
+  Boot BSP
+end
+
+## Boot UP
+define boot_up
+  set_kernel_parameters
+  set $pc=0x08001000
+  si
+  c
+end
+document boot_up
+  Boot BSP
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  setup
+  load_modules
+  boot_mp
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+setup
diff --git a/arch/m32r/mappi2/defconfig.vdec2 b/arch/m32r/mappi2/defconfig.vdec2
new file mode 100644 (file)
index 0000000..7f6125f
--- /dev/null
@@ -0,0 +1,698 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc1-bk21
+# Fri Nov 12 16:08:58 2004
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=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=y
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_PLAT_OPSPUT is not set
+# CONFIG_PLAT_OAKS32R is not set
+CONFIG_PLAT_MAPPI2=y
+# CONFIG_CHIP_M32700 is not set
+# CONFIG_CHIP_M32102 is not set
+CONFIG_CHIP_VDEC2=y
+# CONFIG_CHIP_OPSP is not set
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=16
+CONFIG_ISA_M32R2=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_PCMCIA_OBSOLETE is not set
+CONFIG_PCMCIA=y
+
+#
+# PC-card bridges
+#
+# CONFIG_TCIC is not set
+# CONFIG_M32R_CFC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=y
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_QLOGIC_1280_1040 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# 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 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=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_SMC91X=y
+# CONFIG_NE2000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
+# CONFIG_SERIAL_M32R_PLDSIO is not set
+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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_M32R_AR is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR 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=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/mappi2/dot.gdbinit.vdec2 b/arch/m32r/mappi2/dot.gdbinit.vdec2
new file mode 100644 (file)
index 0000000..797a830
--- /dev/null
@@ -0,0 +1,233 @@
+# .gdbinit file
+# $Id: dot.gdbinit.vdec2,v 1.2 2004/11/11 02:03:15 takata Exp $
+
+# setting
+set width 0d70
+set radix 0d16
+use_debug_dma
+
+# Initialize SDRAM controller for Mappi
+define sdram_init
+  # SDIR0
+  set *(unsigned long *)0x00ef6008=0x00000182
+  # SDIR1
+  set *(unsigned long *)0x00ef600c=0x00000001
+  # Initialize wait
+  shell sleep 1
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c=0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028=0x00041302
+  # Ch0-ADR
+  set *(unsigned long *)0x00ef6020=0x08000004
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004=0x00010705
+  # Access enable
+  set *(unsigned long *)0x00ef6024=0x00000001
+end
+document sdram_init
+  Mappi SDRAM controller initialization
+  0x08000000 - 0x0bffffff (64MB)
+end
+
+# Initialize SDRAM controller for Mappi
+define sdram_init2
+  # SDIR0
+  set *(unsigned long *)0x00ef6008=0x00000182
+  # Ch0-MOD
+  set *(unsigned long *)0x00ef602c=0x00000020
+  # Ch0-TR
+  set *(unsigned long *)0x00ef6028=0x00010002
+  # Ch0-ADR
+  set *(unsigned long *)0x00ef6020=0x08000004
+  # AutoRef On
+  set *(unsigned long *)0x00ef6004=0x00010107
+  # SDIR1
+  set *(unsigned long *)0x00ef600c=0x00000001
+  # Initialize wait
+  shell sleep 1
+  # Access enable
+  set *(unsigned long *)0x00ef6024=0x00000001
+  shell sleep 1
+end
+document sdram_init
+  Mappi SDRAM controller initialization
+  0x08000000 - 0x0bffffff (64MB)
+end
+
+# Initialize LAN controller for Mappi
+define lanc_init
+  # Set BSEL1 (BSEL3 for the Chaos's bselc)
+  #set *(unsigned long *)0x00ef5004 = 0x0fff330f
+  #set *(unsigned long *)0x00ef5004 = 0x01113301
+
+#  set *(unsigned long *)0x00ef5004 = 0x02011101
+#  set *(unsigned long *)0x00ef5004 = 0x04441104
+
+  # BSEL5
+#  set *(unsigned long *)0x00ef5014 = 0x0ccc310c
+#  set *(unsigned long *)0x00ef5014 = 0x0303310f
+#  set *(unsigned long *)0x00ef5014 = 0x01011102 -> NG
+#  set *(unsigned long *)0x00ef5014 = 0x03033103
+
+ set *(unsigned long *)0x00ef500c = 0x0b0b1304
+ set *(unsigned long *)0x00ef5010 = 0x03033302
+# set *(unsigned long *)0x00ef5018 = 0x02223302
+end
+
+# MMU enable
+define mmu_enable
+  set $evb=0x88000000
+  set *(unsigned long *)0xffff0024=1
+end
+
+# MMU disable
+define mmu_disable
+  set $evb=0
+  set *(unsigned long *)0xffff0024=0
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  while ($i < 0d16 )
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb
+end
+
+# Cache ON
+define set_cache_type
+  set $mctype = (void*)0xfffffff8
+# chaos
+# set *(unsigned long *)($mctype) = 0x0000c000
+# m32102 i-cache only
+  set *(unsigned long *)($mctype) = 0x00008000
+# m32102 d-cache only
+#  set *(unsigned long *)($mctype) = 0x00004000
+end
+define cache_on
+  set $param = (void*)0x08001000
+  set *(unsigned long *)($param) = 0x60ff6102
+end
+
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set $task = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[0x%08lX]\n",$evb
+
+  set $mests = *(unsigned long *)0xffff000c
+  set $mdeva = *(unsigned long *)0xffff0010
+  printf "MESTS[0x%08lX] MDEVA[0x%08lX]\n",$mests,$mdeva
+end
+
+
+# Setup all
+define setup
+  sdram_init
+#  lanc_init
+#  dispc_init
+#  set $evb=0x08000000
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+#  load busybox.mot
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x08001000
+
+  ## MOUNT_ROOT_RDONLY
+  set {long}($param+0x00)=0
+  ## RAMDISK_FLAGS
+  #set {long}($param+0x04)=0
+  ## ORIG_ROOT_DEV
+  #set {long}($param+0x08)=0x00000100
+  ## LOADER_TYPE
+  #set {long}($param+0x0C)=0
+  ## INITRD_START
+  set {long}($param+0x10)=0x082a0000
+  ## INITRD_SIZE
+  set {long}($param+0x14)=0d6200000
+
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d25000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d25000000
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+
+ set {char[0x200]}($param + 0x100) = "console=ttyS0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.2.6 nfsaddrs=192.168.0.102:192.168.0.1:192.168.0.1:255.255.255.0:mappi: \0"
+
+
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  debug_chaos
+  set $pc=0x08002000
+  set $fp=0
+  del b
+  si
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  setup
+  load_modules
+  boot
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+
+restart
+boot
+
+
diff --git a/arch/m32r/mm/Makefile b/arch/m32r/mm/Makefile
new file mode 100644 (file)
index 0000000..c51c1c3
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the Linux M32R-specific parts of the memory manager.
+#
+
+ifdef CONFIG_MMU
+obj-y  := init.o fault.o mmu.o extable.o ioremap.o cache.o page.o
+else
+obj-y  := init.o fault-nommu.o mmu.o extable.o ioremap-nommu.o cache.o page.o
+endif
+
+obj-$(CONFIG_DISCONTIGMEM)     += discontig.o
+
diff --git a/arch/m32r/mm/cache.c b/arch/m32r/mm/cache.c
new file mode 100644 (file)
index 0000000..e2dd92d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  linux/arch/m32r/mm/cache.c
+ *
+ *  Copyright (C) 2002  Hirokazu Takata
+ */
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <asm/pgtable.h>
+
+#undef MCCR
+
+#if defined(CONFIG_CHIP_XNUX2) || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_OPSP)
+/* Cache Control Register */
+#define MCCR           ((volatile unsigned long*)0xfffffffc)
+#define MCCR_CC                (1UL << 7)      /* Cache mode modify bit */
+#define MCCR_IIV       (1UL << 6)      /* I-cache invalidate */
+#define MCCR_DIV       (1UL << 5)      /* D-cache invalidate */
+#define MCCR_DCB       (1UL << 4)      /* D-cache copy back */
+#define MCCR_ICM       (1UL << 1)      /* I-cache mode [0:off,1:on] */
+#define MCCR_DCM       (1UL << 0)      /* D-cache mode [0:off,1:on] */
+#define MCCR_ICACHE_INV                (MCCR_CC|MCCR_IIV)
+#define MCCR_DCACHE_CB         (MCCR_CC|MCCR_DCB)
+#define MCCR_DCACHE_CBINV      (MCCR_CC|MCCR_DIV|MCCR_DCB)
+#define CHECK_MCCR(mccr)       (mccr = *MCCR)
+#elif defined(CONFIG_CHIP_M32102)
+#define MCCR           ((volatile unsigned long*)0xfffffffc)
+#define MCCR_IIV       (1UL << 8)      /* I-cache invalidate */
+#define MCCR_ICACHE_INV                MCCR_IIV
+#endif /* CONFIG_CHIP_XNUX2 || CONFIG_CHIP_M32700 */
+
+#ifndef MCCR
+#error Unknown cache type.
+#endif
+
+
+/* Copy back and invalidate D-cache and invalidate I-cache all */
+void _flush_cache_all(void)
+{
+#if defined(CONFIG_CHIP_M32102)
+       *MCCR = MCCR_ICACHE_INV;
+#else
+       unsigned long mccr;
+
+       /* Copyback and invalidate D-cache */
+       /* Invalidate I-cache */
+       *MCCR = MCCR_ICACHE_INV | MCCR_DCACHE_CBINV;
+       while ((mccr = *MCCR) & MCCR_IIV); /* loop while invalidating... */
+#endif
+}
+
+/* Copy back D-cache and invalidate I-cache all */
+void _flush_cache_copyback_all(void)
+{
+#if defined(CONFIG_CHIP_M32102)
+       *MCCR = MCCR_ICACHE_INV;
+#else
+       unsigned long mccr;
+
+       /* Copyback D-cache */
+       /* Invalidate I-cache */
+       *MCCR = MCCR_ICACHE_INV | MCCR_DCACHE_CB;
+       while ((mccr = *MCCR) & MCCR_IIV); /* loop while invalidating... */
+
+#endif
+}
+
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c
new file mode 100644 (file)
index 0000000..3e49ff6
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  linux/arch/m32r/mm/discontig.c
+ *
+ *  Discontig memory support
+ *
+ *  Copyright (c) 2003  Hitoshi Yamamoto
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/mmzone.h>
+#include <linux/initrd.h>
+
+#include <asm/setup.h>
+
+extern char _end[];
+
+struct pglist_data *node_data[MAX_NUMNODES];
+static bootmem_data_t node_bdata[MAX_NUMNODES] __initdata;
+
+pg_data_t m32r_node_data[MAX_NUMNODES];
+
+/* Memory profile */
+typedef struct {
+       unsigned long start_pfn;
+       unsigned long pages;
+       unsigned long holes;
+       unsigned long free_pfn;
+} mem_prof_t;
+static mem_prof_t mem_prof[MAX_NUMNODES];
+
+static void __init mem_prof_init(void)
+{
+       unsigned long start_pfn, holes, free_pfn;
+       const unsigned long zone_alignment = 1UL << (MAX_ORDER - 1);
+       unsigned long ul;
+       mem_prof_t *mp;
+
+       /* Node#0 SDRAM */
+       mp = &mem_prof[0];
+       mp->start_pfn = PFN_UP(CONFIG_MEMORY_START);
+       mp->pages = PFN_DOWN(CONFIG_MEMORY_SIZE);
+       mp->holes = 0;
+       mp->free_pfn = PFN_UP(__pa(_end));
+
+       /* Node#1 internal SRAM */
+       mp = &mem_prof[1];
+       start_pfn = free_pfn = PFN_UP(CONFIG_IRAM_START);
+       holes = 0;
+       if (start_pfn & (zone_alignment - 1)) {
+               ul = zone_alignment;
+               while (start_pfn >= ul)
+                       ul += zone_alignment;
+
+               start_pfn = ul - zone_alignment;
+               holes = free_pfn - start_pfn;
+       }
+
+       mp->start_pfn = start_pfn;
+       mp->pages = PFN_DOWN(CONFIG_IRAM_SIZE) + holes;
+       mp->holes = holes;
+       mp->free_pfn = PFN_UP(CONFIG_IRAM_START);
+}
+
+unsigned long __init setup_memory(void)
+{
+       unsigned long bootmap_size;
+       unsigned long min_pfn;
+       int nid;
+       mem_prof_t *mp;
+
+       max_low_pfn = 0;
+       min_low_pfn = -1;
+
+       mem_prof_init();
+
+       for (nid = 0 ; nid < numnodes ; nid++) {
+               mp = &mem_prof[nid];
+               NODE_DATA(nid)=(pg_data_t *)&m32r_node_data[nid];
+               NODE_DATA(nid)->bdata = &node_bdata[nid];
+               min_pfn = mp->start_pfn;
+               max_pfn = mp->start_pfn + mp->pages;
+               bootmap_size = init_bootmem_node(NODE_DATA(nid), mp->free_pfn,
+                       mp->start_pfn, max_pfn);
+
+               free_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn),
+                       PFN_PHYS(mp->pages));
+
+               reserve_bootmem_node(NODE_DATA(nid), PFN_PHYS(mp->start_pfn),
+                       PFN_PHYS(mp->free_pfn - mp->start_pfn) + bootmap_size);
+
+               if (max_low_pfn < max_pfn)
+                       max_low_pfn = max_pfn;
+
+               if (min_low_pfn > min_pfn)
+                       min_low_pfn = min_pfn;
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (LOADER_TYPE && INITRD_START) {
+               if (INITRD_START + INITRD_SIZE <= PFN_PHYS(max_low_pfn)) {
+                       reserve_bootmem_node(NODE_DATA(0), INITRD_START,
+                               INITRD_SIZE);
+                       initrd_start = INITRD_START ?
+                               INITRD_START + PAGE_OFFSET : 0;
+
+                       initrd_end = initrd_start + INITRD_SIZE;
+                       printk("initrd:start[%08lx],size[%08lx]\n",
+                               initrd_start, INITRD_SIZE);
+               } else {
+                       printk("initrd extends beyond end of memory "
+                               "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+                               INITRD_START + INITRD_SIZE,
+                               PFN_PHYS(max_low_pfn));
+
+                       initrd_start = 0;
+               }
+       }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+       return max_low_pfn;
+}
+
+#define START_PFN(nid) \
+       (NODE_DATA(nid)->bdata->node_boot_start >> PAGE_SHIFT)
+#define MAX_LOW_PFN(nid)       (NODE_DATA(nid)->bdata->node_low_pfn)
+
+unsigned long __init zone_sizes_init(void)
+{
+       unsigned long zones_size[MAX_NR_ZONES], zholes_size[MAX_NR_ZONES];
+       unsigned long low, start_pfn;
+       unsigned long holes = 0;
+       int nid, i;
+       mem_prof_t *mp;
+
+       pgdat_list = NULL;
+       for (nid = numnodes - 1 ; nid >= 0 ; nid--) {
+               NODE_DATA(nid)->pgdat_next = pgdat_list;
+               pgdat_list = NODE_DATA(nid);
+       }
+
+       for (nid = 0 ; nid < numnodes ; nid++) {
+               mp = &mem_prof[nid];
+               for (i = 0 ; i < MAX_NR_ZONES ; i++) {
+                       zones_size[i] = 0;
+                       zholes_size[i] = 0;
+               }
+               start_pfn = START_PFN(nid);
+               low = MAX_LOW_PFN(nid);
+               zones_size[ZONE_DMA] = low - start_pfn;
+               zholes_size[ZONE_DMA] = mp->holes;
+               holes += zholes_size[ZONE_DMA];
+
+               free_area_init_node(nid, NODE_DATA(nid), zones_size,
+                       start_pfn, zholes_size);
+       }
+
+       /*
+        * For test
+        *  Use all area of internal RAM.
+        *  see __alloc_pages()
+        */
+       NODE_DATA(1)->node_zones->pages_min = 0;
+       NODE_DATA(1)->node_zones->pages_low = 0;
+       NODE_DATA(1)->node_zones->pages_high = 0;
+
+       return holes;
+}
+
diff --git a/arch/m32r/mm/extable.c b/arch/m32r/mm/extable.c
new file mode 100644 (file)
index 0000000..9a97363
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+
+int fixup_exception(struct pt_regs *regs)
+{
+       const struct exception_table_entry *fixup;
+
+       fixup = search_exception_tables(regs->bpc);
+       if (fixup) {
+               regs->bpc = fixup->fixup;
+               return 1;
+       }
+
+       return 0;
+}
+
diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c
new file mode 100644 (file)
index 0000000..da267d8
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *  linux/arch/m32r/mm/fault.c
+ *
+ *  Copyright (c) 2001, 2002  Hitoshi Yamamoto, and H. Kondo
+ *
+ *  Some code taken from i386 version.
+ *    Copyright (C) 1995  Linus Torvalds
+ */
+
+/* $Id: fault-nommu.c,v 1.1 2004/03/30 06:40:59 sakugawa Exp $ */
+
+#include <linux/config.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/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/m32r.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+
+extern void die(const char *, struct pt_regs *, long);
+
+#ifndef CONFIG_SMP
+asmlinkage unsigned int tlb_entry_i_dat;
+asmlinkage unsigned int tlb_entry_d_dat;
+#define tlb_entry_i tlb_entry_i_dat
+#define tlb_entry_d tlb_entry_d_dat
+#else
+unsigned int tlb_entry_i_dat[NR_CPUS];
+unsigned int tlb_entry_d_dat[NR_CPUS];
+#define tlb_entry_i tlb_entry_i_dat[smp_processor_id()]
+#define tlb_entry_d tlb_entry_d_dat[smp_processor_id()]
+#endif
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out
+ */
+void bust_spinlocks(int yes)
+{
+       int loglevel_save = console_loglevel;
+
+       if (yes) {
+               oops_in_progress = 1;
+               return;
+       }
+#ifdef CONFIG_VT
+       unblank_screen();
+#endif
+       oops_in_progress = 0;
+       /*
+        * OK, the message is on the console.  Now we call printk()
+        * without oops_in_progress set so that printk will give klogd
+        * a poke.  Hold onto your hats...
+        */
+       console_loglevel = 15;          /* NMI oopser may have shut the console up */
+       printk(" ");
+       console_loglevel = loglevel_save;
+}
+
+void do_BUG(const char *file, int line)
+{
+       bust_spinlocks(1);
+       printk("kernel BUG at %s:%d!\n", file, line);
+}
+
+/*======================================================================*
+ * do_page_fault()
+ *======================================================================*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * ARGUMENT:
+ *  regs       : M32R SP reg.
+ *  error_code : See below
+ *  address    : M32R MMU MDEVA reg. (Operand ACE)
+ *             : M32R BPC reg. (Instruction ACE)
+ *
+ * error_code :
+ *  bit 0 == 0 means no page found, 1 means protection fault
+ *  bit 1 == 0 means read, 1 means write
+ *  bit 2 == 0 means kernel, 1 means user-mode
+ *======================================================================*/
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
+  unsigned long address)
+{
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+
+       bust_spinlocks(1);
+
+       if (address < PAGE_SIZE)
+               printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+       else
+               printk(KERN_ALERT "Unable to handle kernel paging request");
+       printk(" at virtual address %08lx\n",address);
+       printk(" printing bpc:\n");
+       printk(KERN_ALERT "bpc = %08lx\n", regs->bpc);
+
+       die("Oops", regs, error_code);
+       bust_spinlocks(0);
+       do_exit(SIGKILL);
+}
+
+/*======================================================================*
+ * update_mmu_cache()
+ *======================================================================*/
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
+       pte_t pte)
+{
+       BUG();
+}
+
+/*======================================================================*
+ * flush_tlb_page() : flushes one page
+ *======================================================================*/
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       BUG();
+}
+
+/*======================================================================*
+ * flush_tlb_range() : flushes a range of pages
+ *======================================================================*/
+void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+       unsigned long end)
+{
+       BUG();
+}
+
+/*======================================================================*
+ * flush_tlb_mm() : flushes the specified mm context TLB's
+ *======================================================================*/
+void local_flush_tlb_mm(struct mm_struct *mm)
+{
+       BUG();
+}
+
+/*======================================================================*
+ * flush_tlb_all() : flushes all processes TLBs
+ *======================================================================*/
+void local_flush_tlb_all(void)
+{
+       BUG();
+}
+
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
new file mode 100644 (file)
index 0000000..393ff03
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ *  linux/arch/m32r/mm/fault.c
+ *
+ *  Copyright (c) 2001, 2002  Hitoshi Yamamoto, and H. Kondo
+ *
+ *  Some code taken from i386 version.
+ *    Copyright (C) 1995  Linus Torvalds
+ */
+
+/* $Id$ */
+
+#include <linux/config.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/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>             /* For unblank_screen() */
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+#include <asm/m32r.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+
+extern void die(const char *, struct pt_regs *, long);
+
+#ifndef CONFIG_SMP
+asmlinkage unsigned int tlb_entry_i_dat;
+asmlinkage unsigned int tlb_entry_d_dat;
+#define tlb_entry_i tlb_entry_i_dat
+#define tlb_entry_d tlb_entry_d_dat
+#else
+unsigned int tlb_entry_i_dat[NR_CPUS];
+unsigned int tlb_entry_d_dat[NR_CPUS];
+#define tlb_entry_i tlb_entry_i_dat[smp_processor_id()]
+#define tlb_entry_d tlb_entry_d_dat[smp_processor_id()]
+#endif
+
+extern void init_tlb(void);
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out
+ */
+void bust_spinlocks(int yes)
+{
+       int loglevel_save = console_loglevel;
+
+       if (yes) {
+               oops_in_progress = 1;
+               return;
+       }
+#ifdef CONFIG_VT
+       unblank_screen();
+#endif
+       oops_in_progress = 0;
+       /*
+        * OK, the message is on the console.  Now we call printk()
+        * without oops_in_progress set so that printk will give klogd
+        * a poke.  Hold onto your hats...
+        */
+       console_loglevel = 15;          /* NMI oopser may have shut the console up */
+       printk(" ");
+       console_loglevel = loglevel_save;
+}
+
+/*======================================================================*
+ * do_page_fault()
+ *======================================================================*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * ARGUMENT:
+ *  regs       : M32R SP reg.
+ *  error_code : See below
+ *  address    : M32R MMU MDEVA reg. (Operand ACE)
+ *             : M32R BPC reg. (Instruction ACE)
+ *
+ * error_code :
+ *  bit 0 == 0 means no page found, 1 means protection fault
+ *  bit 1 == 0 means read, 1 means write
+ *  bit 2 == 0 means kernel, 1 means user-mode
+ *  bit 3 == 0 means data, 1 means instruction
+ *======================================================================*/
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
+  unsigned long address)
+{
+       struct task_struct *tsk;
+       struct mm_struct *mm;
+       struct vm_area_struct * vma;
+       unsigned long page, addr;
+       int write;
+       siginfo_t info;
+
+       /*
+        * If BPSW IE bit enable --> set PSW IE bit
+        */
+       if (regs->psw & M32R_PSW_BIE)
+               local_irq_enable();
+
+       tsk = current;
+
+       info.si_code = SEGV_MAPERR;
+
+       /*
+        * We fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+        *
+        * NOTE! We MUST NOT take any locks for this case. We may
+        * be in an interrupt or a critical region, and should
+        * only copy the information from the master page table,
+        * nothing more.
+        *
+        * This verifies that the fault happens in kernel space
+        * (error_code & 4) == 0, and that the fault was not a
+        * protection error (error_code & 1) == 0.
+        */
+       if (address >= TASK_SIZE && !(error_code & 4))
+               goto vmalloc_fault;
+
+       mm = tsk->mm;
+
+       /*
+        * If we're in an interrupt or have no user context or are running in an
+        * atomic region then we must not take the fault..
+        */
+       if (in_atomic() || !mm)
+               goto bad_area_nosemaphore;
+
+       /* When running in the kernel we expect faults to occur only to
+        * addresses in user space.  All other faults represent errors in the
+        * kernel and should generate an OOPS.  Unfortunatly, in the case of an
+        * erroneous fault occuring in a code path which already holds mmap_sem
+        * we will deadlock attempting to validate the fault against the
+        * address space.  Luckily the kernel only validly references user
+        * space from well defined areas of code, which are listed in the
+        * exceptions table.
+        *
+        * As the vast majority of faults will be valid we will only perform
+        * the source reference check when there is a possibilty of a deadlock.
+        * Attempt to lock the address space, if we cannot we then validate the
+        * source.  If this is invalid we can skip the address space check,
+        * thus avoiding the deadlock.
+        */
+       if (!down_read_trylock(&mm->mmap_sem)) {
+               if ((error_code & 4) == 0 &&
+                   !search_exception_tables(regs->psw))
+                       goto bad_area_nosemaphore;
+               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 0
+       if (error_code & 4) {
+               /*
+                * accessing the stack below "spu" is always a bug.
+                * The "+ 4" is there due to the push instruction
+                * doing pre-decrement on the stack and that
+                * doesn't show up until later..
+                */
+               if (address + 4 < regs->spu)
+                       goto bad_area;
+       }
+#endif
+       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;
+       write = 0;
+       switch (error_code & 3) {
+               default:        /* 3: write, present */
+                       /* fall through */
+               case 2:         /* write, not present */
+                       if (!(vma->vm_flags & VM_WRITE))
+                               goto bad_area;
+                       write++;
+                       break;
+               case 1:         /* read, present */
+               case 0:         /* read, not present */
+                       if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                               goto bad_area;
+       }
+
+survive:
+       /*
+        * If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+       addr = (address & PAGE_MASK) | (error_code & 8);
+       switch (handle_mm_fault(mm, vma, addr, write)) {
+               case VM_FAULT_MINOR:
+                       tsk->min_flt++;
+                       break;
+               case VM_FAULT_MAJOR:
+                       tsk->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);
+
+bad_area_nosemaphore:
+       /* User mode accesses just cause a SIGSEGV */
+       if (error_code & 4) {
+               tsk->thread.address = address;
+               tsk->thread.error_code = error_code | (address >= TASK_SIZE);
+               tsk->thread.trap_no = 14;
+               info.si_signo = SIGSEGV;
+               info.si_errno = 0;
+               /* info.si_code has been set above */
+               info.si_addr = (void __user *)address;
+               force_sig_info(SIGSEGV, &info, tsk);
+               return;
+       }
+
+no_context:
+       /* Are we prepared to handle this kernel fault?  */
+       if (fixup_exception(regs))
+               return;
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+
+       bust_spinlocks(1);
+
+       if (address < PAGE_SIZE)
+               printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+       else
+               printk(KERN_ALERT "Unable to handle kernel paging request");
+       printk(" at virtual address %08lx\n",address);
+       printk(KERN_ALERT " printing bpc:\n");
+       printk("%08lx\n", regs->bpc);
+       page = *(unsigned long *)MPTB;
+       page = ((unsigned long *) page)[address >> PGDIR_SHIFT];
+       printk(KERN_ALERT "*pde = %08lx\n", page);
+       if (page & _PAGE_PRESENT) {
+               page &= PAGE_MASK;
+               address &= 0x003ff000;
+               page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
+               printk(KERN_ALERT "*pte = %08lx\n", page);
+       }
+       die("Oops", regs, error_code);
+       bust_spinlocks(0);
+       do_exit(SIGKILL);
+
+/*
+ * 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 (tsk->pid == 1) {
+               yield();
+               down_read(&mm->mmap_sem);
+               goto survive;
+       }
+       printk("VM: killing process %s\n", tsk->comm);
+       if (error_code & 4)
+               do_exit(SIGKILL);
+       goto no_context;
+
+do_sigbus:
+       up_read(&mm->mmap_sem);
+
+       /* Kernel mode? Handle exception or die */
+       if (!(error_code & 4))
+               goto no_context;
+
+       tsk->thread.address = address;
+       tsk->thread.error_code = error_code;
+       tsk->thread.trap_no = 14;
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void __user *)address;
+       force_sig_info(SIGBUS, &info, tsk);
+       return;
+
+vmalloc_fault:
+       {
+               /*
+                * Synchronize this task's top level page-table
+                * with the 'reference' page table.
+                *
+                * Do _not_ use "tsk" here. We might be inside
+                * an interrupt in the middle of a task switch..
+                */
+               int offset = pgd_index(address);
+               pgd_t *pgd, *pgd_k;
+               pmd_t *pmd, *pmd_k;
+               pte_t *pte_k;
+
+               pgd = (pgd_t *)*(unsigned long *)MPTB;
+               pgd = offset + (pgd_t *)pgd;
+               pgd_k = init_mm.pgd + offset;
+
+               if (!pgd_present(*pgd_k))
+                       goto no_context;
+
+               /*
+                * set_pgd(pgd, *pgd_k); here would be useless on PAE
+                * and redundant with the set_pmd() on non-PAE.
+                */
+
+               pmd = pmd_offset(pgd, address);
+               pmd_k = pmd_offset(pgd_k, address);
+               if (!pmd_present(*pmd_k))
+                       goto no_context;
+               set_pmd(pmd, *pmd_k);
+
+               pte_k = pte_offset_kernel(pmd_k, address);
+               if (!pte_present(*pte_k))
+                       goto no_context;
+
+               addr = (address & PAGE_MASK) | (error_code & 8);
+               update_mmu_cache(NULL, addr, *pte_k);
+               return;
+       }
+}
+
+/*======================================================================*
+ * update_mmu_cache()
+ *======================================================================*/
+#define TLB_MASK       (NR_TLB_ENTRIES - 1)
+#define ITLB_END       (unsigned long *)(ITLB_BASE + (NR_TLB_ENTRIES * 8))
+#define DTLB_END       (unsigned long *)(DTLB_BASE + (NR_TLB_ENTRIES * 8))
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr,
+       pte_t pte)
+{
+       unsigned long *entry1, *entry2;
+       unsigned long pte_data, flags;
+       unsigned int *entry_dat;
+       int inst = vaddr & 8;
+       int i;
+
+       /* Ptrace may call this routine. */
+       if (vma && current->active_mm != vma->vm_mm)
+               return;
+
+       local_irq_save(flags);
+
+       vaddr = (vaddr & PAGE_MASK) | get_asid();
+
+#ifdef CONFIG_CHIP_OPSP
+       entry1 = (unsigned long *)ITLB_BASE;
+       for(i = 0 ; i < NR_TLB_ENTRIES; i++) {
+               if(*entry1++ == vaddr) {
+                       pte_data = pte_val(pte);
+                       set_tlb_data(entry1, pte_data);
+                       break;
+               }
+               entry1++;
+       }
+       entry2 = (unsigned long *)DTLB_BASE;
+       for(i = 0 ; i < NR_TLB_ENTRIES ; i++) {
+               if(*entry2++ == vaddr) {
+                       pte_data = pte_val(pte);
+                       set_tlb_data(entry2, pte_data);
+                       break;
+               }
+               entry2++;
+       }
+       local_irq_restore(flags);
+       return;
+#else
+       pte_data = pte_val(pte);
+
+       /*
+        * Update TLB entries
+        *  entry1: ITLB entry address
+        *  entry2: DTLB entry address
+        */
+       __asm__ __volatile__ (
+               "seth   %0, #high(%4)   \n\t"
+               "st     %2, @(%5, %0)   \n\t"
+               "ldi    %1, #1          \n\t"
+               "st     %1, @(%6, %0)   \n\t"
+               "add3   r4, %0, %7      \n\t"
+               ".fillinsn              \n"
+               "1:                     \n\t"
+               "ld     %1, @(%6, %0)   \n\t"
+               "bnez   %1, 1b          \n\t"
+               "ld     %0, @r4+        \n\t"
+               "ld     %1, @r4         \n\t"
+               "st     %3, @+%0        \n\t"
+               "st     %3, @+%1        \n\t"
+               : "=&r" (entry1), "=&r" (entry2)
+               : "r" (vaddr), "r" (pte_data), "i" (MMU_REG_BASE),
+               "i" (MSVA_offset), "i" (MTOP_offset), "i" (MIDXI_offset)
+               : "r4", "memory"
+       );
+
+       if ((!inst && entry2 >= DTLB_END) || (inst && entry1 >= ITLB_END))
+               goto notfound;
+
+found:
+       local_irq_restore(flags);
+
+       return;
+
+       /* Valid entry not found */
+notfound:
+       /*
+        * Update ITLB or DTLB entry
+        *  entry1: TLB entry address
+        *  entry2: TLB base address
+        */
+       if (!inst) {
+               entry2 = (unsigned long *)DTLB_BASE;
+               entry_dat = &tlb_entry_d;
+       } else {
+               entry2 = (unsigned long *)ITLB_BASE;
+               entry_dat = &tlb_entry_i;
+       }
+       entry1 = entry2 + (((*entry_dat - 1) & TLB_MASK) << 1);
+
+       for (i = 0 ; i < NR_TLB_ENTRIES ; i++) {
+               if (!(entry1[1] & 2))   /* Valid bit check */
+                       break;
+
+               if (entry1 != entry2)
+                       entry1 -= 2;
+               else
+                       entry1 += TLB_MASK << 1;
+       }
+
+       if (i >= NR_TLB_ENTRIES) {      /* Empty entry not found */
+               entry1 = entry2 + (*entry_dat << 1);
+               *entry_dat = (*entry_dat + 1) & TLB_MASK;
+       }
+       *entry1++ = vaddr;      /* Set TLB tag */
+       set_tlb_data(entry1, pte_data);
+
+       goto found;
+#endif
+}
+
+/*======================================================================*
+ * flush_tlb_page() : flushes one page
+ *======================================================================*/
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       if (vma->vm_mm && mm_context(vma->vm_mm) != NO_CONTEXT) {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               page &= PAGE_MASK;
+               page |= (mm_context(vma->vm_mm) & MMU_CONTEXT_ASID_MASK);
+               __flush_tlb_page(page);
+               local_irq_restore(flags);
+       }
+}
+
+/*======================================================================*
+ * flush_tlb_range() : flushes a range of pages
+ *======================================================================*/
+void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+       unsigned long end)
+{
+       struct mm_struct *mm;
+
+       mm = vma->vm_mm;
+       if (mm_context(mm) != NO_CONTEXT) {
+               unsigned long flags;
+               int size;
+
+               local_irq_save(flags);
+               size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+               if (size > (NR_TLB_ENTRIES / 4)) { /* Too many TLB to flush */
+                       mm_context(mm) = NO_CONTEXT;
+                       if (mm == current->mm)
+                               activate_context(mm);
+               } else {
+                       unsigned long asid;
+
+                       asid = mm_context(mm) & MMU_CONTEXT_ASID_MASK;
+                       start &= PAGE_MASK;
+                       end += (PAGE_SIZE - 1);
+                       end &= PAGE_MASK;
+
+                       start |= asid;
+                       end   |= asid;
+                       while (start < end) {
+                               __flush_tlb_page(start);
+                               start += PAGE_SIZE;
+                       }
+               }
+               local_irq_restore(flags);
+       }
+}
+
+/*======================================================================*
+ * flush_tlb_mm() : flushes the specified mm context TLB's
+ *======================================================================*/
+void local_flush_tlb_mm(struct mm_struct *mm)
+{
+       /* Invalidate all TLB of this process. */
+       /* Instead of invalidating each TLB, we get new MMU context. */
+       if (mm_context(mm) != NO_CONTEXT) {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               mm_context(mm) = NO_CONTEXT;
+               if (mm == current->mm)
+                       activate_context(mm);
+               local_irq_restore(flags);
+       }
+}
+
+/*======================================================================*
+ * flush_tlb_all() : flushes all processes TLBs
+ *======================================================================*/
+void local_flush_tlb_all(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       __flush_tlb_all();
+       local_irq_restore(flags);
+}
+
+/*======================================================================*
+ * init_mmu()
+ *======================================================================*/
+void __init init_mmu(void)
+{
+       tlb_entry_i = 0;
+       tlb_entry_d = 0;
+       mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
+       set_asid(mmu_context_cache & MMU_CONTEXT_ASID_MASK);
+       *(volatile unsigned long *)MPTB = (unsigned long)swapper_pg_dir;
+}
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
new file mode 100644 (file)
index 0000000..a290e37
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ *  linux/arch/m32r/mm/init.c
+ *
+ *  Copyright (c) 2001, 2002  Hitoshi Yamamoto
+ *
+ *  Some code taken from sh version.
+ *    Copyright (C) 1999  Niibe Yutaka
+ *    Based on linux/arch/i386/mm/init.c:
+ *      Copyright (C) 1995  Linus Torvalds
+ */
+
+/* $Id$ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+#include <linux/highmem.h>
+#include <asm/types.h>
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/setup.h>
+#include <asm/tlb.h>
+
+/* References to section boundaries */
+extern char _text, _etext, _edata;
+extern char __init_begin, __init_end;
+
+pgd_t swapper_pg_dir[1024];
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+void show_mem(void)
+{
+       int total = 0, reserved = 0;
+       int shared = 0, cached = 0;
+       int highmem = 0;
+       struct page *page;
+       pg_data_t *pgdat;
+       unsigned long i;
+
+       printk("Mem-info:\n");
+       show_free_areas();
+       printk("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->node_mem_map + i;
+                       total++;
+                       if (PageHighMem(page))
+                               highmem++;
+                       if (PageReserved(page))
+                               reserved++;
+                       else if (PageSwapCache(page))
+                               cached++;
+                       else if (page_count(page))
+                               shared += page_count(page) - 1;
+               }
+       }
+       printk("%d pages of RAM\n", total);
+       printk("%d pages of HIGHMEM\n",highmem);
+       printk("%d reserved pages\n",reserved);
+       printk("%d pages shared\n",shared);
+       printk("%d pages swap cached\n",cached);
+}
+
+/*
+ * Cache of MMU context last used.
+ */
+#ifndef CONFIG_SMP
+unsigned long mmu_context_cache_dat;
+#else
+unsigned long mmu_context_cache_dat[NR_CPUS];
+#endif
+static unsigned long hole_pages;
+
+/*
+ * function prototype
+ */
+void __init paging_init(void);
+void __init mem_init(void);
+void free_initmem(void);
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long, unsigned long);
+#endif
+
+/* It'd be good if these lines were in the standard header file. */
+#define START_PFN(nid) \
+       (NODE_DATA(nid)->bdata->node_boot_start >> PAGE_SHIFT)
+#define MAX_LOW_PFN(nid)       (NODE_DATA(nid)->bdata->node_low_pfn)
+
+#ifndef CONFIG_DISCONTIGMEM
+unsigned long __init zone_sizes_init(void)
+{
+       unsigned long  zones_size[MAX_NR_ZONES] = {0, 0, 0};
+       unsigned long  max_dma;
+       unsigned long  low;
+       unsigned long  start_pfn;
+
+#ifdef CONFIG_MMU
+       start_pfn = START_PFN(0);
+       max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+       low = MAX_LOW_PFN(0);
+
+       if (low < max_dma){
+               zones_size[ZONE_DMA] = low - start_pfn;
+               zones_size[ZONE_NORMAL] = 0;
+       } else {
+               zones_size[ZONE_DMA] = low - start_pfn;
+               zones_size[ZONE_NORMAL] = low - max_dma;
+       }
+#else
+       zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT;
+       zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT;
+       start_pfn = __MEMORY_START >> PAGE_SHIFT;
+#endif /* CONFIG_MMU */
+
+       free_area_init_node(0, NODE_DATA(0), zones_size, start_pfn, 0);
+
+       mem_map = contig_page_data.node_mem_map;
+
+       return 0;
+}
+#else  /* CONFIG_DISCONTIGMEM */
+extern unsigned long zone_sizes_init(void);
+#endif /* CONFIG_DISCONTIGMEM */
+
+/*======================================================================*
+ * paging_init() : sets up the page tables
+ *======================================================================*/
+void __init paging_init(void)
+{
+#ifdef CONFIG_MMU
+       int  i;
+       pgd_t *pg_dir;
+
+       /* We don't need kernel mapping as hardware support that. */
+       pg_dir = swapper_pg_dir;
+
+       for (i = 0 ; i < USER_PTRS_PER_PGD * 2 ; i++)
+               pgd_val(pg_dir[i]) = 0;
+#endif /* CONFIG_MMU */
+       hole_pages = zone_sizes_init();
+}
+
+int __init reservedpages_count(void)
+{
+       int reservedpages, nid, i;
+
+       reservedpages = 0;
+       for (nid = 0 ; nid < numnodes ; nid++)
+               for (i = 0 ; i < MAX_LOW_PFN(nid) - START_PFN(nid) ; i++)
+                       if (PageReserved(NODE_DATA(nid)->node_mem_map + i))
+                               reservedpages++;
+
+       return reservedpages;
+}
+
+/*======================================================================*
+ * mem_init() :
+ * orig : arch/sh/mm/init.c
+ *======================================================================*/
+void __init mem_init(void)
+{
+       int codesize, reservedpages, datasize, initsize;
+       int nid;
+#ifndef CONFIG_MMU
+       extern unsigned long memory_end;
+#endif
+
+       num_physpages = 0;
+       for (nid = 0 ; nid < numnodes ; nid++)
+               num_physpages += MAX_LOW_PFN(nid) - START_PFN(nid) + 1;
+
+       num_physpages -= hole_pages;
+
+#ifndef CONFIG_DISCONTIGMEM
+       max_mapnr = num_physpages;
+#endif /* CONFIG_DISCONTIGMEM */
+
+#ifdef CONFIG_MMU
+       high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0)));
+#else
+       high_memory = (void *)(memory_end & PAGE_MASK);
+#endif /* CONFIG_MMU */
+
+       /* clear the zero-page */
+       memset(empty_zero_page, 0, PAGE_SIZE);
+
+       /* this will put all low memory onto the freelists */
+       for (nid = 0 ; nid < numnodes ; nid++)
+               totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
+
+       reservedpages = reservedpages_count() - hole_pages;
+       codesize = (unsigned long) &_etext - (unsigned long)&_text;
+       datasize = (unsigned long) &_edata - (unsigned long)&_etext;
+       initsize = (unsigned long) &__init_end - (unsigned long)&__init_begin;
+
+       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
+               "%dk reserved, %dk data, %dk init)\n",
+               (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+               num_physpages << (PAGE_SHIFT-10),
+               codesize >> 10,
+               reservedpages << (PAGE_SHIFT-10),
+               datasize >> 10,
+               initsize >> 10);
+}
+
+/*======================================================================*
+ * free_initmem() :
+ * orig : arch/sh/mm/init.c
+ *======================================================================*/
+void free_initmem(void)
+{
+       unsigned long addr;
+
+       addr = (unsigned long)(&__init_begin);
+       for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(addr));
+               set_page_count(virt_to_page(addr), 1);
+               free_page(addr);
+               totalram_pages++;
+       }
+       printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", \
+         (int)(&__init_end - &__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+/*======================================================================*
+ * free_initrd_mem() :
+ * orig : arch/sh/mm/init.c
+ *======================================================================*/
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       unsigned long p;
+       for (p = start; p < end; p += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(p));
+               set_page_count(virt_to_page(p), 1);
+               free_page(p);
+               totalram_pages++;
+       }
+       printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+}
+#endif
+
diff --git a/arch/m32r/mm/ioremap-nommu.c b/arch/m32r/mm/ioremap-nommu.c
new file mode 100644 (file)
index 0000000..2759f2d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  linux/arch/m32r/mm/ioremap-nommu.c
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo
+ *
+ *  Taken from mips version.
+ *    (C) Copyright 1995 1996 Linus Torvalds
+ *    (C) Copyright 2001 Ralf Baechle
+ */
+
+/*
+ * 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/module.h>
+#include <asm/addrspace.h>
+#include <asm/byteorder.h>
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+
+#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL))
+
+void __iomem *
+__ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+       return (void *)phys_addr;
+}
+
+#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1)
+
+void iounmap(volatile void __iomem *addr)
+{
+}
+
diff --git a/arch/m32r/mm/ioremap.c b/arch/m32r/mm/ioremap.c
new file mode 100644 (file)
index 0000000..70c5905
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *  linux/arch/m32r/mm/ioremap.c
+ *
+ *  Copyright (c) 2001, 2002  Hiroyuki Kondo
+ *
+ *  Taken from mips version.
+ *    (C) Copyright 1995 1996 Linus Torvalds
+ *    (C) Copyright 2001 Ralf Baechle
+ */
+
+/*
+ * 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/module.h>
+#include <asm/addrspace.h>
+#include <asm/byteorder.h>
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+static inline void
+remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+              unsigned long phys_addr, unsigned long flags)
+{
+       unsigned long end;
+       unsigned long pfn;
+       pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
+                                  | _PAGE_WRITE | flags);
+
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       if (address >= end)
+               BUG();
+       pfn = phys_addr >> PAGE_SHIFT;
+       do {
+               if (!pte_none(*pte)) {
+                       printk("remap_area_pte: page already exists\n");
+                       BUG();
+               }
+               set_pte(pte, pfn_pte(pfn, pgprot));
+               address += PAGE_SIZE;
+               pfn++;
+               pte++;
+       } while (address && (address < end));
+}
+
+static inline int
+remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+              unsigned long phys_addr, unsigned long flags)
+{
+       unsigned long end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       phys_addr -= address;
+       if (address >= end)
+               BUG();
+       do {
+               pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address && (address < end));
+       return 0;
+}
+
+static int
+remap_area_pages(unsigned long address, unsigned long phys_addr,
+                unsigned long size, unsigned long flags)
+{
+       int error;
+       pgd_t * dir;
+       unsigned long end = address + size;
+
+       phys_addr -= address;
+       dir = pgd_offset(&init_mm, address);
+       flush_cache_all();
+       if (address >= end)
+               BUG();
+       spin_lock(&init_mm.page_table_lock);
+       do {
+               pmd_t *pmd;
+               pmd = pmd_alloc(&init_mm, dir, address);
+               error = -ENOMEM;
+               if (!pmd)
+                       break;
+               if (remap_area_pmd(pmd, address, end - address,
+                                        phys_addr + address, flags))
+                       break;
+               error = 0;
+               address = (address + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       } while (address && (address < end));
+       spin_unlock(&init_mm.page_table_lock);
+       flush_tlb_all();
+       return error;
+}
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+
+#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL))
+
+void __iomem *
+__ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+       void __iomem * addr;
+       struct vm_struct * area;
+       unsigned long offset, last_addr;
+
+       /* Don't allow wraparound or zero size */
+       last_addr = phys_addr + size - 1;
+       if (!size || last_addr < phys_addr)
+               return NULL;
+
+       /*
+        * Map objects in the low 512mb of address space using KSEG1, otherwise
+        * map using page tables.
+        */
+       if (IS_LOW512(phys_addr) && IS_LOW512(phys_addr + size - 1))
+               return (void *) KSEG1ADDR(phys_addr);
+
+       /*
+        * Don't allow anybody to remap normal RAM that we're using..
+        */
+       if (phys_addr < virt_to_phys(high_memory)) {
+               char *t_addr, *t_end;
+               struct page *page;
+
+               t_addr = __va(phys_addr);
+               t_end = t_addr + (size - 1);
+
+               for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
+                       if(!PageReserved(page))
+                               return NULL;
+       }
+
+       /*
+        * Mappings have to be page-aligned
+        */
+       offset = phys_addr & ~PAGE_MASK;
+       phys_addr &= PAGE_MASK;
+       size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+
+       /*
+        * Ok, go for it..
+        */
+       area = get_vm_area(size, VM_IOREMAP);
+       if (!area)
+               return NULL;
+       area->phys_addr = phys_addr;
+       addr = (void __iomem *) area->addr;
+       if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) {
+               vunmap((void __force *) addr);
+               return NULL;
+       }
+
+       return (void __iomem *) (offset + (char __iomem *)addr);
+}
+
+#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1)
+
+void iounmap(volatile void __iomem *addr)
+{
+       if (!IS_KSEG1(addr))
+               vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
+
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S
new file mode 100644 (file)
index 0000000..0c28f11
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ *  linux/arch/m32r/mm/mmu.S
+ *
+ *  Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+/* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */
+
+#include <linux/config.h>      /* CONFIG_MMU */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/smp.h>
+
+       .text
+#ifdef CONFIG_MMU
+
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/m32r.h>
+
+/*
+ * TLB Miss Exception handler
+ */
+       .balign 16
+ENTRY(tme_handler)
+       .global tlb_entry_i_dat
+       .global tlb_entry_d_dat
+
+       SWITCH_TO_KERNEL_STACK
+
+#if defined(CONFIG_ISA_M32R2)
+       st      r0, @-sp
+       st      r1, @-sp
+       st      r2, @-sp
+       st      r3, @-sp
+
+       seth    r3, #high(MMU_REG_BASE)
+       ld      r1, @(MESTS_offset, r3) ; r1: status     (MESTS reg.)
+       ld      r0, @(MDEVP_offset, r3) ; r0: PFN + ASID (MDEVP reg.)
+       st      r1, @(MESTS_offset, r3) ; clear status   (MESTS reg.)
+       and3    r1, r1, #(MESTS_IT)
+       bnez    r1, 1f                  ; instruction TLB miss?
+
+;; data TLB miss
+;;  input
+;;   r0: PFN + ASID (MDEVP reg.)
+;;   r1 - r3: free
+;;  output
+;;   r0: PFN + ASID
+;;   r1: TLB entry base address
+;;   r2: &tlb_entry_{i|d}_dat
+;;   r3: free
+
+#ifndef CONFIG_SMP
+       seth    r2, #high(tlb_entry_d_dat)
+       or3     r2, r2, #low(tlb_entry_d_dat)
+#else  /* CONFIG_SMP */
+       ldi     r1, #-8192
+       seth    r2, #high(tlb_entry_d_dat)
+       or3     r2, r2, #low(tlb_entry_d_dat)
+       and     r1, sp
+       ld      r1, @(16, r1)           ; current_thread_info->cpu
+       slli    r1, #2
+       add     r2, r1
+#endif /* !CONFIG_SMP */
+       seth    r1, #high(DTLB_BASE)
+       or3     r1, r1, #low(DTLB_BASE)
+       bra     2f
+
+       .balign 16
+       .fillinsn
+1:
+;; instrucntion TLB miss
+;;  input
+;;   r0: MDEVP reg. (included ASID)
+;;   r1 - r3: free
+;;  output
+;;   r0: PFN + ASID
+;;   r1: TLB entry base address
+;;   r2: &tlb_entry_{i|d}_dat
+;;   r3: free
+       ldi     r3, #-4096
+       and3    r0, r0, #(MMU_CONTEXT_ASID_MASK)
+       mvfc    r1, bpc
+       and     r1, r3
+       or      r0, r1                  ; r0: PFN + ASID
+#ifndef CONFIG_SMP
+       seth    r2, #high(tlb_entry_i_dat)
+       or3     r2, r2, #low(tlb_entry_i_dat)
+#else  /* CONFIG_SMP */
+       ldi     r1, #-8192
+       seth    r2, #high(tlb_entry_i_dat)
+       or3     r2, r2, #low(tlb_entry_i_dat)
+       and     r1, sp
+       ld      r1, @(16, r1)           ; current_thread_info->cpu
+       slli    r1, #2
+       add     r2, r1
+#endif /* !CONFIG_SMP */
+       seth    r1, #high(ITLB_BASE)
+       or3     r1, r1, #low(ITLB_BASE)
+
+       .fillinsn
+2:
+;; select TLB entry
+;;  input
+;;   r0: PFN + ASID
+;;   r1: TLB entry base address
+;;   r2: &tlb_entry_{i|d}_dat
+;;   r3: free
+;;  output
+;;   r0: PFN + ASID
+;;   r1: TLB entry address
+;;   r2, r3: free
+#ifdef CONFIG_ISA_DUAL_ISSUE
+       ld      r3, @r2         ||      srli    r1, #3
+#else
+       ld      r3, @r2
+       srli    r1, #3
+#endif
+       add     r1, r3
+       ; tlb_entry_{d|i}_dat++;
+       addi    r3, #1
+       and3    r3, r3, #(NR_TLB_ENTRIES - 1)
+#ifdef CONFIG_ISA_DUAL_ISSUE
+       st      r3, @r2         ||      slli    r1, #3
+#else
+       st      r3, @r2
+       slli    r1, #3
+#endif
+
+;; load pte
+;;  input
+;;   r0: PFN + ASID
+;;   r1: TLB entry address
+;;   r2, r3: free
+;;  output
+;;   r0: PFN + ASID
+;;   r1: TLB entry address
+;;   r2: pte_data
+;;   r3: free
+       ; pgd = *(unsigned long *)MPTB;
+       ld24    r2, #(-MPTB - 1)
+       srl3    r3, r0, #22
+#ifdef CONFIG_ISA_DUAL_ISSUE
+       not     r2, r2              ||  slli    r3, #2  ; r3: pgd offset
+#else
+       not     r2, r2
+       slli    r3, #2
+#endif
+       ld      r2, @r2                 ; r2: pgd base addr (MPTB reg.)
+       or      r3, r2                  ; r3: pmd addr
+
+       ; pmd = pmd_offset(pgd, address);
+       ld      r3, @r3                 ; r3: pmd data
+       ldi     r2, #-4096
+       beqz    r3, 3f                  ; pmd_none(*pmd) ?
+
+       ; pte = pte_offset(pmd, address);
+       and     r2, r3                  ; r2: pte base addr
+       srl3    r3, r0, #10
+       and3    r3, r3, #0xffc          ; r3: pte offset
+       or      r3, r2
+       seth    r2, #0x8000
+       or      r3, r2                  ; r3: pte addr
+
+       ; pte_data = (unsigned long)pte_val(*pte);
+       ld      r2, @r3                 ; r2: pte data
+       or3     r2, r2, #2              ; _PAGE_PRESENT(=2)
+
+       .fillinsn
+5:
+;; set tlb
+;;  input
+;;   r0: PFN + ASID
+;;   r1: TLB entry address
+;;   r2: pte_data
+;;   r3: free
+       st      r0, @r1                 ; set_tlb_tag(entry++, address);
+       st      r2, @+r1                ; set_tlb_data(entry, pte_data);
+
+       .fillinsn
+6:
+       ld      r3, @sp+
+       ld      r2, @sp+
+       ld      r1, @sp+
+       ld      r0, @sp+
+       rte
+
+       .fillinsn
+3:
+;; error
+;;  input
+;;   r0: PFN + ASID
+;;   r1: TLB entry address
+;;   r2, r3: free
+;;  output
+;;   r0: PFN + ASID
+;;   r1: TLB entry address
+;;   r2: pte_data
+;;   r3: free
+#ifdef CONFIG_ISA_DUAL_ISSUE
+       bra     5b                  ||  ldi     r2, #2
+#else
+       ldi     r2, #2          ; r2: pte_data = 0 | _PAGE_PRESENT(=2)
+       bra     5b
+#endif
+
+#elif defined (CONFIG_ISA_M32R)
+
+       st      sp, @-sp
+       st      r0, @-sp
+       st      r1, @-sp
+       st      r2, @-sp
+       st      r3, @-sp
+       st      r4, @-sp
+
+       seth    r3, #high(MMU_REG_BASE)
+       ld      r0, @(MDEVA_offset,r3)  ; r0: address  (MDEVA reg.)
+       mvfc    r2, bpc                 ; r2: bpc
+       ld      r1, @(MESTS_offset,r3)  ; r1: status   (MESTS reg.)
+       st      r1, @(MESTS_offset,r3)  ; clear status (MESTS reg.)
+       and3    r1, r1, #(MESTS_IT)
+       beqz    r1, 1f                  ; data TLB miss?
+
+;; instrucntion TLB miss
+       mv      r0, r2                  ; address = bpc;
+       ; entry = (unsigned long *)ITLB_BASE+tlb_entry_i*2;
+       seth    r3, #shigh(tlb_entry_i_dat)
+       ld      r4, @(low(tlb_entry_i_dat),r3)
+       sll3    r2, r4, #3
+       seth    r1, #high(ITLB_BASE)
+       or3     r1, r1, #low(ITLB_BASE)
+       add     r2, r1                  ; r2: entry
+       addi    r4, #1                  ; tlb_entry_i++;
+       and3    r4, r4, #(NR_TLB_ENTRIES-1)
+       st      r4, @(low(tlb_entry_i_dat),r3)
+       bra     2f
+       .fillinsn
+1:
+;; data TLB miss
+       ; entry = (unsigned long *)DTLB_BASE+tlb_entry_d*2;
+       seth    r3, #shigh(tlb_entry_d_dat)
+       ld      r4, @(low(tlb_entry_d_dat),r3)
+       sll3    r2, r4, #3
+       seth    r1, #high(DTLB_BASE)
+       or3     r1, r1, #low(DTLB_BASE)
+       add     r2, r1                  ; r2: entry
+       addi    r4, #1                  ; tlb_entry_d++;
+       and3    r4, r4, #(NR_TLB_ENTRIES-1)
+       st      r4, @(low(tlb_entry_d_dat),r3)
+       .fillinsn
+2:
+;; load pte
+; r0: address, r2: entry
+; r1,r3,r4: (free)
+       ; pgd = *(unsigned long *)MPTB;
+       ld24    r1, #(-MPTB-1)
+       not     r1, r1
+       ld      r1, @r1
+       srl3    r4, r0, #22
+       sll3    r3, r4, #2
+       add     r3, r1                  ; r3: pgd
+       ; pmd = pmd_offset(pgd, address);
+       ld      r1, @r3                 ; r1: pmd
+       beqz    r1, 3f                  ; pmd_none(*pmd) ?
+;
+       and3    r1, r1, #0xeff
+       ldi     r4, #611                ; _KERNPG_TABLE(=611)
+       beq     r1, r4, 4f              ; !pmd_bad(*pmd) ?
+       .fillinsn
+3:
+       ldi     r1, #0                  ; r1: pte_data = 0
+       bra     5f
+       .fillinsn
+4:
+       ; pte = pte_offset(pmd, address);
+       ld      r4, @r3                 ; r4: pte
+       ldi     r3, #-4096
+       and     r4, r3
+       srl3    r3, r0, #10
+       and3    r3, r3, #0xffc
+       add     r4, r3
+       seth    r3, #0x8000
+       add     r4, r3                  ; r4: pte
+       ; pte_data = (unsigned long)pte_val(*pte);
+       ld      r1, @r4                 ; r1: pte_data
+       .fillinsn
+
+;; set tlb
+; r0: address, r1: pte_data, r2: entry
+; r3,r4: (free)
+5:
+       ldi     r3, #-4096              ; set_tlb_tag(entry++, address);
+       and     r3, r0
+       seth    r4, #shigh(MASID)
+       ld      r4, @(low(MASID),r4)    ; r4: MASID
+       and3    r4, r4, #(MMU_CONTEXT_ASID_MASK)
+       or      r3, r4
+       st      r3, @r2
+       or3     r4, r1, #2              ; _PAGE_PRESENT(=2)
+       st      r4, @(4,r2)             ; set_tlb_data(entry, pte_data);
+
+       ld      r4, @sp+
+       ld      r3, @sp+
+       ld      r2, @sp+
+       ld      r1, @sp+
+       ld      r0, @sp+
+       ld      sp, @sp+
+       rte
+
+#else
+#error unknown isa configuration
+#endif
+
+ENTRY(init_tlb)
+;; Set MMU Register
+       seth    r0, #high(MMU_REG_BASE)  ; Set MMU_REG_BASE higher
+       or3     r0, r0, #low(MMU_REG_BASE)  ; Set MMU_REG_BASE lower
+       ldi     r1, #0
+       st      r1, @(MPSZ_offset,r0)   ; Set MPSZ Reg(Page size 4KB:0 16KB:1 64KB:2)
+       ldi     r1, #0
+       st      r1, @(MASID_offset,r0)  ; Set ASID Zero
+
+;; Set TLB
+       seth    r0, #high(ITLB_BASE)    ; Set ITLB_BASE higher
+       or3     r0, r0, #low(ITLB_BASE) ; Set ITLB_BASE lower
+       seth    r1, #high(DTLB_BASE)    ; Set DTLB_BASE higher
+       or3     r1, r1, #low(DTLB_BASE) ; Set DTLB_BASE lower
+       ldi     r2, #0
+       ldi     r3, #NR_TLB_ENTRIES
+       addi    r0, #-4
+       addi    r1, #-4
+clear_tlb:
+       st      r2, @+r0                ; VPA <- 0
+       st      r2, @+r0                ; PPA <- 0
+       st      r2, @+r1                ; VPA <- 0
+       st      r2, @+r1                ; PPA <- 0
+       addi    r3, #-1
+       bnez    r3, clear_tlb
+;;
+       jmp     r14
+
+ENTRY(m32r_itlb_entrys)
+ENTRY(m32r_otlb_entrys)
+
+#endif  /* CONFIG_MMU */
+
+.end
+
diff --git a/arch/m32r/mm/page.S b/arch/m32r/mm/page.S
new file mode 100644 (file)
index 0000000..a2e9367
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  linux/arch/m32r/mm/page.S
+ *
+ *  Clear/Copy page with CPU
+ *
+ *  Copyright (C) 2004  The Free Software Initiative of Japan
+ *
+ *  Written by Niibe Yutaka
+ *
+ * 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.
+ *
+ */
+       .text
+       .global copy_page
+       /*
+        * copy_page (to, from)
+        *
+        * PAGE_SIZE = 4096-byte
+        * Cache line = 16-byte
+        * 16 * 256
+        */
+       .align  4
+copy_page:
+       ldi     r2, #255
+       ld      r3, @r0         /* cache line allocate */
+       ld      r4, @r1+
+       ld      r5, @r1+
+       ld      r6, @r1+
+       ld      r7, @r1+
+       .fillinsn
+0:
+       st      r4, @r0
+       st      r5, @+r0
+       st      r6, @+r0
+       st      r7, @+r0
+       ld      r4, @r1+
+       addi    r0, #4
+       ld      r5, @r1+
+       ld      r6, @r1+
+       ld      r7, @r1+
+       ld      r3, @r0         /* cache line allocate */
+       addi    r2, #-1
+       bnez    r2, 0b
+
+       st      r4, @r0
+       st      r5, @+r0
+       st      r6, @+r0
+       st      r7, @+r0
+       jmp     r14
+
+       .text
+       .global clear_page
+       /*
+        * clear_page (to)
+        *
+        * PAGE_SIZE = 4096-byte
+        * Cache line = 16-byte
+        * 16 * 256
+        */
+       .align  4
+clear_page:
+       ldi     r2, #255
+       ldi     r4, #0
+       ld      r3, @r0         /* cache line allocate */
+       .fillinsn
+0:
+       st      r4, @r0
+       st      r4, @+r0
+       st      r4, @+r0
+       st      r4, @+r0
+       addi    r0, #4
+       ld      r3, @r0         /* cache line allocate */
+       addi    r2, #-1
+       bnez    r2, 0b
+
+       st      r4, @r0
+       st      r4, @+r0
+       st      r4, @+r0
+       st      r4, @+r0
+       jmp     r14
diff --git a/arch/m32r/oaks32r/defconfig.nommu b/arch/m32r/oaks32r/defconfig.nommu
new file mode 100644 (file)
index 0000000..816b53e
--- /dev/null
@@ -0,0 +1,521 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+# 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=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_PLAT_OPSPUT is not set
+CONFIG_PLAT_OAKS32R=y
+# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_CHIP_M32700 is not set
+CONFIG_CHIP_M32102=y
+# CONFIG_CHIP_VDEC2 is not set
+# CONFIG_CHIP_OPSP is not set
+CONFIG_ISA_M32R=y
+CONFIG_BUS_CLOCK=33333333
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x01000000
+CONFIG_MEMORY_SIZE=0x00800000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_PREEMPT=y
+# CONFIG_HAVE_DEC_LOCK is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+CONFIG_M32R_NE2000=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_FLAT=y
+# CONFIG_BINFMT_ZFLAT is not set
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_M32R_SIO=y
+CONFIG_SERIAL_M32R_SIO_CONSOLE=y
+# CONFIG_SERIAL_M32R_PLDSIO is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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 is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+# 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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/oaks32r/dot.gdbinit.nommu b/arch/m32r/oaks32r/dot.gdbinit.nommu
new file mode 100644 (file)
index 0000000..48420f7
--- /dev/null
@@ -0,0 +1,155 @@
+# .gdbinit file
+# $Id: dot.gdbinit.oaks32r,v 1.2 2004/04/15 02:33:14 takata Exp $
+#-----
+# NOTE: this file is generated by a script, "gen_gdbinit.pl".
+# (Please type "gen_gdbinit.pl --help" and check the help message).
+# $ Id: gen_gdbinit.pl,v 1.10 2004/04/15 02:10:45 takata Exp $
+#-----
+# target platform: oaks32r
+
+# setting
+set width 0d70
+set radix 0d16
+
+# clk xin:cpu:bus=16:66:33
+define clock_init
+  set *(unsigned long *)0x00ef4008 = 1
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef4000 = 0x00020100
+end
+
+# Initialize programmable ports
+define port_init
+  set *(unsigned long *)0x00ef1000 = 0x1
+  set *(unsigned long *)0x00ef1060 = 0x01400001
+  set *(unsigned long *)0x00ef1064 = 0x00015555
+  set *(unsigned long *)0x00ef1068 = 0x55555050
+  set *(unsigned long *)0x00ef106c = 0x05150040
+end
+
+# Initialize SDRAM controller
+define sdram_init
+  set *(unsigned long *)0x00ef6008 = 0x00000182
+  set *(unsigned long *)0x00ef600c = 0x00000001
+  shell sleep 0.1
+  set *(unsigned long *)0x00ef602c = 0x00000010
+  set *(unsigned long *)0x00ef6028 = 0x00000300
+  set *(unsigned long *)0x00ef6048 = 0x00000001
+  set *(unsigned long *)0x00ef6020 = 0x01000041
+  set *(unsigned long *)0x00ef6004 = 0x00010117
+  set *(unsigned long *)0x00ef6010 = 0x00000001
+  set *(unsigned long *)0x00ef6024 = 0x00000001
+end
+document sdram_init
+  SDRAM controller initialization
+  0x01000000 - 0x017fffff (8MB)
+end
+
+# Initialize LAN controller
+define lanc_init
+  set *(unsigned long *)0x00ef5008 = 0x03031303
+  #RST DRV (P64)
+  set *(unsigned char *)0x00ef1046 = 0x08
+  set *(unsigned char *)0x00ef1026 = 0xff
+  set *(unsigned char *)0x00ef1026 = 0x00
+  set *(unsigned short *)0x02000630 = 0xffff
+end
+
+# Show current task structure
+define show_current
+  set $current = $spi & 0xffffe000
+  printf "$current=0x%08lX\n",$current
+  print *(struct task_struct *)$current
+end
+
+# Show user assigned task structure
+define show_task
+  set  = $arg0 & 0xffffe000
+  printf "$task=0x%08lX\n",$task
+  print *(struct task_struct *)$task
+end
+document show_task
+  Show user assigned task structure
+  arg0 : task structure address
+end
+
+# Show M32R registers
+define show_regs
+  printf " R0[0x%08lX]   R1[0x%08lX]   R2[0x%08lX]   R3[0x%08lX]\n",$r0,$r1,$r2,$r3
+  printf " R4[0x%08lX]   R5[0x%08lX]   R6[0x%08lX]   R7[0x%08lX]\n",$r4,$r5,$r6,$r7
+  printf " R8[0x%08lX]   R9[0x%08lX]  R10[0x%08lX]  R11[0x%08lX]\n",$r8,$r9,$r10,$r11
+  printf "R12[0x%08lX]   FP[0x%08lX]   LR[0x%08lX]   SP[0x%08lX]\n",$r12,$fp,$lr,$sp
+  printf "PSW[0x%08lX]  CBR[0x%08lX]  SPI[0x%08lX]  SPU[0x%08lX]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[0x%08lX]   PC[0x%08lX] ACCL[0x%08lX] ACCH[0x%08lX]\n",$bpc,$pc,$accl,$acch
+end
+
+# Setup all
+define setup
+  use_mon_code
+  set *(unsigned int)0xfffffffc=0x60
+  shell sleep 0.1
+  clock_init
+  shell sleep 0.1
+  port_init
+  sdram_init
+  lanc_init
+end
+
+# Load modules
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x01002000
+  # INITRD_START
+  set *(unsigned long *)($param + 0x0010) = 0x00000000
+  # INITRD_SIZE
+  set *(unsigned long *)($param + 0x0014) = 0x00000000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d66666667
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d33333333
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+#  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/rootfs nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0"
+  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x root=/dev/nfsroot nfsroot=192.168.0.1:/project/m32r-linux/export/root.busybox.flat nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \0"
+end
+
+# Boot
+define boot
+  set_kernel_parameters
+  set $fp = 0
+  set $pc = 0x01001000
+  si
+  c
+end
+
+# Set breakpoints
+define set_breakpoints
+  b *0x00000020
+  b *0x00000030
+end
+
+# Restart
+define restart
+  sdireset
+  sdireset
+  setup
+  load_modules
+  boot
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+setup
+#load_modules
+#set_breakpoints
+#boot
+
diff --git a/arch/m32r/oprofile/Kconfig b/arch/m32r/oprofile/Kconfig
new file mode 100644 (file)
index 0000000..19d3773
--- /dev/null
@@ -0,0 +1,23 @@
+
+menu "Profiling support"
+       depends on EXPERIMENTAL
+
+config PROFILING
+       bool "Profiling support (EXPERIMENTAL)"
+       help
+         Say Y here to enable the extended profiling support mechanisms used
+         by profilers such as OProfile.
+
+
+config OPROFILE
+       tristate "OProfile system profiling (EXPERIMENTAL)"
+       depends on PROFILING
+       help
+         OProfile is a profiling system capable of profiling the
+         whole system, include the kernel, kernel modules, libraries,
+         and applications.
+
+         If unsure, say N.
+
+endmenu
+
diff --git a/arch/m32r/oprofile/Makefile b/arch/m32r/oprofile/Makefile
new file mode 100644 (file)
index 0000000..06e7c81
--- /dev/null
@@ -0,0 +1,9 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
+               oprof.o cpu_buffer.o buffer_sync.o \
+               event_buffer.o oprofile_files.o \
+               oprofilefs.o oprofile_stats.o \
+               timer_int.o )
+
+oprofile-y := $(DRIVER_OBJS) init.o
diff --git a/arch/m32r/oprofile/init.c b/arch/m32r/oprofile/init.c
new file mode 100644 (file)
index 0000000..f5843c8
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * @file init.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/oprofile.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+extern void timer_init(struct oprofile_operations ** ops);
+
+int __init oprofile_arch_init(struct oprofile_operations ** ops)
+{
+       return -ENODEV;
+}
+
+
+void oprofile_arch_exit(void)
+{
+}
diff --git a/arch/m32r/opsput/defconfig.opsput b/arch/m32r/opsput/defconfig.opsput
new file mode 100644 (file)
index 0000000..07eae96
--- /dev/null
@@ -0,0 +1,598 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_M32R=y
+CONFIG_UID16=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+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=y
+CONFIG_IKCONFIG=y
+# CONFIG_IKCONFIG_PROC is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+# CONFIG_PLAT_MAPPI is not set
+# CONFIG_PLAT_USRV is not set
+# CONFIG_PLAT_M32700UT is not set
+CONFIG_PLAT_OPSPUT=y
+# CONFIG_PLAT_OAKS32R is not set
+# CONFIG_PLAT_MAPPI2 is not set
+# CONFIG_CHIP_M32700 is not set
+# CONFIG_CHIP_M32102 is not set
+# CONFIG_CHIP_VDEC2 is not set
+CONFIG_CHIP_OPSP=y
+CONFIG_MMU=y
+CONFIG_TLB_ENTRIES=32
+CONFIG_ISA_M32R2=y
+CONFIG_ISA_DSP_LEVEL2=y
+CONFIG_ISA_DUAL_ISSUE=y
+CONFIG_BUS_CLOCK=50000000
+CONFIG_TIMER_DIVIDE=128
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_NOHIGHMEM=y
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_SMP is not set
+
+#
+# M32R drivers
+#
+# CONFIG_M32R_CFC is not set
+CONFIG_M32R_SMC91111=y
+CONFIG_M32700UT_DS1302=y
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# 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_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_M32R_SIO is not set
+CONFIG_SERIAL_M32R_PLDSIO=y
+CONFIG_SERIAL_M32R_PLDSIO_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+CONFIG_JBD_DEBUG=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR 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_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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_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_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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_IOVIRT is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/m32r/opsput/dot.gdbinit b/arch/m32r/opsput/dot.gdbinit
new file mode 100644 (file)
index 0000000..9883f00
--- /dev/null
@@ -0,0 +1,180 @@
+# .gdbinit file
+# $Id: dot.gdbinit,v 1.1 2004/07/27 06:54:20 sakugawa Exp $
+
+# setting
+set width 0d70
+set radix 0d16
+set height 0
+debug_chaos
+
+define tlb_init
+  set $tlbbase = 0xfe000000
+  set *(unsigned long *)($tlbbase + 0x04) = 0x0
+  set *(unsigned long *)($tlbbase + 0x0c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x14) = 0x0
+  set *(unsigned long *)($tlbbase + 0x1c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x24) = 0x0
+  set *(unsigned long *)($tlbbase + 0x2c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x34) = 0x0
+  set *(unsigned long *)($tlbbase + 0x3c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x44) = 0x0
+  set *(unsigned long *)($tlbbase + 0x4c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x54) = 0x0
+  set *(unsigned long *)($tlbbase + 0x5c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x64) = 0x0
+  set *(unsigned long *)($tlbbase + 0x6c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x74) = 0x0
+  set *(unsigned long *)($tlbbase + 0x7c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x84) = 0x0
+  set *(unsigned long *)($tlbbase + 0x8c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x94) = 0x0
+  set *(unsigned long *)($tlbbase + 0x9c) = 0x0
+  set *(unsigned long *)($tlbbase + 0xa4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xac) = 0x0
+  set *(unsigned long *)($tlbbase + 0xb4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xbc) = 0x0
+  set *(unsigned long *)($tlbbase + 0xc4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xcc) = 0x0
+  set *(unsigned long *)($tlbbase + 0xd4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xdc) = 0x0
+  set *(unsigned long *)($tlbbase + 0xe4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xec) = 0x0
+  set *(unsigned long *)($tlbbase + 0xf4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xfc) = 0x0
+  set $tlbbase = 0xfe000800
+  set *(unsigned long *)($tlbbase + 0x04) = 0x0
+  set *(unsigned long *)($tlbbase + 0x0c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x14) = 0x0
+  set *(unsigned long *)($tlbbase + 0x1c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x24) = 0x0
+  set *(unsigned long *)($tlbbase + 0x2c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x34) = 0x0
+  set *(unsigned long *)($tlbbase + 0x3c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x44) = 0x0
+  set *(unsigned long *)($tlbbase + 0x4c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x54) = 0x0
+  set *(unsigned long *)($tlbbase + 0x5c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x64) = 0x0
+  set *(unsigned long *)($tlbbase + 0x6c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x74) = 0x0
+  set *(unsigned long *)($tlbbase + 0x7c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x84) = 0x0
+  set *(unsigned long *)($tlbbase + 0x8c) = 0x0
+  set *(unsigned long *)($tlbbase + 0x94) = 0x0
+  set *(unsigned long *)($tlbbase + 0x9c) = 0x0
+  set *(unsigned long *)($tlbbase + 0xa4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xac) = 0x0
+  set *(unsigned long *)($tlbbase + 0xb4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xbc) = 0x0
+  set *(unsigned long *)($tlbbase + 0xc4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xcc) = 0x0
+  set *(unsigned long *)($tlbbase + 0xd4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xdc) = 0x0
+  set *(unsigned long *)($tlbbase + 0xe4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xec) = 0x0
+  set *(unsigned long *)($tlbbase + 0xf4) = 0x0
+  set *(unsigned long *)($tlbbase + 0xfc) = 0x0
+end
+
+define load_modules
+  use_debug_dma
+  load
+end
+
+# Set kernel parameters
+define set_kernel_parameters
+  set $param = (void*)0x88002000
+  # INITRD_START
+#  set *(unsigned long *)($param + 0x0010) = 0x08300000
+  # INITRD_SIZE
+#  set *(unsigned long *)($param + 0x0014) = 0x00400000
+  # M32R_CPUCLK
+  set *(unsigned long *)($param + 0x0018) = 0d200000000
+  # M32R_BUSCLK
+  set *(unsigned long *)($param + 0x001c) = 0d50000000
+#  set *(unsigned long *)($param + 0x001c) = 0d25000000
+
+  # M32R_TIMER_DIVIDE
+  set *(unsigned long *)($param + 0x0020) = 0d128
+
+  set {char[0x200]}($param + 0x100) = "console=ttyD0,115200n8x\
+  root=/dev/nfsroot \
+  nfsroot=192.168.0.1:/project/m32r-linux/export/root.2.6 \
+  nfsaddrs=192.168.0.101:192.168.0.1:192.168.0.1:255.255.255.0:mappi001 \
+  mem=16m \0"
+end
+
+define boot
+  set_kernel_parameters
+  set $pc=0x88001000
+  set $fp=0
+  set $evb=0x88000000
+  # I/D-Cache ON
+
+# IPI
+#  set *(long *)0x00eff2f8 = 0x2
+  set $fp=0
+#  set *(unsigned long *)0xa0ef4000 = 0x100
+  si
+end
+
+# Show TLB entries
+define show_tlb_entries
+  set $i = 0
+  set $addr = $arg0
+  use_mon_code
+  while ($i < 0d32 )
+    set $tlb_tag = *(unsigned long*)$addr
+    set $tlb_data = *(unsigned long*)($addr + 4)
+    printf " [%2d] 0x%08lx : 0x%08lx - 0x%08lx\n", $i, $addr, $tlb_tag, $tlb_data
+    set $i = $i + 1
+    set $addr = $addr + 8
+  end
+#  use_debug_dma
+end
+define itlb
+  set $itlb=0xfe000000
+  show_tlb_entries $itlb
+end
+define dtlb
+  set $dtlb=0xfe000800
+  show_tlb_entries $dtlb
+end
+
+define show_regs
+  printf " R0[%08lx]   R1[%08lx]   R2[%08lx]   R3[%08lx]\n",$r0,$r1,$r2,$r3
+  printf " R4[%08lx]   R5[%08lx]   R6[%08lx]   R7[%08lx]\n",$r4,$r5,$r6,$r7
+  printf " R8[%08lx]   R9[%08lx]  R10[%08lx]  R11[%08lx]\n",$r8,$r9,$r10,$r11
+  printf "R12[%08lx]   FP[%08lx]   LR[%08lx]   SP[%08lx]\n",$r12,$fp,$lr,$sp
+  printf "PSW[%08lx]  CBR[%08lx]  SPI[%08lx]  SPU[%08lx]\n",$psw,$cbr,$spi,$spu
+  printf "BPC[%08lx]   PC[%08lx] ACCL[%08lx] ACCH[%08lx]\n",$bpc,$pc,$accl,$acch
+  printf "EVB[%08lx]\n",$evb
+end
+
+define setup
+  debug_chaos
+  set *(unsigned long *)0xa0ef6004 = 0x0001053f
+  set *(unsigned long *)0xa0ef6028 = 0x00031102
+#  set *(unsigned long *)0xa0ef400c = 0x2
+end
+
+sdireset
+sdireset
+file vmlinux
+target m32rsdi
+set $pc=0x0
+b *0x30000
+c
+setup
+tlb_init
+load_modules
+#set *(long *)0xa0ef4000=0x101
+#set *(long *)0xa0ef400c=0x002
+
+boot
+#b tme_handler
+b *0x88000020
+
+
+
+
diff --git a/arch/m68k/Kconfig.debug b/arch/m68k/Kconfig.debug
new file mode 100644 (file)
index 0000000..f53b6d5
--- /dev/null
@@ -0,0 +1,5 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+endmenu
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
new file mode 100644 (file)
index 0000000..a912df1
--- /dev/null
@@ -0,0 +1,964 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:25 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-amiga"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+CONFIG_AMIGA=y
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_ZORRO=y
+CONFIG_AMIGA_PCMCIA=y
+# CONFIG_HEARTBEAT is not set
+CONFIG_PROC_HARDWARE=y
+CONFIG_ISA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_ZORRO_NAMES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_AMIGA=m
+CONFIG_PARPORT_MFC3=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+CONFIG_AMIGA_FLOPPY=y
+CONFIG_AMIGA_Z2RAM=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_GAYLE=y
+CONFIG_BLK_DEV_IDEDOUBLER=y
+CONFIG_BLK_DEV_BUDDHA=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 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_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_A3000_SCSI=y
+CONFIG_A2091_SCSI=y
+CONFIG_GVP11_SCSI=y
+CONFIG_CYBERSTORM_SCSI=y
+CONFIG_CYBERSTORMII_SCSI=y
+CONFIG_BLZ2060_SCSI=y
+CONFIG_BLZ1230_SCSI=y
+CONFIG_FASTLANE_SCSI=y
+CONFIG_OKTAGON_SCSI=y
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_ARIADNE=m
+CONFIG_A2065=m
+CONFIG_HYDRA=m
+CONFIG_ZORRO8390=m
+CONFIG_APNE=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_AMIGA=y
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+CONFIG_MOUSE_AMIGA=y
+# CONFIG_MOUSE_VSXXXAA is not set
+CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_JOYSTICK_DB9 is not set
+# CONFIG_JOYSTICK_GAMECON is not set
+# CONFIG_JOYSTICK_TURBOGRAFX is not set
+CONFIG_JOYSTICK_AMIGA=m
+# 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
+CONFIG_A2232=m
+
+#
+# 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
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_CIRRUS=m
+CONFIG_FB_AMIGA=y
+CONFIG_FB_AMIGA_OCS=y
+CONFIG_FB_AMIGA_ECS=y
+CONFIG_FB_AMIGA_AGA=y
+CONFIG_FB_FM2=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_PEARL_8x8=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+CONFIG_DMASOUND_PAULA=m
+CONFIG_DMASOUND=m
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_AMIGA_BUILTIN_SERIAL=y
+# CONFIG_WHIPPET_SERIAL is not set
+CONFIG_MULTIFACE_III_TTY=m
+# CONFIG_SERIAL_CONSOLE is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_AMIGA_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
new file mode 100644 (file)
index 0000000..45ed614
--- /dev/null
@@ -0,0 +1,821 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:29 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-apollo"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+CONFIG_APOLLO=y
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_HEARTBEAT=y
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_APOLLO_ELPLUS=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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_DUMMY_CONSOLE=y
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_DN_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
new file mode 100644 (file)
index 0000000..2e3a162
--- /dev/null
@@ -0,0 +1,876 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:34 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-atari"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+CONFIG_ATARI=y
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_STRAM_PROC=y
+CONFIG_HEARTBEAT=y
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_ATARI=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+CONFIG_ATARI_FLOPPY=y
+# CONFIG_PARIDE is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_FALCON_IDE=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_ATARILANCE=m
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_M68K_BEEP=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# 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
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+CONFIG_DMASOUND_ATARI=m
+CONFIG_DMASOUND=m
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_ATARI_MFPSER=m
+CONFIG_ATARI_SCC=y
+CONFIG_ATARI_SCC_DMA=y
+CONFIG_ATARI_MIDI=m
+CONFIG_ATARI_DSP56K=m
+# CONFIG_SERIAL_CONSOLE is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_ATARI_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
new file mode 100644 (file)
index 0000000..5416c54
--- /dev/null
@@ -0,0 +1,820 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:38 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-bvme6000"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+CONFIG_VME=y
+# CONFIG_MVME147 is not set
+# CONFIG_MVME16x is not set
+CONFIG_BVME6000=y
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+# CONFIG_M68020 is not set
+# CONFIG_M68030 is not set
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_BVME6000_NET=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+# 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_DUMMY_CONSOLE=y
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_BVME6000_SCC=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=m
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
new file mode 100644 (file)
index 0000000..3ff6b3b
--- /dev/null
@@ -0,0 +1,820 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:44 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-hp300"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+CONFIG_HP300=y
+CONFIG_DIO=y
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_HEARTBEAT=y
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_HPLANCE=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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_DUMMY_CONSOLE=y
+
+#
+# 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
+
+#
+# Character devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
new file mode 100644 (file)
index 0000000..7d7fd05
--- /dev/null
@@ -0,0 +1,899 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:47 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-mac"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+CONFIG_MAC=y
+CONFIG_NUBUS=y
+CONFIG_M68K_L2_CACHE=y
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_M68030=y
+CONFIG_M68040=y
+# CONFIG_M68060 is not set
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_HEARTBEAT is not set
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_MAC_IDE=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_MAC_SCSI=y
+CONFIG_SCSI_MAC_ESP=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+CONFIG_ADB=y
+CONFIG_ADB_MACII=y
+CONFIG_ADB_MACIISI=y
+CONFIG_ADB_IOP=y
+CONFIG_ADB_PMU68K=y
+CONFIG_ADB_CUDA=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+# 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_MAC8390=y
+CONFIG_MAC89x0=y
+CONFIG_MACSONIC=y
+CONFIG_MACMACE=y
+# CONFIG_NET_VENDOR_SMC is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_MAC=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_6x11=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_LOGO_MAC_CLUT224=y
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_MAC_SCC=y
+CONFIG_MAC_HID=y
+CONFIG_MAC_ADBKEYCODES=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=m
+CONFIG_HFS_FS=y
+CONFIG_HFSPLUS_FS=y
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
new file mode 100644 (file)
index 0000000..84610d3
--- /dev/null
@@ -0,0 +1,839 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:49 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-mvme147"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+CONFIG_VME=y
+CONFIG_MVME147=y
+# CONFIG_MVME16x is not set
+# CONFIG_BVME6000 is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+# CONFIG_M68020 is not set
+CONFIG_M68030=y
+# CONFIG_M68040 is not set
+# CONFIG_M68060 is not set
+CONFIG_MMU_MOTOROLA=y
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_MVME147_SCSI=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_MVME147_NET=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_MVME147_SCC=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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=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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
new file mode 100644 (file)
index 0000000..688c9e7
--- /dev/null
@@ -0,0 +1,838 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:52 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-mvme16x"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+CONFIG_VME=y
+# CONFIG_MVME147 is not set
+CONFIG_MVME16x=y
+# CONFIG_BVME6000 is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+# CONFIG_M68020 is not set
+# CONFIG_M68030 is not set
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+# CONFIG_M68KFPU_EMU is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_MVME16x_NET=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# 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
+
+#
+# Character devices
+#
+CONFIG_MVME162_SCC=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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=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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
new file mode 100644 (file)
index 0000000..6ede4e7
--- /dev/null
@@ -0,0 +1,911 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:55 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-q40"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+# CONFIG_SUN3X is not set
+CONFIG_Q40=y
+
+#
+# Processor type
+#
+# CONFIG_M68020 is not set
+# CONFIG_M68030 is not set
+CONFIG_M68040=y
+CONFIG_M68060=y
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_HEARTBEAT is not set
+CONFIG_PROC_HARDWARE=y
+CONFIG_ISA=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_Q40IDE=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 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_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NE2000=m
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_Q40KBD=m
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=m
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_Q40=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+CONFIG_DMASOUND_Q40=y
+CONFIG_DMASOUND=y
+
+#
+# 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
+
+#
+# Character devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS 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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_UFS_FS_WRITE=y
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
new file mode 100644 (file)
index 0000000..e4e473e
--- /dev/null
@@ -0,0 +1,826 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:21:58 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-sun3"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+CONFIG_SUN3=y
+
+#
+# Processor type
+#
+CONFIG_M68020=y
+CONFIG_MMU_SUN3=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SUN3_SCSI=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_SUN3LANCE=y
+CONFIG_SUN3_82586=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_SUNKBD=y
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# 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
+
+#
+# Character devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_UFS_FS_WRITE=y
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
new file mode 100644 (file)
index 0000000..f9acd19
--- /dev/null
@@ -0,0 +1,836 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc3-m68k
+# Sun Dec  5 14:22:01 2004
+#
+CONFIG_M68K=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION="-sun3x"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Platform dependent setup
+#
+# CONFIG_SUN3 is not set
+# CONFIG_AMIGA is not set
+# CONFIG_ATARI is not set
+# CONFIG_MAC is not set
+# CONFIG_APOLLO is not set
+# CONFIG_VME is not set
+# CONFIG_HP300 is not set
+CONFIG_SUN3X=y
+# CONFIG_Q40 is not set
+
+#
+# Processor type
+#
+# CONFIG_M68020 is not set
+CONFIG_M68030=y
+# CONFIG_M68040 is not set
+# CONFIG_M68060 is not set
+CONFIG_MMU_MOTOROLA=y
+CONFIG_M68KFPU_EMU=y
+CONFIG_M68KFPU_EMU_EXTRAPREC=y
+# CONFIG_M68KFPU_EMU_ONLY is not set
+# CONFIG_ADVANCED is not set
+
+#
+# General setup
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_HARDWARE=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SUN3X_ESP=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID5=m
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+
+#
+# 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=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_REALM=m
+# CONFIG_IP_NF_MATCH_SCTP is not set
+# CONFIG_IP_NF_MATCH_COMMENT is not set
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_LOCAL=y
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_COMPAT_IPFWADM=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK 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_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_EQUALIZER=m
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_SUN3LANCE=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
+
+#
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_SUNKBD=y
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA 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 is not set
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# 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=y
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# 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
+
+#
+# Character devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_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=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+CONFIG_HPFS_FS=m
+# CONFIG_QNX4FS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_UFS_FS_WRITE=y
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+# CONFIG_CIFS is not set
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+CONFIG_NCPFS_NLS=y
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+# CONFIG_CODA_FS_OLD_API 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug
new file mode 100644 (file)
index 0000000..763c9aa
--- /dev/null
@@ -0,0 +1,42 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config FULLDEBUG
+       bool "Full Symbolic/Source Debugging support"
+       help
+         Enable debuging symbols on kernel build.
+
+config HIGHPROFILE
+       bool "Use fast second timer for profiling"
+       depends on COLDFIRE
+       help
+         Use a fast secondary clock to produce profiling information.
+
+config BOOTPARAM
+       bool 'Compiled-in Kernel Boot Parameter'
+
+config BOOTPARAM_STRING
+       string 'Kernel Boot Parameter'
+       default 'console=ttyS0,19200'
+       depends on BOOTPARAM
+
+config DUMPTOFLASH
+       bool "Panic/Dump to FLASH"
+       depends on COLDFIRE
+       help
+         Dump any panic of trap output into a flash memory segment
+         for later analysis.
+
+config NO_KERNEL_MSG
+       bool "Suppress Kernel BUG Messages"
+       help
+         Do not output any debug BUG messages within the kernel.
+
+config BDM_DISABLE
+       bool "Disable BDM signals"
+       depends on (EXPERIMENTAL && COLDFIRE)
+       help
+         Disable the ColdFire CPU's BDM signals.
+
+endmenu
diff --git a/arch/m68knommu/lib/delay.c b/arch/m68knommu/lib/delay.c
new file mode 100644 (file)
index 0000000..7bd4323
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *     arch/m68knommu/lib/delay.c
+ *
+ *     (C) Copyright 2004, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/param.h>
+#include <asm/delay.h>
+
+void udelay(unsigned long usecs)
+{
+       _udelay(usecs);
+}
+
diff --git a/arch/m68knommu/platform/5272/CANCam/crt0_ram.S b/arch/m68knommu/platform/5272/CANCam/crt0_ram.S
new file mode 100644 (file)
index 0000000..06ee803
--- /dev/null
@@ -0,0 +1,154 @@
+/*****************************************************************************/
+
+/*
+ *     crt0_ram.S -- startup code for Feith CANCan board.
+ *
+ *     (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
+ *     (C) Copyright 2000, Lineo (www.lineo.com).
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*****************************************************************************/
+
+/*
+ *     Feith ColdFire CANCam, chip select and memory setup.
+ */
+
+#define        MEM_BASE        0x00000000      /* Memory base at address 0 */
+#define        VBR_BASE        MEM_BASE        /* Vector address */
+#define MEM_SIZE  0x04000000      /* Memory size 64Mb */
+
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     Set up the usable of RAM stuff. Size of RAM is determined then
+ *     an initial stack set up at the end.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+
+/*****************************************************************************/
+
+.text
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* Filler */
+       move.w  #0x2700, %sr                    /* No interrupts */
+
+       /*
+        * Setup VBR here, otherwise buserror remap will not work.
+        * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
+        *
+        * bkr@cut.de 19990306
+        *
+        * Note: this is because dBUG points VBR to ROM, making vectors read
+        * only, so the bus trap can't be changed. (RS)
+        */
+       move.l  #VBR_BASE, %a7                  /* Note VBR can't be read */
+       movec   %a7, %VBR
+       move.l  %a7, _ramvec                    /* Set up vector addr */
+       move.l  %a7, _rambase                   /* Set up base RAM addr */
+
+
+       /*
+        *      Set memory size.
+        */
+       move.l  #MEM_SIZE, %a0
+
+       move.l  %a0, %d0                        /* Mem end addr is in a0 */
+       move.l  %d0, %sp                        /* Set up initial stack ptr */
+       move.l  %d0, _ramend                    /* Set end ram addr */
+
+       /*
+        *      Enable CPU internal cache.
+        */
+       move.l  #0x01000000, %d0                /* Invalidate cache cmd */
+       movec   %d0, %CACR                      /* Invalidate cache */
+       move.l  #0x80000100, %d0                /* Setup cache mask */
+       movec   %d0, %CACR                      /* Enable cache */
+       nop
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Set up destination  */
+       move.l  %a0, %a2                        /* Copy of bss start */
+
+       move.l  8(%a0), %d0                     /* Get size of ROMFS */
+       addq.l  #8, %d0                         /* Allow for rounding */
+       and.l   #0xfffffffc, %d0                /* Whole words */
+
+       add.l   %d0, %a0                        /* Copy from end */
+       add.l   %d0, %a1                        /* Copy from end */
+       move.l  %a1, _ramstart                  /* Set start of ram */
+
+_copy_romfs:
+       move.l  -(%a0), %d0                     /* Copy dword */
+       move.l  %d0, -(%a1)
+       cmp.l   %a0, %a2                        /* Check if at end */
+       bne     _copy_romfs
+
+#else /* CONFIG_ROMFS_FS */
+       lea.l   _ebss, %a1
+       move.l  %a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Get end of bss */
+       clr.l   %d0                             /* Set value */
+_clear_bss:
+       move.l  %d0, (%a0)+                     /* Clear each word */
+       cmp.l   %a0, %a1                        /* Check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current thread pointer and stack.
+        */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* Start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* Should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5272/SCALES/crt0_ram.S b/arch/m68knommu/platform/5272/SCALES/crt0_ram.S
new file mode 100644 (file)
index 0000000..fd69270
--- /dev/null
@@ -0,0 +1,154 @@
+/*****************************************************************************/
+
+/*
+ *     crt0_ram.S -- startup code for Feith SCALES board.
+ *
+ *     (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com).
+ *     (C) Copyright 2000, Lineo (www.lineo.com).
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*****************************************************************************/
+
+/*
+ *     Feith ColdFire SCALES, chip select and memory setup.
+ */
+
+#define        MEM_BASE        0x00000000      /* Memory base at address 0 */
+#define        VBR_BASE        MEM_BASE        /* Vector address */
+#define MEM_SIZE  0x02000000      /* Memory size 32Mb */
+
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     Set up the usable of RAM stuff. Size of RAM is determined then
+ *     an initial stack set up at the end.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+
+/*****************************************************************************/
+
+.text
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* Filler */
+       move.w  #0x2700, %sr                    /* No interrupts */
+
+       /*
+        * Setup VBR here, otherwise buserror remap will not work.
+        * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
+        *
+        * bkr@cut.de 19990306
+        *
+        * Note: this is because dBUG points VBR to ROM, making vectors read
+        * only, so the bus trap can't be changed. (RS)
+        */
+       move.l  #VBR_BASE, %a7                  /* Note VBR can't be read */
+       movec   %a7, %VBR
+       move.l  %a7, _ramvec                    /* Set up vector addr */
+       move.l  %a7, _rambase                   /* Set up base RAM addr */
+
+
+       /*
+        *      Set memory size.
+        */
+       move.l  #MEM_SIZE, %a0
+
+       move.l  %a0, %d0                        /* Mem end addr is in a0 */
+       move.l  %d0, %sp                        /* Set up initial stack ptr */
+       move.l  %d0, _ramend                    /* Set end ram addr */
+
+       /*
+        *      Enable CPU internal cache.
+        */
+       move.l  #0x01000000, %d0                /* Invalidate cache cmd */
+       movec   %d0, %CACR                      /* Invalidate cache */
+       move.l  #0x80000100, %d0                /* Setup cache mask */
+       movec   %d0, %CACR                      /* Enable cache */
+       nop
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Set up destination  */
+       move.l  %a0, %a2                        /* Copy of bss start */
+
+       move.l  8(%a0), %d0                     /* Get size of ROMFS */
+       addq.l  #8, %d0                         /* Allow for rounding */
+       and.l   #0xfffffffc, %d0                /* Whole words */
+
+       add.l   %d0, %a0                        /* Copy from end */
+       add.l   %d0, %a1                        /* Copy from end */
+       move.l  %a1, _ramstart                  /* Set start of ram */
+
+_copy_romfs:
+       move.l  -(%a0), %d0                     /* Copy dword */
+       move.l  %d0, -(%a1)
+       cmp.l   %a0, %a2                        /* Check if at end */
+       bne     _copy_romfs
+
+#else /* CONFIG_ROMFS_FS */
+       lea.l   _ebss, %a1
+       move.l  %a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Get end of bss */
+       clr.l   %d0                             /* Set value */
+_clear_bss:
+       move.l  %d0, (%a0)+                     /* Clear each word */
+       cmp.l   %a0, %a1                        /* Check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current thread pointer and stack.
+        */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* Start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* Should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68knommu/platform/527x/M5271EVB/crt0_ram.S b/arch/m68knommu/platform/527x/M5271EVB/crt0_ram.S
new file mode 100644 (file)
index 0000000..41f533f
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************/
+
+/*
+ *     crt0_ram.S -- startup code for MCF527x ColdFire based Freescale boards.
+ *
+ *     (C) Copyright 2003-2004, Greg Ungerer (gerg@snapgear.com).
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*****************************************************************************/
+
+/*
+ *     Freescale M5271EVB ColdFire eval board, chip select and memory setup.
+ */
+
+#define        MEM_BASE        0x00000000      /* Memory base at address 0 */
+#define        VBR_BASE        MEM_BASE        /* Vector address */
+
+#if defined(CONFIG_RAM4MB)
+#define        MEM_SIZE        0x00400000      /* Memory size 4Mb */
+#elif defined(CONFIG_RAM8MB)
+#define        MEM_SIZE        0x00800000      /* Memory size 8Mb */
+#else
+#define        MEM_SIZE        0x01000000      /* Memory size 16Mb */
+#endif
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     Set up the usable of RAM stuff. Size of RAM is determined then
+ *     an initial stack set up at the end.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+
+/*****************************************************************************/
+
+.text
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* Filler */
+       move.w  #0x2700, %sr                    /* No interrupts */
+
+       /*
+        * Setup VBR here, otherwise buserror remap will not work.
+        * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
+        *
+        * bkr@cut.de 19990306
+        *
+        * Note: this is because dBUG points VBR to ROM, making vectors read
+        * only, so the bus trap can't be changed. (RS)
+        */
+       move.l  #VBR_BASE, %a7                  /* Note VBR can't be read */
+       movec   %a7, %VBR
+       move.l  %a7, _ramvec                    /* Set up vector addr */
+       move.l  %a7, _rambase                   /* Set up base RAM addr */
+
+
+       /*
+        *      Set memory size.
+        */
+       move.l  #MEM_SIZE, %a0
+
+       move.l  %a0, %d0                        /* Mem end addr is in a0 */
+       move.l  %d0, %sp                        /* Set up initial stack ptr */
+       move.l  %d0, _ramend                    /* Set end ram addr */
+
+       /*
+        *      Enable CPU internal cache.
+        */
+       move.l  #0x01400000, %d0
+       movec   %d0, %CACR                      /* Invalidate cache */
+       nop
+
+       move.l  #0x0000c000, %d0                /* Set SDRAM cached only */
+       movec   %d0, %ACR0
+       move.l  #0x00000000, %d0                /* No other regions cached */
+       movec   %d0, %ACR1
+
+       move.l  #0x80400100, %d0                /* Configure cache */
+       movec   %d0, %CACR                      /* Enable cache */
+       nop
+
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Set up destination  */
+       move.l  %a0, %a2                        /* Copy of bss start */
+
+       move.l  8(%a0), %d0                     /* Get size of ROMFS */
+       addq.l  #8, %d0                         /* Allow for rounding */
+       and.l   #0xfffffffc, %d0                /* Whole words */
+
+       add.l   %d0, %a0                        /* Copy from end */
+       add.l   %d0, %a1                        /* Copy from end */
+       move.l  %a1, _ramstart                  /* Set start of ram */
+
+_copy_romfs:
+       move.l  -(%a0), %d0                     /* Copy dword */
+       move.l  %d0, -(%a1)
+       cmp.l   %a0, %a2                        /* Check if at end */
+       bne     _copy_romfs
+#else /* CONFIG_ROMFS_FS */
+       lea.l   _ebss, %a1
+       move.l  %a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Get end of bss */
+       clr.l   %d0                             /* Set value */
+_clear_bss:
+       move.l  %d0, (%a0)+                     /* Clear each word */
+       cmp.l   %a0, %a1                        /* Check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current thread pointer and stack.
+        */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* Start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* Should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68knommu/platform/527x/M5275EVB/crt0_ram.S b/arch/m68knommu/platform/527x/M5275EVB/crt0_ram.S
new file mode 100644 (file)
index 0000000..ceb9920
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************/
+
+/*
+ *     crt0_ram.S -- startup code for MCF527x ColdFire based Freescale boards.
+ *
+ *     (C) Copyright 2003-2004, Greg Ungerer (gerg@snapgear.com).
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*****************************************************************************/
+
+/*
+ *     Freescale M5275EVB ColdFire eval board, chip select and memory setup.
+ */
+
+#define        MEM_BASE        0x00000000      /* Memory base at address 0 */
+#define        VBR_BASE        MEM_BASE        /* Vector address */
+
+#if defined(CONFIG_RAM4MB)
+#define        MEM_SIZE        0x00400000      /* Memory size 4Mb */
+#elif defined(CONFIG_RAM8MB)
+#define        MEM_SIZE        0x00800000      /* Memory size 8Mb */
+#else
+#define        MEM_SIZE        0x01000000      /* Memory size 16Mb */
+#endif
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     Set up the usable of RAM stuff. Size of RAM is determined then
+ *     an initial stack set up at the end.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+
+/*****************************************************************************/
+
+.text
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* Filler */
+       move.w  #0x2700, %sr                    /* No interrupts */
+
+       /*
+        * Setup VBR here, otherwise buserror remap will not work.
+        * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
+        *
+        * bkr@cut.de 19990306
+        *
+        * Note: this is because dBUG points VBR to ROM, making vectors read
+        * only, so the bus trap can't be changed. (RS)
+        */
+       move.l  #VBR_BASE, %a7                  /* Note VBR can't be read */
+       movec   %a7, %VBR
+       move.l  %a7, _ramvec                    /* Set up vector addr */
+       move.l  %a7, _rambase                   /* Set up base RAM addr */
+
+
+       /*
+        *      Set memory size.
+        */
+       move.l  #MEM_SIZE, %a0
+
+       move.l  %a0, %d0                        /* Mem end addr is in a0 */
+       move.l  %d0, %sp                        /* Set up initial stack ptr */
+       move.l  %d0, _ramend                    /* Set end ram addr */
+
+       /*
+        *      Enable CPU internal cache.
+        */
+       move.l  #0x01400000, %d0
+       movec   %d0, %CACR                      /* Invalidate cache */
+       nop
+
+       move.l  #0x0000c000, %d0                /* Set SDRAM cached only */
+       movec   %d0, %ACR0
+       move.l  #0x00000000, %d0                /* No other regions cached */
+       movec   %d0, %ACR1
+
+       move.l  #0x80400100, %d0                /* Configure cache */
+       movec   %d0, %CACR                      /* Enable cache */
+       nop
+
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Set up destination  */
+       move.l  %a0, %a2                        /* Copy of bss start */
+
+       move.l  8(%a0), %d0                     /* Get size of ROMFS */
+       addq.l  #8, %d0                         /* Allow for rounding */
+       and.l   #0xfffffffc, %d0                /* Whole words */
+
+       add.l   %d0, %a0                        /* Copy from end */
+       add.l   %d0, %a1                        /* Copy from end */
+       move.l  %a1, _ramstart                  /* Set start of ram */
+
+_copy_romfs:
+       move.l  -(%a0), %d0                     /* Copy dword */
+       move.l  %d0, -(%a1)
+       cmp.l   %a0, %a2                        /* Check if at end */
+       bne     _copy_romfs
+#else /* CONFIG_ROMFS_FS */
+       lea.l   _ebss, %a1
+       move.l  %a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Get end of bss */
+       clr.l   %d0                             /* Set value */
+_clear_bss:
+       move.l  %d0, (%a0)+                     /* Clear each word */
+       cmp.l   %a0, %a1                        /* Check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current thread pointer and stack.
+        */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* Start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* Should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile
new file mode 100644 (file)
index 0000000..e49335f
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# Makefile for the linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+ifdef CONFIG_FULLDEBUG
+AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
+endif
+
+obj-y := config.o
+
+extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c
new file mode 100644 (file)
index 0000000..804de33
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/527x/config.c
+ *
+ *     Sub-architcture dependant initialization code for the Freescale
+ *     5270/5271 CPUs.
+ *
+ *     Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+void coldfire_pit_tick(void);
+void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+unsigned long coldfire_pit_offset(void);
+void coldfire_trap_init(void);
+void coldfire_reset(void);
+
+/***************************************************************************/
+
+/*
+ *     DMA channel base address table.
+ */
+unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+        MCF_MBAR + MCFDMA_BASE0,
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
+
+void mcf_disableall(void)
+{
+       *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
+       *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
+}
+
+/***************************************************************************/
+
+void mcf_autovector(unsigned int vec)
+{
+       /* Everything is auto-vectored on the 5272 */
+}
+
+/***************************************************************************/
+
+void config_BSP(char *commandp, int size)
+{
+       mcf_disableall();
+
+#ifdef CONFIG_BOOTPARAM
+       strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+       commandp[size-1] = 0;
+#else
+       memset(commandp, 0, size);
+#endif
+
+       mach_sched_init = coldfire_pit_init;
+       mach_tick = coldfire_pit_tick;
+       mach_gettimeoffset = coldfire_pit_offset;
+       mach_trap_init = coldfire_trap_init;
+       mach_reset = coldfire_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/528x/M5282EVB/crt0_ram.S b/arch/m68knommu/platform/528x/M5282EVB/crt0_ram.S
new file mode 100644 (file)
index 0000000..2b14d9a
--- /dev/null
@@ -0,0 +1,171 @@
+/*****************************************************************************/
+
+/*
+ *     crt0_ram.S -- startup code for M5282EVB ColdFire based MOTOROLA boards.
+ *
+ *     (C) Copyright 2003, Greg Ungerer (gerg@snapgear.com).
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*****************************************************************************/
+
+/*
+ *     Motorola M5282EVB ColdFire eval board, chip select and memory setup.
+ */
+
+#define        MEM_BASE        0x00000000      /* Memory base at address 0 */
+#define        VBR_BASE        MEM_BASE        /* Vector address */
+
+#if defined(CONFIG_RAM16MB)
+#define        MEM_SIZE        0x01000000      /* Memory size 16Mb */
+#elif defined(CONFIG_RAM8MB)
+#define        MEM_SIZE        0x00800000      /* Memory size 8Mb */
+#else
+#define        MEM_SIZE        0x00400000      /* Memory size 4Mb */
+#endif
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     Set up the usable of RAM stuff. Size of RAM is determined then
+ *     an initial stack set up at the end.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+
+/*****************************************************************************/
+
+.text
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* Filler */
+       move.w  #0x2700, %sr                    /* No interrupts */
+
+       /*
+        * Setup VBR here, otherwise buserror remap will not work.
+        * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
+        *
+        * bkr@cut.de 19990306
+        *
+        * Note: this is because dBUG points VBR to ROM, making vectors read
+        * only, so the bus trap can't be changed. (RS)
+        */
+       move.l  #VBR_BASE, %a7                  /* Note VBR can't be read */
+       movec   %a7, %VBR
+       move.l  %a7, _ramvec                    /* Set up vector addr */
+       move.l  %a7, _rambase                   /* Set up base RAM addr */
+
+
+       /*
+        *      Set memory size.
+        */
+       move.l  #MEM_SIZE, %a0
+
+       move.l  %a0, %d0                        /* Mem end addr is in a0 */
+       move.l  %d0, %sp                        /* Set up initial stack ptr */
+       move.l  %d0, _ramend                    /* Set end ram addr */
+
+       /*
+        *      Enable CPU internal cache.
+        *
+        *      Cache is totally broken in first 5282 silicon.
+        *      No point enabling it for now.
+        */
+#if 0
+       move.l  #0x01000000, %d0
+       movec   %d0, %CACR                      /* Invalidate cache */
+       nop
+
+       move.l  #0x0000c000, %d0                /* Set SDRAM cached only */
+       movec   %d0, %ACR0
+       move.l  #0x00000000, %d0                /* No other regions cached */
+       movec   %d0, %ACR1
+
+       move.l  #0x00000000, %d0                /* Setup cache mask */
+       movec   %d0, %CACR                      /* Enable cache */
+       nop
+#endif
+
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Set up destination  */
+       move.l  %a0, %a2                        /* Copy of bss start */
+
+       move.l  8(%a0), %d0                     /* Get size of ROMFS */
+       addq.l  #8, %d0                         /* Allow for rounding */
+       and.l   #0xfffffffc, %d0                /* Whole words */
+
+       add.l   %d0, %a0                        /* Copy from end */
+       add.l   %d0, %a1                        /* Copy from end */
+       move.l  %a1, _ramstart                  /* Set start of ram */
+
+_copy_romfs:
+       move.l  -(%a0), %d0                     /* Copy dword */
+       move.l  %d0, -(%a1)
+       cmp.l   %a0, %a2                        /* Check if at end */
+       bne     _copy_romfs
+#else /* CONFIG_ROMFS_FS */
+       lea.l   _ebss, %a1
+       move.l  %a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Get end of bss */
+       clr.l   %d0                             /* Set value */
+_clear_bss:
+       move.l  %d0, (%a0)+                     /* Clear each word */
+       cmp.l   %a0, %a1                        /* Check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current thread pointer and stack.
+        */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* Start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* Should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile
new file mode 100644 (file)
index 0000000..e49335f
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# Makefile for the linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+ifdef CONFIG_FULLDEBUG
+AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
+endif
+
+obj-y := config.o
+
+extra-y := $(BOARD)/crt0_$(MODEL).o
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
new file mode 100644 (file)
index 0000000..a5d2aa3
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/528x/config.c
+ *
+ *     Sub-architcture dependant initialization code for the Motorola
+ *     5280 and 5282 CPUs.
+ *
+ *     Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+void coldfire_pit_tick(void);
+void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+unsigned long coldfire_pit_offset(void);
+void coldfire_trap_init(void);
+void coldfire_reset(void);
+
+/***************************************************************************/
+
+/*
+ *     DMA channel base address table.
+ */
+unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+        MCF_MBAR + MCFDMA_BASE0,
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
+
+void mcf_disableall(void)
+{
+       *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
+       *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL)) = 0xffffffff;
+}
+
+/***************************************************************************/
+
+void mcf_autovector(unsigned int vec)
+{
+       /* Everything is auto-vectored on the 5272 */
+}
+
+/***************************************************************************/
+
+void config_BSP(char *commandp, int size)
+{
+       mcf_disableall();
+
+#ifdef CONFIG_BOOTPARAM
+       strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+       commandp[size-1] = 0;
+#else
+       memset(commandp, 0, size);
+#endif
+
+       mach_sched_init = coldfire_pit_init;
+       mach_tick = coldfire_pit_tick;
+       mach_gettimeoffset = coldfire_pit_offset;
+       mach_trap_init = coldfire_trap_init;
+       mach_reset = coldfire_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/528x/senTec/crt0_ram.S b/arch/m68knommu/platform/528x/senTec/crt0_ram.S
new file mode 100644 (file)
index 0000000..c2f3bbd
--- /dev/null
@@ -0,0 +1,180 @@
+/*****************************************************************************/
+
+/*
+ *     crt0_ram.S -- startup code for senTec COBRA5282 ColdFire based boards.
+ *
+ *     (C) Copyright 2003, Greg Ungerer (gerg@snapgear.com).
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*****************************************************************************/
+
+/*
+ *     senTec COBRA5282 board, chip select and memory setup.
+ */
+
+#define        MEM_BASE        0x00000000      /* Memory base at address 0 */
+#define        VBR_BASE        MEM_BASE        /* Vector address */
+
+#if defined(CONFIG_RAM16MB)
+#define        MEM_SIZE        0x01000000      /* Memory size 16Mb */
+#elif defined(CONFIG_RAM8MB)
+#define        MEM_SIZE        0x00800000      /* Memory size 8Mb */
+#else
+#define        MEM_SIZE        0x00400000      /* Memory size 4Mb */
+#endif
+
+#define IPSBAR 0x40000000
+#define GPACR0 0x30
+/*****************************************************************************/
+
+.global        _start
+.global        _rambase
+.global        _ramvec
+.global        _ramstart
+.global        _ramend
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     Set up the usable of RAM stuff. Size of RAM is determined then
+ *     an initial stack set up at the end.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+
+/*****************************************************************************/
+
+.text
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                                             /* Filler */
+       move.w  #0x2700, %sr                    /* No interrupts */
+
+       /*
+        * Setup VBR here, otherwise buserror remap will not work.
+        * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
+        *
+        * bkr@cut.de 19990306
+        *
+        * Note: this is because dBUG points VBR to ROM, making vectors read
+        * only, so the bus trap can't be changed. (RS)
+        */
+       move.l  #VBR_BASE, %a7                  /* Note VBR can't be read */
+       movec   %a7, %VBR
+       move.l  %a7, _ramvec                    /* Set up vector addr */
+       move.l  %a7, _rambase                   /* Set up base RAM addr */
+
+
+       /*
+        *      Set memory size.
+        */
+       move.l  #MEM_SIZE, %a0
+
+       move.l  %a0, %d0                        /* Mem end addr is in a0 */
+       move.l  %d0, %sp                        /* Set up initial stack ptr */
+       move.l  %d0, _ramend            /* Set end ram addr */
+
+       /*
+        *      Enable CPU internal cache.
+        *
+        *      Cache is totally broken in first 5282 silicon.
+        *      No point enabling it for now.
+        */
+#if 0
+       move.l  #0x01000000, %d0
+       movec   %d0, %CACR                              /* Invalidate cache */
+       nop
+
+       move.l  #0x0000c000, %d0                /* Set SDRAM cached only */
+       movec   %d0, %ACR0
+       move.l  #0x00000000, %d0                /* No other regions cached */
+       movec   %d0, %ACR1
+
+       move.l  #0x00000000, %d0                /* Setup cache mask */
+       movec   %d0, %CACR                              /* Enable cache */
+       nop
+#endif
+
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Set up destination  */
+       move.l  %a0, %a2                        /* Copy of bss start */
+
+       move.l  8(%a0), %d0                     /* Get size of ROMFS */
+       addq.l  #8, %d0                         /* Allow for rounding */
+       and.l   #0xfffffffc, %d0        /* Whole words */
+
+       add.l   %d0, %a0                        /* Copy from end */
+       add.l   %d0, %a1                        /* Copy from end */
+       move.l  %a1, _ramstart          /* Set start of ram */
+
+_copy_romfs:
+       move.l  -(%a0), %d0                     /* Copy dword */
+       move.l  %d0, -(%a1)
+       cmp.l   %a0, %a2                        /* Check if at end */
+       bne     _copy_romfs
+#else /* CONFIG_ROMFS_FS */
+       lea.l   _ebss, %a1
+       move.l  %a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea.l   _sbss, %a0                      /* Get start of bss */
+       lea.l   _ebss, %a1                      /* Get end of bss */
+       clr.l   %d0                                     /* Set value */
+_clear_bss:
+       move.l  %d0, (%a0)+                     /* Clear each word */
+       cmp.l   %a0, %a1                        /* Check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current thread pointer and stack.
+        */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+   /*
+    * User mode port access
+    */
+   move.l   #0x0000000c, %d0
+   move.b   %d0, (IPSBAR+GPACR0)
+
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* Start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* Should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c
new file mode 100644 (file)
index 0000000..a9b2c2e
--- /dev/null
@@ -0,0 +1,88 @@
+/***************************************************************************/
+
+/*
+ *     pit.c -- Motorola ColdFire PIT timer. Currently this type of
+ *              hardware timer only exists in the Motorola ColdFire
+ *              5270/5271 and 5282 CPUs.
+ *
+ *     Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ *
+ */
+
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/coldfire.h>
+#include <asm/mcfpit.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+void coldfire_pit_tick(void)
+{
+       volatile struct mcfpit *tp;
+
+       /* Reset the ColdFire timer */
+       tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1);
+       tp->pcsr |= MCFPIT_PCSR_PIF;
+}
+
+/***************************************************************************/
+
+void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *))
+{
+       volatile unsigned char *icrp;
+       volatile unsigned long *imrp;
+       volatile struct mcfpit *tp;
+
+       request_irq(MCFINT_VECBASE + MCFINT_PIT1, handler, SA_INTERRUPT,
+               "ColdFire Timer", NULL);
+
+       icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
+               MCFINTC_ICR0 + MCFINT_PIT1);
+       *icrp = 0x2b; /* PIT1 with level 5, priority 3 */
+
+       imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+       *imrp &= ~(1 << (MCFINT_PIT1 - 32));
+
+       /* Set up PIT timer 1 as poll clock */
+       tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1);
+       tp->pcsr = MCFPIT_PCSR_DISABLE;
+
+       tp->pmr = ((MCF_CLK / 2) / 64) / HZ;
+       tp->pcsr = MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
+               MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64;
+}
+
+/***************************************************************************/
+
+unsigned long coldfire_pit_offset(void)
+{
+       volatile struct mcfpit *tp;
+       volatile unsigned long *ipr;
+       unsigned long pmr, pcntr, offset;
+
+       tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1);
+       ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IPRH);
+
+       pmr = *(&tp->pmr);
+       pcntr = *(&tp->pcntr);
+
+       /*
+        * If we are still in the first half of the upcount and a
+        * timer interupt is pending, then add on a ticks worth of time.
+        */
+       offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr;
+       if ((offset < (1000000 / HZ / 2)) && (*ipr & (1 << (MCFINT_PIT1 - 32))))
+               offset += 1000000 / HZ;
+       return offset;  
+}
+
+/***************************************************************************/
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
new file mode 100644 (file)
index 0000000..d3c5cc3
--- /dev/null
@@ -0,0 +1,76 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config CROSSCOMPILE
+       bool "Are you using a crosscompiler"
+       help
+         Say Y here if you are compiling the kernel on a different
+         architecture than the one it is intended to run on.
+
+config CMDLINE
+       string "Default kernel command string"
+       default ""
+       help
+          On some platforms, there is currently no way for the boot loader to
+          pass arguments to the kernel. For these platforms, you can supply
+          some command-line options at build time by entering them here.  In
+          other cases you can specify kernel args so that you don't have
+         to set them up in board prom initialization routines.
+
+config DEBUG_STACK_USAGE
+       bool "Enable stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+config KGDB
+       bool "Remote GDB kernel debugging"
+       depends on DEBUG_KERNEL
+       select DEBUG_INFO
+       help
+         If you say Y here, it will be possible to remotely debug the MIPS
+         kernel using gdb. This enlarges your kernel image disk size by
+         several megabytes and requires a machine with more than 16 MB,
+         better 32 MB RAM to avoid excessive linking time. This is only
+         useful for kernel hackers. If unsure, say N.
+
+config GDB_CONSOLE
+       bool "Console output to GDB"
+       depends on KGDB
+       help
+         If you are using GDB for remote debugging over a serial port and
+         would like kernel messages to be formatted into GDB $O packets so
+         that GDB prints them as program output, say 'Y'.
+
+config SB1XXX_CORELIS
+       bool "Corelis Debugger"
+       depends on SIBYTE_SB1xxx_SOC
+       select DEBUG_INFO
+       help
+         Select compile flags that produce code that can be processed by the
+         Corelis mksym utility and UDB Emulator.
+
+config RUNTIME_DEBUG
+       bool "Enable run-time debugging"
+       depends on DEBUG_KERNEL
+       help
+         If you say Y here, some debugging macros will do run-time checking.
+         If you say N here, those macros will mostly turn to no-ops.  See
+         include/asm-mips/debug.h for debuging macros.
+         If unsure, say N.
+
+config MIPS_UNCACHED
+       bool "Run uncached"
+       depends on DEBUG_KERNEL && !SMP && !SGI_IP27
+       help
+         If you say Y here there kernel will disable all CPU caches.  This will
+         reduce the system's performance dramatically but can help finding
+         otherwise hard to track bugs.  It can also useful if you're doing
+         hardware debugging with a logic analyzer and need to see all traffic
+         on the bus.
+
+endmenu
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
new file mode 100644 (file)
index 0000000..22acce0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Platform device support for Au1x00 SoCs.
+ *
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+static struct resource au1xxx_usb_ohci_resources[] = {
+       [0] = {
+               .start          = USB_OHCI_BASE,
+               .end            = USB_OHCI_BASE + USB_OHCI_LEN,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = AU1000_USB_HOST_INT,
+               .end            = AU1000_USB_HOST_INT,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct platform_device au1xxx_usb_ohci_device = {
+       .name           = "au1xxx-ohci",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &ohci_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(au1xxx_usb_ohci_resources),
+       .resource       = au1xxx_usb_ohci_resources,
+};
+
+static struct platform_device *au1xxx_platform_devices[] __initdata = {
+       &au1xxx_usb_ohci_device,
+};
+
+int au1xxx_platform_init(void)
+{
+       return platform_add_devices(au1xxx_platform_devices, ARRAY_SIZE(au1xxx_platform_devices));
+}
+
+arch_initcall(au1xxx_platform_init);
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
new file mode 100644 (file)
index 0000000..73d45f7
--- /dev/null
@@ -0,0 +1,906 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc2
+# Sun Nov 21 14:11:57 2004
+#
+CONFIG_MIPS=y
+# CONFIG_MIPS64 is not set
+# CONFIG_64BIT is not set
+CONFIG_MIPS32=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=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_SGI_IP22 is not set
+CONFIG_SOC_AU1X00=y
+# CONFIG_SOC_AU1000 is not set
+# CONFIG_SOC_AU1100 is not set
+# CONFIG_SOC_AU1500 is not set
+CONFIG_SOC_AU1550=y
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+CONFIG_MIPS_DB1550=y
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_DMA_COHERENT=y
+CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_FB is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+CONFIG_64BIT_PHYS_ADDR=y
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_PREEMPT is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_PCMCIA_OBSOLETE is not set
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+# CONFIG_YENTA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_AU1X00=m
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_DB1550=y
+CONFIG_MTD_DB1550_BOOT=y
+CONFIG_MTD_DB1550_USER=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_IDS=m
+CONFIG_MTD_NAND_AU1550=m
+# CONFIG_MTD_NAND_DISKONCHIP 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD 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=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_IP_TCPDIAG=m
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# 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 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=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_MIPS_AU1X00_ENET=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 is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+# 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=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=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=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_RAW=m
+
+#
+# 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_AU1X00_GPIO is not set
+# CONFIG_TS_AU1X00_ADS7846 is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_AU1X00=y
+CONFIG_SERIAL_AU1X00_CONSOLE=y
+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_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_SYNCLINK_CS=m
+# 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
+#
+
+#
+# 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
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# 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=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# 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 is not set
+CONFIG_DEVPTS_FS_XATTR=y
+CONFIG_DEVPTS_FS_SECURITY=y
+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_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=m
+# 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 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=y
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_WP512=m
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_TEA=m
+# CONFIG_CRYPTO_ARC4 is not set
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
new file mode 100644 (file)
index 0000000..37fbacb
--- /dev/null
@@ -0,0 +1,846 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.10-rc2
+# Sun Nov 21 14:12:03 2004
+#
+CONFIG_MIPS=y
+# CONFIG_MIPS64 is not set
+# CONFIG_64BIT is not set
+CONFIG_MIPS32=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=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# 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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+CONFIG_MOMENCO_OCELOT_3=y
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SOC_AU1X00 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_IRQ_CPU=y
+CONFIG_IRQ_CPU_RM7K=y
+CONFIG_IRQ_MV64340=y
+CONFIG_PCI_MARVELL=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_FB=y
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+CONFIG_CPU_RM9000=y
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_BOARD_SCACHE=y
+CONFIG_RM7000_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_LLDSCD=y
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_MMU=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# 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_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
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLOGIC_1280_1040 is not set
+CONFIG_SCSI_QLA2XXX=m
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# 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_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+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 is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=m
+CONFIG_IP_TCPDIAG_IPV6=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER 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 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=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=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=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 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
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_LAN_SAA9730 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+CONFIG_MV643XX_ETH=y
+CONFIG_MV643XX_ETH_0=y
+CONFIG_MV643XX_ETH_1=y
+CONFIG_MV643XX_ETH_2=y
+
+#
+# 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 is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC 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 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=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=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# 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_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_E1356 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# 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
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL 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=y
+CONFIG_AUTOFS4_FS=m
+
+#
+# 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=y
+CONFIG_DEVPTS_FS_SECURITY=y
+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=y
+CONFIG_CRAMFS=y
+# 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=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="ip=any root=nfs"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
new file mode 100644 (file)
index 0000000..43c00ac
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2004 MIPS Inc
+ * Author: chris@mips.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/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/ptrace.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/msc01_ic.h>
+
+static unsigned long _icctrl_msc;
+#define MSC01_IC_REG_BASE      _icctrl_msc
+
+#define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0)
+#define MSCIC_READ(reg, data)  do { data = *(volatile u32 *)(reg); } while (0)
+
+static unsigned int irq_base;
+
+/* mask off an interrupt */
+static inline void mask_msc_irq(unsigned int irq)
+{
+       if (irq < (irq_base + 32))
+               MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base));
+       else
+               MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32));
+}
+
+/* unmask an interrupt */
+static inline void unmask_msc_irq(unsigned int irq)
+{
+       if (irq < (irq_base + 32))
+               MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base));
+       else
+               MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32));
+}
+
+/*
+ * Enables the IRQ on SOC-it
+ */
+static void enable_msc_irq(unsigned int irq)
+{
+       unmask_msc_irq(irq);
+}
+
+/*
+ * Initialize the IRQ on SOC-it
+ */
+static unsigned int startup_msc_irq(unsigned int irq)
+{
+       unmask_msc_irq(irq);
+       return 0;
+}
+
+/*
+ * Disables the IRQ on SOC-it
+ */
+static void disable_msc_irq(unsigned int irq)
+{
+       mask_msc_irq(irq);
+}
+
+/*
+ * Masks and ACKs an IRQ
+ */
+static void level_mask_and_ack_msc_irq(unsigned int irq)
+{
+       mask_msc_irq(irq);
+       if (!cpu_has_ei)
+               MSCIC_WRITE(MSC01_IC_EOI, 0);
+}
+
+/*
+ * Masks and ACKs an IRQ
+ */
+static void edge_mask_and_ack_msc_irq(unsigned int irq)
+{
+       mask_msc_irq(irq);
+       if (!cpu_has_ei)
+               MSCIC_WRITE(MSC01_IC_EOI, 0);
+       else {
+               u32 r;
+               MSCIC_READ(MSC01_IC_SUP+irq*8, r);
+               MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT);
+               MSCIC_WRITE(MSC01_IC_SUP+irq*8, r);
+       }
+}
+
+/*
+ * End IRQ processing
+ */
+static void end_msc_irq(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+               unmask_msc_irq(irq);
+}
+
+/*
+ * Interrupt handler for interrupts coming from SOC-it.
+ */
+void ll_msc_irq(struct pt_regs *regs)
+{
+       unsigned int irq;
+
+       /* read the interrupt vector register */
+       MSCIC_READ(MSC01_IC_VEC, irq);
+       if (irq < 64)
+               do_IRQ(irq + irq_base, regs);
+       else {
+               /* Ignore spurious interrupt */
+       }
+}
+
+void
+msc_bind_eic_interrupt (unsigned int irq, unsigned int set)
+{
+       MSCIC_WRITE(MSC01_IC_RAMW,
+                   (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF));
+}
+
+#define shutdown_msc_irq       disable_msc_irq
+
+struct hw_interrupt_type msc_levelirq_type = {
+       "SOC-it-Level",
+       startup_msc_irq,
+       shutdown_msc_irq,
+       enable_msc_irq,
+       disable_msc_irq,
+       level_mask_and_ack_msc_irq,
+       end_msc_irq,
+       NULL
+};
+
+struct hw_interrupt_type msc_edgeirq_type = {
+       "SOC-it-Edge",
+       startup_msc_irq,
+       shutdown_msc_irq,
+       enable_msc_irq,
+       disable_msc_irq,
+       edge_mask_and_ack_msc_irq,
+       end_msc_irq,
+       NULL
+};
+
+
+void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq)
+{
+       extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset);
+
+       _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000);
+
+       /* Reset interrupt controller - initialises all registers to 0 */
+       MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT);
+
+       board_bind_eic_interrupt = &msc_bind_eic_interrupt;
+
+       for (; nirq >= 0; nirq--, imp++) {
+               int n = imp->im_irq;
+
+               switch (imp->im_type) {
+               case MSC01_IRQ_EDGE:
+                       irq_desc[base+n].handler = &msc_edgeirq_type;
+                       if (cpu_has_ei)
+                               MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
+                       else
+                               MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
+                       break;
+               case MSC01_IRQ_LEVEL:
+                       irq_desc[base+n].handler = &msc_levelirq_type;
+                       if (cpu_has_ei)
+                               MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
+                       else
+                               MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl);
+               }
+       }
+
+       irq_base = base;
+
+       MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT);     /* Enable interrupt generation */
+
+}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
new file mode 100644 (file)
index 0000000..fc3f5c5
--- /dev/null
@@ -0,0 +1,1177 @@
+/*
+ * 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.
+ *
+ * Synthesize TLB refill handlers at runtime.
+ *
+ * Copyright (C) 2004 by Thiemo Seufer
+ */
+
+#include <stdarg.h>
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
+#include <asm/inst.h>
+#include <asm/elf.h>
+#include <asm/smp.h>
+
+/* #define DEBUG_TLB */
+
+static __init int __attribute__((unused)) r45k_bvahwbug(void)
+{
+       /* XXX: We should probe for the presence of this bug, but we don't. */
+       return 0;
+}
+
+static __init int __attribute__((unused)) r4k_250MHZhwbug(void)
+{
+       /* XXX: We should probe for the presence of this bug, but we don't. */
+       return 0;
+}
+
+static __init int __attribute__((unused)) bcm1250_m3_war(void)
+{
+       return BCM1250_M3_WAR;
+}
+
+/*
+ * A little micro-assembler, intended for TLB refill handler
+ * synthesizing. It is intentionally kept simple, does only support
+ * a subset of instructions, and does not try to hide pipeline effects
+ * like branch delay slots.
+ */
+
+enum fields
+{
+       RS = 0x001,
+       RT = 0x002,
+       RD = 0x004,
+       RE = 0x008,
+       SIMM = 0x010,
+       UIMM = 0x020,
+       BIMM = 0x040,
+       JIMM = 0x080,
+       FUNC = 0x100,
+};
+
+#define OP_MASK                0x2f
+#define OP_SH          26
+#define RS_MASK                0x1f
+#define RS_SH          21
+#define RT_MASK                0x1f
+#define RT_SH          16
+#define RD_MASK                0x1f
+#define RD_SH          11
+#define RE_MASK                0x1f
+#define RE_SH          6
+#define IMM_MASK       0xffff
+#define IMM_SH         0
+#define JIMM_MASK      0x3ffffff
+#define JIMM_SH                0
+#define FUNC_MASK      0x2f
+#define FUNC_SH                0
+
+enum opcode {
+       insn_invalid,
+       insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
+       insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, insn_bne,
+       insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
+       insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
+       insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
+       insn_lui, insn_lw, insn_mfc0, insn_mtc0, insn_ori, insn_rfe,
+       insn_sd, insn_sll, insn_sra, insn_srl, insn_subu, insn_sw,
+       insn_tlbp, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori
+};
+
+struct insn {
+       enum opcode opcode;
+       u32 match;
+       enum fields fields;
+};
+
+/* This macro sets the non-variable bits of an instruction. */
+#define M(a, b, c, d, e, f)                                    \
+       ((a) << OP_SH                                           \
+        | (b) << RS_SH                                         \
+        | (c) << RT_SH                                         \
+        | (d) << RD_SH                                         \
+        | (e) << RE_SH                                         \
+        | (f) << FUNC_SH)
+
+static __initdata struct insn insn_table[] = {
+       { insn_addiu, M(addiu_op,0,0,0,0,0), RS | RT | SIMM },
+       { insn_addu, M(spec_op,0,0,0,0,addu_op), RS | RT | RD },
+       { insn_and, M(spec_op,0,0,0,0,and_op), RS | RT | RD },
+       { insn_andi, M(andi_op,0,0,0,0,0), RS | RT | UIMM },
+       { insn_beq, M(beq_op,0,0,0,0,0), RS | RT | BIMM },
+       { insn_bgez, M(bcond_op,0,bgez_op,0,0,0), RS | BIMM },
+       { insn_bgezl, M(bcond_op,0,bgezl_op,0,0,0), RS | BIMM },
+       { insn_bltz, M(bcond_op,0,bltz_op,0,0,0), RS | BIMM },
+       { insn_bltzl, M(bcond_op,0,bltzl_op,0,0,0), RS | BIMM },
+       { insn_bne, M(bne_op,0,0,0,0,0), RS | RT | BIMM },
+       { insn_daddiu, M(daddiu_op,0,0,0,0,0), RS | RT | SIMM },
+       { insn_daddu, M(spec_op,0,0,0,0,daddu_op), RS | RT | RD },
+       { insn_dmfc0, M(cop0_op,dmfc_op,0,0,0,0), RT | RD },
+       { insn_dmtc0, M(cop0_op,dmtc_op,0,0,0,0), RT | RD },
+       { insn_dsll, M(spec_op,0,0,0,0,dsll_op), RT | RD | RE },
+       { insn_dsll32, M(spec_op,0,0,0,0,dsll32_op), RT | RD | RE },
+       { insn_dsra, M(spec_op,0,0,0,0,dsra_op), RT | RD | RE },
+       { insn_dsrl, M(spec_op,0,0,0,0,dsrl_op), RT | RD | RE },
+       { insn_dsrl32, M(spec_op,0,0,0,0,dsrl32_op), RT | RD | RE },
+       { insn_dsubu, M(spec_op,0,0,0,0,dsubu_op), RS | RT | RD },
+       { insn_eret, M(cop0_op,cop_op,0,0,0,eret_op), 0 },
+       { insn_j, M(j_op,0,0,0,0,0), JIMM },
+       { insn_jal, M(jal_op,0,0,0,0,0), JIMM },
+       { insn_jr, M(spec_op,0,0,0,0,jr_op), RS },
+       { insn_ld, M(ld_op,0,0,0,0,0), RS | RT | SIMM },
+       { insn_lui, M(lui_op,0,0,0,0,0), RT | SIMM },
+       { insn_lw, M(lw_op,0,0,0,0,0), RS | RT | SIMM },
+       { insn_mfc0, M(cop0_op,mfc_op,0,0,0,0), RT | RD },
+       { insn_mtc0, M(cop0_op,mtc_op,0,0,0,0), RT | RD },
+       { insn_ori, M(ori_op,0,0,0,0,0), RS | RT | UIMM },
+       { insn_rfe, M(cop0_op,cop_op,0,0,0,rfe_op), 0 },
+       { insn_sd, M(sd_op,0,0,0,0,0), RS | RT | SIMM },
+       { insn_sll, M(spec_op,0,0,0,0,sll_op), RT | RD | RE },
+       { insn_sra, M(spec_op,0,0,0,0,sra_op), RT | RD | RE },
+       { insn_srl, M(spec_op,0,0,0,0,srl_op), RT | RD | RE },
+       { insn_subu, M(spec_op,0,0,0,0,subu_op), RS | RT | RD },
+       { insn_sw, M(sw_op,0,0,0,0,0), RS | RT | SIMM },
+       { insn_tlbp, M(cop0_op,cop_op,0,0,0,tlbp_op), 0 },
+       { insn_tlbwi, M(cop0_op,cop_op,0,0,0,tlbwi_op), 0 },
+       { insn_tlbwr, M(cop0_op,cop_op,0,0,0,tlbwr_op), 0 },
+       { insn_xor, M(spec_op,0,0,0,0,xor_op), RS | RT | RD },
+       { insn_xori, M(xori_op,0,0,0,0,0), RS | RT | UIMM },
+       { insn_invalid, 0, 0 }
+};
+
+#undef M
+
+static __init u32 build_rs(u32 arg)
+{
+       if (arg & ~RS_MASK)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return (arg & RS_MASK) << RS_SH;
+}
+
+static __init u32 build_rt(u32 arg)
+{
+       if (arg & ~RT_MASK)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return (arg & RT_MASK) << RT_SH;
+}
+
+static __init u32 build_rd(u32 arg)
+{
+       if (arg & ~RD_MASK)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return (arg & RD_MASK) << RD_SH;
+}
+
+static __init u32 build_re(u32 arg)
+{
+       if (arg & ~RE_MASK)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return (arg & RE_MASK) << RE_SH;
+}
+
+static __init u32 build_simm(s32 arg)
+{
+       if (arg > 0x7fff || arg < -0x8000)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return arg & 0xffff;
+}
+
+static __init u32 build_uimm(u32 arg)
+{
+       if (arg & ~IMM_MASK)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return arg & IMM_MASK;
+}
+
+static __init u32 build_bimm(s32 arg)
+{
+       if (arg > 0x1ffff || arg < -0x20000)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       if (arg & 0x3)
+               printk(KERN_WARNING "Invalid TLB synthesizer branch target\n");
+
+       return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
+}
+
+static __init u32 build_jimm(u32 arg)
+{
+       if (arg & ~((JIMM_MASK) << 2))
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return (arg >> 2) & JIMM_MASK;
+}
+
+static __init u32 build_func(u32 arg)
+{
+       if (arg & ~FUNC_MASK)
+               printk(KERN_WARNING "TLB synthesizer field overflow\n");
+
+       return arg & FUNC_MASK;
+}
+
+/*
+ * The order of opcode arguments is implicitly left to right,
+ * starting with RS and ending with FUNC or IMM.
+ */
+static void __init build_insn(u32 **buf, enum opcode opc, ...)
+{
+       struct insn *ip = NULL;
+       unsigned int i;
+       va_list ap;
+       u32 op;
+
+       for (i = 0; insn_table[i].opcode != insn_invalid; i++)
+               if (insn_table[i].opcode == opc) {
+                       ip = &insn_table[i];
+                       break;
+               }
+
+       if (!ip)
+               panic("Unsupported TLB synthesizer instruction %d", opc);
+
+       op = ip->match;
+       va_start(ap, opc);
+       if (ip->fields & RS) op |= build_rs(va_arg(ap, u32));
+       if (ip->fields & RT) op |= build_rt(va_arg(ap, u32));
+       if (ip->fields & RD) op |= build_rd(va_arg(ap, u32));
+       if (ip->fields & RE) op |= build_re(va_arg(ap, u32));
+       if (ip->fields & SIMM) op |= build_simm(va_arg(ap, s32));
+       if (ip->fields & UIMM) op |= build_uimm(va_arg(ap, u32));
+       if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
+       if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
+       if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
+       va_end(ap);
+
+       **buf = op;
+       (*buf)++;
+}
+
+#define I_u1u2u3(op)                                           \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               unsigned int b, unsigned int c)                 \
+       {                                                       \
+               build_insn(buf, insn##op, a, b, c);             \
+       }
+
+#define I_u2u1u3(op)                                           \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               unsigned int b, unsigned int c)                 \
+       {                                                       \
+               build_insn(buf, insn##op, b, a, c);             \
+       }
+
+#define I_u3u1u2(op)                                           \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               unsigned int b, unsigned int c)                 \
+       {                                                       \
+               build_insn(buf, insn##op, b, c, a);             \
+       }
+
+#define I_u1u2s3(op)                                           \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               unsigned int b, signed int c)                   \
+       {                                                       \
+               build_insn(buf, insn##op, a, b, c);             \
+       }
+
+#define I_u2s3u1(op)                                           \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               signed int b, unsigned int c)                   \
+       {                                                       \
+               build_insn(buf, insn##op, c, a, b);             \
+       }
+
+#define I_u2u1s3(op)                                           \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               unsigned int b, signed int c)                   \
+       {                                                       \
+               build_insn(buf, insn##op, b, a, c);             \
+       }
+
+#define I_u1u2(op)                                             \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               unsigned int b)                                 \
+       {                                                       \
+               build_insn(buf, insn##op, a, b);                \
+       }
+
+#define I_u1s2(op)                                             \
+       static inline void i##op(u32 **buf, unsigned int a,     \
+               signed int b)                                   \
+       {                                                       \
+               build_insn(buf, insn##op, a, b);                \
+       }
+
+#define I_u1(op)                                               \
+       static inline void i##op(u32 **buf, unsigned int a)     \
+       {                                                       \
+               build_insn(buf, insn##op, a);                   \
+       }
+
+#define I_0(op)                                                        \
+       static inline void i##op(u32 **buf)                     \
+       {                                                       \
+               build_insn(buf, insn##op);                      \
+       }
+
+I_u2u1s3(_addiu);
+I_u3u1u2(_addu);
+I_u2u1u3(_andi);
+I_u3u1u2(_and);
+I_u1u2s3(_beq);
+I_u1s2(_bgez);
+I_u1s2(_bgezl);
+I_u1s2(_bltz);
+I_u1s2(_bltzl);
+I_u1u2s3(_bne);
+I_u1u2(_dmfc0);
+I_u1u2(_dmtc0);
+I_u2u1s3(_daddiu);
+I_u3u1u2(_daddu);
+I_u2u1u3(_dsll);
+I_u2u1u3(_dsll32);
+I_u2u1u3(_dsra);
+I_u2u1u3(_dsrl);
+I_u2u1u3(_dsrl32);
+I_u3u1u2(_dsubu);
+I_0(_eret);
+I_u1(_j);
+I_u1(_jal);
+I_u1(_jr);
+I_u2s3u1(_ld);
+I_u1s2(_lui);
+I_u2s3u1(_lw);
+I_u1u2(_mfc0);
+I_u1u2(_mtc0);
+I_u2u1u3(_ori);
+I_0(_rfe);
+I_u2s3u1(_sd);
+I_u2u1u3(_sll);
+I_u2u1u3(_sra);
+I_u2u1u3(_srl);
+I_u3u1u2(_subu);
+I_u2s3u1(_sw);
+I_0(_tlbp);
+I_0(_tlbwi);
+I_0(_tlbwr);
+I_u3u1u2(_xor)
+I_u2u1u3(_xori);
+
+/*
+ * handling labels
+ */
+
+enum label_id {
+       label_invalid,
+       label_second_part,
+       label_leave,
+       label_vmalloc,
+       label_vmalloc_done,
+       label_tlbwr_hazard,
+       label_split
+};
+
+struct label {
+       u32 *addr;
+       enum label_id lab;
+};
+
+static __init void build_label(struct label **lab, u32 *addr,
+                              enum label_id l)
+{
+       (*lab)->addr = addr;
+       (*lab)->lab = l;
+       (*lab)++;
+}
+
+#define L_LA(lb)                                               \
+       static inline void l##lb(struct label **lab, u32 *addr) \
+       {                                                       \
+               build_label(lab, addr, label##lb);              \
+       }
+
+L_LA(_second_part)
+L_LA(_leave)
+L_LA(_vmalloc)
+L_LA(_vmalloc_done)
+L_LA(_tlbwr_hazard)
+L_LA(_split)
+
+/* convenience macros for instructions */
+#ifdef CONFIG_MIPS64
+# define i_LW(buf, rs, rt, off) i_ld(buf, rs, rt, off)
+# define i_SW(buf, rs, rt, off) i_sd(buf, rs, rt, off)
+# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
+# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
+# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
+# define i_MFC0(buf, rt, rd) i_dmfc0(buf, rt, rd)
+# define i_MTC0(buf, rt, rd) i_dmtc0(buf, rt, rd)
+# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
+# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
+# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
+#else
+# define i_LW(buf, rs, rt, off) i_lw(buf, rs, rt, off)
+# define i_SW(buf, rs, rt, off) i_sw(buf, rs, rt, off)
+# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
+# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
+# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
+# define i_MFC0(buf, rt, rd) i_mfc0(buf, rt, rd)
+# define i_MTC0(buf, rt, rd) i_mtc0(buf, rt, rd)
+# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
+# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
+# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
+#endif
+
+#define i_b(buf, off) i_beq(buf, 0, 0, off)
+#define i_bnez(buf, rs, off) i_bne(buf, rs, 0, off)
+#define i_move(buf, a, b) i_ADDU(buf, a, 0, b)
+#define i_nop(buf) i_sll(buf, 0, 0, 0)
+#define i_ssnop(buf) i_sll(buf, 0, 0, 1)
+#define i_ehb(buf) i_sll(buf, 0, 0, 3)
+
+#if CONFIG_MIPS64
+static __init int in_compat_space_p(long addr)
+{
+       /* Is this address in 32bit compat space? */
+       return (((addr) & 0xffffffff00000000) == 0xffffffff00000000);
+}
+
+static __init int rel_highest(long val)
+{
+       return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+static __init int rel_higher(long val)
+{
+       return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
+}
+#endif
+
+static __init int rel_hi(long val)
+{
+       return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+static __init int rel_lo(long val)
+{
+       return ((val & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+static __init void i_LA_mostly(u32 **buf, unsigned int rs, long addr)
+{
+#if CONFIG_MIPS64
+       if (!in_compat_space_p(addr)) {
+               i_lui(buf, rs, rel_highest(addr));
+               if (rel_higher(addr))
+                       i_daddiu(buf, rs, rs, rel_higher(addr));
+               if (rel_hi(addr)) {
+                       i_dsll(buf, rs, rs, 16);
+                       i_daddiu(buf, rs, rs, rel_hi(addr));
+                       i_dsll(buf, rs, rs, 16);
+               } else
+                       i_dsll32(buf, rs, rs, 0);
+       } else
+#endif
+               i_lui(buf, rs, rel_hi(addr));
+}
+
+static __init void __attribute__((unused)) i_LA(u32 **buf, unsigned int rs,
+                                               long addr)
+{
+       i_LA_mostly(buf, rs, addr);
+       if (rel_lo(addr))
+               i_ADDIU(buf, rs, rs, rel_lo(addr));
+}
+
+/*
+ * handle relocations
+ */
+
+struct reloc {
+       u32 *addr;
+       unsigned int type;
+       enum label_id lab;
+};
+
+static __init void r_mips_pc16(struct reloc **rel, u32 *addr,
+                              enum label_id l)
+{
+       (*rel)->addr = addr;
+       (*rel)->type = R_MIPS_PC16;
+       (*rel)->lab = l;
+       (*rel)++;
+}
+
+static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
+{
+       long laddr = (long)lab->addr;
+       long raddr = (long)rel->addr;
+
+       switch (rel->type) {
+       case R_MIPS_PC16:
+               *rel->addr |= build_bimm(laddr - (raddr + 4));
+               break;
+
+       default:
+               panic("Unsupported TLB synthesizer relocation %d",
+                     rel->type);
+       }
+}
+
+static __init void resolve_relocs(struct reloc *rel, struct label *lab)
+{
+       struct label *l;
+
+       for (; rel->lab != label_invalid; rel++)
+               for (l = lab; l->lab != label_invalid; l++)
+                       if (rel->lab == l->lab)
+                               __resolve_relocs(rel, l);
+}
+
+static __init void copy_handler(struct reloc *rel, struct label *lab,
+                               u32 *first, u32 *end, u32* target)
+{
+       long off = (long)(target - first);
+
+       memcpy(target, first, (end - first) * sizeof(u32));
+
+       for (; rel->lab != label_invalid; rel++)
+               if (rel->addr >= first && rel->addr < end)
+                       rel->addr += off;
+
+       for (; lab->lab != label_invalid; lab++)
+               if (lab->addr >= first && lab->addr < end)
+                       lab->addr += off;
+}
+
+static __init int __attribute__((unused)) insn_has_bdelay(struct reloc *rel,
+                                                         u32 *addr)
+{
+       for (; rel->lab != label_invalid; rel++) {
+               if (rel->addr == addr
+                   && (rel->type == R_MIPS_PC16
+                       || rel->type == R_MIPS_26))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/* convenience functions for labeled branches */
+static void __attribute__((unused)) il_bltz(u32 **p, struct reloc **r,
+                                           unsigned int reg, enum label_id l)
+{
+       r_mips_pc16(r, *p, l);
+       i_bltz(p, reg, 0);
+}
+
+static void __attribute__((unused)) il_b(u32 **p, struct reloc **r,
+                                        enum label_id l)
+{
+       r_mips_pc16(r, *p, l);
+       i_b(p, 0);
+}
+
+static void il_bnez(u32 **p, struct reloc **r, unsigned int reg,
+                   enum label_id l)
+{
+       r_mips_pc16(r, *p, l);
+       i_bnez(p, reg, 0);
+}
+
+static void il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
+                    enum label_id l)
+{
+       r_mips_pc16(r, *p, l);
+       i_bgezl(p, reg, 0);
+}
+
+/* The only registers allowed in TLB handlers. */
+#define K0             26
+#define K1             27
+
+/* Some CP0 registers */
+#define C0_INDEX       0
+#define C0_ENTRYLO0    2
+#define C0_ENTRYLO1    3
+#define C0_CONTEXT     4
+#define C0_BADVADDR    8
+#define C0_ENTRYHI     10
+#define C0_EPC         14
+#define C0_XCONTEXT    20
+
+#ifdef CONFIG_MIPS64
+# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
+#else
+# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_CONTEXT)
+#endif
+
+/* The worst case length of the handler is around 18 instructions for
+ * R3000-style TLBs and up to 63 instructions for R4000-style TLBs.
+ * Maximum space available is 32 instructions for R3000 and 64
+ * instructions for R4000.
+ *
+ * We deliberately chose a buffer size of 128, so we won't scribble
+ * over anything important on overflow before we panic.
+ */
+static __initdata u32 tlb_handler[128];
+
+/* simply assume worst case size for labels and relocs */
+static __initdata struct label labels[128];
+static __initdata struct reloc relocs[128];
+
+#ifdef CONFIG_MIPS32
+/*
+ * The R3000 TLB handler is simple.
+ */
+static void __init build_r3000_tlb_refill_handler(void)
+{
+       long pgdc = (long)pgd_current;
+       u32 *p;
+
+       memset(tlb_handler, 0, sizeof(tlb_handler));
+       p = tlb_handler;
+
+       i_mfc0(&p, K0, C0_BADVADDR);
+       i_lui(&p, K1, rel_hi(pgdc)); /* cp0 delay */
+       i_lw(&p, K1, rel_lo(pgdc), K1);
+       i_srl(&p, K0, K0, 22); /* load delay */
+       i_sll(&p, K0, K0, 2);
+       i_addu(&p, K1, K1, K0);
+       i_mfc0(&p, K0, C0_CONTEXT);
+       i_lw(&p, K1, 0, K1); /* cp0 delay */
+       i_andi(&p, K0, K0, 0xffc); /* load delay */
+       i_addu(&p, K1, K1, K0);
+       i_lw(&p, K0, 0, K1);
+       i_nop(&p); /* load delay */
+       i_mtc0(&p, K0, C0_ENTRYLO0);
+       i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
+       i_tlbwr(&p); /* cp0 delay */
+       i_jr(&p, K1);
+       i_rfe(&p); /* branch delay */
+
+       if (p > tlb_handler + 32)
+               panic("TLB refill handler space exceeded");
+
+       printk("Synthesized TLB handler (%u instructions).\n",
+              p - tlb_handler);
+#ifdef DEBUG_TLB
+       {
+               int i;
+               for (i = 0; i < (p - tlb_handler); i++)
+                       printk("%08x\n", tlb_handler[i]);
+       }
+#endif
+
+       memcpy((void *)CAC_BASE, tlb_handler, 0x80);
+       flush_icache_range(CAC_BASE, CAC_BASE + 0x80);
+}
+#endif /* CONFIG_MIPS32 */
+
+/*
+ * The R4000 TLB handler is much more complicated. We have two
+ * consecutive handler areas with 32 instructions space each.
+ * Since they aren't used at the same time, we can overflow in the
+ * other one.To keep things simple, we first assume linear space,
+ * then we relocate it to the final handler layout as needed.
+ */
+static __initdata u32 final_handler[64];
+
+/*
+ * Hazards
+ *
+ * From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
+ * 2. A timing hazard exists for the TLBP instruction.
+ *
+ *      stalling_instruction
+ *      TLBP
+ *
+ * The JTLB is being read for the TLBP throughout the stall generated by the
+ * previous instruction. This is not really correct as the stalling instruction
+ * can modify the address used to access the JTLB.  The failure symptom is that
+ * the TLBP instruction will use an address created for the stalling instruction
+ * and not the address held in C0_ENHI and thus report the wrong results.
+ *
+ * The software work-around is to not allow the instruction preceding the TLBP
+ * to stall - make it an NOP or some other instruction guaranteed not to stall.
+ *
+ * Errata 2 will not be fixed.  This errata is also on the R5000.
+ *
+ * As if we MIPS hackers wouldn't know how to nop pipelines happy ...
+ */
+static __init void __attribute__((unused)) build_tlb_probe_entry(u32 **p)
+{
+       switch (current_cpu_data.cputype) {
+       case CPU_R5000:
+       case CPU_R5000A:
+       case CPU_NEVADA:
+               i_nop(p);
+               i_tlbp(p);
+               break;
+
+       default:
+               i_tlbp(p);
+               break;
+       }
+}
+
+/*
+ * Write random TLB entry, and care about the hazards from the
+ * preceeding mtc0 and for the following eret.
+ */
+static __init void build_tlb_write_random_entry(u32 **p, struct label **l,
+                                               struct reloc **r)
+{
+       switch (current_cpu_data.cputype) {
+       case CPU_R4000PC:
+       case CPU_R4000SC:
+       case CPU_R4000MC:
+       case CPU_R4400PC:
+       case CPU_R4400SC:
+       case CPU_R4400MC:
+               /*
+                * This branch uses up a mtc0 hazard nop slot and saves
+                * two nops after the tlbwr.
+                */
+               il_bgezl(p, r, 0, label_tlbwr_hazard);
+               i_tlbwr(p);
+               l_tlbwr_hazard(l, *p);
+               i_nop(p);
+               break;
+
+       case CPU_R4600:
+       case CPU_R4700:
+       case CPU_R5000:
+       case CPU_R5000A:
+       case CPU_5KC:
+       case CPU_AU1000:
+       case CPU_AU1100:
+       case CPU_AU1500:
+       case CPU_AU1550:
+               i_nop(p);
+               i_tlbwr(p);
+               break;
+
+       case CPU_R10000:
+       case CPU_R12000:
+       case CPU_4KC:
+       case CPU_SB1:
+       case CPU_4KSC:
+       case CPU_20KC:
+       case CPU_25KF:
+               i_tlbwr(p);
+               break;
+
+       case CPU_NEVADA:
+               i_nop(p); /* QED specifies 2 nops hazard */
+               /*
+                * This branch uses up a mtc0 hazard nop slot and saves
+                * a nop after the tlbwr.
+                */
+               il_bgezl(p, r, 0, label_tlbwr_hazard);
+               i_tlbwr(p);
+               l_tlbwr_hazard(l, *p);
+               break;
+
+       case CPU_4KEC:
+       case CPU_24K:
+               i_ehb(p);
+               i_tlbwr(p);
+               break;
+
+       case CPU_RM9000:
+               /*
+                * When the JTLB is updated by tlbwi or tlbwr, a subsequent
+                * use of the JTLB for instructions should not occur for 4
+                * cpu cycles and use for data translations should not occur
+                * for 3 cpu cycles.
+                */
+               i_ssnop(p);
+               i_ssnop(p);
+               i_ssnop(p);
+               i_ssnop(p);
+               i_tlbwr(p);
+               i_ssnop(p);
+               i_ssnop(p);
+               i_ssnop(p);
+               i_ssnop(p);
+               break;
+
+       default:
+               panic("No TLB refill handler yet (CPU type: %d)",
+                     current_cpu_data.cputype);
+               break;
+       }
+}
+
+#if CONFIG_MIPS64
+/*
+ * TMP and PTR are scratch.
+ * TMP will be clobbered, PTR will hold the pmd entry.
+ */
+static __init void
+build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
+                unsigned int tmp, unsigned int ptr)
+{
+       long pgdc = (long)pgd_current;
+
+       /*
+        * The vmalloc handling is not in the hotpath.
+        */
+       i_dmfc0(p, tmp, C0_BADVADDR);
+       il_bltz(p, r, tmp, label_vmalloc);
+       /* No i_nop needed here, since the next insn doesn't touch TMP. */
+
+# ifdef CONFIG_SMP
+       /*
+        * 64 bit SMP has the lower part of &pgd_current[smp_processor_id()]
+        * stored in CONTEXT.
+        */
+       if (in_compat_space_p(pgdc)) {
+               i_dmfc0(p, ptr, C0_CONTEXT);
+               i_dsra(p, ptr, ptr, 23);
+       } else {
+               i_dmfc0(p, ptr, C0_CONTEXT);
+               i_lui(p, tmp, rel_highest(pgdc));
+               i_dsll(p, ptr, ptr, 9);
+               i_daddiu(p, tmp, tmp, rel_higher(pgdc));
+               i_dsrl32(p, ptr, ptr, 0);
+               i_and(p, ptr, ptr, tmp);
+               i_dmfc0(p, tmp, C0_BADVADDR);
+       }
+       i_ld(p, ptr, 0, ptr);
+# else
+       i_LA_mostly(p, ptr, pgdc);
+       i_ld(p, ptr, rel_lo(pgdc), ptr);
+# endif
+
+       l_vmalloc_done(l, *p);
+       i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3); /* get pgd offset in bytes */
+       i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
+       i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
+       i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+       i_ld(p, ptr, 0, ptr); /* get pmd pointer */
+       i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
+       i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
+       i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
+}
+
+/*
+ * BVADDR is the faulting address, PTR is scratch.
+ * PTR will hold the pgd for vmalloc.
+ */
+static __init void
+build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+                       unsigned int bvaddr, unsigned int ptr)
+{
+       long swpd = (long)swapper_pg_dir;
+
+       l_vmalloc(l, *p);
+       i_LA(p, ptr, VMALLOC_START);
+       i_dsubu(p, bvaddr, bvaddr, ptr);
+
+       if (in_compat_space_p(swpd) && !rel_lo(swpd)) {
+               il_b(p, r, label_vmalloc_done);
+               i_lui(p, ptr, rel_hi(swpd));
+       } else {
+               i_LA_mostly(p, ptr, swpd);
+               il_b(p, r, label_vmalloc_done);
+               i_daddiu(p, ptr, ptr, rel_lo(swpd));
+       }
+}
+
+#else /* CONFIG_MIPS32 */
+
+/*
+ * TMP and PTR are scratch.
+ * TMP will be clobbered, PTR will hold the pgd entry.
+ */
+static __init void build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
+{
+       long pgdc = (long)pgd_current;
+
+       /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */
+#ifdef CONFIG_SMP
+       i_mfc0(p, ptr, C0_CONTEXT);
+       i_LA_mostly(p, tmp, pgdc);
+       i_srl(p, ptr, ptr, 23);
+       i_sll(p, ptr, ptr, 2);
+       i_addu(p, ptr, tmp, ptr);
+#else
+       i_LA_mostly(p, ptr, pgdc);
+#endif
+       i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+       i_lw(p, ptr, rel_lo(pgdc), ptr);
+       i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
+       i_sll(p, tmp, tmp, PGD_T_LOG2);
+       i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
+}
+#endif /* CONFIG_MIPS32 */
+
+static __init void build_adjust_context(u32 **p, unsigned int ctx)
+{
+       unsigned int shift = 0;
+       unsigned int mask = 0xff0;
+
+#if !defined(CONFIG_MIPS64) && !defined(CONFIG_64BIT_PHYS_ADDR)
+       shift++;
+       mask |= 0x008;
+#endif
+
+       switch (current_cpu_data.cputype) {
+       case CPU_VR41XX:
+       case CPU_VR4111:
+       case CPU_VR4121:
+       case CPU_VR4122:
+       case CPU_VR4131:
+       case CPU_VR4181:
+       case CPU_VR4181A:
+       case CPU_VR4133:
+               shift += 2;
+               break;
+
+       default:
+               break;
+       }
+
+       if (shift)
+               i_SRL(p, ctx, ctx, shift);
+       i_andi(p, ctx, ctx, mask);
+}
+
+static __init void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
+{
+       /*
+        * Bug workaround for the Nevada. It seems as if under certain
+        * circumstances the move from cp0_context might produce a
+        * bogus result when the mfc0 instruction and its consumer are
+        * in a different cacheline or a load instruction, probably any
+        * memory reference, is between them.
+        */
+       switch (current_cpu_data.cputype) {
+       case CPU_NEVADA:
+               i_LW(p, ptr, 0, ptr);
+               GET_CONTEXT(p, tmp); /* get context reg */
+               break;
+
+       default:
+               GET_CONTEXT(p, tmp); /* get context reg */
+               i_LW(p, ptr, 0, ptr);
+               break;
+       }
+
+       build_adjust_context(p, tmp);
+       i_ADDU(p, ptr, ptr, tmp); /* add in offset */
+}
+
+static __init void build_update_entries(u32 **p, unsigned int tmp,
+                                       unsigned int ptep)
+{
+       /*
+        * 64bit address support (36bit on a 32bit CPU) in a 32bit
+        * Kernel is a special case. Only a few CPUs use it.
+        */
+#ifdef CONFIG_64BIT_PHYS_ADDR
+       if (cpu_has_64bit_gp_regs) {
+               i_ld(p, tmp, 0, ptep); /* get even pte */
+               i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+               i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
+               i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+               i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
+               i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+       } else {
+               int pte_off_even = sizeof(pte_t) / 2;
+               int pte_off_odd = pte_off_even + sizeof(pte_t);
+
+               /* The pte entries are pre-shifted */
+               i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
+               i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+               i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
+               i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+       }
+#else
+       i_LW(p, tmp, 0, ptep); /* get even pte */
+       i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+       if (r45k_bvahwbug())
+               build_tlb_probe_entry(p);
+       i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
+       if (r4k_250MHZhwbug())
+               i_mtc0(p, 0, C0_ENTRYLO0);
+       i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+       i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
+       if (r45k_bvahwbug())
+               i_mfc0(p, tmp, C0_INDEX);
+       if (r4k_250MHZhwbug())
+               i_mtc0(p, 0, C0_ENTRYLO1);
+       i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+#endif
+}
+
+static void __init build_r4000_tlb_refill_handler(void)
+{
+       u32 *p = tlb_handler;
+       struct label *l = labels;
+       struct reloc *r = relocs;
+       u32 *f;
+       unsigned int final_len;
+
+       memset(tlb_handler, 0, sizeof(tlb_handler));
+       memset(labels, 0, sizeof(labels));
+       memset(relocs, 0, sizeof(relocs));
+       memset(final_handler, 0, sizeof(final_handler));
+
+       /*
+        * create the plain linear handler
+        */
+       if (bcm1250_m3_war()) {
+               i_MFC0(&p, K0, C0_BADVADDR);
+               i_MFC0(&p, K1, C0_ENTRYHI);
+               i_xor(&p, K0, K0, K1);
+               i_SRL(&p, K0, K0, PAGE_SHIFT+1);
+               il_bnez(&p, &r, K0, label_leave);
+               /* No need for i_nop */
+       }
+
+#ifdef CONFIG_MIPS64
+       build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd ptr in K1 */
+#else
+       build_get_pgde32(&p, K0, K1); /* get pgd ptr in K1 */
+#endif
+
+       build_get_ptep(&p, K0, K1);
+       build_update_entries(&p, K0, K1);
+       build_tlb_write_random_entry(&p, &l, &r);
+       l_leave(&l, p);
+       i_eret(&p); /* return from trap */
+
+#ifdef CONFIG_MIPS64
+       build_get_pgd_vmalloc64(&p, &l, &r, K0, K1);
+#endif
+
+       /*
+        * Overflow check: For the 64bit handler, we need at least one
+        * free instruction slot for the wrap-around branch. In worst
+        * case, if the intended insertion point is a delay slot, we
+        * need three, with the the second nop'ed and the third being
+        * unused.
+        */
+#ifdef CONFIG_MIPS32
+       if ((p - tlb_handler) > 64)
+               panic("TLB refill handler space exceeded");
+#else
+       if (((p - tlb_handler) > 63)
+           || (((p - tlb_handler) > 61)
+               && insn_has_bdelay(relocs, tlb_handler + 29)))
+               panic("TLB refill handler space exceeded");
+#endif
+
+       /*
+        * Now fold the handler in the TLB refill handler space.
+        */
+#ifdef CONFIG_MIPS32
+       f = final_handler;
+       /* Simplest case, just copy the handler. */
+       copy_handler(relocs, labels, tlb_handler, p, f);
+       final_len = p - tlb_handler;
+#else /* CONFIG_MIPS64 */
+       f = final_handler + 32;
+       if ((p - tlb_handler) <= 32) {
+               /* Just copy the handler. */
+               copy_handler(relocs, labels, tlb_handler, p, f);
+               final_len = p - tlb_handler;
+       } else {
+               u32 *split = tlb_handler + 30;
+
+               /*
+                * Find the split point.
+                */
+               if (insn_has_bdelay(relocs, split - 1))
+                       split--;
+
+               /* Copy first part of the handler. */
+               copy_handler(relocs, labels, tlb_handler, split, f);
+               f += split - tlb_handler;
+
+               /* Insert branch. */
+               l_split(&l, final_handler);
+               il_b(&f, &r, label_split);
+               if (insn_has_bdelay(relocs, split))
+                       i_nop(&f);
+               else {
+                       copy_handler(relocs, labels, split, split + 1, f);
+                       f++;
+                       split++;
+               }
+
+               /* Copy the rest of the handler. */
+               copy_handler(relocs, labels, split, p, final_handler);
+               final_len = (f - (final_handler + 32)) + (p - split);
+       }
+#endif /* CONFIG_MIPS64 */
+
+       resolve_relocs(relocs, labels);
+       printk("Synthesized TLB handler (%u instructions).\n", final_len);
+
+#ifdef DEBUG_TLB
+       {
+               int i;
+
+               for (i = 0; i < 64; i++)
+                       printk("%08x\n", final_handler[i]);
+       }
+#endif
+
+       memcpy((void *)CAC_BASE, final_handler, 0x100);
+       flush_icache_range(CAC_BASE, CAC_BASE + 0x100);
+}
+
+void __init build_tlb_refill_handler(void)
+{
+       switch (current_cpu_data.cputype) {
+#ifdef CONFIG_MIPS32
+       case CPU_R2000:
+       case CPU_R3000:
+       case CPU_R3000A:
+       case CPU_R3081E:
+       case CPU_TX3912:
+       case CPU_TX3922:
+       case CPU_TX3927:
+               build_r3000_tlb_refill_handler();
+               break;
+
+       case CPU_R6000:
+       case CPU_R6000A:
+               panic("No R6000 TLB refill handler yet");
+               break;
+#endif
+
+       case CPU_R8000:
+               panic("No R8000 TLB refill handler yet");
+               break;
+
+       default:
+               build_r4000_tlb_refill_handler();
+       }
+}
diff --git a/arch/mips/mm/tlbex32-mips32.S b/arch/mips/mm/tlbex32-mips32.S
new file mode 100644 (file)
index 0000000..96b3329
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * TLB exception handling code for MIPS32 CPUs.
+ *
+ * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
+ *
+ * Multi-cpu abstraction and reworking:
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * Pete Popov, ppopov@pacbell.net
+ * Added 36 bit phys address support.
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ */
+#include <linux/init.h>
+#include <asm/asm.h>
+#include <asm/cachectl.h>
+#include <asm/fpregdef.h>
+#include <asm/mipsregs.h>
+#include <asm/page.h>
+#include <asm/pgtable-bits.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+#define TLB_OPTIMIZE /* If you are paranoid, disable this. */
+
+#ifdef CONFIG_64BIT_PHYS_ADDR
+
+/* We really only support 36 bit physical addresses on MIPS32 */
+#define PTE_L          lw
+#define PTE_S          sw
+#define PTE_SRL                srl
+#define P_MTC0         mtc0
+#define PTE_HALF        4 /* pte_high contains pre-shifted, ready to go entry */
+#define PTE_SIZE        8
+#define PTEP_INDX_MSK  0xff0
+#define PTE_INDX_MSK   0xff8
+#define PTE_INDX_SHIFT 9
+#define CONVERT_PTE(pte)
+#define PTE_MAKEWRITE_HIGH(pte, ptr) \
+       lw      pte, PTE_HALF(ptr); \
+       ori     pte, (_PAGE_VALID | _PAGE_DIRTY); \
+       sw      pte, PTE_HALF(ptr); \
+       lw      pte, 0(ptr);
+
+#define PTE_MAKEVALID_HIGH(pte, ptr) \
+       lw      pte, PTE_HALF(ptr); \
+       ori     pte, pte, _PAGE_VALID; \
+       sw      pte, PTE_HALF(ptr); \
+       lw      pte, 0(ptr);
+
+#else
+
+#define PTE_L          lw
+#define PTE_S          sw
+#define PTE_SRL                srl
+#define P_MTC0         mtc0
+#define PTE_HALF        0
+#define PTE_SIZE       4
+#define PTEP_INDX_MSK  0xff8
+#define PTE_INDX_MSK   0xffc
+#define PTE_INDX_SHIFT 10
+#define CONVERT_PTE(pte) srl pte, pte, 6
+#define PTE_MAKEWRITE_HIGH(pte, ptr)
+#define PTE_MAKEVALID_HIGH(pte, ptr)
+
+#endif  /* CONFIG_64BIT_PHYS_ADDR */
+
+#ifdef CONFIG_64BIT_PHYS_ADDR
+#define GET_PTE_OFF(reg)
+#else
+#define GET_PTE_OFF(reg)       srl     reg, reg, 1
+#endif
+
+/*
+ * ABUSE of CPP macros 101.
+ *
+ * After this macro runs, the pte faulted on is
+ * in register PTE, a ptr into the table in which
+ * the pte belongs is in PTR.
+ */
+
+#ifdef CONFIG_SMP
+#define GET_PGD(scratch, ptr)        \
+       mfc0    ptr, CP0_CONTEXT;    \
+       la      scratch, pgd_current;\
+       srl     ptr, 23;             \
+       sll     ptr, 2;              \
+       addu    ptr, scratch, ptr;   \
+       lw      ptr, (ptr);
+#else
+#define GET_PGD(scratch, ptr)    \
+       lw      ptr, pgd_current;
+#endif
+
+#define LOAD_PTE(pte, ptr) \
+       GET_PGD(pte, ptr)          \
+       mfc0    pte, CP0_BADVADDR; \
+       srl     pte, pte, _PGDIR_SHIFT; \
+       sll     pte, pte, 2; \
+       addu    ptr, ptr, pte; \
+       mfc0    pte, CP0_BADVADDR; \
+       lw      ptr, (ptr); \
+       srl     pte, pte, PTE_INDX_SHIFT; \
+       and     pte, pte, PTE_INDX_MSK; \
+       addu    ptr, ptr, pte; \
+       PTE_L   pte, (ptr);
+
+       /* This places the even/odd pte pair in the page
+        * table at PTR into ENTRYLO0 and ENTRYLO1 using
+        * TMP as a scratch register.
+        */
+#define PTE_RELOAD(ptr, tmp) \
+       ori     ptr, ptr, PTE_SIZE; \
+       xori    ptr, ptr, PTE_SIZE; \
+       PTE_L   tmp, (PTE_HALF+PTE_SIZE)(ptr); \
+       CONVERT_PTE(tmp); \
+       P_MTC0  tmp, CP0_ENTRYLO1; \
+       PTE_L   ptr, PTE_HALF(ptr); \
+       CONVERT_PTE(ptr); \
+       P_MTC0  ptr, CP0_ENTRYLO0;
+
+#define DO_FAULT(write) \
+       .set    noat; \
+       SAVE_ALL; \
+       mfc0    a2, CP0_BADVADDR; \
+       KMODE; \
+       .set    at; \
+       move    a0, sp; \
+       jal     do_page_fault; \
+        li     a1, write; \
+       j       ret_from_exception; \
+        nop; \
+       .set    noat;
+
+       /* Check is PTE is present, if not then jump to LABEL.
+        * PTR points to the page table where this PTE is located,
+        * when the macro is done executing PTE will be restored
+        * with it's original value.
+        */
+#define PTE_PRESENT(pte, ptr, label) \
+       andi    pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
+       xori    pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
+       bnez    pte, label; \
+       PTE_L   pte, (ptr);
+
+       /* Make PTE valid, store result in PTR. */
+#define PTE_MAKEVALID(pte, ptr) \
+       ori     pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
+       PTE_S   pte, (ptr);
+
+       /* Check if PTE can be written to, if not branch to LABEL.
+        * Regardless restore PTE with value from PTR when done.
+        */
+#define PTE_WRITABLE(pte, ptr, label) \
+       andi    pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
+       xori    pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
+       bnez    pte, label; \
+       PTE_L   pte, (ptr);
+
+       /* Make PTE writable, update software status bits as well,
+        * then store at PTR.
+        */
+#define PTE_MAKEWRITE(pte, ptr) \
+       ori     pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
+                          _PAGE_VALID | _PAGE_DIRTY); \
+       PTE_S   pte, (ptr);
+
+       .set    noreorder
+
+       .align  5
+       NESTED(handle_tlbl, PT_SIZE, sp)
+       .set    noat
+invalid_tlbl:
+#ifdef TLB_OPTIMIZE
+       /* Test present bit in entry. */
+       LOAD_PTE(k0, k1)
+       tlbp
+       PTE_PRESENT(k0, k1, nopage_tlbl)
+       PTE_MAKEVALID_HIGH(k0, k1)
+       PTE_MAKEVALID(k0, k1)
+       PTE_RELOAD(k1, k0)
+       nop
+       b       1f
+        tlbwi
+1:
+       nop
+       .set    mips3
+       eret
+       .set    mips0
+#endif
+
+nopage_tlbl:
+       DO_FAULT(0)
+       END(handle_tlbl)
+
+       .align  5
+       NESTED(handle_tlbs, PT_SIZE, sp)
+       .set    noat
+#ifdef TLB_OPTIMIZE
+       .set    mips3
+        li      k0,0
+       LOAD_PTE(k0, k1)
+       tlbp                            # find faulting entry
+       PTE_WRITABLE(k0, k1, nopage_tlbs)
+       PTE_MAKEWRITE(k0, k1)
+       PTE_MAKEWRITE_HIGH(k0, k1)
+       PTE_RELOAD(k1, k0)
+       nop
+       b       1f
+        tlbwi
+1:
+       nop
+       .set    mips3
+       eret
+       .set    mips0
+#endif
+
+nopage_tlbs:
+       DO_FAULT(1)
+       END(handle_tlbs)
+
+       .align  5
+       NESTED(handle_mod, PT_SIZE, sp)
+       .set    noat
+#ifdef TLB_OPTIMIZE
+       .set    mips3
+       LOAD_PTE(k0, k1)
+       tlbp                                    # find faulting entry
+       andi    k0, k0, _PAGE_WRITE
+       beqz    k0, nowrite_mod
+       PTE_L   k0, (k1)
+
+       /* Present and writable bits set, set accessed and dirty bits. */
+       PTE_MAKEWRITE(k0, k1)
+       PTE_MAKEWRITE_HIGH(k0, k1)
+       /* Now reload the entry into the tlb. */
+       PTE_RELOAD(k1, k0)
+       nop
+       b       1f
+        tlbwi
+1:
+       nop
+       .set    mips3
+       eret
+       .set    mips0
+#endif
+
+nowrite_mod:
+       DO_FAULT(1)
+       END(handle_mod)
+
diff --git a/arch/mips/momentum/ocelot_3/Makefile b/arch/mips/momentum/ocelot_3/Makefile
new file mode 100644 (file)
index 0000000..aab8fd8
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for Momentum Computer's Ocelot-3 board.
+#
+# 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).
+#
+obj-y   += int-handler.o irq.o prom.o reset.o setup.o
diff --git a/arch/mips/momentum/ocelot_3/int-handler.S b/arch/mips/momentum/ocelot_3/int-handler.S
new file mode 100644 (file)
index 0000000..4522f09
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2002 Momentum Computer Inc.
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright 2004 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ *
+ * First-level interrupt dispatcher for Ocelot-3 board.
+ *
+ * This 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/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * First level interrupt dispatcher for Ocelot-3 board
+ */
+               .align  5
+               NESTED(ocelot3_handle_int, PT_SIZE, sp)
+               SAVE_ALL
+               CLI
+               .set    at
+
+               mfc0    t0, CP0_CAUSE
+               mfc0    t2, CP0_STATUS
+
+               and     t0, t2
+
+               andi    t1, t0, STATUSF_IP0     /* sw0 software interrupt (IRQ0) */
+               bnez    t1, ll_sw0_irq
+
+               andi    t1, t0, STATUSF_IP1     /* sw1 software interrupt (IRQ1) */
+               bnez    t1, ll_sw1_irq
+
+               andi    t1, t0, STATUSF_IP2     /* int0 hardware line (IRQ2) */
+               bnez    t1, ll_pci0slot1_irq
+
+               andi    t1, t0, STATUSF_IP3     /* int1 hardware line (IRQ3) */
+               bnez    t1, ll_pci0slot2_irq
+
+               andi    t1, t0, STATUSF_IP4     /* int2 hardware line (IRQ4) */
+               bnez    t1, ll_pci1slot1_irq
+
+               andi    t1, t0, STATUSF_IP5     /* int3 hardware line (IRQ5) */
+               bnez    t1, ll_pci1slot2_irq
+
+               andi    t1, t0, STATUSF_IP6     /* int4 hardware line (IRQ6) */
+               bnez    t1, ll_uart_irq
+
+               andi    t1, t0, STATUSF_IP7     /* cpu timer (IRQ7) */
+               bnez    t1, ll_cputimer_irq
+
+                /* now look at extended interrupts */
+                mfc0    t0, CP0_CAUSE
+                cfc0    t1, CP0_S1_INTCONTROL
+
+                /* shift the mask 8 bits left to line up the bits */
+                sll     t2, t1, 8
+
+                and     t0, t2
+                srl     t0, t0, 16
+
+                andi    t1, t0, STATUSF_IP8     /* int6 hardware line (IRQ9) */
+                bnez    t1, ll_mv64340_decode_irq
+
+               .set    reorder
+
+               /* wrong alarm or masked ... */
+               j       spurious_interrupt
+               nop
+               END(ocelot3_handle_int)
+
+               .align  5
+ll_sw0_irq:
+               li      a0, 0           /* IRQ 1 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+ll_sw1_irq:
+               li      a0, 1           /* IRQ 2 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_pci0slot1_irq:
+               li      a0, 2           /* IRQ 3 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_pci0slot2_irq:
+               li      a0, 3           /* IRQ 4 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_pci1slot1_irq:
+               li      a0, 4           /* IRQ 5 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_pci1slot2_irq:
+               li      a0, 5           /* IRQ 6 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_uart_irq:
+               li      a0, 6           /* IRQ 7 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_cputimer_irq:
+               li      a0, 7           /* IRQ 8 */
+               move    a1, sp
+               jal     do_IRQ
+               j       ret_from_irq
+
+ll_mv64340_decode_irq:
+               move    a0, sp
+               jal     ll_mv64340_irq
+               j       ret_from_irq
+
diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
new file mode 100644 (file)
index 0000000..42464db
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
+ *
+ * Copyright 2004 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  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 AUTHOR  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.
+ *
+ *  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.
+ *
+ *  Copyright (C) 2004 MontaVista Software Inc.
+ *  Author: Manish Lachwani, mlachwani@mvista.com
+ *
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+extern asmlinkage void ocelot3_handle_int(void);
+
+static struct irqaction cascade_mv64340 = {
+       no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
+};
+
+void __init arch_init_irq(void)
+{
+       /*
+        * Clear all of the interrupts while we change the able around a bit.
+        * int-handler is not on bootstrap
+        */
+       clear_c0_status(ST0_IM | ST0_BEV);
+
+       /* Sets the first-level interrupt dispatcher. */
+       set_except_vector(0, ocelot3_handle_int);
+       mips_cpu_irq_init(0);
+       rm7k_cpu_irq_init(8);
+
+       /* set up the cascading interrupts */
+       setup_irq(8, &cascade_mv64340);         /* unmask intControl IM8, IRQ 9 */
+       mv64340_irq_init(16);
+
+       set_c0_status(ST0_IM); /* IE in the status register */
+
+}
diff --git a/arch/mips/momentum/ocelot_3/ocelot_3_fpga.h b/arch/mips/momentum/ocelot_3/ocelot_3_fpga.h
new file mode 100644 (file)
index 0000000..227e429
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Ocelot-3 Board Register Definitions
+ *
+ * (C) 2002 Momentum Computer 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.
+ *
+ *  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 AUTHOR  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.
+ *
+ *  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.
+ *
+ *  Louis Hamilton, Red Hat, Inc.
+ *    hamilton@redhat.com  [MIPS64 modifications]
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ */
+
+#ifndef __OCELOT_3_FPGA_H__
+#define __OCELOT_3_FPGA_H__
+
+#define OCELOT_3_REG_BOARDREV          0x0
+#define OCELOT_3_REG_FPGA_REV          0x1
+#define OCELOT_3_REG_FPGA_TYPE         0x2
+#define OCELOT_3_REG_RESET_STATUS      0x3
+#define OCELOT_3_REG_BOARD_STATUS      0x4
+#define OCELOT_3_REG_CPCI_ID           0x5
+#define OCELOT_3_REG_SET               0x6
+#define OCELOT_3_REG_CLR               0x7
+#define OCELOT_3_REG_EEPROM_MODE       0x9
+#define OCELOT_3_REG_INTMASK           0xa
+#define OCELOT_3_REG_INTSTAT           0xb
+#define OCELOT_3_REG_UART_INTMASK      0xc
+#define OCELOT_3_REG_UART_INTSTAT      0xd
+#define OCELOT_3_REG_INTSET            0xe
+#define OCELOT_3_REG_INTCLR            0xf
+
+extern unsigned long ocelot_fpga_base;
+
+#define OCELOT_FPGA_WRITE(x, y) writeb(x, ocelot_fpga_base + OCELOT_3_REG_##y)
+#define OCELOT_FPGA_READ(x) readb(ocelot_fpga_base + OCELOT_3_REG_##x)
+
+#endif
diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c
new file mode 100644 (file)
index 0000000..89c17a0
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2002 Momentum Computer Inc.
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ * Louis Hamilton, Red Hat, Inc.
+ *   hamilton@redhat.com  [MIPS64 modifications]
+ *
+ * Copyright 2004 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * Based on Ocelot Linux port, which is
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mv643xx.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/pmon.h>
+#include "ocelot_3_fpga.h"
+
+struct callvectors* debug_vectors;
+extern unsigned long marvell_base;
+extern unsigned long cpu_clock;
+
+#ifdef CONFIG_MV643XX_ETH
+extern unsigned char prom_mac_addr_base[6];
+#endif
+
+const char *get_system_type(void)
+{
+       return "Momentum Ocelot-3";
+}
+
+#ifdef CONFIG_MV643XX_ETH
+void burn_clocks(void)
+{
+       int i;
+
+       /* this loop should burn at least 1us -- this should be plenty */
+       for (i = 0; i < 0x10000; i++)
+               ;
+}
+
+u8 exchange_bit(u8 val, u8 cs)
+{
+       /* place the data */
+       OCELOT_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
+       burn_clocks();
+
+       /* turn the clock on */
+       OCELOT_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
+       burn_clocks();
+
+       /* turn the clock off and read-strobe */
+       OCELOT_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
+
+       /* return the data */
+       return ((OCELOT_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
+}
+
+void get_mac(char dest[6])
+{
+       u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       int i,j;
+
+       for (i = 0; i < 12; i++)
+               exchange_bit(read_opcode[i], 1);
+
+       for (j = 0; j < 6; j++) {
+               dest[j] = 0;
+               for (i = 0; i < 8; i++) {
+                       dest[j] <<= 1;
+                       dest[j] |= exchange_bit(0, 1);
+               }
+       }
+
+       /* turn off CS */
+       exchange_bit(0,0);
+}
+#endif
+
+
+#ifdef CONFIG_MIPS64
+
+unsigned long signext(unsigned long addr)
+{
+       addr &= 0xffffffff;
+       return (unsigned long)((int)addr);
+}
+
+void *get_arg(unsigned long args, int arc)
+{
+       unsigned long ul;
+       unsigned char *puc, uc;
+
+       args += (arc * 4);
+       ul = (unsigned long)signext(args);
+       puc = (unsigned char *)ul;
+       if (puc == 0)
+               return (void *)0;
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+       uc = *puc++;
+       ul = (unsigned long)uc;
+       uc = *puc++;
+       ul |= (((unsigned long)uc) << 8);
+       uc = *puc++;
+       ul |= (((unsigned long)uc) << 16);
+       uc = *puc++;
+       ul |= (((unsigned long)uc) << 24);
+#else  /* CONFIG_CPU_LITTLE_ENDIAN */
+       uc = *puc++;
+       ul = ((unsigned long)uc) << 24;
+       uc = *puc++;
+       ul |= (((unsigned long)uc) << 16);
+       uc = *puc++;
+       ul |= (((unsigned long)uc) << 8);
+       uc = *puc++;
+       ul |= ((unsigned long)uc);
+#endif  /* CONFIG_CPU_LITTLE_ENDIAN */
+       ul = signext(ul);
+       return (void *)ul;
+}
+
+char *arg64(unsigned long addrin, int arg_index)
+{
+       unsigned long args;
+       char *p;
+
+       args = signext(addrin);
+       p = (char *)get_arg(args, arg_index);
+
+       return p;
+}
+#endif  /* CONFIG_MIPS64 */
+
+void __init prom_init(void)
+{
+       int argc = fw_arg0;
+       char **arg = (char **) fw_arg1;
+       char **env = (char **) fw_arg2;
+       struct callvectors *cv = (struct callvectors *) fw_arg3;
+       int i;
+
+#ifdef CONFIG_MIPS64
+       char *ptr;
+       printk("prom_init - MIPS64\n");
+
+       /* save the PROM vectors for debugging use */
+       debug_vectors = (struct callvectors *)signext((unsigned long)cv);
+
+       /* arg[0] is "g", the rest is boot parameters */
+       arcs_cmdline[0] = '\0';
+
+       for (i = 1; i < argc; i++) {
+               ptr = (char *)arg64((unsigned long)arg, i);
+               if ((strlen(arcs_cmdline) + strlen(ptr) + 1) >=
+                   sizeof(arcs_cmdline))
+                       break;
+               strcat(arcs_cmdline, ptr);
+               strcat(arcs_cmdline, " ");
+       }
+       i = 0;
+
+       while (1) {
+               ptr = (char *)arg64((unsigned long)env, i);
+               if (! ptr)
+                       break;
+
+               if (strncmp("gtbase", ptr, strlen("gtbase")) == 0) {
+                       marvell_base = simple_strtol(ptr + strlen("gtbase="),
+                                                       NULL, 16);
+
+                       if ((marvell_base & 0xffffffff00000000) == 0)
+                               marvell_base |= 0xffffffff00000000;
+
+                       printk("marvell_base set to 0x%016lx\n", marvell_base);
+               }
+               if (strncmp("cpuclock", ptr, strlen("cpuclock")) == 0) {
+                       cpu_clock = simple_strtol(ptr + strlen("cpuclock="),
+                                                       NULL, 10);
+                       printk("cpu_clock set to %d\n", cpu_clock);
+               }
+               i++;
+       }
+       printk("arcs_cmdline: %s\n", arcs_cmdline);
+
+#else   /* CONFIG_MIPS64 */
+
+       /* save the PROM vectors for debugging use */
+       debug_vectors = cv;
+
+       /* arg[0] is "g", the rest is boot parameters */
+       arcs_cmdline[0] = '\0';
+       for (i = 1; i < argc; i++) {
+               if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
+                   >= sizeof(arcs_cmdline))
+                       break;
+               strcat(arcs_cmdline, arg[i]);
+               strcat(arcs_cmdline, " ");
+       }
+
+       while (*env) {
+               if (strncmp("gtbase", *env, strlen("gtbase")) == 0) {
+                       marvell_base = simple_strtol(*env + strlen("gtbase="),
+                                                       NULL, 16);
+               }
+               if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0) {
+                       cpu_clock = simple_strtol(*env + strlen("cpuclock="),
+                                                       NULL, 10);
+               }
+               env++;
+       }
+#endif /* CONFIG_MIPS64 */
+
+       mips_machgroup = MACH_GROUP_MOMENCO;
+       mips_machtype = MACH_MOMENCO_OCELOT_3;
+
+#ifdef CONFIG_MV643XX_ETH
+       /* get the base MAC address for on-board ethernet ports */
+       get_mac(prom_mac_addr_base);
+#endif
+
+#ifndef CONFIG_MIPS64
+       debug_vectors->printf("Booting Linux kernel...\n");
+#endif
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
+{
+}
diff --git a/arch/mips/momentum/ocelot_3/reset.c b/arch/mips/momentum/ocelot_3/reset.c
new file mode 100644 (file)
index 0000000..cb7e356
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * This 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) 1997, 2001 Ralf Baechle
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright (C) 2002 Momentum Computer Inc.
+ * Author: Matthew Dharm <mdharm@momenco.com>
+ *
+ * Louis Hamilton, Red Hat, Inc.
+ * hamilton@redhat.com  [MIPS64 modifications]
+ *
+ * Copyright 2004 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+
+void momenco_ocelot_restart(char *command)
+{
+       /* base address of timekeeper portion of part */
+       void *nvram = (void *) 0xfc807000L;
+
+       /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
+       writeb(0x84, nvram + 0xff7);
+
+       /* wait for the watchdog to go off */
+       mdelay(100+(1000/16));
+
+       /* if the watchdog fails for some reason, let people know */
+       printk(KERN_NOTICE "Watchdog reset failed\n");
+}
+
+void momenco_ocelot_halt(void)
+{
+       printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+       while (1)
+               __asm__(".set\tmips3\n\t"
+                       "wait\n\t"
+                       ".set\tmips0");
+}
+
+void momenco_ocelot_power_off(void)
+{
+       momenco_ocelot_halt();
+}
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
new file mode 100644 (file)
index 0000000..9c73363
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * setup.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Momentum Computer Ocelot-3 board dependent boot routines
+ *
+ * Copyright (C) 1996, 1997, 2001  Ralf Baechle
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2002 Momentum Computer
+ *
+ * Author: Matthew Dharm, Momentum Computer
+ *   mdharm@momenco.com
+ *
+ * Louis Hamilton, Red Hat, Inc.
+ *   hamilton@redhat.com  [MIPS64 modifications]
+ *
+ * Author: RidgeRun, Inc.
+ *   glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright 2004 PMC-Sierra
+ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  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 AUTHOR  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.
+ *
+ *  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/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/timex.h>
+#include <linux/bootmem.h>
+#include <linux/mv643xx.h>
+#include <asm/time.h>
+#include <asm/page.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pci.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/reboot.h>
+#include <asm/mc146818rtc.h>
+#include <asm/tlbflush.h>
+#include "ocelot_3_fpga.h"
+
+/* Marvell Discovery Register Base */
+unsigned long marvell_base = (signed)0xf4000000;
+
+/* CPU clock */
+unsigned long cpu_clock;
+
+/* RTC/NVRAM */
+unsigned char* rtc_base = (unsigned char*)(signed)0xfc800000;
+
+/* FPGA Base */
+unsigned long ocelot_fpga_base = (signed)0xfc000000;
+
+/* Serial base */
+unsigned long uart_base = (signed)0xfd000000;
+
+/*
+ * Marvell Discovery SRAM. This is one place where Ethernet
+ * Tx and Rx descriptors can be placed to improve performance
+ */
+extern unsigned long mv64340_sram_base;
+
+/* These functions are used for rebooting or halting the machine*/
+extern void momenco_ocelot_restart(char *command);
+extern void momenco_ocelot_halt(void);
+extern void momenco_ocelot_power_off(void);
+
+void momenco_time_init(void);
+static char reset_reason;
+
+void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+                    unsigned long entryhi, unsigned long pagemask);
+
+static inline unsigned long ENTRYLO(unsigned long paddr)
+{
+       return ((paddr & PAGE_MASK) |
+               (_PAGE_PRESENT | __READABLE | __WRITEABLE | _PAGE_GLOBAL |
+               _CACHE_UNCACHED)) >> 6;
+}
+
+void __init bus_error_init(void)
+{
+       /* nothing */
+}
+
+/*
+ * setup code for a handoff from a version 2 PMON 2000 PROM
+ */
+void setup_wired_tlb_entries(void)
+{
+       write_c0_wired(0);
+       local_flush_tlb_all();
+
+       /* marvell and extra space */
+       add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000), (signed)0xf4000000, PM_64K);
+
+       /* fpga, rtc, and uart */
+       add_wired_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfd000000), (signed)0xfc000000, PM_16M);
+}
+
+#define CONV_BCD_TO_BIN(val)   (((val) & 0xf) + (((val) >> 4) * 10))
+#define CONV_BIN_TO_BCD(val)   (((val) % 10) + (((val) / 10) << 4))
+
+unsigned long m48t37y_get_time(void)
+{
+       unsigned int year, month, day, hour, min, sec;
+
+       /* stop the update */
+       rtc_base[0x7ff8] = 0x40;
+
+       year = CONV_BCD_TO_BIN(rtc_base[0x7fff]);
+       year += CONV_BCD_TO_BIN(rtc_base[0x7ff1]) * 100;
+
+       month = CONV_BCD_TO_BIN(rtc_base[0x7ffe]);
+
+       day = CONV_BCD_TO_BIN(rtc_base[0x7ffd]);
+
+       hour = CONV_BCD_TO_BIN(rtc_base[0x7ffb]);
+       min = CONV_BCD_TO_BIN(rtc_base[0x7ffa]);
+       sec = CONV_BCD_TO_BIN(rtc_base[0x7ff9]);
+
+       /* start the update */
+       rtc_base[0x7ff8] = 0x00;
+
+       return mktime(year, month, day, hour, min, sec);
+}
+
+int m48t37y_set_time(unsigned long sec)
+{
+       struct rtc_time tm;
+
+       /* convert to a more useful format -- note months count from 0 */
+       to_tm(sec, &tm);
+       tm.tm_mon += 1;
+
+       /* enable writing */
+       rtc_base[0x7ff8] = 0x80;
+
+       /* year */
+       rtc_base[0x7fff] = CONV_BIN_TO_BCD(tm.tm_year % 100);
+       rtc_base[0x7ff1] = CONV_BIN_TO_BCD(tm.tm_year / 100);
+
+       /* month */
+       rtc_base[0x7ffe] = CONV_BIN_TO_BCD(tm.tm_mon);
+
+       /* day */
+       rtc_base[0x7ffd] = CONV_BIN_TO_BCD(tm.tm_mday);
+
+       /* hour/min/sec */
+       rtc_base[0x7ffb] = CONV_BIN_TO_BCD(tm.tm_hour);
+       rtc_base[0x7ffa] = CONV_BIN_TO_BCD(tm.tm_min);
+       rtc_base[0x7ff9] = CONV_BIN_TO_BCD(tm.tm_sec);
+
+       /* day of week -- not really used, but let's keep it up-to-date */
+       rtc_base[0x7ffc] = CONV_BIN_TO_BCD(tm.tm_wday + 1);
+
+       /* disable writing */
+       rtc_base[0x7ff8] = 0x00;
+
+       return 0;
+}
+
+void momenco_timer_setup(struct irqaction *irq)
+{
+       setup_irq(7, irq);      /* Timer interrupt, unmask status IM7 */
+}
+
+void momenco_time_init(void)
+{
+       setup_wired_tlb_entries();
+
+       /*
+        * Ocelot-3 board has been built with both
+        * the Rm7900 and the Rm7065C
+        */
+       mips_hpt_frequency = cpu_clock / 2;
+       board_timer_setup = momenco_timer_setup;
+
+       rtc_get_time = m48t37y_get_time;
+       rtc_set_time = m48t37y_set_time;
+}
+
+/*
+ * PCI Support for Ocelot-3
+ */
+
+/* Bus #0 IO and MEM space */
+#define        OCELOT_3_PCI_IO_0_START         0xe0000000
+#define        OCELOT_3_PCI_IO_0_SIZE          0x08000000
+#define        OCELOT_3_PCI_MEM_0_START        0xc0000000
+#define        OCELOT_3_PCI_MEM_0_SIZE         0x10000000
+
+/* Bus #1 IO and MEM space */
+#define        OCELOT_3_PCI_IO_1_START         0xe8000000
+#define        OCELOT_3_PCI_IO_1_SIZE          0x08000000
+#define        OCELOT_3_PCI_MEM_1_START        0xd0000000
+#define        OCELOT_3_PCI_MEM_1_SIZE         0x10000000
+
+static struct resource mv_pci_io_mem0_resource = {
+       .name   = "MV64340 PCI0 IO MEM",
+       .start  = OCELOT_3_PCI_IO_0_START,
+       .end    = OCELOT_3_PCI_IO_0_START + OCELOT_3_PCI_IO_0_SIZE - 1,
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource mv_pci_io_mem1_resource = {
+       .name   = "MV64340 PCI1 IO MEM",
+       .start  = OCELOT_3_PCI_IO_1_START,
+       .end    = OCELOT_3_PCI_IO_1_START + OCELOT_3_PCI_IO_1_SIZE - 1,
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource mv_pci_mem0_resource = {
+       .name   = "MV64340 PCI0 MEM",
+       .start  = OCELOT_3_PCI_MEM_0_START,
+       .end    = OCELOT_3_PCI_MEM_0_START + OCELOT_3_PCI_MEM_0_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource mv_pci_mem1_resource = {
+       .name   = "MV64340 PCI1 MEM",
+       .start  = OCELOT_3_PCI_MEM_1_START,
+       .end    = OCELOT_3_PCI_MEM_1_START + OCELOT_3_PCI_MEM_1_SIZE - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct mv_pci_controller mv_bus0_controller = {
+       .pcic = {
+                .pci_ops       = &mv_pci_ops,
+                .mem_resource  = &mv_pci_mem0_resource,
+                .io_resource   = &mv_pci_io_mem0_resource,
+       },
+       .config_addr    = MV64340_PCI_0_CONFIG_ADDR,
+       .config_vreg    = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG,
+};
+
+static struct mv_pci_controller mv_bus1_controller = {
+       .pcic = {
+                .pci_ops       = &mv_pci_ops,
+                .mem_resource  = &mv_pci_mem1_resource,
+                .io_resource   = &mv_pci_io_mem1_resource,
+       },
+       .config_addr    = MV64340_PCI_1_CONFIG_ADDR,
+       .config_vreg    = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG,
+};
+
+static __init int __init ja_pci_init(void)
+{
+       uint32_t enable;
+       extern int pci_probe_only;
+
+       /* PMON will assign PCI resources */
+       pci_probe_only = 1;
+
+       enable = ~MV_READ(MV64340_BASE_ADDR_ENABLE);
+       /*
+        * We require at least one enabled I/O or PCI memory window or we
+        * will ignore this PCI bus.  We ignore PCI windows 1, 2 and 3.
+        */
+       if (enable & (0x01 <<  9) || enable & (0x01 << 10))
+               register_pci_controller(&mv_bus0_controller.pcic);
+
+       if (enable & (0x01 << 14) || enable & (0x01 << 15))
+               register_pci_controller(&mv_bus1_controller.pcic);
+
+       ioport_resource.end = OCELOT_3_PCI_IO_0_START + OCELOT_3_PCI_IO_0_SIZE +
+                                       OCELOT_3_PCI_IO_1_SIZE - 1;
+
+       iomem_resource.end = OCELOT_3_PCI_MEM_0_START + OCELOT_3_PCI_MEM_0_SIZE +
+                                       OCELOT_3_PCI_MEM_1_SIZE - 1;
+
+       set_io_port_base(OCELOT_3_PCI_IO_0_START); /* mips_io_port_base */
+
+       return 0;
+}
+
+arch_initcall(ja_pci_init);
+
+static int __init momenco_ocelot_3_setup(void)
+{
+       unsigned int tmpword;
+
+       board_time_init = momenco_time_init;
+
+       _machine_restart = momenco_ocelot_restart;
+       _machine_halt = momenco_ocelot_halt;
+       _machine_power_off = momenco_ocelot_power_off;
+
+       /* Wired TLB entries */
+       setup_wired_tlb_entries();
+
+       /* shut down ethernet ports, just to be sure our memory doesn't get
+        * corrupted by random ethernet traffic.
+        */
+       MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
+       MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
+       do {}
+         while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
+       do {}
+         while (MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
+       do {}
+         while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
+       do {}
+         while (MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
+       MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0),
+                MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
+       MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1),
+                MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
+
+       /* Turn off the Bit-Error LED */
+       OCELOT_FPGA_WRITE(0x80, CLR);
+
+       tmpword = OCELOT_FPGA_READ(BOARDREV);
+       if (tmpword < 26)
+               printk("Momenco Ocelot-3: Board Assembly Rev. %c\n",
+                       'A'+tmpword);
+       else
+               printk("Momenco Ocelot-3: Board Assembly Revision #0x%x\n",
+                       tmpword);
+
+       tmpword = OCELOT_FPGA_READ(FPGA_REV);
+       printk("FPGA Rev: %d.%d\n", tmpword>>4, tmpword&15);
+       tmpword = OCELOT_FPGA_READ(RESET_STATUS);
+       printk("Reset reason: 0x%x\n", tmpword);
+       switch (tmpword) {
+               case 0x1:
+                       printk("  - Power-up reset\n");
+                       break;
+               case 0x2:
+                       printk("  - Push-button reset\n");
+                       break;
+               case 0x4:
+                       printk("  - cPCI bus reset\n");
+                       break;
+               case 0x8:
+                       printk("  - Watchdog reset\n");
+                       break;
+               case 0x10:
+                       printk("  - Software reset\n");
+                       break;
+               default:
+                       printk("  - Unknown reset cause\n");
+       }
+       reset_reason = tmpword;
+       OCELOT_FPGA_WRITE(0xff, RESET_STATUS);
+
+       tmpword = OCELOT_FPGA_READ(CPCI_ID);
+       printk("cPCI ID register: 0x%02x\n", tmpword);
+       printk("  - Slot number: %d\n", tmpword & 0x1f);
+       printk("  - PCI bus present: %s\n", tmpword & 0x40 ? "yes" : "no");
+       printk("  - System Slot: %s\n", tmpword & 0x20 ? "yes" : "no");
+
+       tmpword = OCELOT_FPGA_READ(BOARD_STATUS);
+       printk("Board Status register: 0x%02x\n", tmpword);
+       printk("  - User jumper: %s\n", (tmpword & 0x80)?"installed":"absent");
+       printk("  - Boot flash write jumper: %s\n", (tmpword&0x40)?"installed":"absent");
+       printk("  - L3 cache size: %d MB\n", (1<<((tmpword&12) >> 2))&~1);
+
+       /* Support for 128 MB memory */
+       add_memory_region(0x0, 0x08000000, BOOT_MEM_RAM);
+
+       return 0;
+}
+
+early_initcall(momenco_ocelot_3_setup);
diff --git a/arch/mips/pci/fixup-ocelot3.c b/arch/mips/pci/fixup-ocelot3.c
new file mode 100644 (file)
index 0000000..ececc03
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 Montavista Software Inc.
+ * Author: Manish Lachwani (mlachwani@mvista.com)
+ *
+ * Looking at the schematics for the Ocelot-3 board, there are
+ * two PCI busses and each bus has two PCI slots.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/mipsregs.h>
+
+/*
+ * Do platform specific device initialization at
+ * pci_enable_device() time
+ */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int bus = dev->bus->number;
+
+       if (bus == 0 && slot == 1)
+               return 2;       /* PCI-X A */
+       if (bus == 0 && slot == 2)
+               return 3;       /* PCI-X B */
+       if (bus == 1 && slot == 1)
+               return 4;       /* PCI A */
+       if (bus == 1 && slot == 2)
+               return 5;       /* PCI B */
+
+return 0;
+       panic("Whooops in pcibios_map_irq");
+}
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug
new file mode 100644 (file)
index 0000000..8caaed1
--- /dev/null
@@ -0,0 +1,14 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_RWLOCK
+        bool "Read-write spinlock debugging"
+        depends on DEBUG_KERNEL && SMP
+        help
+          If you say Y here then read-write lock processing will count how many
+          times it has tried to get the lock and issue an error message after
+          too many attempts.  If you suspect a rwlock problem or a kernel
+          hacker asks for this option then say Y.  Otherwise say N.
+
+endmenu
diff --git a/arch/parisc/install.sh b/arch/parisc/install.sh
new file mode 100644 (file)
index 0000000..9632b3e
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# arch/parisc/install.sh, derived from arch/i386/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
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for i386 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
+if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
+
+# Default install
+
+if [ -f $4/vmlinux ]; then
+       mv $4/vmlinux $4/vmlinux.old
+fi
+
+if [ -f $4/System.map ]; then
+       mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinux
+cp $3 $4/System.map
diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c
new file mode 100644 (file)
index 0000000..ac2a406
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * arch/parisc/kernel/topology.c - Populate driverfs with topology 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.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+
+static struct cpu cpu_devices[NR_CPUS];
+
+static int __init topology_init(void)
+{
+       struct node *parent = NULL;
+       int num;
+
+       for_each_present_cpu(num) {
+               register_cpu(&cpu_devices[num], num, parent);
+       }
+       return 0;
+}
+
+subsys_initcall(topology_init);
diff --git a/arch/parisc/lib/fixup.S b/arch/parisc/lib/fixup.S
new file mode 100644 (file)
index 0000000..134f0cd
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ *  Copyright (C) 2004  Randolph Chung <tausq@debian.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * Fixup routines for kernel exception handling.
+ */
+#include <linux/config.h>
+#include <asm/offsets.h>
+#include <asm/assembly.h>
+#include <asm/errno.h>
+
+#ifdef CONFIG_SMP
+       .macro  get_fault_ip t1 t2
+       addil LT%__per_cpu_offset,%r27
+       LDREG RT%__per_cpu_offset(%r1),\t1
+       /* t2 = smp_processor_id() */
+       mfctl 30,\t2
+       ldw TI_CPU(\t2),\t2
+#ifdef __LP64__
+       extrd,u \t2,63,32,\t2
+#endif
+       /* t2 = &__per_cpu_offset[smp_processor_id()]; */
+       LDREG,s \t2(\t1),\t2 
+       addil LT%per_cpu__exception_data,%r27
+       LDREG RT%per_cpu__exception_data(%r1),\t1
+       /* t1 = &__get_cpu_var(exception_data) */
+       add,l \t1,\t2,\t1
+       /* t1 = t1->fault_ip */
+       LDREG EXCDATA_IP(\t1), \t1
+       .endm
+#else
+       .macro  get_fault_ip t1 t2
+       /* t1 = &__get_cpu_var(exception_data) */
+       addil LT%per_cpu__exception_data,%r27
+       LDREG RT%per_cpu__exception_data(%r1),\t2
+       /* t1 = t2->fault_ip */
+       LDREG EXCDATA_IP(\t2), \t1
+       .endm
+#endif
+
+       .text
+       .section .fixup, "ax"
+
+       /* get_user() fixups, store -EFAULT in r8, and 0 in r9 */
+       .export fixup_get_user_skip_1
+fixup_get_user_skip_1:
+       get_fault_ip %r1,%r8
+       ldo 4(%r1), %r1
+       ldi -EFAULT, %r8
+       bv %r0(%r1)
+       copy %r0, %r9
+
+       .export fixup_get_user_skip_2
+fixup_get_user_skip_2:
+       get_fault_ip %r1,%r8
+       ldo 8(%r1), %r1
+       ldi -EFAULT, %r8
+       bv %r0(%r1)
+       copy %r0, %r9
+
+       /* put_user() fixups, store -EFAULT in r8 */
+       .export fixup_put_user_skip_1
+fixup_put_user_skip_1:
+       get_fault_ip %r1,%r8
+       ldo 4(%r1), %r1
+       bv %r0(%r1)
+       ldi -EFAULT, %r8
+
+       .export fixup_put_user_skip_2
+fixup_put_user_skip_2:
+       get_fault_ip %r1,%r8
+       ldo 8(%r1), %r1
+       bv %r0(%r1)
+       ldi -EFAULT, %r8
diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
new file mode 100644 (file)
index 0000000..e743ca5
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ *    Optimized memory copy routines.
+ *
+ *    Copyright (C) 2004 Randolph Chung <tausq@debian.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Portions derived from the GNU C Library
+ *    Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc.
+ *
+ * Several strategies are tried to try to get the best performance for various
+ * conditions. In the optimal case, we copy 64-bytes in an unrolled loop using 
+ * fp regs. This is followed by loops that copy 32- or 16-bytes at a time using
+ * general registers.  Unaligned copies are handled either by aligning the 
+ * destination and then using shift-and-write method, or in a few cases by 
+ * falling back to a byte-at-a-time copy.
+ *
+ * I chose to implement this in C because it is easier to maintain and debug,
+ * and in my experiments it appears that the C code generated by gcc (3.3/3.4
+ * at the time of writing) is fairly optimal. Unfortunately some of the 
+ * semantics of the copy routine (exception handling) is difficult to express
+ * in C, so we have to play some tricks to get it to work.
+ *
+ * All the loads and stores are done via explicit asm() code in order to use
+ * the right space registers. 
+ * 
+ * Testing with various alignments and buffer sizes shows that this code is 
+ * often >10x faster than a simple byte-at-a-time copy, even for strangely
+ * aligned operands. It is interesting to note that the glibc version
+ * of memcpy (written in C) is actually quite fast already. This routine is 
+ * able to beat it by 30-40% for aligned copies because of the loop unrolling, 
+ * but in some cases the glibc version is still slightly faster. This lends 
+ * more credibility that gcc can generate very good code as long as we are 
+ * careful.
+ *
+ * TODO:
+ * - cache prefetching needs more experimentation to get optimal settings
+ * - try not to use the post-increment address modifiers; they create additional
+ *   interlocks
+ * - replace byte-copy loops with stybs sequences
+ */
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <asm/uaccess.h>
+#define s_space "%%sr1"
+#define d_space "%%sr2"
+#else
+#include "memcpy.h"
+#define s_space "%%sr0"
+#define d_space "%%sr0"
+#define pa_memcpy new2_copy
+#endif
+
+DECLARE_PER_CPU(struct exception_data, exception_data);
+
+#define preserve_branch(label) do {                                    \
+       volatile int dummy;                                             \
+       /* The following branch is never taken, it's just here to  */   \
+       /* prevent gcc from optimizing away our exception code. */      \
+       if (unlikely(dummy != dummy))                                   \
+               goto label;                                             \
+} while (0)
+
+#define get_user_space() (segment_eq(get_fs(), KERNEL_DS) ? 0 : mfsp(3))
+#define get_kernel_space() (0)
+
+#define MERGE(w0, sh_1, w1, sh_2)  ({                                  \
+       unsigned int _r;                                                \
+       asm volatile (                                                  \
+       "mtsar %3\n"                                                    \
+       "shrpw %1, %2, %%sar, %0\n"                                     \
+       : "=r"(_r)                                                      \
+       : "r"(w0), "r"(w1), "r"(sh_2)                                   \
+       );                                                              \
+       _r;                                                             \
+})
+#define THRESHOLD      16
+
+#ifdef DEBUG_MEMCPY
+#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#ifndef __LP64__
+#define EXC_WORD ".word"
+#else
+#define EXC_WORD ".dword"
+#endif
+
+#define def_load_ai_insn(_insn,_sz,_tt,_s,_a,_t,_e)    \
+       __asm__ __volatile__ (                          \
+       "1:\t" #_insn ",ma " #_sz "(" _s ",%1), %0\n"   \
+       "\t.section __ex_table,\"aw\"\n"                \
+       "\t" EXC_WORD "\t1b\n"                          \
+       "\t" EXC_WORD "\t" #_e "\n"                     \
+       "\t.previous\n"                                 \
+       : _tt(_t), "+r"(_a)                             \
+       : "1"(_a)                                       \
+       : "r8")
+
+#define def_store_ai_insn(_insn,_sz,_tt,_s,_a,_t,_e)   \
+       __asm__ __volatile__ (                          \
+       "1:\t" #_insn ",ma %1, " #_sz "(" _s ",%0)\n"   \
+       "\t.section __ex_table,\"aw\"\n"                \
+       "\t" EXC_WORD "\t1b\n"                          \
+       "\t" EXC_WORD "\t" #_e "\n"                     \
+       "\t.previous\n"                                 \
+       : "+r"(_a)                                      \
+       : _tt(_t), "0"(_a)                              \
+       : "r8")
+
+#define ldbma(_s, _a, _t, _e) def_load_ai_insn(ldbs,1,"=r",_s,_a,_t,_e)
+#define stbma(_s, _t, _a, _e) def_store_ai_insn(stbs,1,"r",_s,_a,_t,_e)
+#define ldwma(_s, _a, _t, _e) def_load_ai_insn(ldw,4,"=r",_s,_a,_t,_e)
+#define stwma(_s, _t, _a, _e) def_store_ai_insn(stw,4,"r",_s,_a,_t,_e)
+#define flddma(_s, _a, _t, _e) def_load_ai_insn(fldd,8,"=f",_s,_a,_t,_e)
+#define fstdma(_s, _t, _a, _e) def_store_ai_insn(fstd,8,"f",_s,_a,_t,_e)
+
+#define def_load_insn(_insn,_tt,_s,_o,_a,_t,_e)        \
+       __asm__ __volatile__ (                          \
+       "1:\t" #_insn " " #_o "(" _s ",%1), %0\n"       \
+       "\t.section __ex_table,\"aw\"\n"                \
+       "\t" EXC_WORD "\t1b\n"                          \
+       "\t" EXC_WORD "\t" #_e "\n"                     \
+       "\t.previous\n"                                 \
+       : _tt(_t)                                       \
+       : "r"(_a)                                       \
+       : "r8")
+
+#define def_store_insn(_insn,_tt,_s,_t,_o,_a,_e)       \
+       __asm__ __volatile__ (                          \
+       "1:\t" #_insn " %0, " #_o "(" _s ",%1)\n"       \
+       "\t.section __ex_table,\"aw\"\n"                \
+       "\t" EXC_WORD "\t1b\n"                          \
+       "\t" EXC_WORD "\t" #_e "\n"                     \
+       "\t.previous\n"                                 \
+       :                                               \
+       : _tt(_t), "r"(_a)                              \
+       : "r8")
+
+#define ldw(_s,_o,_a,_t,_e)    def_load_insn(ldw,"=r",_s,_o,_a,_t,_e)
+#define stw(_s,_t,_o,_a,_e)    def_store_insn(stw,"r",_s,_t,_o,_a,_e)
+
+#ifdef  CONFIG_PREFETCH
+extern inline void prefetch_src(const void *addr)
+{
+       __asm__("ldw 0(" s_space ",%0), %%r0" : : "r" (addr));
+}
+
+extern inline void prefetch_dst(const void *addr)
+{
+       __asm__("ldd 0(" d_space ",%0), %%r0" : : "r" (addr));
+}
+#else
+#define prefetch_src(addr)
+#define prefetch_dst(addr)
+#endif
+
+/* Copy from a not-aligned src to an aligned dst, using shifts. Handles 4 words
+ * per loop.  This code is derived from glibc. 
+ */
+static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src, unsigned long len, unsigned long o_dst, unsigned long o_src, unsigned long o_len)
+{
+       /* gcc complains that a2 and a3 may be uninitialized, but actually
+        * they cannot be.  Initialize a2/a3 to shut gcc up.
+        */
+       register unsigned int a0, a1, a2 = 0, a3 = 0;
+       int sh_1, sh_2;
+       struct exception_data *d;
+
+       /* prefetch_src((const void *)src); */
+
+       /* Calculate how to shift a word read at the memory operation
+          aligned srcp to make it aligned for copy.  */
+       sh_1 = 8 * (src % sizeof(unsigned int));
+       sh_2 = 8 * sizeof(unsigned int) - sh_1;
+
+       /* Make src aligned by rounding it down.  */
+       src &= -sizeof(unsigned int);
+
+       switch (len % 4)
+       {
+               case 2:
+                       /* a1 = ((unsigned int *) src)[0];
+                          a2 = ((unsigned int *) src)[1]; */
+                       ldw(s_space, 0, src, a1, cda_ldw_exc);
+                       ldw(s_space, 4, src, a2, cda_ldw_exc);
+                       src -= 1 * sizeof(unsigned int);
+                       dst -= 3 * sizeof(unsigned int);
+                       len += 2;
+                       goto do1;
+               case 3:
+                       /* a0 = ((unsigned int *) src)[0];
+                          a1 = ((unsigned int *) src)[1]; */
+                       ldw(s_space, 0, src, a0, cda_ldw_exc);
+                       ldw(s_space, 4, src, a1, cda_ldw_exc);
+                       src -= 0 * sizeof(unsigned int);
+                       dst -= 2 * sizeof(unsigned int);
+                       len += 1;
+                       goto do2;
+               case 0:
+                       if (len == 0)
+                               return 0;
+                       /* a3 = ((unsigned int *) src)[0];
+                          a0 = ((unsigned int *) src)[1]; */
+                       ldw(s_space, 0, src, a3, cda_ldw_exc);
+                       ldw(s_space, 4, src, a0, cda_ldw_exc);
+                       src -=-1 * sizeof(unsigned int);
+                       dst -= 1 * sizeof(unsigned int);
+                       len += 0;
+                       goto do3;
+               case 1:
+                       /* a2 = ((unsigned int *) src)[0];
+                          a3 = ((unsigned int *) src)[1]; */
+                       ldw(s_space, 0, src, a2, cda_ldw_exc);
+                       ldw(s_space, 4, src, a3, cda_ldw_exc);
+                       src -=-2 * sizeof(unsigned int);
+                       dst -= 0 * sizeof(unsigned int);
+                       len -= 1;
+                       if (len == 0)
+                               goto do0;
+                       goto do4;                       /* No-op.  */
+       }
+
+       do
+       {
+               /* prefetch_src((const void *)(src + 4 * sizeof(unsigned int))); */
+do4:
+               /* a0 = ((unsigned int *) src)[0]; */
+               ldw(s_space, 0, src, a0, cda_ldw_exc);
+               /* ((unsigned int *) dst)[0] = MERGE (a2, sh_1, a3, sh_2); */
+               stw(d_space, MERGE (a2, sh_1, a3, sh_2), 0, dst, cda_stw_exc);
+do3:
+               /* a1 = ((unsigned int *) src)[1]; */
+               ldw(s_space, 4, src, a1, cda_ldw_exc);
+               /* ((unsigned int *) dst)[1] = MERGE (a3, sh_1, a0, sh_2); */
+               stw(d_space, MERGE (a3, sh_1, a0, sh_2), 4, dst, cda_stw_exc);
+do2:
+               /* a2 = ((unsigned int *) src)[2]; */
+               ldw(s_space, 8, src, a2, cda_ldw_exc);
+               /* ((unsigned int *) dst)[2] = MERGE (a0, sh_1, a1, sh_2); */
+               stw(d_space, MERGE (a0, sh_1, a1, sh_2), 8, dst, cda_stw_exc);
+do1:
+               /* a3 = ((unsigned int *) src)[3]; */
+               ldw(s_space, 12, src, a3, cda_ldw_exc);
+               /* ((unsigned int *) dst)[3] = MERGE (a1, sh_1, a2, sh_2); */
+               stw(d_space, MERGE (a1, sh_1, a2, sh_2), 12, dst, cda_stw_exc);
+
+               src += 4 * sizeof(unsigned int);
+               dst += 4 * sizeof(unsigned int);
+               len -= 4;
+       }
+       while (len != 0);
+
+do0:
+       /* ((unsigned int *) dst)[0] = MERGE (a2, sh_1, a3, sh_2); */
+       stw(d_space, MERGE (a2, sh_1, a3, sh_2), 0, dst, cda_stw_exc);
+
+       preserve_branch(handle_load_error);
+       preserve_branch(handle_store_error);
+
+       return 0;
+
+handle_load_error:
+       __asm__ __volatile__ ("cda_ldw_exc:\n");
+       d = &__get_cpu_var(exception_data);
+       DPRINTF("cda_ldw_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n",
+               o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src);
+       return o_len * 4 - d->fault_addr + o_src;
+
+handle_store_error:
+       __asm__ __volatile__ ("cda_stw_exc:\n");
+       d = &__get_cpu_var(exception_data);
+       DPRINTF("cda_stw_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n",
+               o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst);
+       return o_len * 4 - d->fault_addr + o_dst;
+}
+
+
+/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
+unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
+{
+       register unsigned long src, dst, t1, t2, t3;
+       register char *pcs, *pcd;
+       register unsigned int *pws, *pwd;
+       register double *pds, *pdd;
+       unsigned long ret = 0;
+       unsigned long o_dst, o_src, o_len;
+       struct exception_data *d;
+
+       src = (unsigned long)srcp;
+       dst = (unsigned long)dstp;
+       pcs = (unsigned char *)srcp;
+       pcd = (unsigned char *)dstp;
+
+       o_dst = dst; o_src = src; o_len = len;
+
+       /* prefetch_src((const void *)srcp); */
+
+       if (len < THRESHOLD)
+               goto byte_copy;
+
+       /* Check alignment */
+       t1 = (src ^ dst);
+       if (unlikely(t1 & (sizeof(double)-1)))
+               goto unaligned_copy;
+
+       /* src and dst have same alignment. */
+
+       /* Copy bytes till we are double-aligned. */
+       t2 = src & (sizeof(double) - 1);
+       if (unlikely(t2 != 0)) {
+               t2 = sizeof(double) - t2;
+               while (t2 && len) {
+                       /* *pcd++ = *pcs++; */
+                       ldbma(s_space, pcs, t3, pmc_load_exc);
+                       len--;
+                       stbma(d_space, t3, pcd, pmc_store_exc);
+                       t2--;
+               }
+       }
+
+       pds = (double *)pcs;
+       pdd = (double *)pcd;
+
+       /* Copy 8 doubles at a time */
+       while (len >= 8*sizeof(double)) {
+               register double r1, r2, r3, r4, r5, r6, r7, r8;
+               /* prefetch_src((char *)pds + L1_CACHE_BYTES); */
+               flddma(s_space, pds, r1, pmc_load_exc);
+               flddma(s_space, pds, r2, pmc_load_exc);
+               flddma(s_space, pds, r3, pmc_load_exc);
+               flddma(s_space, pds, r4, pmc_load_exc);
+               fstdma(d_space, r1, pdd, pmc_store_exc);
+               fstdma(d_space, r2, pdd, pmc_store_exc);
+               fstdma(d_space, r3, pdd, pmc_store_exc);
+               fstdma(d_space, r4, pdd, pmc_store_exc);
+
+#if 0
+               if (L1_CACHE_BYTES <= 32)
+                       prefetch_src((char *)pds + L1_CACHE_BYTES);
+#endif
+               flddma(s_space, pds, r5, pmc_load_exc);
+               flddma(s_space, pds, r6, pmc_load_exc);
+               flddma(s_space, pds, r7, pmc_load_exc);
+               flddma(s_space, pds, r8, pmc_load_exc);
+               fstdma(d_space, r5, pdd, pmc_store_exc);
+               fstdma(d_space, r6, pdd, pmc_store_exc);
+               fstdma(d_space, r7, pdd, pmc_store_exc);
+               fstdma(d_space, r8, pdd, pmc_store_exc);
+               len -= 8*sizeof(double);
+       }
+
+       pws = (unsigned int *)pds;
+       pwd = (unsigned int *)pdd;
+
+word_copy:
+       while (len >= 8*sizeof(unsigned int)) {
+               register unsigned int r1,r2,r3,r4,r5,r6,r7,r8;
+               /* prefetch_src((char *)pws + L1_CACHE_BYTES); */
+               ldwma(s_space, pws, r1, pmc_load_exc);
+               ldwma(s_space, pws, r2, pmc_load_exc);
+               ldwma(s_space, pws, r3, pmc_load_exc);
+               ldwma(s_space, pws, r4, pmc_load_exc);
+               stwma(d_space, r1, pwd, pmc_store_exc);
+               stwma(d_space, r2, pwd, pmc_store_exc);
+               stwma(d_space, r3, pwd, pmc_store_exc);
+               stwma(d_space, r4, pwd, pmc_store_exc);
+
+               ldwma(s_space, pws, r5, pmc_load_exc);
+               ldwma(s_space, pws, r6, pmc_load_exc);
+               ldwma(s_space, pws, r7, pmc_load_exc);
+               ldwma(s_space, pws, r8, pmc_load_exc);
+               stwma(d_space, r5, pwd, pmc_store_exc);
+               stwma(d_space, r6, pwd, pmc_store_exc);
+               stwma(d_space, r7, pwd, pmc_store_exc);
+               stwma(d_space, r8, pwd, pmc_store_exc);
+               len -= 8*sizeof(unsigned int);
+       }
+
+       while (len >= 4*sizeof(unsigned int)) {
+               register unsigned int r1,r2,r3,r4;
+               ldwma(s_space, pws, r1, pmc_load_exc);
+               ldwma(s_space, pws, r2, pmc_load_exc);
+               ldwma(s_space, pws, r3, pmc_load_exc);
+               ldwma(s_space, pws, r4, pmc_load_exc);
+               stwma(d_space, r1, pwd, pmc_store_exc);
+               stwma(d_space, r2, pwd, pmc_store_exc);
+               stwma(d_space, r3, pwd, pmc_store_exc);
+               stwma(d_space, r4, pwd, pmc_store_exc);
+               len -= 4*sizeof(unsigned int);
+       }
+
+       pcs = (unsigned char *)pws;
+       pcd = (unsigned char *)pwd;
+
+byte_copy:
+       while (len) {
+               /* *pcd++ = *pcs++; */
+               ldbma(s_space, pcs, t3, pmc_load_exc);
+               stbma(d_space, t3, pcd, pmc_store_exc);
+               len--;
+       }
+
+       return 0;
+
+unaligned_copy:
+       /* possibly we are aligned on a word, but not on a double... */
+       if (likely(t1 & (sizeof(unsigned int)-1)) == 0) {
+               t2 = src & (sizeof(unsigned int) - 1);
+
+               if (unlikely(t2 != 0)) {
+                       t2 = sizeof(unsigned int) - t2;
+                       while (t2) {
+                               /* *pcd++ = *pcs++; */
+                               ldbma(s_space, pcs, t3, pmc_load_exc);
+                               stbma(d_space, t3, pcd, pmc_store_exc);
+                               len--;
+                               t2--;
+                       }
+               }
+
+               pws = (unsigned int *)pcs;
+               pwd = (unsigned int *)pcd;
+               goto word_copy;
+       }
+
+       /* Align the destination.  */
+       if (unlikely((dst & (sizeof(unsigned int) - 1)) != 0)) {
+               t2 = sizeof(unsigned int) - (dst & (sizeof(unsigned int) - 1));
+               while (t2) {
+                       /* *pcd++ = *pcs++; */
+                       ldbma(s_space, pcs, t3, pmc_load_exc);
+                       stbma(d_space, t3, pcd, pmc_store_exc);
+                       len--;
+                       t2--;
+               }
+               dst = (unsigned long)pcd;
+               src = (unsigned long)pcs;
+       }
+
+       ret = copy_dstaligned(dst, src, len / sizeof(unsigned int), 
+               o_dst, o_src, o_len);
+       if (ret)
+               return ret;
+
+       pcs += (len & -sizeof(unsigned int));
+       pcd += (len & -sizeof(unsigned int));
+       len %= sizeof(unsigned int);
+
+       preserve_branch(handle_load_error);
+       preserve_branch(handle_store_error);
+
+       goto byte_copy;
+
+handle_load_error:
+       __asm__ __volatile__ ("pmc_load_exc:\n");
+       d = &__get_cpu_var(exception_data);
+       DPRINTF("pmc_load_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n",
+               o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src);
+       return o_len - d->fault_addr + o_src;
+
+handle_store_error:
+       __asm__ __volatile__ ("pmc_store_exc:\n");
+       d = &__get_cpu_var(exception_data);
+       DPRINTF("pmc_store_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n",
+               o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst);
+       return o_len - d->fault_addr + o_dst;
+}
+
+#ifdef __KERNEL__
+unsigned long copy_to_user(void __user *dst, const void *src, unsigned long len)
+{
+       mtsp(get_kernel_space(), 1);
+       mtsp(get_user_space(), 2);
+       return pa_memcpy((void __force *)dst, src, len);
+}
+
+unsigned long copy_from_user(void *dst, const void __user *src, unsigned long len)
+{
+       mtsp(get_user_space(), 1);
+       mtsp(get_kernel_space(), 2);
+       return pa_memcpy(dst, (void __force *)src, len);
+}
+
+unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned long len)
+{
+       mtsp(get_user_space(), 1);
+       mtsp(get_user_space(), 2);
+       return pa_memcpy((void __force *)dst, (void __force *)src, len);
+}
+
+
+void * memcpy(void * dst,const void *src, size_t count)
+{
+       mtsp(get_kernel_space(), 1);
+       mtsp(get_kernel_space(), 2);
+       pa_memcpy(dst, src, count);
+       return dst;
+}
+
+void bcopy(const void * srcp, void * destp, size_t count)
+{
+       mtsp(get_kernel_space(), 1);
+       mtsp(get_kernel_space(), 2);
+       pa_memcpy(destp, srcp, count);
+}
+
+EXPORT_SYMBOL(copy_to_user);
+EXPORT_SYMBOL(copy_from_user);
+EXPORT_SYMBOL(copy_in_user);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(bcopy);
+#endif
diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug
new file mode 100644 (file)
index 0000000..0df2814
--- /dev/null
@@ -0,0 +1,84 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config KGDB
+       bool "Include kgdb kernel debugger"
+       depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx)
+       select DEBUG_INFO
+       help
+         Include in-kernel hooks for kgdb, the Linux kernel source level
+         debugger.  See <http://kgdb.sourceforge.net/> for more information.
+         Unless you are intending to debug the kernel, say N here.
+
+choice
+       prompt "Serial Port"
+       depends on KGDB
+       default KGDB_TTYS1
+
+config KGDB_TTYS0
+       bool "ttyS0"
+
+config KGDB_TTYS1
+       bool "ttyS1"
+
+config KGDB_TTYS2
+       bool "ttyS2"
+
+config KGDB_TTYS3
+       bool "ttyS3"
+
+endchoice
+
+config KGDB_CONSOLE
+       bool "Enable serial console thru kgdb port"
+       depends on KGDB && 8xx || CPM2
+       help
+         If you enable this, all serial console messages will be sent
+         over the gdb stub.
+         If unsure, say N.
+
+config XMON
+       bool "Include xmon kernel debugger"
+       depends on DEBUG_KERNEL
+       help
+         Include in-kernel hooks for the xmon kernel monitor/debugger.
+         Unless you are intending to debug the kernel, say N here.
+
+config BDI_SWITCH
+       bool "Include BDI-2000 user context switcher"
+       depends on DEBUG_KERNEL
+       help
+         Include in-kernel support for the Abatron BDI2000 debugger.
+         Unless you are intending to debug the kernel with one of these
+         machines, say N here.
+
+config SCHEDSTATS
+       bool "Collect scheduler statistics"
+       depends on DEBUG_KERNEL && PROC_FS
+       help
+         If you say Y here, additional code will be inserted into the
+         scheduler and related routines to collect statistics about
+         scheduler behavior and provide them in /proc/schedstat.  These
+         stats may be useful for both tuning and debugging the scheduler
+         If you aren't debugging the scheduler or trying to tune a specific
+         application, you can say N to avoid the very slight overhead
+         this adds.
+
+config BOOTX_TEXT
+       bool "Support for early boot text console (BootX or OpenFirmware only)"
+       depends PPC_OF
+       help
+         Say Y here to see progress messages from the boot firmware in text
+         mode. Requires either BootX or Open Firmware.
+
+config SERIAL_TEXT_DEBUG
+       bool "Support for early boot texts over serial port"
+       depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx
+
+config PPC_OCP
+       bool
+       depends on IBM_OCP || FSL_OCP
+       default y
+
+endmenu
diff --git a/arch/ppc/boot/include/serial.h b/arch/ppc/boot/include/serial.h
new file mode 100644 (file)
index 0000000..d710eab
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * A really private header file for the (dumb) serial driver in arch/ppc/boot
+ *
+ * Shamelessly taken from include/linux/serialP.h:
+ *
+ * Copyright (C) 1997 by Theodore Ts'o.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _PPC_BOOT_SERIALP_H
+#define _PPC_BOOT_SERIALP_H
+
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * Given that this is how SERIAL_PORT_DFNS are done, and that we need
+ * to use a few of their fields, we need to have our own copy of it.
+ */
+struct serial_state {
+       int     magic;
+       int     baud_base;
+       unsigned long   port;
+       int     irq;
+       int     flags;
+       int     hub6;
+       int     type;
+       int     line;
+       int     revision;       /* Chip revision (950) */
+       int     xmit_fifo_size;
+       int     custom_divisor;
+       int     count;
+       u8      *iomem_base;
+       u16     iomem_reg_shift;
+       unsigned short  close_delay;
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned long   icount;
+       int     io_type;
+       void    *info;
+       void    *dev;
+};
+#endif /* _PPC_BOOT_SERIAL_H */
diff --git a/arch/ppc/boot/simple/chrpmap.c b/arch/ppc/boot/simple/chrpmap.c
new file mode 100644 (file)
index 0000000..14d9e05
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * 2004 (C) IBM. This file is licensed under the terms of the GNU General
+ * Public License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <nonstdio.h>
+
+void board_isa_init(void)
+{
+       ISA_init(0xFE000000);
+}
diff --git a/arch/ppc/boot/simple/pibs.c b/arch/ppc/boot/simple/pibs.c
new file mode 100644 (file)
index 0000000..9ce8847
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/ppcboot.h>
+#include <platforms/4xx/ocotea.h>
+
+extern unsigned long decompress_kernel(unsigned long load_addr, int num_words,
+                                      unsigned long cksum);
+
+/* We need to make sure that this is before the images to ensure
+ * that it's in a mapped location. - Tom */
+bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
+bd_t *hold_residual = &hold_resid_buf;
+
+/* String functions lifted from lib/vsprintf.c and lib/ctype.c */
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,                /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,                       /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,                   /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,                       /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,                       /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,                       /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,     /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,                       /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,                       /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,                       /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,     /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,                       /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,                       /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,                       /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,               /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+       unsigned long long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*cp == '0') {
+                       base = 8;
+                       cp++;
+                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                               cp++;
+                               base = 16;
+                       }
+               }
+       } else if (base == 16) {
+               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+                       cp += 2;
+       }
+       while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+           ? toupper(*cp) : *cp)-'A'+10) < base) {
+               result = result*base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+       return result;
+}
+
+void *
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+               void *ign1, void *ign2)
+{
+       unsigned long long mac64;
+
+       decompress_kernel(load_addr, num_words, cksum);
+
+       mac64 = simple_strtoull((char *)OCOTEA_PIBS_MAC_BASE, 0, 16);
+       memcpy(hold_residual->bi_enetaddr, (char *)&mac64+2, 6);
+       mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET), 0, 16);
+       memcpy(hold_residual->bi_enet1addr, (char *)&mac64+2, 6);
+       mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*2), 0, 16);
+       memcpy(hold_residual->bi_enet2addr, (char *)&mac64+2, 6);
+       mac64 = simple_strtoull((char *)(OCOTEA_PIBS_MAC_BASE+OCOTEA_PIBS_MAC_OFFSET*3), 0, 16);
+       memcpy(hold_residual->bi_enet3addr, (char *)&mac64+2, 6);
+       return (void *)hold_residual;
+}
diff --git a/arch/ppc/boot/simple/prepmap.c b/arch/ppc/boot/simple/prepmap.c
new file mode 100644 (file)
index 0000000..c871a4d
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * 2004 (C) IBM. This file is licensed under the terms of the GNU General
+ * Public License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <nonstdio.h>
+
+void board_isa_init(void)
+{
+       ISA_init(0x80000000);
+}
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
new file mode 100644 (file)
index 0000000..6f54039
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef __HEAD_BOOKE_H__
+#define __HEAD_BOOKE_H__
+
+/*
+ * Macros used for common Book-e exception handling
+ */
+
+#define SET_IVOR(vector_number, vector_label)          \
+               li      r26,vector_label@l;             \
+               mtspr   SPRN_IVOR##vector_number,r26;   \
+               sync
+
+#define NORMAL_EXCEPTION_PROLOG                                                     \
+       mtspr   SPRN_SPRG0,r10;         /* save two registers to work with */\
+       mtspr   SPRN_SPRG1,r11;                                              \
+       mtspr   SPRN_SPRG4W,r1;                                              \
+       mfcr    r10;                    /* save CR in r10 for now          */\
+       mfspr   r11,SPRN_SRR1;          /* check whether user or kernel    */\
+       andi.   r11,r11,MSR_PR;                                              \
+       beq     1f;                                                          \
+       mfspr   r1,SPRG3;               /* if from user, start at top of   */\
+       lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
+       addi    r1,r1,THREAD_SIZE;                                           \
+1:     subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame     */\
+       tophys(r11,r1);                                                      \
+       stw     r10,_CCR(r11);          /* save various registers          */\
+       stw     r12,GPR12(r11);                                              \
+       stw     r9,GPR9(r11);                                                \
+       mfspr   r10,SPRG0;                                                   \
+       stw     r10,GPR10(r11);                                              \
+       mfspr   r12,SPRG1;                                                   \
+       stw     r12,GPR11(r11);                                              \
+       mflr    r10;                                                         \
+       stw     r10,_LINK(r11);                                              \
+       mfspr   r10,SPRG4R;                                                  \
+       mfspr   r12,SRR0;                                                    \
+       stw     r10,GPR1(r11);                                               \
+       mfspr   r9,SRR1;                                                     \
+       stw     r10,0(r11);                                                  \
+       rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
+       stw     r0,GPR0(r11);                                                \
+       SAVE_4GPRS(3, r11);                                                  \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Exception prolog for critical exceptions.  This is a little different
+ * from the normal exception prolog above since a critical exception
+ * can potentially occur at any point during normal exception processing.
+ * Thus we cannot use the same SPRG registers as the normal prolog above.
+ * Instead we use a couple of words of memory at low physical addresses.
+ * This is OK since we don't support SMP on these processors. For Book E
+ * processors, we also have a reserved register (SPRG2) that is only used
+ * in critical exceptions so we can free up a GPR to use as the base for
+ * indirect access to the critical exception save area.  This is necessary
+ * since the MMU is always on and the save area is offset from KERNELBASE.
+ */
+#define CRITICAL_EXCEPTION_PROLOG                                           \
+       mtspr   SPRG2,r8;               /* SPRG2 only used in criticals */   \
+       lis     r8,crit_save@ha;                                             \
+       stw     r10,crit_r10@l(r8);                                          \
+       stw     r11,crit_r11@l(r8);                                          \
+       mfspr   r10,SPRG0;                                                   \
+       stw     r10,crit_sprg0@l(r8);                                        \
+       mfspr   r10,SPRG1;                                                   \
+       stw     r10,crit_sprg1@l(r8);                                        \
+       mfspr   r10,SPRG4R;                                                  \
+       stw     r10,crit_sprg4@l(r8);                                        \
+       mfspr   r10,SPRG5R;                                                  \
+       stw     r10,crit_sprg5@l(r8);                                        \
+       mfspr   r10,SPRG7R;                                                  \
+       stw     r10,crit_sprg7@l(r8);                                        \
+       mfspr   r10,SPRN_PID;                                                \
+       stw     r10,crit_pid@l(r8);                                          \
+       mfspr   r10,SRR0;                                                    \
+       stw     r10,crit_srr0@l(r8);                                         \
+       mfspr   r10,SRR1;                                                    \
+       stw     r10,crit_srr1@l(r8);                                         \
+       mfspr   r8,SPRG2;               /* SPRG2 only used in criticals */   \
+       mfcr    r10;                    /* save CR in r10 for now          */\
+       mfspr   r11,SPRN_CSRR1;         /* check whether user or kernel    */\
+       andi.   r11,r11,MSR_PR;                                              \
+       lis     r11,critical_stack_top@h;                                    \
+       ori     r11,r11,critical_stack_top@l;                                \
+       beq     1f;                                                          \
+       /* COMING FROM USER MODE */                                          \
+       mfspr   r11,SPRG3;              /* if from user, start at top of   */\
+       lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+       addi    r11,r11,THREAD_SIZE;                                         \
+1:     subi    r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame     */\
+       stw     r10,_CCR(r11);          /* save various registers          */\
+       stw     r12,GPR12(r11);                                              \
+       stw     r9,GPR9(r11);                                                \
+       mflr    r10;                                                         \
+       stw     r10,_LINK(r11);                                              \
+       mfspr   r12,SPRN_DEAR;          /* save DEAR and ESR in the frame  */\
+       stw     r12,_DEAR(r11);         /* since they may have had stuff   */\
+       mfspr   r9,SPRN_ESR;            /* in them at the point where the  */\
+       stw     r9,_ESR(r11);           /* exception was taken             */\
+       mfspr   r12,CSRR0;                                                   \
+       stw     r1,GPR1(r11);                                                \
+       mfspr   r9,CSRR1;                                                    \
+       stw     r1,0(r11);                                                   \
+       tovirt(r1,r11);                                                      \
+       rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
+       stw     r0,GPR0(r11);                                                \
+       SAVE_4GPRS(3, r11);                                                  \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Exception prolog for machine check exceptions.  This is similar to
+ * the critical exception prolog, except that machine check exceptions
+ * have their own save area.  For Book E processors, we also have a
+ * reserved register (SPRG6) that is only used in machine check exceptions
+ * so we can free up a GPR to use as the base for indirect access to the
+ * machine check exception save area.  This is necessary since the MMU
+ * is always on and the save area is offset from KERNELBASE.
+ */
+#define MCHECK_EXCEPTION_PROLOG                                             \
+       mtspr   SPRG6W,r8;              /* SPRG6 used in machine checks */   \
+       lis     r8,mcheck_save@ha;                                           \
+       stw     r10,mcheck_r10@l(r8);                                        \
+       stw     r11,mcheck_r11@l(r8);                                        \
+       mfspr   r10,SPRG0;                                                   \
+       stw     r10,mcheck_sprg0@l(r8);                                      \
+       mfspr   r10,SPRG1;                                                   \
+       stw     r10,mcheck_sprg1@l(r8);                                      \
+       mfspr   r10,SPRG4R;                                                  \
+       stw     r10,mcheck_sprg4@l(r8);                                      \
+       mfspr   r10,SPRG5R;                                                  \
+       stw     r10,mcheck_sprg5@l(r8);                                      \
+       mfspr   r10,SPRG7R;                                                  \
+       stw     r10,mcheck_sprg7@l(r8);                                      \
+       mfspr   r10,SPRN_PID;                                                \
+       stw     r10,mcheck_pid@l(r8);                                        \
+       mfspr   r10,SRR0;                                                    \
+       stw     r10,mcheck_srr0@l(r8);                                       \
+       mfspr   r10,SRR1;                                                    \
+       stw     r10,mcheck_srr1@l(r8);                                       \
+       mfspr   r10,CSRR0;                                                   \
+       stw     r10,mcheck_csrr0@l(r8);                                      \
+       mfspr   r10,CSRR1;                                                   \
+       stw     r10,mcheck_csrr1@l(r8);                                      \
+       mfspr   r8,SPRG6R;              /* SPRG6 used in machine checks */   \
+       mfcr    r10;                    /* save CR in r10 for now          */\
+       mfspr   r11,SPRN_MCSRR1;        /* check whether user or kernel    */\
+       andi.   r11,r11,MSR_PR;                                              \
+       lis     r11,mcheck_stack_top@h;                                      \
+       ori     r11,r11,mcheck_stack_top@l;                                  \
+       beq     1f;                                                          \
+       /* COMING FROM USER MODE */                                          \
+       mfspr   r11,SPRG3;              /* if from user, start at top of   */\
+       lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+       addi    r11,r11,THREAD_SIZE;                                         \
+1:     subi    r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame     */\
+       stw     r10,_CCR(r11);          /* save various registers          */\
+       stw     r12,GPR12(r11);                                              \
+       stw     r9,GPR9(r11);                                                \
+       mflr    r10;                                                         \
+       stw     r10,_LINK(r11);                                              \
+       mfspr   r12,SPRN_DEAR;          /* save DEAR and ESR in the frame  */\
+       stw     r12,_DEAR(r11);         /* since they may have had stuff   */\
+       mfspr   r9,SPRN_ESR;            /* in them at the point where the  */\
+       stw     r9,_ESR(r11);           /* exception was taken             */\
+       mfspr   r12,MCSRR0;                                                  \
+       stw     r1,GPR1(r11);                                                \
+       mfspr   r9,MCSRR1;                                                   \
+       stw     r1,0(r11);                                                   \
+       tovirt(r1,r11);                                                      \
+       rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
+       stw     r0,GPR0(r11);                                                \
+       SAVE_4GPRS(3, r11);                                                  \
+       SAVE_2GPRS(7, r11)
+
+/*
+ * Exception vectors.
+ */
+#define        START_EXCEPTION(label)                                               \
+        .align 5;                                                                   \
+label:
+
+#define FINISH_EXCEPTION(func)                                 \
+       bl      transfer_to_handler_full;                       \
+       .long   func;                                           \
+       .long   ret_from_except_full
+
+#define EXCEPTION(n, label, hdlr, xfer)                                \
+       START_EXCEPTION(label);                                 \
+       NORMAL_EXCEPTION_PROLOG;                                \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       xfer(n, hdlr)
+
+#define CRITICAL_EXCEPTION(n, label, hdlr)                     \
+       START_EXCEPTION(label);                                 \
+       CRITICAL_EXCEPTION_PROLOG;                              \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+                         NOCOPY, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define MCHECK_EXCEPTION(n, label, hdlr)                       \
+       START_EXCEPTION(label);                                 \
+       MCHECK_EXCEPTION_PROLOG;                                \
+       mfspr   r5,SPRN_ESR;                                    \
+       stw     r5,_ESR(r11);                                   \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
+       EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+                         NOCOPY, mcheck_transfer_to_handler,   \
+                         ret_from_mcheck_exc)
+
+#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)  \
+       li      r10,trap;                                       \
+       stw     r10,TRAP(r11);                                  \
+       lis     r10,msr@h;                                      \
+       ori     r10,r10,msr@l;                                  \
+       copyee(r10, r9);                                        \
+       bl      tfer;                                           \
+       .long   hdlr;                                           \
+       .long   ret
+
+#define COPY_EE(d, s)          rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)          \
+       EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)         \
+       EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+                         ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)           \
+       EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
+                         ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)      \
+       EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
+                         ret_from_except)
+
+
+#endif /* __HEAD_BOOKE_H__ */
diff --git a/arch/ppc/platforms/4xx/virtex-ii_pro.c b/arch/ppc/platforms/4xx/virtex-ii_pro.c
new file mode 100644 (file)
index 0000000..097cc9d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/ppc/platforms/4xx/virtex-ii_pro.c
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ocp.h>
+#include "virtex-ii_pro.h"
+
+/* Have OCP take care of the serial ports. */
+struct ocp_def core_ocp[] = {
+#ifdef XPAR_UARTNS550_0_BASEADDR
+       { .vendor       = OCP_VENDOR_XILINX,
+         .function     = OCP_FUNC_16550,
+         .index        = 0,
+         .paddr        = XPAR_UARTNS550_0_BASEADDR,
+         .irq          = XPAR_INTC_0_UARTNS550_0_VEC_ID,
+         .pm           = OCP_CPM_NA
+       },
+#ifdef XPAR_UARTNS550_1_BASEADDR
+       { .vendor       = OCP_VENDOR_XILINX,
+         .function     = OCP_FUNC_16550,
+         .index        = 1,
+         .paddr        = XPAR_UARTNS550_1_BASEADDR,
+         .irq          = XPAR_INTC_0_UARTNS550_1_VEC_ID,
+         .pm           = OCP_CPM_NA
+       },
+#ifdef XPAR_UARTNS550_2_BASEADDR
+       { .vendor       = OCP_VENDOR_XILINX,
+         .function     = OCP_FUNC_16550,
+         .index        = 2,
+         .paddr        = XPAR_UARTNS550_2_BASEADDR,
+         .irq          = XPAR_INTC_0_UARTNS550_2_VEC_ID,
+         .pm           = OCP_CPM_NA
+       },
+#ifdef XPAR_UARTNS550_3_BASEADDR
+       { .vendor       = OCP_VENDOR_XILINX,
+         .function     = OCP_FUNC_16550,
+         .index        = 3,
+         .paddr        = XPAR_UARTNS550_3_BASEADDR,
+         .irq          = XPAR_INTC_0_UARTNS550_3_VEC_ID,
+         .pm           = OCP_CPM_NA
+       },
+#ifdef XPAR_UARTNS550_4_BASEADDR
+#error Edit this file to add more devices.
+#endif                 /* 4 */
+#endif                 /* 3 */
+#endif                 /* 2 */
+#endif                 /* 1 */
+#endif                 /* 0 */
+       { .vendor       = OCP_VENDOR_INVALID
+       }
+};
diff --git a/arch/ppc/platforms/4xx/virtex-ii_pro.h b/arch/ppc/platforms/4xx/virtex-ii_pro.h
new file mode 100644 (file)
index 0000000..9014c48
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * arch/ppc/platforms/4xx/virtex-ii_pro.h
+ *
+ * Include file that defines the Xilinx Virtex-II Pro processor
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_VIRTEXIIPRO_H__
+#define __ASM_VIRTEXIIPRO_H__
+
+#include <linux/config.h>
+#include <asm/xparameters.h>
+
+/* serial defines */
+
+#define RS_TABLE_SIZE  4       /* change this and add more devices below
+                                  if you have more then 4 16x50 UARTs */
+
+#define BASE_BAUD              (XPAR_UARTNS550_0_CLOCK_FREQ_HZ/16)
+
+/* The serial ports in the Virtex-II Pro have each I/O byte in the
+ * LSByte of a word.  This means that iomem_reg_shift needs to be 2 to
+ * change the byte offsets into word offsets.  In addition the base
+ * addresses need to have 3 added to them to get to the LSByte.
+ */
+#define STD_UART_OP(num)                                                \
+       { 0, BASE_BAUD, 0, XPAR_INTC_0_UARTNS550_##num##_VEC_ID,         \
+               ASYNC_BOOT_AUTOCONF,                                     \
+               .iomem_base = (u8 *)XPAR_UARTNS550_##num##_BASEADDR + 3, \
+               .iomem_reg_shift = 2,                                    \
+               .io_type = SERIAL_IO_MEM},
+
+#if defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
+#define ML300_UART0 STD_UART_OP(0)
+#else
+#define ML300_UART0
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
+#define ML300_UART1 STD_UART_OP(1)
+#else
+#define ML300_UART1
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
+#define ML300_UART2 STD_UART_OP(2)
+#else
+#define ML300_UART2
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
+#define ML300_UART3 STD_UART_OP(3)
+#else
+#define ML300_UART3
+#endif
+
+#if defined(XPAR_INTC_0_UARTNS550_4_VEC_ID)
+#error Edit this file to add more devices.
+#elif defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
+#define NR_SER_PORTS   4
+#elif defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
+#define NR_SER_PORTS   3
+#elif defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
+#define NR_SER_PORTS   2
+#elif defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
+#define NR_SER_PORTS   1
+#else
+#define NR_SER_PORTS   0
+#endif
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_PORT_DFNS       \
+       ML300_UART0             \
+       ML300_UART1             \
+       ML300_UART2             \
+       ML300_UART3
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_PORT_DFNS       \
+       ML300_UART1             \
+       ML300_UART0             \
+       ML300_UART2             \
+       ML300_UART3
+#endif
+
+#define DCRN_CPMFR_BASE        0
+
+#include <asm/ibm405.h>
+
+#endif                         /* __ASM_VIRTEXIIPRO_H__ */
+#endif                         /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
new file mode 100644 (file)
index 0000000..d07fe02
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * arch/ppc/platforms/4xx/xilinx_ml300.c
+ *
+ * Xilinx ML300 evaluation board initialization
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serialP.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+
+#include <platforms/4xx/virtex-ii_pro.h>       /* for NR_SER_PORTS */
+
+/*
+ * As an overview of how the following functions (platform_init,
+ * ml300_map_io, ml300_setup_arch and ml300_init_IRQ) fit into the
+ * kernel startup procedure, here's a call tree:
+ *
+ * start_here                                  arch/ppc/kernel/head_4xx.S
+ *  early_init                                 arch/ppc/kernel/setup.c
+ *  machine_init                               arch/ppc/kernel/setup.c
+ *    platform_init                            this file
+ *      ppc4xx_init                            arch/ppc/syslib/ppc4xx_setup.c
+ *        parse_bootinfo
+ *          find_bootinfo
+ *        "setup some default ppc_md pointers"
+ *  MMU_init                                   arch/ppc/mm/init.c
+ *    *ppc_md.setup_io_mappings == ml300_map_io        this file
+ *      ppc4xx_map_io                          arch/ppc/syslib/ppc4xx_setup.c
+ *  start_kernel                               init/main.c
+ *    setup_arch                               arch/ppc/kernel/setup.c
+ * #if defined(CONFIG_KGDB)
+ *      *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc
+ * #endif
+ *      *ppc_md.setup_arch == ml300_setup_arch this file
+ *        ppc4xx_setup_arch                    arch/ppc/syslib/ppc4xx_setup.c
+ *          ppc4xx_find_bridges                        arch/ppc/syslib/ppc405_pci.c
+ *    init_IRQ                                 arch/ppc/kernel/irq.c
+ *      *ppc_md.init_IRQ == ml300_init_IRQ     this file
+ *        ppc4xx_init_IRQ                      arch/ppc/syslib/ppc4xx_setup.c
+ *          ppc4xx_pic_init                    arch/ppc/syslib/xilinx_pic.c
+ */
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+
+static volatile unsigned *powerdown_base =
+    (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
+
+static void
+xilinx_power_off(void)
+{
+       local_irq_disable();
+       out_be32(powerdown_base, XPAR_POWER_0_POWERDOWN_VALUE);
+       while (1) ;
+}
+#endif
+
+void __init
+ml300_map_io(void)
+{
+       ppc4xx_map_io();
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+       powerdown_base = ioremap((unsigned long) powerdown_base,
+                                XPAR_POWER_0_POWERDOWN_HIGHADDR -
+                                XPAR_POWER_0_POWERDOWN_BASEADDR + 1);
+#endif
+}
+
+static void __init
+ml300_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+       struct serial_state old_ports[] = { SERIAL_PORT_DFNS };
+       struct uart_port port;
+       int i;
+
+       /* Setup ioremapped serial port access */
+       for (i = 0; i < ARRAY_SIZE(old_ports); i++ ) {
+               memset(&port, 0, sizeof(port));
+               port.membase = ioremap((phys_addr_t)(old_ports[i].iomem_base), 16);
+               port.irq = old_ports[i].irq;
+               port.uartclk = old_ports[i].baud_base * 16;
+               port.regshift = old_ports[i].iomem_reg_shift;
+               port.iotype = SERIAL_IO_MEM;
+               port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+               port.line = i;
+
+               if (early_serial_setup(&port) != 0) {
+                       printk("Early serial init of port %d failed\n", i);
+               }
+       }
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+void __init
+ml300_setup_arch(void)
+{
+       ppc4xx_setup_arch();    /* calls ppc4xx_find_bridges() */
+
+       ml300_early_serial_map();
+
+       /* Identify the system */
+       printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
+       printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+/* Called after board_setup_irq from ppc4xx_init_IRQ(). */
+void __init
+ml300_init_irq(void)
+{
+       unsigned int i;
+
+       ppc4xx_init_IRQ();
+
+       /*
+        * For PowerPC 405 cores the default value for NR_IRQS is 32.
+        * See include/asm-ppc/irq.h for details.
+        * This is just fine for ML300.
+        */
+#if (NR_IRQS != 32)
+#error NR_IRQS must be 32 for ML300
+#endif
+
+       for (i = 0; i < NR_IRQS; i++) {
+               if (XPAR_INTC_0_KIND_OF_INTR & (0x80000000 >> i))
+                       irq_desc[i].status &= ~IRQ_LEVEL;
+               else
+                       irq_desc[i].status |= IRQ_LEVEL;
+       }
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       ppc4xx_init(r3, r4, r5, r6, r7);
+
+       ppc_md.setup_arch = ml300_setup_arch;
+       ppc_md.setup_io_mappings = ml300_map_io;
+       ppc_md.init_IRQ = ml300_init_irq;
+
+#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
+       ppc_md.power_off = xilinx_power_off;
+#endif
+
+#ifdef CONFIG_KGDB
+       ppc_md.early_serial_map = ml300_early_serial_map;
+#endif
+}
+
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h
new file mode 100644 (file)
index 0000000..f8c5884
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * arch/ppc/platforms/4xx/xilinx_ml300.h
+ *
+ * Include file that defines the Xilinx ML300 evaluation board
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
+ * terms of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_XILINX_ML300_H__
+#define __ASM_XILINX_ML300_H__
+
+/* ML300 has a Xilinx Virtex-II Pro processor */
+#include <platforms/4xx/virtex-ii_pro.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+typedef struct board_info {
+       unsigned int     bi_memsize;            /* DRAM installed, in bytes */
+       unsigned char    bi_enetaddr[6];        /* Local Ethernet MAC address */
+       unsigned int     bi_intfreq;            /* Processor speed, in Hz */
+       unsigned int     bi_busfreq;            /* PLB Bus speed, in Hz */
+       unsigned int     bi_pci_busfreq;        /* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped.  Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR    0u
+#define PPC4xx_ONB_IO_VADDR    0u
+#define PPC4xx_ONB_IO_SIZE     0u
+
+#define PPC4xx_MACHINE_NAME "Xilinx ML300"
+
+#endif /* __ASM_XILINX_ML300_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h b/arch/ppc/platforms/4xx/xparameters/xparameters_ml300.h
new file mode 100644 (file)
index 0000000..97e3f4d
--- /dev/null
@@ -0,0 +1,310 @@
+/*******************************************************************
+*
+*     Author: Xilinx, 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.
+*
+*
+*     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
+*     COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
+*     ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD,
+*     XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
+*     FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING
+*     ANY THIRD PARTY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
+*     XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
+*     THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY
+*     WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM
+*     CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND
+*     FITNESS FOR A PARTICULAR PURPOSE.
+*
+*
+*     Xilinx hardware products are not intended for use in life support
+*     appliances, devices, or systems. Use in such applications is
+*     expressly prohibited.
+*
+*
+*     (c) Copyright 2002-2004 Xilinx Inc.
+*     All rights reserved.
+*
+*
+*     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.
+*
+* Description: Driver parameters
+*
+*******************************************************************/
+
+#define XPAR_XPCI_NUM_INSTANCES 1
+#define XPAR_XPCI_CLOCK_HZ 33333333
+#define XPAR_OPB_PCI_REF_0_DEVICE_ID 0
+#define XPAR_OPB_PCI_REF_0_BASEADDR 0x20000000
+#define XPAR_OPB_PCI_REF_0_HIGHADDR 0x3FFFFFFF
+#define XPAR_OPB_PCI_REF_0_CONFIG_ADDR 0x3C000000
+#define XPAR_OPB_PCI_REF_0_CONFIG_DATA 0x3C000004
+#define XPAR_OPB_PCI_REF_0_LCONFIG_ADDR 0x3E000000
+#define XPAR_OPB_PCI_REF_0_MEM_BASEADDR 0x20000000
+#define XPAR_OPB_PCI_REF_0_MEM_HIGHADDR 0x37FFFFFF
+#define XPAR_OPB_PCI_REF_0_IO_BASEADDR 0x38000000
+#define XPAR_OPB_PCI_REF_0_IO_HIGHADDR 0x3BFFFFFF
+
+/******************************************************************/
+
+#define XPAR_XEMAC_NUM_INSTANCES 1
+#define XPAR_OPB_ETHERNET_0_BASEADDR 0x60000000
+#define XPAR_OPB_ETHERNET_0_HIGHADDR 0x60003FFF
+#define XPAR_OPB_ETHERNET_0_DEVICE_ID 0
+#define XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST 1
+#define XPAR_OPB_ETHERNET_0_DMA_PRESENT 1
+#define XPAR_OPB_ETHERNET_0_MII_EXIST 1
+
+/******************************************************************/
+
+#define XPAR_MY_OPB_GPIO_0_DEVICE_ID_0 0
+#define XPAR_MY_OPB_GPIO_0_BASEADDR_0 0x90000000
+#define XPAR_MY_OPB_GPIO_0_HIGHADDR_0 (0x90000000+0x7)
+#define XPAR_MY_OPB_GPIO_0_DEVICE_ID_1 1
+#define XPAR_MY_OPB_GPIO_0_BASEADDR_1 (0x90000000+0x8)
+#define XPAR_MY_OPB_GPIO_0_HIGHADDR_1 (0x90000000+0x1F)
+#define XPAR_XGPIO_NUM_INSTANCES 2
+
+/******************************************************************/
+
+#define XPAR_XIIC_NUM_INSTANCES 1
+#define XPAR_OPB_IIC_0_BASEADDR 0xA8000000
+#define XPAR_OPB_IIC_0_HIGHADDR 0xA80001FF
+#define XPAR_OPB_IIC_0_DEVICE_ID 0
+#define XPAR_OPB_IIC_0_TEN_BIT_ADR 0
+
+/******************************************************************/
+
+#define XPAR_XUARTNS550_NUM_INSTANCES 2
+#define XPAR_XUARTNS550_CLOCK_HZ 100000000
+#define XPAR_OPB_UART16550_0_BASEADDR 0xA0000000
+#define XPAR_OPB_UART16550_0_HIGHADDR 0xA0001FFF
+#define XPAR_OPB_UART16550_0_DEVICE_ID 0
+#define XPAR_OPB_UART16550_1_BASEADDR 0xA0010000
+#define XPAR_OPB_UART16550_1_HIGHADDR 0xA0011FFF
+#define XPAR_OPB_UART16550_1_DEVICE_ID 1
+
+/******************************************************************/
+
+#define XPAR_XSPI_NUM_INSTANCES 1
+#define XPAR_OPB_SPI_0_BASEADDR 0xA4000000
+#define XPAR_OPB_SPI_0_HIGHADDR 0xA400007F
+#define XPAR_OPB_SPI_0_DEVICE_ID 0
+#define XPAR_OPB_SPI_0_FIFO_EXIST 1
+#define XPAR_OPB_SPI_0_SPI_SLAVE_ONLY 0
+#define XPAR_OPB_SPI_0_NUM_SS_BITS 1
+
+/******************************************************************/
+
+#define XPAR_XPS2_NUM_INSTANCES 2
+#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0 0
+#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0 0xA9000000
+#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0 (0xA9000000+0x3F)
+#define XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1 1
+#define XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1 (0xA9000000+0x1000)
+#define XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1 (0xA9000000+0x103F)
+
+/******************************************************************/
+
+#define XPAR_XTOUCHSCREEN_NUM_INSTANCES 1
+#define XPAR_OPB_TSD_REF_0_BASEADDR 0xAA000000
+#define XPAR_OPB_TSD_REF_0_HIGHADDR 0xAA000007
+#define XPAR_OPB_TSD_REF_0_DEVICE_ID 0
+
+/******************************************************************/
+
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_BASEADDR 0xA6000000
+#define XPAR_OPB_AC97_CONTROLLER_REF_0_HIGHADDR 0xA60000FF
+#define XPAR_OPB_PAR_PORT_REF_0_BASEADDR 0x90010000
+#define XPAR_OPB_PAR_PORT_REF_0_HIGHADDR 0x900100FF
+#define XPAR_PLB_DDR_0_BASEADDR 0x00000000
+#define XPAR_PLB_DDR_0_HIGHADDR 0x0FFFFFFF
+
+/******************************************************************/
+
+#define XPAR_XINTC_HAS_IPR 1
+#define XPAR_INTC_MAX_NUM_INTR_INPUTS 18
+#define XPAR_XINTC_USE_DCR 0
+#define XPAR_XINTC_NUM_INSTANCES 1
+#define XPAR_DCR_INTC_0_BASEADDR 0xD0000FC0
+#define XPAR_DCR_INTC_0_HIGHADDR 0xD0000FDF
+#define XPAR_DCR_INTC_0_DEVICE_ID 0
+#define XPAR_DCR_INTC_0_KIND_OF_INTR 0x00038000
+
+/******************************************************************/
+
+#define XPAR_DCR_INTC_0_MISC_LOGIC_0_PHY_MII_INT_INTR 0
+#define XPAR_DCR_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR 1
+#define XPAR_DCR_INTC_0_MISC_LOGIC_0_IIC_TEMP_CRIT_INTR 2
+#define XPAR_DCR_INTC_0_MISC_LOGIC_0_IIC_IRQ_INTR 3
+#define XPAR_DCR_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR 4
+#define XPAR_DCR_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR 5
+#define XPAR_DCR_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR 6
+#define XPAR_DCR_INTC_0_OPB_UART16550_1_IP2INTC_IRPT_INTR 7
+#define XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR 8
+#define XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR 9
+#define XPAR_DCR_INTC_0_OPB_SPI_0_IP2INTC_IRPT_INTR 10
+#define XPAR_DCR_INTC_0_OPB_TSD_REF_0_INTR_INTR 11
+#define XPAR_DCR_INTC_0_OPB_AC97_CONTROLLER_REF_0_PLAYBACK_INTERRUPT_INTR 12
+#define XPAR_DCR_INTC_0_OPB_AC97_CONTROLLER_REF_0_RECORD_INTERRUPT_INTR 13
+#define XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR 14
+#define XPAR_DCR_INTC_0_PLB2OPB_BRIDGE_0_BUS_ERROR_DET_INTR 15
+#define XPAR_DCR_INTC_0_PLB_V34_0_BUS_ERROR_DET_INTR 16
+#define XPAR_DCR_INTC_0_OPB2PLB_BRIDGE_0_BUS_ERROR_DET_INTR 17
+
+/******************************************************************/
+
+#define XPAR_XTFT_NUM_INSTANCES 1
+#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR 0xD0000200
+#define XPAR_PLB_TFT_CNTLR_REF_0_DCR_HIGHADDR 0xD0000207
+#define XPAR_PLB_TFT_CNTLR_REF_0_DEVICE_ID 0
+
+/******************************************************************/
+
+#define XPAR_XSYSACE_MEM_WIDTH 8
+#define XPAR_XSYSACE_NUM_INSTANCES 1
+#define XPAR_OPB_SYSACE_0_BASEADDR 0xCF000000
+#define XPAR_OPB_SYSACE_0_HIGHADDR 0xCF0001FF
+#define XPAR_OPB_SYSACE_0_DEVICE_ID 0
+#define XPAR_OPB_SYSACE_0_MEM_WIDTH 8
+
+/******************************************************************/
+
+#define XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ 300000000
+
+/******************************************************************/
+
+/******************************************************************/
+
+/* Linux Redefines */
+
+/******************************************************************/
+
+#define XPAR_UARTNS550_0_BASEADDR (XPAR_OPB_UART16550_0_BASEADDR+0x1000)
+#define XPAR_UARTNS550_0_HIGHADDR XPAR_OPB_UART16550_0_HIGHADDR
+#define XPAR_UARTNS550_0_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ
+#define XPAR_UARTNS550_0_DEVICE_ID XPAR_OPB_UART16550_0_DEVICE_ID
+#define XPAR_UARTNS550_1_BASEADDR (XPAR_OPB_UART16550_1_BASEADDR+0x1000)
+#define XPAR_UARTNS550_1_HIGHADDR XPAR_OPB_UART16550_1_HIGHADDR
+#define XPAR_UARTNS550_1_CLOCK_FREQ_HZ XPAR_XUARTNS550_CLOCK_HZ
+#define XPAR_UARTNS550_1_DEVICE_ID XPAR_OPB_UART16550_1_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_GPIO_0_BASEADDR XPAR_MY_OPB_GPIO_0_BASEADDR_0
+#define XPAR_GPIO_0_HIGHADDR XPAR_MY_OPB_GPIO_0_HIGHADDR_0
+#define XPAR_GPIO_0_DEVICE_ID XPAR_MY_OPB_GPIO_0_DEVICE_ID_0
+#define XPAR_GPIO_1_BASEADDR XPAR_MY_OPB_GPIO_0_BASEADDR_1
+#define XPAR_GPIO_1_HIGHADDR XPAR_MY_OPB_GPIO_0_HIGHADDR_1
+#define XPAR_GPIO_1_DEVICE_ID XPAR_MY_OPB_GPIO_0_DEVICE_ID_1
+
+/******************************************************************/
+
+#define XPAR_IIC_0_BASEADDR XPAR_OPB_IIC_0_BASEADDR
+#define XPAR_IIC_0_HIGHADDR XPAR_OPB_IIC_0_HIGHADDR
+#define XPAR_IIC_0_TEN_BIT_ADR XPAR_OPB_IIC_0_TEN_BIT_ADR
+#define XPAR_IIC_0_DEVICE_ID XPAR_OPB_IIC_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_SYSACE_0_BASEADDR XPAR_OPB_SYSACE_0_BASEADDR
+#define XPAR_SYSACE_0_HIGHADDR XPAR_OPB_SYSACE_0_HIGHADDR
+#define XPAR_SYSACE_0_DEVICE_ID XPAR_OPB_SYSACE_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_INTC_0_BASEADDR XPAR_DCR_INTC_0_BASEADDR
+#define XPAR_INTC_0_HIGHADDR XPAR_DCR_INTC_0_HIGHADDR
+#define XPAR_INTC_0_KIND_OF_INTR XPAR_DCR_INTC_0_KIND_OF_INTR
+#define XPAR_INTC_0_DEVICE_ID XPAR_DCR_INTC_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_INTC_0_EMAC_0_VEC_ID XPAR_DCR_INTC_0_OPB_ETHERNET_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_IIC_0_VEC_ID XPAR_DCR_INTC_0_OPB_IIC_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_SYSACE_0_VEC_ID XPAR_DCR_INTC_0_OPB_SYSACE_0_SYSACE_IRQ_INTR
+#define XPAR_INTC_0_UARTNS550_0_VEC_ID XPAR_DCR_INTC_0_OPB_UART16550_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_UARTNS550_1_VEC_ID XPAR_DCR_INTC_0_OPB_UART16550_1_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_PS2_0_VEC_ID XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR1_INTR
+#define XPAR_INTC_0_PS2_1_VEC_ID XPAR_DCR_INTC_0_OPB_PS2_DUAL_REF_0_SYS_INTR2_INTR
+#define XPAR_INTC_0_SPI_0_VEC_ID XPAR_DCR_INTC_0_OPB_SPI_0_IP2INTC_IRPT_INTR
+#define XPAR_INTC_0_TOUCHSCREEN_0_VEC_ID XPAR_DCR_INTC_0_OPB_TSD_REF_0_INTR_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_A XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_B XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_C XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+#define XPAR_INTC_0_PCI_0_VEC_ID_D XPAR_DCR_INTC_0_OPB_PCI_REF_0_INTR_OUT_INTR
+
+/******************************************************************/
+
+#define XPAR_EMAC_0_BASEADDR XPAR_OPB_ETHERNET_0_BASEADDR
+#define XPAR_EMAC_0_HIGHADDR XPAR_OPB_ETHERNET_0_HIGHADDR
+#define XPAR_EMAC_0_DMA_PRESENT XPAR_OPB_ETHERNET_0_DMA_PRESENT
+#define XPAR_EMAC_0_MII_EXIST XPAR_OPB_ETHERNET_0_MII_EXIST
+#define XPAR_EMAC_0_ERR_COUNT_EXIST XPAR_OPB_ETHERNET_0_ERR_COUNT_EXIST
+#define XPAR_EMAC_0_DEVICE_ID XPAR_OPB_ETHERNET_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_SPI_0_BASEADDR XPAR_OPB_SPI_0_BASEADDR
+#define XPAR_SPI_0_HIGHADDR XPAR_OPB_SPI_0_HIGHADDR
+#define XPAR_SPI_0_DEVICE_ID XPAR_OPB_SPI_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_TOUCHSCREEN_0_BASEADDR XPAR_OPB_TSD_REF_0_BASEADDR
+#define XPAR_TOUCHSCREEN_0_HIGHADDR XPAR_OPB_TSD_REF_0_HIGHADDR
+#define XPAR_TOUCHSCREEN_0_DEVICE_ID XPAR_OPB_TSD_REF_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_TFT_0_BASEADDR XPAR_PLB_TFT_CNTLR_REF_0_DCR_BASEADDR
+
+/******************************************************************/
+
+#define XPAR_PCI_0_BASEADDR XPAR_OPB_PCI_REF_0_BASEADDR
+#define XPAR_PCI_0_HIGHADDR XPAR_OPB_PCI_REF_0_HIGHADDR
+#define XPAR_PCI_0_CONFIG_ADDR XPAR_OPB_PCI_REF_0_CONFIG_ADDR
+#define XPAR_PCI_0_CONFIG_DATA XPAR_OPB_PCI_REF_0_CONFIG_DATA
+#define XPAR_PCI_0_LCONFIG_ADDR XPAR_OPB_PCI_REF_0_LCONFIG_ADDR
+#define XPAR_PCI_0_MEM_BASEADDR XPAR_OPB_PCI_REF_0_MEM_BASEADDR
+#define XPAR_PCI_0_MEM_HIGHADDR XPAR_OPB_PCI_REF_0_MEM_HIGHADDR
+#define XPAR_PCI_0_IO_BASEADDR XPAR_OPB_PCI_REF_0_IO_BASEADDR
+#define XPAR_PCI_0_IO_HIGHADDR XPAR_OPB_PCI_REF_0_IO_HIGHADDR
+#define XPAR_PCI_0_CLOCK_FREQ_HZ XPAR_XPCI_CLOCK_HZ
+#define XPAR_PCI_0_DEVICE_ID XPAR_OPB_PCI_REF_0_DEVICE_ID
+
+/******************************************************************/
+
+#define XPAR_PS2_0_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_0
+#define XPAR_PS2_0_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_0
+#define XPAR_PS2_0_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_0
+#define XPAR_PS2_1_BASEADDR XPAR_OPB_PS2_DUAL_REF_0_BASEADDR_1
+#define XPAR_PS2_1_HIGHADDR XPAR_OPB_PS2_DUAL_REF_0_HIGHADDR_1
+#define XPAR_PS2_1_DEVICE_ID XPAR_OPB_PS2_DUAL_REF_0_DEVICE_ID_1
+
+/******************************************************************/
+
+#define XPAR_PLB_CLOCK_FREQ_HZ 100000000
+#define XPAR_CORE_CLOCK_FREQ_HZ XPAR_CPU_PPC405_CORE_CLOCK_FREQ_HZ
+#define XPAR_DDR_0_SIZE 0x08000000
+
+/******************************************************************/
+
+#define XPAR_PERSISTENT_0_IIC_0_BASEADDR 0x00000400
+#define XPAR_PERSISTENT_0_IIC_0_HIGHADDR 0x000007FF
+#define XPAR_PERSISTENT_0_IIC_0_EEPROMADDR 0xA0
+
+/******************************************************************/
+
+#define XPAR_POWER_0_POWERDOWN_BASEADDR 0x90000004
+#define XPAR_POWER_0_POWERDOWN_HIGHADDR 0x90000007
+#define XPAR_POWER_0_POWERDOWN_VALUE 0xFF
+
+/******************************************************************/
diff --git a/arch/ppc/platforms/lopec.c b/arch/ppc/platforms/lopec.c
new file mode 100644 (file)
index 0000000..0037f5c
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * arch/ppc/platforms/lopec.c
+ *
+ * Setup routines for the Motorola LoPEC.
+ *
+ * Author: Dan Cox
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci_ids.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/root_dev.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/io.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/hw_irq.h>
+#include <asm/prep_nvram.h>
+#include <asm/kgdb.h>
+
+/*
+ * Define all of the IRQ senses and polarities.  Taken from the
+ * LoPEC Programmer's Reference Guide.
+ */
+static u_char lopec_openpic_initsenses[16] __initdata = {
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* IRQ 0 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 1 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* IRQ 2 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 3 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* IRQ 4 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* IRQ 5 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 6 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 7 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 8 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 9 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 10 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 11 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),      /* IRQ 12 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* IRQ 13 */
+       (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),       /* IRQ 14 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE)       /* IRQ 15 */
+};
+
+static inline int __init
+lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       int irq;
+       static char pci_irq_table[][4] = {
+               {16, 0, 0, 0}, /* ID 11 - Winbond */
+               {22, 0, 0, 0}, /* ID 12 - SCSI */
+               {0, 0, 0, 0}, /* ID 13 - nothing */
+               {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */
+               {27, 0, 0, 0}, /* ID 15 - USB */
+               {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */
+               {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */
+               {25, 0, 0, 0}, /* ID 18 - PCI slot */
+               {0, 0, 0, 0}, /* ID 19 - nothing */
+               {0, 0, 0, 0}, /* ID 20 - nothing */
+               {0, 0, 0, 0}, /* ID 21 - nothing */
+               {0, 0, 0, 0}, /* ID 22 - nothing */
+               {0, 0, 0, 0}, /* ID 23 - nothing */
+               {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */
+               {0, 0, 0, 0}, /* ID 25 - nothing */
+               {0, 0, 0, 0}  /* ID 26 - PMC Slot 2b */
+       };
+       const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4;
+
+       irq = PCI_IRQ_TABLE_LOOKUP;
+       if (!irq)
+               return 0;
+
+       return irq;
+}
+
+static void __init
+lopec_setup_winbond_83553(struct pci_controller *hose)
+{
+       int devfn;
+
+       devfn = PCI_DEVFN(11,0);
+
+       /* IDE interrupt routing (primary 14, secondary 15) */
+       early_write_config_byte(hose, 0, devfn, 0x43, 0xef);
+       /* PCI interrupt routing */
+       early_write_config_word(hose, 0, devfn, 0x44, 0x0000);
+
+       /* ISA-PCI address decoder */
+       early_write_config_byte(hose, 0, devfn, 0x48, 0xf0);
+
+       /* RTC, kb, not used in PPC */
+       early_write_config_byte(hose, 0, devfn, 0x4d, 0x00);
+       early_write_config_byte(hose, 0, devfn, 0x4e, 0x04);
+       devfn = PCI_DEVFN(11, 1);
+       early_write_config_byte(hose, 0, devfn, 0x09, 0x8f);
+       early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011);
+}
+
+static void __init
+lopec_find_bridges(void)
+{
+       struct pci_controller *hose;
+
+       hose = pcibios_alloc_controller();
+       if (!hose)
+               return;
+
+       hose->first_busno = 0;
+       hose->last_busno = 0xff;
+
+       if (mpc10x_bridge_init(hose, MPC10X_MEM_MAP_B, MPC10X_MEM_MAP_B,
+                               MPC10X_MAPB_EUMB_BASE) == 0) {
+
+               hose->mem_resources[0].end = 0xffffffff;
+               lopec_setup_winbond_83553(hose);
+               hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+               ppc_md.pci_swizzle = common_swizzle;
+               ppc_md.pci_map_irq = lopec_map_irq;
+       }
+}
+
+static int
+lopec_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "machine\t\t: Motorola LoPEC\n");
+       return 0;
+}
+
+static u32
+lopec_irq_canonicalize(u32 irq)
+{
+       if (irq == 2)
+               return 9;
+       else
+               return irq;
+}
+
+static void
+lopec_restart(char *cmd)
+{
+#define LOPEC_SYSSTAT1 0xffe00000
+       /* force a hard reset, if possible */
+       unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1);
+       reg |= 0x80;
+       *((unsigned char *) LOPEC_SYSSTAT1) = reg;
+
+       local_irq_disable();
+       while(1);
+#undef LOPEC_SYSSTAT1
+}
+
+static void
+lopec_halt(void)
+{
+       local_irq_disable();
+       while(1);
+}
+
+static void
+lopec_power_off(void)
+{
+       lopec_halt();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+int lopec_ide_ports_known = 0;
+static unsigned long lopec_ide_regbase[MAX_HWIFS];
+static unsigned long lopec_ide_ctl_regbase[MAX_HWIFS];
+static unsigned long lopec_idedma_regbase;
+
+static void
+lopec_ide_probe(void)
+{
+       struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                             PCI_DEVICE_ID_WINBOND_82C105,
+                                             NULL);
+       lopec_ide_ports_known = 1;
+
+       if (dev) {
+               lopec_ide_regbase[0] = dev->resource[0].start;
+               lopec_ide_regbase[1] = dev->resource[2].start;
+               lopec_ide_ctl_regbase[0] = dev->resource[1].start;
+               lopec_ide_ctl_regbase[1] = dev->resource[3].start;
+               lopec_idedma_regbase = dev->resource[4].start;
+       }
+}
+
+static int
+lopec_ide_default_irq(unsigned long base)
+{
+       if (lopec_ide_ports_known == 0)
+               lopec_ide_probe();
+
+       if (base == lopec_ide_regbase[0])
+               return 14;
+       else if (base == lopec_ide_regbase[1])
+               return 15;
+       else
+               return 0;
+}
+
+static unsigned long
+lopec_ide_default_io_base(int index)
+{
+       if (lopec_ide_ports_known == 0)
+               lopec_ide_probe();
+       return lopec_ide_regbase[index];
+}
+
+static void __init
+lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data,
+                         unsigned long ctl, int *irq)
+{
+       unsigned long reg = data;
+       uint alt_status_base;
+       int i;
+
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+               hw->io_ports[i] = reg++;
+
+       if (data == lopec_ide_regbase[0]) {
+               alt_status_base = lopec_ide_ctl_regbase[0] + 2;
+               hw->irq = 14;
+       } else if (data == lopec_ide_regbase[1]) {
+               alt_status_base = lopec_ide_ctl_regbase[1] + 2;
+               hw->irq = 15;
+       } else {
+               alt_status_base = 0;
+               hw->irq = 0;
+       }
+
+       if (ctl)
+               hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+       else
+               hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base;
+
+       if (irq != NULL)
+               *irq = hw->irq;
+
+}
+#endif /* BLK_DEV_IDE */
+
+static void __init
+lopec_init_IRQ(void)
+{
+       int i;
+
+       /*
+        * Provide the open_pic code with the correct table of interrupts.
+        */
+       OpenPIC_InitSenses = lopec_openpic_initsenses;
+       OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses);
+
+       mpc10x_set_openpic();
+
+       /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+       openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+                       &i8259_irq);
+
+       /* Map i8259 interrupts */
+       for(i = 0; i < NUM_8259_INTERRUPTS; i++)
+               irq_desc[i].handler = &i8259_pic;
+
+       /*
+        * The EPIC allows for a read in the range of 0xFEF00000 ->
+        * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction.
+        */
+       i8259_init(0xfef00000);
+}
+
+static int __init
+lopec_request_io(void)
+{
+       outb(0x00, 0x4d0);
+       outb(0xc0, 0x4d1);
+
+       request_region(0x00, 0x20, "dma1");
+       request_region(0x20, 0x20, "pic1");
+       request_region(0x40, 0x20, "timer");
+       request_region(0x80, 0x10, "dma page reg");
+       request_region(0xa0, 0x20, "pic2");
+       request_region(0xc0, 0x20, "dma2");
+
+       return 0;
+}
+
+device_initcall(lopec_request_io);
+
+static void __init
+lopec_map_io(void)
+{
+       io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+       io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO);
+}
+
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+lopec_set_bat(void)
+{
+       mb();
+       mtspr(DBAT1U, 0xf8000ffe);
+       mtspr(DBAT1L, 0xf800002a);
+       mb();
+}
+
+TODC_ALLOC();
+
+static void __init
+lopec_setup_arch(void)
+{
+
+       TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
+                 ioremap(0xffe80000, 0x8000), 8);
+
+       loops_per_jiffy = 100000000/HZ;
+
+       lopec_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#elif defined(CONFIG_ROOT_NFS)
+               ROOT_DEV = Root_NFS;
+#elif defined(CONFIG_BLK_DEV_IDEDISK)
+               ROOT_DEV = Root_HDA1;
+#else
+               ROOT_DEV = Root_SDA1;
+#endif
+
+#ifdef CONFIG_PPCBUG_NVRAM
+       /* Read in NVRAM data */
+       init_prep_nvram();
+
+       /* if no bootargs, look in NVRAM */
+       if ( cmd_line[0] == '\0' ) {
+               char *bootargs;
+                bootargs = prep_nvram_get_var("bootargs");
+                if (bootargs != NULL) {
+                        strcpy(cmd_line, bootargs);
+                        /* again.. */
+                        strcpy(saved_command_line, cmd_line);
+               }
+       }
+#endif
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       parse_bootinfo(find_bootinfo());
+       lopec_set_bat();
+
+       isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+       isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+       pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+       ISA_DMA_THRESHOLD = 0x00ffffff;
+       DMA_MODE_READ = 0x44;
+       DMA_MODE_WRITE = 0x48;
+
+       ppc_md.setup_arch = lopec_setup_arch;
+       ppc_md.show_cpuinfo = lopec_show_cpuinfo;
+       ppc_md.irq_canonicalize = lopec_irq_canonicalize;
+       ppc_md.init_IRQ = lopec_init_IRQ;
+       ppc_md.get_irq = openpic_get_irq;
+
+       ppc_md.restart = lopec_restart;
+       ppc_md.power_off = lopec_power_off;
+       ppc_md.halt = lopec_halt;
+
+       ppc_md.setup_io_mappings = lopec_map_io;
+
+       ppc_md.time_init = todc_time_init;
+       ppc_md.set_rtc_time = todc_set_rtc_time;
+       ppc_md.get_rtc_time = todc_get_rtc_time;
+       ppc_md.calibrate_decr = todc_calibrate_decr;
+
+       ppc_md.nvram_read_val = todc_direct_read_val;
+       ppc_md.nvram_write_val = todc_direct_write_val;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+       ppc_ide_md.default_irq = lopec_ide_default_irq;
+       ppc_ide_md.default_io_base = lopec_ide_default_io_base;
+       ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports;
+#endif
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+       ppc_md.progress = gen550_progress;
+#endif
+}
diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h
new file mode 100644 (file)
index 0000000..5490edb
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * include/asm-ppc/lopec_serial.h
+ *
+ * Definitions for Motorola LoPEC board.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com (or, alternately, source@mvista.com)
+ *
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __H_LOPEC_SERIAL
+#define __H_LOPEC_SERIAL
+
+#define RS_TABLE_SIZE 3
+
+#define BASE_BAUD (1843200 / 16)
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#endif
+
+#define SERIAL_PORT_DFNS \
+         { 0, BASE_BAUD, 0xffe10000, 29, STD_COM_FLAGS, \
+           iomem_base: (u8 *) 0xffe10000, \
+           io_type: SERIAL_IO_MEM }, \
+         { 0, BASE_BAUD, 0xffe11000, 20, STD_COM_FLAGS, \
+           iomem_base: (u8 *) 0xffe11000, \
+           io_type: SERIAL_IO_MEM }, \
+         { 0, BASE_BAUD, 0xffe12000, 21, STD_COM_FLAGS, \
+           iomem_base: (u8 *) 0xffe12000, \
+           io_type: SERIAL_IO_MEM }
+
+#endif
diff --git a/arch/ppc/platforms/mvme5100.c b/arch/ppc/platforms/mvme5100.c
new file mode 100644 (file)
index 0000000..b08be24
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * arch/ppc/platforms/mvme5100.c
+ *
+ * Board setup routines for the Motorola MVME5100.
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * 2001-2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/kdev_t.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/todc.h>
+#include <asm/pci-bridge.h>
+#include <asm/bootinfo.h>
+#include <asm/hawk.h>
+
+#include <platforms/pplus.h>
+#include <platforms/mvme5100.h>
+
+static u_char mvme5100_openpic_initsenses[16] __initdata = {
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* i8259 cascade */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* TL16C550 UART 1,2 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet1 front panel or P2 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Hawk Watchdog 1,2 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* DS1621 thermal alarm */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT0# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT1# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT2# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT3# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTA#, PMC2 INTB# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTB#, PMC2 INTC# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTC#, PMC2 INTD# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTD#, PMC2 INTA# */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet 2 (front panel) */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Abort Switch */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* RTC Alarm */
+};
+
+static inline int
+mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       int irq;
+
+       static char pci_irq_table[][4] =
+       /*
+        *      PCI IDSEL/INTPIN->INTLINE
+        *         A   B   C   D
+        */
+       {
+               {  0,  0,  0,  0 },     /* IDSEL 11 - Winbond */
+               {  0,  0,  0,  0 },     /* IDSEL 12 - unused */
+               { 21, 22, 23, 24 },     /* IDSEL 13 - Universe II */
+               { 18,  0,  0,  0 },     /* IDSEL 14 - Enet 1 */
+               {  0,  0,  0,  0 },     /* IDSEL 15 - unused */
+               { 25, 26, 27, 28 },     /* IDSEL 16 - PMC Slot 1 */
+               { 28, 25, 26, 27 },     /* IDSEL 17 - PMC Slot 2 */
+               {  0,  0,  0,  0 },     /* IDSEL 18 - unused */
+               { 29,  0,  0,  0 },     /* IDSEL 19 - Enet 2 */
+               {  0,  0,  0,  0 },     /* IDSEL 20 - PMCSPAN */
+       };
+
+       const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
+       irq = PCI_IRQ_TABLE_LOOKUP;
+       /* If lookup is zero, always return 0 */
+       if (!irq)
+               return 0;
+       else
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+       /* If IPMC761 present, return table value */
+       return irq;
+#else
+       /* If IPMC761 not present, we don't have an i8259 so adjust */
+       return (irq - NUM_8259_INTERRUPTS);
+#endif
+}
+
+static void
+mvme5100_pcibios_fixup_resources(struct pci_dev *dev)
+{
+       int i;
+
+       if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+                       (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK))
+               for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
+               {
+                       dev->resource[i].start = 0;
+                       dev->resource[i].end = 0;
+               }
+}
+
+static void __init
+mvme5100_setup_bridge(void)
+{
+       struct pci_controller*  hose;
+
+       hose = pcibios_alloc_controller();
+
+       if (!hose)
+               return;
+
+       hose->first_busno = 0;
+       hose->last_busno = 0xff;
+       hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET;
+
+       pci_init_resource(&hose->io_resource, MVME5100_PCI_LOWER_IO,
+                       MVME5100_PCI_UPPER_IO, IORESOURCE_IO,
+                       "PCI host bridge");
+
+       pci_init_resource(&hose->mem_resources[0], MVME5100_PCI_LOWER_MEM,
+                       MVME5100_PCI_UPPER_MEM, IORESOURCE_MEM,
+                       "PCI host bridge");
+
+       hose->io_space.start = MVME5100_PCI_LOWER_IO;
+       hose->io_space.end = MVME5100_PCI_UPPER_IO;
+       hose->mem_space.start = MVME5100_PCI_LOWER_MEM;
+       hose->mem_space.end = MVME5100_PCI_UPPER_MEM;
+       hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE;
+
+       /* Use indirect method of Hawk */
+       setup_indirect_pci(hose, MVME5100_PCI_CONFIG_ADDR,
+                       MVME5100_PCI_CONFIG_DATA);
+
+       hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+       ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources;
+       ppc_md.pci_swizzle = common_swizzle;
+       ppc_md.pci_map_irq = mvme5100_map_irq;
+}
+
+static void __init
+mvme5100_setup_arch(void)
+{
+       if ( ppc_md.progress )
+               ppc_md.progress("mvme5100_setup_arch: enter", 0);
+
+       loops_per_jiffy = 50000000 / HZ;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else
+#endif
+#ifdef CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+               ROOT_DEV = Root_SDA2;
+#endif
+
+       if ( ppc_md.progress )
+               ppc_md.progress("mvme5100_setup_arch: find_bridges", 0);
+
+       /* Setup PCI host bridge */
+       mvme5100_setup_bridge();
+
+       /* Find and map our OpenPIC */
+       hawk_mpic_init(MVME5100_PCI_MEM_OFFSET);
+       OpenPIC_InitSenses = mvme5100_openpic_initsenses;
+       OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses);
+
+       printk("MVME5100 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
+
+       if ( ppc_md.progress )
+               ppc_md.progress("mvme5100_setup_arch: exit", 0);
+
+       return;
+}
+
+static void __init
+mvme5100_init2(void)
+{
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+               request_region(0x00,0x20,"dma1");
+               request_region(0x20,0x20,"pic1");
+               request_region(0x40,0x20,"timer");
+               request_region(0x80,0x10,"dma page reg");
+               request_region(0xa0,0x20,"pic2");
+               request_region(0xc0,0x20,"dma2");
+#endif
+       return;
+}
+
+/*
+ * Interrupt setup and service.
+ * Have MPIC on HAWK and cascaded 8259s on Winbond cascaded to MPIC.
+ */
+static void __init
+mvme5100_init_IRQ(void)
+{
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+       int i;
+#endif
+
+       if ( ppc_md.progress )
+               ppc_md.progress("init_irq: enter", 0);
+
+       openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000);
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+       openpic_init(NUM_8259_INTERRUPTS);
+       openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+                       &i8259_irq);
+
+       /* Map i8259 interrupts. */
+       for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+               irq_desc[i].handler = &i8259_pic;
+
+       i8259_init(NULL);
+#else
+       openpic_init(0);
+#endif
+
+       if ( ppc_md.progress )
+               ppc_md.progress("init_irq: exit", 0);
+
+       return;
+}
+
+/*
+ * Set BAT 3 to map 0xf0000000 to end of physical memory space.
+ */
+static __inline__ void
+mvme5100_set_bat(void)
+{
+       mb();
+       mtspr(DBAT1U, 0xf0001ffe);
+       mtspr(DBAT1L, 0xf000002a);
+       mb();
+}
+
+static unsigned long __init
+mvme5100_find_end_of_memory(void)
+{
+       return hawk_get_mem_size(MVME5100_HAWK_SMC_BASE);
+}
+
+static void __init
+mvme5100_map_io(void)
+{
+       io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO);
+       ioremap_base = 0xfe000000;
+}
+
+static void
+mvme5100_reset_board(void)
+{
+       local_irq_disable();
+
+       /* Set exception prefix high - to the firmware */
+       _nmask_and_or_msr(0, MSR_IP);
+
+       out_8((u_char *)MVME5100_BOARD_MODRST_REG, 0x01);
+
+       return;
+}
+
+static void
+mvme5100_restart(char *cmd)
+{
+       volatile ulong i = 10000000;
+
+       mvme5100_reset_board();
+
+       while (i-- > 0);
+       panic("restart failed\n");
+}
+
+static void
+mvme5100_halt(void)
+{
+       local_irq_disable();
+       while (1);
+}
+
+static void
+mvme5100_power_off(void)
+{
+       mvme5100_halt();
+}
+
+static int
+mvme5100_show_cpuinfo(struct seq_file *m)
+{
+       seq_printf(m, "vendor\t\t: Motorola\n");
+       seq_printf(m, "machine\t\t: MVME5100\n");
+
+       return 0;
+}
+
+TODC_ALLOC();
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+             unsigned long r6, unsigned long r7)
+{
+       parse_bootinfo(find_bootinfo());
+       mvme5100_set_bat();
+
+       isa_io_base = MVME5100_ISA_IO_BASE;
+       isa_mem_base = MVME5100_ISA_MEM_BASE;
+       pci_dram_offset = MVME5100_PCI_DRAM_OFFSET;
+
+       ppc_md.setup_arch = mvme5100_setup_arch;
+       ppc_md.show_cpuinfo = mvme5100_show_cpuinfo;
+       ppc_md.init_IRQ = mvme5100_init_IRQ;
+       ppc_md.get_irq = openpic_get_irq;
+       ppc_md.init = mvme5100_init2;
+
+       ppc_md.restart = mvme5100_restart;
+       ppc_md.power_off = mvme5100_power_off;
+       ppc_md.halt = mvme5100_halt;
+
+       ppc_md.find_end_of_memory = mvme5100_find_end_of_memory;
+       ppc_md.setup_io_mappings = mvme5100_map_io;
+
+       TODC_INIT(TODC_TYPE_MK48T37, MVME5100_NVRAM_AS0, MVME5100_NVRAM_AS1,
+                       MVME5100_NVRAM_DATA, 8);
+
+       ppc_md.time_init = todc_time_init;
+       ppc_md.set_rtc_time = todc_set_rtc_time;
+       ppc_md.get_rtc_time = todc_get_rtc_time;
+       ppc_md.calibrate_decr = todc_calibrate_decr;
+
+       ppc_md.nvram_read_val = todc_m48txx_read_val;
+       ppc_md.nvram_write_val = todc_m48txx_write_val;
+}
diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c
new file mode 100644 (file)
index 0000000..cecaba6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * arch/ppc/platforms/pq2ads.c
+ *
+ * PQ2ADS platform support
+ *
+ * Author: Kumar Gala <kumar.gala@freescale.com>
+ * Derived from: est8260_setup.c by Allen Curtis
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+
+#include <asm/mpc8260.h>
+
+void __init
+m82xx_board_init(void)
+{
+       /* Enable the 2nd UART port */
+        *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2;
+}
diff --git a/arch/ppc/syslib/gen550.h b/arch/ppc/syslib/gen550.h
new file mode 100644 (file)
index 0000000..039d249
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * arch/ppc/syslib/gen550.h
+ *
+ * gen550 prototypes
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 2004 (c) MontaVista Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct uart_port *);
+extern void gen550_kgdb_map_scc(void);
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
new file mode 100644 (file)
index 0000000..7838a44
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * m8xx_wdt.c - MPC8xx watchdog driver
+ *
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/8xx_immap.h>
+#include <syslib/m8xx_wdt.h>
+
+static int wdt_timeout;
+
+void m8xx_wdt_reset(void)
+{
+       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+       imap->im_siu_conf.sc_swsr = 0x556c;     /* write magic1 */
+       imap->im_siu_conf.sc_swsr = 0xaa39;     /* write magic2 */
+}
+
+static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+       m8xx_wdt_reset();
+
+       imap->im_sit.sit_piscr |= PISCR_PS;     /* clear irq */
+
+       return IRQ_HANDLED;
+}
+
+void __init m8xx_wdt_handler_install(bd_t * binfo)
+{
+       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+       u32 pitc;
+       u32 sypcr;
+       u32 pitrtclk;
+
+       sypcr = imap->im_siu_conf.sc_sypcr;
+
+       if (!(sypcr & 0x04)) {
+               printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
+                      sypcr);
+               return;
+       }
+
+       m8xx_wdt_reset();
+
+       printk(KERN_NOTICE
+              "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
+              (sypcr >> 16), sypcr & 0x01);
+
+       wdt_timeout = (sypcr >> 16) & 0xFFFF;
+
+       if (!wdt_timeout)
+               wdt_timeout = 0xFFFF;
+
+       if (sypcr & 0x01)
+               wdt_timeout *= 2048;
+
+       /*
+        * Fire trigger if half of the wdt ticked down 
+        */
+
+       if (imap->im_sit.sit_rtcsc & RTCSC_38K)
+               pitrtclk = 9600;
+       else
+               pitrtclk = 8192;
+
+       if ((wdt_timeout) > (UINT_MAX / pitrtclk))
+               pitc = wdt_timeout / binfo->bi_intfreq * pitrtclk / 2;
+       else
+               pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2;
+
+       imap->im_sit.sit_pitc = pitc << 16;
+       imap->im_sit.sit_piscr =
+           (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE;
+
+       if (request_irq(PIT_INTERRUPT, m8xx_wdt_interrupt, 0, "watchdog", NULL))
+               panic("m8xx_wdt: could not allocate watchdog irq!");
+
+       printk(KERN_NOTICE
+              "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
+
+       wdt_timeout /= binfo->bi_intfreq;
+}
+
+int m8xx_wdt_get_timeout(void)
+{
+       return wdt_timeout;
+}
diff --git a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h
new file mode 100644 (file)
index 0000000..0d81a9f
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef _PPC_SYSLIB_M8XX_WDT_H
+#define _PPC_SYSLIB_M8XX_WDT_H
+
+extern void m8xx_wdt_handler_install(bd_t * binfo);
+extern int m8xx_wdt_get_timeout(void);
+extern void m8xx_wdt_reset(void);
+
+#endif                         /* _PPC_SYSLIB_M8XX_WDT_H */
diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c
new file mode 100644 (file)
index 0000000..89b5ac1
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * arch/ppc/syslib/xilinx_pic.c
+ *
+ * Interrupt controller driver for Xilinx Virtex-II Pro.
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include <asm/xparameters.h>
+#include <asm/ibm4xx.h>
+
+/* No one else should require these constants, so define them locally here. */
+#define ISR 0                  /* Interrupt Status Register */
+#define IPR 1                  /* Interrupt Pending Register */
+#define IER 2                  /* Interrupt Enable Register */
+#define IAR 3                  /* Interrupt Acknowledge Register */
+#define SIE 4                  /* Set Interrupt Enable bits */
+#define CIE 5                  /* Clear Interrupt Enable bits */
+#define IVR 6                  /* Interrupt Vector Register */
+#define MER 7                  /* Master Enable Register */
+
+#if XPAR_XINTC_USE_DCR == 0
+static volatile u32 *intc;
+#define intc_out_be32(addr, mask)     out_be32((addr), (mask))
+#define intc_in_be32(addr)            in_be32((addr))
+#else
+#define intc    XPAR_INTC_0_BASEADDR
+#define intc_out_be32(addr, mask)     mtdcr((addr), (mask))
+#define intc_in_be32(addr)            mfdcr((addr))
+#endif
+
+/* Global Variables */
+struct hw_interrupt_type *ppc4xx_pic;
+
+static void
+xilinx_intc_enable(unsigned int irq)
+{
+       unsigned long mask = (0x00000001 << (irq & 31));
+       pr_debug("enable: %d\n", irq);
+       intc_out_be32(intc + SIE, mask);
+}
+
+static void
+xilinx_intc_disable(unsigned int irq)
+{
+       unsigned long mask = (0x00000001 << (irq & 31));
+       pr_debug("disable: %d\n", irq);
+       intc_out_be32(intc + CIE, mask);
+}
+
+static void
+xilinx_intc_disable_and_ack(unsigned int irq)
+{
+       unsigned long mask = (0x00000001 << (irq & 31));
+       pr_debug("disable_and_ack: %d\n", irq);
+       intc_out_be32(intc + CIE, mask);
+       if (!(irq_desc[irq].status & IRQ_LEVEL))
+               intc_out_be32(intc + IAR, mask);        /* ack edge triggered intr */
+}
+
+static void
+xilinx_intc_end(unsigned int irq)
+{
+       unsigned long mask = (0x00000001 << (irq & 31));
+
+       pr_debug("end: %d\n", irq);
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+               intc_out_be32(intc + SIE, mask);
+               /* ack level sensitive intr */
+               if (irq_desc[irq].status & IRQ_LEVEL)
+                       intc_out_be32(intc + IAR, mask);
+       }
+}
+
+static struct hw_interrupt_type xilinx_intc = {
+       "Xilinx Interrupt Controller",
+       NULL,
+       NULL,
+       xilinx_intc_enable,
+       xilinx_intc_disable,
+       xilinx_intc_disable_and_ack,
+       xilinx_intc_end,
+       0
+};
+
+int
+xilinx_pic_get_irq(struct pt_regs *regs)
+{
+       int irq;
+
+       /*
+        * NOTE: This function is the one that needs to be improved in
+        * order to handle multiple interrupt controllers.  It currently
+        * is hardcoded to check for interrupts only on the first INTC.
+        */
+
+       irq = intc_in_be32(intc + IVR);
+       if (irq != -1)
+               irq = irq;
+
+       pr_debug("get_irq: %d\n", irq);
+
+       return (irq);
+}
+
+void __init
+ppc4xx_pic_init(void)
+{
+#if XPAR_XINTC_USE_DCR == 0
+       intc = ioremap(XPAR_INTC_0_BASEADDR, 32);
+
+       printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n",
+              (unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc);
+#else
+       printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n",
+              (unsigned long) XPAR_INTC_0_BASEADDR);
+#endif
+
+       /*
+        * Disable all external interrupts until they are
+        * explicity requested.
+        */
+       intc_out_be32(intc + IER, 0);
+
+       /* Acknowledge any pending interrupts just in case. */
+       intc_out_be32(intc + IAR, ~(u32) 0);
+
+       /* Turn on the Master Enable. */
+       intc_out_be32(intc + MER, 0x3UL);
+
+       ppc4xx_pic = &xilinx_intc;
+       ppc_md.get_irq = xilinx_pic_get_irq;
+}
diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug
new file mode 100644 (file)
index 0000000..c3cd4c7
--- /dev/null
@@ -0,0 +1,59 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       depends on DEBUG_KERNEL
+
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+config DEBUGGER
+       bool "Enable debugger hooks"
+       depends on DEBUG_KERNEL
+       help
+         Include in-kernel hooks for kernel debuggers. Unless you are
+         intending to debug the kernel, say N here.
+
+config XMON
+       bool "Include xmon kernel debugger"
+       depends on DEBUGGER
+       help
+         Include in-kernel hooks for the xmon kernel monitor/debugger.
+         Unless you are intending to debug the kernel, say N here.
+
+config XMON_DEFAULT
+       bool "Enable xmon by default"
+       depends on XMON
+
+config PPCDBG
+       bool "Include PPCDBG realtime debugging"
+       depends on DEBUG_KERNEL
+
+config IRQSTACKS
+       bool "Use separate kernel stacks when processing interrupts"
+       help
+         If you say Y here the kernel will use separate kernel stacks
+         for handling hard and soft interrupts.  This can help avoid
+         overflowing the process kernel stacks.
+
+config SCHEDSTATS
+       bool "Collect scheduler statistics"
+       depends on DEBUG_KERNEL && PROC_FS
+       help
+         If you say Y here, additional code will be inserted into the
+         scheduler and related routines to collect statistics about
+         scheduler behavior and provide them in /proc/schedstat.  These
+         stats may be useful for both tuning and debugging the scheduler
+         If you aren't debugging the scheduler or trying to tune a specific
+         application, you can say N to avoid the very slight overhead
+         this adds.
+
+endmenu
diff --git a/arch/ppc64/configs/maple_defconfig b/arch/ppc64/configs/maple_defconfig
new file mode 100644 (file)
index 0000000..65571a0
--- /dev/null
@@ -0,0 +1,921 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9
+# Wed Oct 20 15:39:14 2004
+#
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=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=17
+# CONFIG_HOTPLUG is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_SYSVIPC_COMPAT=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_PSERIES is not set
+# CONFIG_PPC_PMAC is not set
+CONFIG_PPC_MAPLE=y
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_PPC_OF=y
+# CONFIG_ALTIVEC is not set
+CONFIG_U3_DART=y
+CONFIG_MPIC_BROKEN_U3=y
+CONFIG_BOOTX_TEXT=y
+CONFIG_POWER4_ONLY=y
+CONFIG_IOMMU_VMERGE=y
+CONFIG_SMP=y
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_NR_CPUS=2
+# CONFIG_SCHED_SMT is not set
+# CONFIG_PREEMPT is not set
+
+#
+# General setup
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# 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_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_IDE_TASK_IOCTL=y
+CONFIG_IDE_TASKFILE_IO=y
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+CONFIG_BLK_DEV_AMD74XX=y
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD 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
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES 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_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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=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=y
+# CONFIG_PCNET32 is not set
+CONFIG_AMD8111_ETH=y
+# CONFIG_AMD8111E_NAPI is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI 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 is not set
+
+#
+# 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=1600
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1200
+# 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=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_SERIAL_PMACZILOG is not set
+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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+CONFIG_I2C_AMD8111=y
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 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
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_CONSOLE is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# 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
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG 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_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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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=y
+# 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_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf-8"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+# CONFIG_PPCDBG is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_SCHEDSTATS is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/ppc64/kernel/iSeries_smp.c b/arch/ppc64/kernel/iSeries_smp.c
new file mode 100644 (file)
index 0000000..a5835eb
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * SMP support for iSeries machines.
+ *
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ *
+ * Plus various changes from other IBM teams...
+ *
+ *      This 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.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/cpu.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/iSeries/HvCallCfg.h>
+#include <asm/time.h>
+#include <asm/ppcdebug.h>
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/system.h>
+
+static unsigned long iSeries_smp_message[NR_CPUS];
+
+void iSeries_smp_message_recv( struct pt_regs * regs )
+{
+       int cpu = smp_processor_id();
+       int msg;
+
+       if ( num_online_cpus() < 2 )
+               return;
+
+       for ( msg = 0; msg < 4; ++msg )
+               if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) )
+                       smp_message_recv( msg, regs );
+}
+
+static inline void smp_iSeries_do_message(int cpu, int msg)
+{
+       set_bit(msg, &iSeries_smp_message[cpu]);
+       HvCall_sendIPI(&(paca[cpu]));
+}
+
+static void smp_iSeries_message_pass(int target, int msg)
+{
+       int i;
+
+       if (target < NR_CPUS)
+               smp_iSeries_do_message(target, msg);
+       else {
+               for_each_online_cpu(i) {
+                       if (target == MSG_ALL_BUT_SELF
+                           && i == smp_processor_id())
+                               continue;
+                       smp_iSeries_do_message(i, msg);
+               }
+       }
+}
+
+static int smp_iSeries_numProcs(void)
+{
+       unsigned np, i;
+
+       np = 0;
+        for (i=0; i < NR_CPUS; ++i) {
+                if (paca[i].lppaca.xDynProcStatus < 2) {
+                       cpu_set(i, cpu_possible_map);
+                       cpu_set(i, cpu_present_map);
+                       cpu_set(i, cpu_sibling_map[i]);
+                        ++np;
+                }
+        }
+       return np;
+}
+
+static int smp_iSeries_probe(void)
+{
+       unsigned i;
+       unsigned np = 0;
+
+       for (i=0; i < NR_CPUS; ++i) {
+               if (paca[i].lppaca.xDynProcStatus < 2) {
+                       /*paca[i].active = 1;*/
+                       ++np;
+               }
+       }
+
+       return np;
+}
+
+static void smp_iSeries_kick_cpu(int nr)
+{
+       BUG_ON(nr < 0 || nr >= NR_CPUS);
+
+       /* Verify that our partition has a processor nr */
+       if (paca[nr].lppaca.xDynProcStatus >= 2)
+               return;
+
+       /* The processor is currently spinning, waiting
+        * for the cpu_start field to become non-zero
+        * After we set cpu_start, the processor will
+        * continue on to secondary_start in iSeries_head.S
+        */
+       paca[nr].cpu_start = 1;
+}
+
+static void __devinit smp_iSeries_setup_cpu(int nr)
+{
+}
+
+static struct smp_ops_t iSeries_smp_ops = {
+       .message_pass = smp_iSeries_message_pass,
+       .probe        = smp_iSeries_probe,
+       .kick_cpu     = smp_iSeries_kick_cpu,
+       .setup_cpu    = smp_iSeries_setup_cpu,
+};
+
+/* This is called very early. */
+void __init smp_init_iSeries(void)
+{
+       smp_ops = &iSeries_smp_ops;
+       systemcfg->processorCount       = smp_iSeries_numProcs();
+}
+
diff --git a/arch/ppc64/kernel/iomap.c b/arch/ppc64/kernel/iomap.c
new file mode 100644 (file)
index 0000000..b70a924
--- /dev/null
@@ -0,0 +1,119 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+
+/*
+ * Here comes the ppc64 implementation of the IOMAP 
+ * interfaces.
+ */
+unsigned int fastcall ioread8(void __iomem *addr)
+{
+       return readb(addr);
+}
+unsigned int fastcall ioread16(void __iomem *addr)
+{
+       return readw(addr);
+}
+unsigned int fastcall ioread32(void __iomem *addr)
+{
+       return readl(addr);
+}
+EXPORT_SYMBOL(ioread8);
+EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread32);
+
+void fastcall iowrite8(u8 val, void __iomem *addr)
+{
+       writeb(val, addr);
+}
+void fastcall iowrite16(u16 val, void __iomem *addr)
+{
+       writew(val, addr);
+}
+void fastcall iowrite32(u32 val, void __iomem *addr)
+{
+       writel(val, addr);
+}
+EXPORT_SYMBOL(iowrite8);
+EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite32);
+
+/*
+ * These are the "repeat read/write" functions. Note the
+ * non-CPU byte order. We do things in "IO byteorder"
+ * here.
+ *
+ * FIXME! We could make these do EEH handling if we really
+ * wanted. Not clear if we do.
+ */
+void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       _insb((u8 __force *) addr, dst, count);
+}
+void ioread16_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       _insw_ns((u16 __force *) addr, dst, count);
+}
+void ioread32_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       _insl_ns((u32 __force *) addr, dst, count);
+}
+EXPORT_SYMBOL(ioread8_rep);
+EXPORT_SYMBOL(ioread16_rep);
+EXPORT_SYMBOL(ioread32_rep);
+
+void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       _outsb((u8 __force *) addr, src, count);
+}
+void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       _outsw_ns((u16 __force *) addr, src, count);
+}
+void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       _outsl_ns((u32 __force *) addr, src, count);
+}
+EXPORT_SYMBOL(iowrite8_rep);
+EXPORT_SYMBOL(iowrite16_rep);
+EXPORT_SYMBOL(iowrite32_rep);
+
+void __iomem *ioport_map(unsigned long port, unsigned int len)
+{
+       if (!_IO_IS_VALID(port))
+               return NULL;
+       return (void __iomem *) (port+pci_io_base);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+       /* Nothing to do */
+}
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len)
+               return NULL;
+       if (max && len > max)
+               len = max;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM)
+               return (void __iomem *) start;
+       /* What? */
+       return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       /* Nothing to do */
+}
+EXPORT_SYMBOL(pci_iomap);
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c
new file mode 100644 (file)
index 0000000..bf3a3c0
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
+ *                   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.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/iommu.h>
+
+#include "pci.h"
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static struct pci_controller *u3_agp, *u3_ht;
+
+static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+       for (; node != 0;node = node->sibling) {
+               int * bus_range;
+               unsigned int *class_code;
+               int len;
+
+               /* For PCI<->PCI bridges or CardBus bridges, we go down */
+               class_code = (unsigned int *) get_property(node, "class-code", NULL);
+               if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+                       (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+                       continue;
+               bus_range = (int *) get_property(node, "bus-range", &len);
+               if (bus_range != NULL && len > 2 * sizeof(int)) {
+                       if (bus_range[1] > higher)
+                               higher = bus_range[1];
+               }
+               higher = fixup_one_level_bus_range(node->child, higher);
+       }
+       return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ *
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init fixup_bus_range(struct device_node *bridge)
+{
+       int * bus_range;
+       int len;
+
+       /* Lookup the "bus-range" property for the hose */
+       bus_range = (int *) get_property(bridge, "bus-range", &len);
+       if (bus_range == NULL || len < 2 * sizeof(int)) {
+               printk(KERN_WARNING "Can't get bus-range for %s\n",
+                              bridge->full_name);
+               return;
+       }
+       bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
+
+
+#define U3_AGP_CFA0(devfn, off)        \
+       ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+       | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+       | (((unsigned long)(off)) & 0xFCUL))
+
+#define U3_AGP_CFA1(bus, devfn, off)   \
+       ((((unsigned long)(bus)) << 16) \
+       |(((unsigned long)(devfn)) << 8) \
+       |(((unsigned long)(off)) & 0xFCUL) \
+       |1UL)
+
+static unsigned long u3_agp_cfg_access(struct pci_controller* hose,
+                                      u8 bus, u8 dev_fn, u8 offset)
+{
+       unsigned int caddr;
+
+       if (bus == hose->first_busno) {
+               if (dev_fn < (11 << 3))
+                       return 0;
+               caddr = U3_AGP_CFA0(dev_fn, offset);
+       } else
+               caddr = U3_AGP_CFA1(bus, dev_fn, offset);
+
+       /* Uninorth will return garbage if we don't read back the value ! */
+       do {
+               out_le32(hose->cfg_addr, caddr);
+       } while (in_le32(hose->cfg_addr) != caddr);
+
+       offset &= 0x07;
+       return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn,
+                             int offset, int len, u32 *val)
+{
+       struct pci_controller *hose;
+       unsigned long addr;
+
+       hose = pci_bus_to_host(bus);
+       if (hose == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       addr = u3_agp_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               *val = in_8((u8 *)addr);
+               break;
+       case 2:
+               *val = in_le16((u16 *)addr);
+               break;
+       default:
+               *val = in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn,
+                              int offset, int len, u32 val)
+{
+       struct pci_controller *hose;
+       unsigned long addr;
+
+       hose = pci_bus_to_host(bus);
+       if (hose == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       addr = u3_agp_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               out_8((u8 *)addr, val);
+               (void) in_8((u8 *)addr);
+               break;
+       case 2:
+               out_le16((u16 *)addr, val);
+               (void) in_le16((u16 *)addr);
+               break;
+       default:
+               out_le32((u32 *)addr, val);
+               (void) in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u3_agp_pci_ops =
+{
+       u3_agp_read_config,
+       u3_agp_write_config
+};
+
+
+#define U3_HT_CFA0(devfn, off)         \
+               ((((unsigned long)devfn) << 8) | offset)
+#define U3_HT_CFA1(bus, devfn, off)    \
+               (U3_HT_CFA0(devfn, off) \
+               + (((unsigned long)bus) << 16) \
+               + 0x01000000UL)
+
+static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
+                                     u8 bus, u8 devfn, u8 offset)
+{
+       if (bus == hose->first_busno) {
+               if (PCI_SLOT(devfn) == 0)
+                       return 0;
+               return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
+       } else
+               return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
+}
+
+static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
+                            int offset, int len, u32 *val)
+{
+       struct pci_controller *hose;
+       unsigned long addr;
+
+       hose = pci_bus_to_host(bus);
+       if (hose == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               *val = in_8((u8 *)addr);
+               break;
+       case 2:
+               *val = in_le16((u16 *)addr);
+               break;
+       default:
+               *val = in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
+                             int offset, int len, u32 val)
+{
+       struct pci_controller *hose;
+       unsigned long addr;
+
+       hose = pci_bus_to_host(bus);
+       if (hose == NULL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+       if (!addr)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       switch (len) {
+       case 1:
+               out_8((u8 *)addr, val);
+               (void) in_8((u8 *)addr);
+               break;
+       case 2:
+               out_le16((u16 *)addr, val);
+               (void) in_le16((u16 *)addr);
+               break;
+       default:
+               out_le32((u32 *)addr, val);
+               (void) in_le32((u32 *)addr);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u3_ht_pci_ops =
+{
+       u3_ht_read_config,
+       u3_ht_write_config
+};
+
+static void __init setup_u3_agp(struct pci_controller* hose)
+{
+       /* On G5, we move AGP up to high bus number so we don't need
+        * to reassign bus numbers for HT. If we ever have P2P bridges
+        * on AGP, we'll have to move pci_assign_all_busses to the
+        * pci_controller structure so we enable it for AGP and not for
+        * HT childs.
+        * We hard code the address because of the different size of
+        * the reg address cell, we shall fix that by killing struct
+        * reg_property and using some accessor functions instead
+        */
+               hose->first_busno = 0xf0;
+       hose->last_busno = 0xff;
+       hose->ops = &u3_agp_pci_ops;
+       hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+       hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+       u3_agp = hose;
+}
+
+static void __init setup_u3_ht(struct pci_controller* hose)
+{
+       hose->ops = &u3_ht_pci_ops;
+
+       /* We hard code the address because of the different size of
+        * the reg address cell, we shall fix that by killing struct
+        * reg_property and using some accessor functions instead
+        */
+       hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);
+
+       hose->first_busno = 0;
+       hose->last_busno = 0xef;
+
+       u3_ht = hose;
+}
+
+static int __init add_bridge(struct device_node *dev)
+{
+       int len;
+       struct pci_controller *hose;
+       char* disp_name;
+       int *bus_range;
+       int primary = 1;
+       struct property *of_prop;
+
+       DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+               bus_range = (int *) get_property(dev, "bus-range", &len);
+               if (bus_range == NULL || len < 2 * sizeof(int)) {
+                       printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+                                      dev->full_name);
+               }
+
+       hose = alloc_bootmem(sizeof(struct pci_controller));
+       if (hose == NULL)
+               return -ENOMEM;
+               pci_setup_pci_controller(hose);
+
+               hose->arch_data = dev;
+               hose->first_busno = bus_range ? bus_range[0] : 0;
+               hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+       of_prop = alloc_bootmem(sizeof(struct property) +
+                               sizeof(hose->global_number));
+       if (of_prop) {
+               memset(of_prop, 0, sizeof(struct property));
+               of_prop->name = "linux,pci-domain";
+               of_prop->length = sizeof(hose->global_number);
+               of_prop->value = (unsigned char *)&of_prop[1];
+               memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number));
+               prom_add_property(dev, of_prop);
+       }
+
+       disp_name = NULL;
+               if (device_is_compatible(dev, "u3-agp")) {
+                       setup_u3_agp(hose);
+                       disp_name = "U3-AGP";
+                       primary = 0;
+               } else if (device_is_compatible(dev, "u3-ht")) {
+                       setup_u3_ht(hose);
+                       disp_name = "U3-HT";
+                       primary = 1;
+               }
+               printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
+                       disp_name, hose->first_busno, hose->last_busno);
+
+               /* Interpret the "ranges" property */
+               /* This also maps the I/O region and sets isa_io/mem_base */
+               pci_process_bridge_OF_ranges(hose, dev);
+       pci_setup_phb_io(hose, primary);
+
+               /* Fixup "bus-range" OF property */
+               fixup_bus_range(dev);
+
+       return 0;
+}
+
+
+void __init maple_pcibios_fixup(void)
+{
+       struct pci_dev *dev = NULL;
+
+       DBG(" -> maple_pcibios_fixup\n");
+
+       for_each_pci_dev(dev)
+               pci_read_irq_line(dev);
+
+       /* Do the mapping of the IO space */
+       phbs_remap_io();
+
+       /* Fixup the pci_bus sysdata pointers */
+       pci_fix_bus_sysdata();
+
+       /* Setup the iommu */
+       iommu_setup_u3();
+
+       DBG(" <- maple_pcibios_fixup\n");
+}
+
+static void __init maple_fixup_phb_resources(void)
+{
+       struct pci_controller *hose, *tmp;
+       
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
+               hose->io_resource.start += offset;
+               hose->io_resource.end += offset;
+               printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
+                      hose->global_number,
+                      hose->io_resource.start, hose->io_resource.end);
+       }
+}
+
+void __init maple_pci_init(void)
+{
+       struct device_node *np, *root;
+       struct device_node *ht = NULL;
+
+       /* Probe root PCI hosts, that is on U3 the AGP host and the
+        * HyperTransport host. That one is actually "kept" around
+        * and actually added last as it's resource management relies
+        * on the AGP resources to have been setup first
+        */
+       root = of_find_node_by_path("/");
+       if (root == NULL) {
+               printk(KERN_CRIT "maple_find_bridges: can't find root of device tree\n");
+               return;
+       }
+       for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
+               if (np->name == NULL)
+                       continue;
+               if (strcmp(np->name, "pci") == 0) {
+                       if (add_bridge(np) == 0)
+                               of_node_get(np);
+               }
+               if (strcmp(np->name, "ht") == 0) {
+                       of_node_get(np);
+                       ht = np;
+               }
+       }
+       of_node_put(root);
+
+       /* Now setup the HyperTransport host if we found any
+        */
+       if (ht && add_bridge(ht) != 0)
+               of_node_put(ht);
+
+       /* Fixup the IO resources on our host bridges as the common code
+        * does it only for childs of the host bridges
+        */
+       maple_fixup_phb_resources();
+
+       /* Setup the linkage between OF nodes and PHBs */ 
+       pci_devs_phb_init();
+
+       /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
+        * assume there is no P2P bridge on the AGP bus, which should be a
+        * safe assumptions hopefully.
+        */
+       if (u3_agp) {
+               struct device_node *np = u3_agp->arch_data;
+               np->busno = 0xf0;
+               for (np = np->child; np; np = np->sibling)
+                       np->busno = 0xf0;
+       }
+
+       /* Tell pci.c to use the common resource allocation mecanism */
+       pci_probe_only = 0;
+       
+       /* Allow all IO */
+       io_page_mask = -1;
+}
+
+int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
+{
+       struct device_node *np;
+       int irq = channel ? 15 : 14;
+
+       if (pdev->vendor != PCI_VENDOR_ID_AMD ||
+           pdev->device != PCI_DEVICE_ID_AMD_8111_IDE)
+               return irq;
+
+       np = pci_device_to_OF_node(pdev);
+       if (np == NULL)
+               return irq;
+       if (np->n_intrs < 2)
+               return irq;
+       return np->intrs[channel & 0x1].line;
+}
+
+/* XXX: To remove once all firmwares are ok */
+static void fixup_maple_ide(struct pci_dev* dev)
+{
+#if 0 /* Enable this to enable IDE port 0 */
+       {
+               u8 v;
+
+               pci_read_config_byte(dev, 0x40, &v);
+               v |= 2;
+               pci_write_config_byte(dev, 0x40, v);
+       }
+#endif
+#if 0 /* fix bus master base */
+       pci_write_config_dword(dev, 0x20, 0xcc01);
+       printk("old ide resource: %lx -> %lx \n",
+              dev->resource[4].start, dev->resource[4].end);
+       dev->resource[4].start = 0xcc00;
+       dev->resource[4].end = 0xcc10;
+#endif
+#if 1 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */
+       {
+               struct pci_dev *apicdev;
+               u32 v;
+
+               apicdev = pci_get_slot (dev->bus, PCI_DEVFN(5,0));
+               if (apicdev == NULL)
+                       printk("IDE Fixup IRQ: Can't find IO-APIC !\n");
+               else {
+                       pci_write_config_byte(apicdev, 0xf2, 0x10 + 2*14);
+                       pci_read_config_dword(apicdev, 0xf4, &v);
+                       v &= ~0x00000022;
+                       pci_write_config_dword(apicdev, 0xf4, v);
+                       pci_write_config_byte(apicdev, 0xf2, 0x10 + 2*15);
+                       pci_read_config_dword(apicdev, 0xf4, &v);
+                       v &= ~0x00000022;
+                       pci_write_config_dword(apicdev, 0xf4, v);
+                       pci_dev_put(apicdev);
+               }
+       }
+#endif
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE,
+                        fixup_maple_ide);
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c
new file mode 100644 (file)
index 0000000..29d5859
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *  arch/ppc64/kernel/maple_setup.c
+ *
+ *  (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org),
+ *                     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.
+ *
+ */
+
+#define DEBUG
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
+#include <asm/machdep.h>
+#include <asm/dma.h>
+#include <asm/cputable.h>
+#include <asm/time.h>
+#include <asm/of_device.h>
+#include <asm/lmb.h>
+
+#include "mpic.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+extern int maple_set_rtc_time(struct rtc_time *tm);
+extern void maple_get_rtc_time(struct rtc_time *tm);
+extern void maple_get_boot_time(struct rtc_time *tm);
+extern void maple_calibrate_decr(void);
+extern void maple_pci_init(void);
+extern void maple_pcibios_fixup(void);
+extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel);
+extern void generic_find_legacy_serial_ports(unsigned int *default_speed);
+
+
+static void maple_restart(char *cmd)
+{
+}
+
+static void maple_power_off(void)
+{
+}
+
+static void maple_halt(void)
+{
+}
+
+#ifdef CONFIG_SMP
+struct smp_ops_t maple_smp_ops = {
+       .probe          = smp_mpic_probe,
+       .message_pass   = smp_mpic_message_pass,
+       .kick_cpu       = smp_generic_kick_cpu,
+       .setup_cpu      = smp_mpic_setup_cpu,
+       .give_timebase  = smp_generic_give_timebase,
+       .take_timebase  = smp_generic_take_timebase,
+};
+#endif /* CONFIG_SMP */
+
+void __init maple_setup_arch(void)
+{
+       /* init to some ~sane value until calibrate_delay() runs */
+       loops_per_jiffy = 50000000;
+
+       /* Setup SMP callback */
+#ifdef CONFIG_SMP
+       smp_ops = &maple_smp_ops;
+#endif
+       /* Setup the PCI DMA to "direct" by default. May be overriden
+        * by iommu later on
+        */
+       pci_dma_init_direct();
+
+       /* Lookup PCI hosts */
+               maple_pci_init();
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+}
+
+/* 
+ * Early initialization.
+ */
+static void __init maple_init_early(void)
+{
+       unsigned int default_speed;
+
+       DBG(" -> maple_init_early\n");
+
+       /* Initialize hash table, from now on, we can take hash faults
+        * and call ioremap
+        */
+       hpte_init_native();
+
+       /* Find the serial port */
+               generic_find_legacy_serial_ports(&default_speed);
+
+       DBG("naca->serialPortAddr: %lx\n", (long)naca->serialPortAddr);
+
+       if (naca->serialPortAddr) {
+               void *comport;
+               /* Map the uart for udbg. */
+               comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
+               udbg_init_uart(comport, default_speed);
+
+               ppc_md.udbg_putc = udbg_putc;
+               ppc_md.udbg_getc = udbg_getc;
+               ppc_md.udbg_getc_poll = udbg_getc_poll;
+               DBG("Hello World !\n");
+       }
+
+       /* Setup interrupt mapping options */
+       naca->interrupt_controller = IC_OPEN_PIC;
+
+       DBG(" <- maple_init_early\n");
+}
+
+
+static __init void maple_init_IRQ(void)
+{
+       struct device_node *root;
+       unsigned int *opprop;
+       unsigned long opic_addr;
+       struct mpic *mpic;
+       unsigned char senses[128];
+       int n;
+
+       DBG(" -> maple_init_IRQ\n");
+
+       /* XXX: Non standard, replace that with a proper openpic/mpic node
+        * in the device-tree. Find the Open PIC if present */
+       root = of_find_node_by_path("/");
+       opprop = (unsigned int *) get_property(root,
+                               "platform-open-pic", NULL);
+       if (opprop == 0)
+               panic("OpenPIC not found !\n");
+
+       n = prom_n_addr_cells(root);
+       for (opic_addr = 0; n > 0; --n)
+               opic_addr = (opic_addr << 32) + *opprop++;
+       of_node_put(root);
+
+       /* Obtain sense values from device-tree */
+       prom_get_irq_senses(senses, 0, 128);
+
+       mpic = mpic_alloc(opic_addr,
+                         MPIC_PRIMARY | MPIC_BIG_ENDIAN |
+                         MPIC_BROKEN_U3 | MPIC_WANTS_RESET,
+                         0, 0, 128, 128, senses, 128, "U3-MPIC");
+       BUG_ON(mpic == NULL);
+       mpic_init(mpic);
+
+       DBG(" <- maple_init_IRQ\n");
+}
+
+static void __init maple_progress(char *s, unsigned short hex)
+{
+       printk("*** %04x : %s\n", hex, s ? s : "");
+}
+
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init maple_probe(int platform)
+{
+       if (platform != PLATFORM_MAPLE)
+               return 0;
+       /*
+        * On U3, the DART (iommu) must be allocated now since it
+        * has an impact on htab_initialize (due to the large page it
+        * occupies having to be broken up so the DART itself is not
+        * part of the cacheable linar mapping
+        */
+       alloc_u3_dart_table();
+
+       return 1;
+}
+
+struct machdep_calls __initdata maple_md = {
+       .probe                  = maple_probe,
+       .setup_arch             = maple_setup_arch,
+       .init_early             = maple_init_early,
+       .init_IRQ               = maple_init_IRQ,
+       .get_irq                = mpic_get_irq,
+       .pcibios_fixup          = maple_pcibios_fixup,
+       .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq,
+       .restart                = maple_restart,
+       .power_off              = maple_power_off,
+       .halt                   = maple_halt,
+               .get_boot_time          = maple_get_boot_time,
+               .set_rtc_time           = maple_set_rtc_time,
+               .get_rtc_time           = maple_get_rtc_time,
+       .calibrate_decr         = maple_calibrate_decr,
+       .progress               = maple_progress,
+};
diff --git a/arch/ppc64/kernel/maple_time.c b/arch/ppc64/kernel/maple_time.c
new file mode 100644 (file)
index 0000000..07ce789
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *  arch/ppc64/kernel/maple_time.c
+ *
+ *  (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org),
+ *                     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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+extern void setup_default_decr(void);
+extern void GregorianDay(struct rtc_time * tm);
+
+extern unsigned long ppc_tb_freq;
+extern unsigned long ppc_proc_freq;
+static int maple_rtc_addr;
+
+static int maple_clock_read(int addr)
+{
+       outb_p(addr, maple_rtc_addr);
+       return inb_p(maple_rtc_addr+1);
+}
+
+static void maple_clock_write(unsigned long val, int addr)
+{
+       outb_p(addr, maple_rtc_addr);
+       outb_p(val, maple_rtc_addr+1);
+}
+
+void maple_get_rtc_time(struct rtc_time *tm)
+{
+       int uip, i;
+
+       /* The Linux interpretation of the CMOS clock register contents:
+        * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+        * RTC registers show the second which has precisely just started.
+        * Let's hope other operating systems interpret the RTC the same way.
+        */
+
+       /* Since the UIP flag is set for about 2.2 ms and the clock
+        * is typically written with a precision of 1 jiffy, trying
+        * to obtain a precision better than a few milliseconds is
+        * an illusion. Only consistency is interesting, this also
+        * allows to use the routine for /dev/rtc without a potential
+        * 1 second kernel busy loop triggered by any reader of /dev/rtc.
+        */
+
+       for (i = 0; i<1000000; i++) {
+               uip = maple_clock_read(RTC_FREQ_SELECT);
+               tm->tm_sec = maple_clock_read(RTC_SECONDS);
+               tm->tm_min = maple_clock_read(RTC_MINUTES);
+               tm->tm_hour = maple_clock_read(RTC_HOURS);
+               tm->tm_mday = maple_clock_read(RTC_DAY_OF_MONTH);
+               tm->tm_mon = maple_clock_read(RTC_MONTH);
+               tm->tm_year = maple_clock_read(RTC_YEAR);
+               uip |= maple_clock_read(RTC_FREQ_SELECT);
+               if ((uip & RTC_UIP)==0)
+                       break;
+       }
+
+       if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY)
+           || RTC_ALWAYS_BCD) {
+               BCD_TO_BIN(tm->tm_sec);
+               BCD_TO_BIN(tm->tm_min);
+               BCD_TO_BIN(tm->tm_hour);
+               BCD_TO_BIN(tm->tm_mday);
+               BCD_TO_BIN(tm->tm_mon);
+               BCD_TO_BIN(tm->tm_year);
+         }
+       if ((tm->tm_year + 1900) < 1970)
+               tm->tm_year += 100;
+
+       GregorianDay(tm);
+}
+
+int maple_set_rtc_time(struct rtc_time *tm)
+{
+       unsigned char save_control, save_freq_select;
+       int sec, min, hour, mon, mday, year;
+
+       spin_lock(&rtc_lock);
+
+       save_control = maple_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+       maple_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+       save_freq_select = maple_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+       maple_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+       sec = tm->tm_sec;
+       min = tm->tm_min;
+       hour = tm->tm_hour;
+       mon = tm->tm_mon;
+       mday = tm->tm_mday;
+       year = tm->tm_year;
+
+       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+               BIN_TO_BCD(sec);
+               BIN_TO_BCD(min);
+               BIN_TO_BCD(hour);
+               BIN_TO_BCD(mon);
+               BIN_TO_BCD(mday);
+               BIN_TO_BCD(year);
+       }
+       maple_clock_write(sec, RTC_SECONDS);
+       maple_clock_write(min, RTC_MINUTES);
+       maple_clock_write(hour, RTC_HOURS);
+       maple_clock_write(mon, RTC_MONTH);
+       maple_clock_write(mday, RTC_DAY_OF_MONTH);
+       maple_clock_write(year, RTC_YEAR);
+
+       /* The following flags have to be released exactly in this order,
+        * otherwise the DS12887 (popular MC146818A clone with integrated
+        * battery and quartz) will not reset the oscillator and will not
+        * update precisely 500 ms later. You won't find this mentioned in
+        * the Dallas Semiconductor data sheets, but who believes data
+        * sheets anyway ...                           -- Markus Kuhn
+        */
+       maple_clock_write(save_control, RTC_CONTROL);
+       maple_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+       spin_unlock(&rtc_lock);
+
+       return 0;
+}
+
+void __init maple_get_boot_time(struct rtc_time *tm)
+{
+       struct device_node *rtcs;
+
+       rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+       if (rtcs && rtcs->addrs) {
+               maple_rtc_addr = rtcs->addrs[0].address;
+               printk(KERN_INFO "Maple: Found RTC at 0x%x\n", maple_rtc_addr);
+       } else {
+               maple_rtc_addr = RTC_PORT(0); /* legacy address */
+               printk(KERN_INFO "Maple: No device node for RTC, assuming "
+                      "legacy address (0x%x)\n", maple_rtc_addr);
+       }
+       
+       maple_get_rtc_time(tm);
+}
+
+/* XXX FIXME: Some sane defaults: 125 MHz timebase, 1GHz processor */
+#define DEFAULT_TB_FREQ                125000000UL
+#define DEFAULT_PROC_FREQ      (DEFAULT_TB_FREQ * 8)
+
+void __init maple_calibrate_decr(void)
+{
+       struct device_node *cpu;
+       struct div_result divres;
+       unsigned int *fp = NULL;
+
+       /*
+        * The cpu node should have a timebase-frequency property
+        * to tell us the rate at which the decrementer counts.
+        */
+       cpu = of_find_node_by_type(NULL, "cpu");
+
+       ppc_tb_freq = DEFAULT_TB_FREQ;
+       if (cpu != 0)
+               fp = (unsigned int *)get_property(cpu, "timebase-frequency", NULL);
+       if (fp != NULL)
+               ppc_tb_freq = *fp;
+       else
+               printk(KERN_ERR "WARNING: Estimating decrementer frequency (not found)\n");
+       fp = NULL;
+       ppc_proc_freq = DEFAULT_PROC_FREQ;
+       if (cpu != 0)
+               fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL);
+       if (fp != NULL)
+               ppc_proc_freq = *fp;
+       else
+               printk(KERN_ERR "WARNING: Estimating processor frequency (not found)\n");
+
+       of_node_put(cpu);
+
+       printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+              ppc_tb_freq/1000000, ppc_tb_freq%1000000);
+       printk(KERN_INFO "time_init: processor frequency   = %lu.%.6lu MHz\n",
+              ppc_proc_freq/1000000, ppc_proc_freq%1000000);
+
+       tb_ticks_per_jiffy = ppc_tb_freq / HZ;
+       tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
+       tb_ticks_per_usec = ppc_tb_freq / 1000000;
+       tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
+       div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres);
+       tb_to_xs = divres.result_low;
+
+       setup_default_decr();
+}
diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c
new file mode 100644 (file)
index 0000000..e013e85
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ *  arch/ppc64/kernel/mpic.c
+ *
+ *  Driver for interrupt controllers following the OpenPIC standard, the
+ *  common implementation beeing IBM's MPIC. This driver also can deal
+ *  with various broken implementations of this HW.
+ *
+ *  Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
+ *
+ *  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.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+#include "mpic.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static struct mpic *mpics;
+static struct mpic *mpic_primary;
+static spinlock_t mpic_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ * Register accessor functions
+ */
+
+
+static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base,
+                           unsigned int reg)
+{
+       if (be)
+               return in_be32(base + (reg >> 2));
+       else
+               return in_le32(base + (reg >> 2));
+}
+
+static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base,
+                             unsigned int reg, u32 value)
+{
+       if (be)
+               out_be32(base + (reg >> 2), value);
+       else
+               out_le32(base + (reg >> 2), value);
+}
+
+static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
+{
+       unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0;
+       unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+
+       if (mpic->flags & MPIC_BROKEN_IPI)
+               be = !be;
+       return _mpic_read(be, mpic->gregs, offset);
+}
+
+static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value)
+{
+       unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+
+       _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value);
+}
+
+static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
+{
+       unsigned int cpu = 0;
+
+       if (mpic->flags & MPIC_PRIMARY)
+               cpu = hard_smp_processor_id();
+
+       return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg);
+}
+
+static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
+{
+       unsigned int cpu = 0;
+
+       if (mpic->flags & MPIC_PRIMARY)
+               cpu = hard_smp_processor_id();
+
+       _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value);
+}
+
+static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg)
+{
+       unsigned int    isu = src_no >> mpic->isu_shift;
+       unsigned int    idx = src_no & mpic->isu_mask;
+
+       return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
+                         reg + (idx * MPIC_IRQ_STRIDE));
+}
+
+static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
+                                  unsigned int reg, u32 value)
+{
+       unsigned int    isu = src_no >> mpic->isu_shift;
+       unsigned int    idx = src_no & mpic->isu_mask;
+
+       _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
+                   reg + (idx * MPIC_IRQ_STRIDE), value);
+}
+
+#define mpic_read(b,r)         _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r))
+#define mpic_write(b,r,v)      _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v))
+#define mpic_ipi_read(i)       _mpic_ipi_read(mpic,(i))
+#define mpic_ipi_write(i,v)    _mpic_ipi_write(mpic,(i),(v))
+#define mpic_cpu_read(i)       _mpic_cpu_read(mpic,(i))
+#define mpic_cpu_write(i,v)    _mpic_cpu_write(mpic,(i),(v))
+#define mpic_irq_read(s,r)     _mpic_irq_read(mpic,(s),(r))
+#define mpic_irq_write(s,r,v)  _mpic_irq_write(mpic,(s),(r),(v))
+
+
+/*
+ * Low level utility functions
+ */
+
+
+
+/* Check if we have one of those nice broken MPICs with a flipped endian on
+ * reads from IPI registers
+ */
+static void __init mpic_test_broken_ipi(struct mpic *mpic)
+{
+       u32 r;
+
+       mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK);
+       r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0);
+
+       if (r == le32_to_cpu(MPIC_VECPRI_MASK)) {
+               printk(KERN_INFO "mpic: Detected reversed IPI registers\n");
+               mpic->flags |= MPIC_BROKEN_IPI;
+       }
+}
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+
+/* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
+ * to force the edge setting on the MPIC and do the ack workaround.
+ */
+static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no)
+{
+       if (source_no >= 128 || !mpic->fixups)
+               return 0;
+       return mpic->fixups[source_no].base != NULL;
+}
+
+static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no)
+{
+       struct mpic_irq_fixup *fixup = &mpic->fixups[source_no];
+       u32 tmp;
+
+       spin_lock(&mpic->fixup_lock);
+       writeb(0x11 + 2 * fixup->irq, fixup->base);
+       tmp = readl(fixup->base + 2);
+       writel(tmp | 0x80000000ul, fixup->base + 2);
+       /* config writes shouldn't be posted but let's be safe ... */
+       (void)readl(fixup->base + 2);
+       spin_unlock(&mpic->fixup_lock);
+}
+
+
+static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+{
+       int i, irq;
+       u32 tmp;
+
+       printk(KERN_INFO "mpic:    - Workarounds on AMD 8111 @ %p\n", devbase);
+
+       for (i=0; i < 24; i++) {
+               writeb(0x10 + 2*i, devbase + 0xf2);
+               tmp = readl(devbase + 0xf4);
+               if ((tmp & 0x1) || !(tmp & 0x20))
+                       continue;
+               irq = (tmp >> 16) & 0xff;
+               mpic->fixups[irq].irq = i;
+               mpic->fixups[irq].base = devbase + 0xf2;
+       }
+}
+static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase)
+{
+       int i, irq;
+       u32 tmp;
+
+       printk(KERN_INFO "mpic:    - Workarounds on AMD 8131 @ %p\n", devbase);
+
+       for (i=0; i < 4; i++) {
+               writeb(0x10 + 2*i, devbase + 0xba);
+               tmp = readl(devbase + 0xbc);
+               if ((tmp & 0x1) || !(tmp & 0x20))
+                       continue;
+               irq = (tmp >> 16) & 0xff;
+               mpic->fixups[irq].irq = i;
+               mpic->fixups[irq].base = devbase + 0xba;
+       }
+}
+static void __init mpic_scan_ioapics(struct mpic *mpic)
+{
+       unsigned int devfn;
+       u8 __iomem *cfgspace;
+
+       printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n");
+
+       /* Allocate fixups array */
+       mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
+       BUG_ON(mpic->fixups == NULL);
+       memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup));
+
+       /* Init spinlock */
+       spin_lock_init(&mpic->fixup_lock);
+
+       /* Map u3 config space. We assume all IO-APICs are on the primary bus
+        * and slot will never be above "0xf" so we only need to map 32k
+        */
+       cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000);
+       BUG_ON(cfgspace == NULL);
+
+       /* Now we scan all slots. We do a very quick scan, we read the header type,
+        * vendor ID and device ID only, that's plenty enough
+        */
+       for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) {
+               u8 __iomem *devbase = cfgspace + (devfn << 8);
+               u8 hdr_type = readb(devbase + PCI_HEADER_TYPE);
+               u32 l = readl(devbase + PCI_VENDOR_ID);
+               u16 vendor_id, device_id;
+               int multifunc = 0;
+
+               DBG("devfn %x, l: %x\n", devfn, l);
+
+               /* If no device, skip */
+               if (l == 0xffffffff || l == 0x00000000 ||
+                   l == 0x0000ffff || l == 0xffff0000)
+                       goto next;
+
+               /* Check if it's a multifunction device (only really used
+                * to function 0 though
+                */
+               multifunc = !!(hdr_type & 0x80);
+               vendor_id = l & 0xffff;
+               device_id = (l >> 16) & 0xffff;
+
+               /* If a known device, go to fixup setup code */
+               if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460)
+                       mpic_amd8111_read_irq(mpic, devbase);
+               if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450)
+                       mpic_amd8131_read_irq(mpic, devbase);
+       next:
+               /* next device, if function 0 */
+               if ((PCI_FUNC(devfn) == 0) && !multifunc)
+                       devfn += 7;
+       }
+}
+
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+
+/* Find an mpic associated with a given linux interrupt */
+static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
+{
+       struct mpic *mpic = mpics;
+
+       while(mpic) {
+               /* search IPIs first since they may override the main interrupts */
+               if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) {
+                       if (is_ipi)
+                               *is_ipi = 1;
+                       return mpic;
+               }
+               if (irq >= mpic->irq_offset &&
+                   irq < (mpic->irq_offset + mpic->irq_count)) {
+                       if (is_ipi)
+                               *is_ipi = 0;
+                       return mpic;
+               }
+               mpic = mpic -> next;
+       }
+       return NULL;
+}
+
+/* Convert a cpu mask from logical to physical cpu numbers. */
+static inline u32 mpic_physmask(u32 cpumask)
+{
+       int i;
+       u32 mask = 0;
+
+       for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
+               mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
+       return mask;
+}
+
+#ifdef CONFIG_SMP
+/* Get the mpic structure from the IPI number */
+static inline struct mpic * mpic_from_ipi(unsigned int ipi)
+{
+       return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi);
+}
+#endif
+
+/* Get the mpic structure from the irq number */
+static inline struct mpic * mpic_from_irq(unsigned int irq)
+{
+       return container_of(irq_desc[irq].handler, struct mpic, hc_irq);
+}
+
+/* Send an EOI */
+static inline void mpic_eoi(struct mpic *mpic)
+{
+       mpic_cpu_write(MPIC_CPU_EOI, 0);
+       (void)mpic_cpu_read(MPIC_CPU_WHOAMI);
+}
+
+#ifdef CONFIG_SMP
+static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct mpic *mpic = dev_id;
+
+       smp_message_recv(irq - mpic->ipi_offset, regs);
+       return IRQ_HANDLED;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * Linux descriptor level callbacks
+ */
+
+
+static void mpic_enable_irq(unsigned int irq)
+{
+       unsigned int loops = 100000;
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
+
+       DBG("%s: enable_irq: %d (src %d)\n", mpic->name, irq, src);
+
+       mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+                      mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & ~MPIC_VECPRI_MASK);
+
+       /* make sure mask gets to controller before we return to user */
+       do {
+               if (!loops--) {
+                       printk(KERN_ERR "mpic_enable_irq timeout\n");
+                       break;
+               }
+       } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);    
+}
+
+static void mpic_disable_irq(unsigned int irq)
+{
+       unsigned int loops = 100000;
+       struct mpic *mpic = mpic_from_irq(irq);
+       unsigned int src = irq - mpic->irq_offset;
+
+       DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
+
+       mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+                      mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | MPIC_VECPRI_MASK);
+
+       /* make sure mask gets to controller before we return to user */
+       do {
+               if (!loops--) {
+                       printk(KERN_ERR "mpic_enable_irq timeout\n");
+                       break;
+               }
+       } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
+}
+
+static void mpic_end_irq(unsigned int irq)
+{
+       struct mpic *mpic = mpic_from_irq(irq);
+
+       DBG("%s: end_irq: %d\n", mpic->name, irq);
+
+       /* We always EOI on end_irq() even for edge interrupts since that
+        * should only lower the priority, the MPIC should have properly
+        * latched another edge interrupt coming in anyway
+        */
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+       if (mpic->flags & MPIC_BROKEN_U3) {
+               unsigned int src = irq - mpic->irq_offset;
+               if (mpic_is_ht_interrupt(mpic, src))
+                       mpic_apic_end_irq(mpic, src);
+       }
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+       mpic_eoi(mpic);
+}
+
+#ifdef CONFIG_SMP
+
+static void mpic_enable_ipi(unsigned int irq)
+{
+       struct mpic *mpic = mpic_from_ipi(irq);
+       unsigned int src = irq - mpic->ipi_offset;
+
+       DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
+       mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
+}
+
+static void mpic_disable_ipi(unsigned int irq)
+{
+       /* NEVER disable an IPI... that's just plain wrong! */
+}
+
+static void mpic_end_ipi(unsigned int irq)
+{
+       struct mpic *mpic = mpic_from_ipi(irq);
+
+       /*
+        * IPIs are marked IRQ_PER_CPU. This has the side effect of
+        * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
+        * applying to them. We EOI them late to avoid re-entering.
+        * We mark IPI's with SA_INTERRUPT as they must run with
+        * irqs disabled.
+        */
+       mpic_eoi(mpic);
+}
+
+#endif /* CONFIG_SMP */
+
+static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
+{
+       struct mpic *mpic = mpic_from_irq(irq);
+
+       cpumask_t tmp;
+
+       cpus_and(tmp, cpumask, cpu_online_map);
+
+       mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION,
+                      mpic_physmask(cpus_addr(tmp)[0]));       
+}
+
+
+/*
+ * Exported functions
+ */
+
+
+struct mpic * __init mpic_alloc(unsigned long phys_addr,
+                               unsigned int flags,
+                               unsigned int isu_size,
+                               unsigned int irq_offset,
+                               unsigned int irq_count,
+                               unsigned int ipi_offset,
+                               unsigned char *senses,
+                               unsigned int senses_count,
+                               const char *name)
+{
+       struct mpic     *mpic;
+       u32             reg;
+       const char      *vers;
+       int             i;
+
+       mpic = alloc_bootmem(sizeof(struct mpic));
+       if (mpic == NULL)
+               return NULL;
+       
+       memset(mpic, 0, sizeof(struct mpic));
+       mpic->name = name;
+
+       mpic->hc_irq.typename = name;
+       mpic->hc_irq.enable = mpic_enable_irq;
+       mpic->hc_irq.disable = mpic_disable_irq;
+       mpic->hc_irq.end = mpic_end_irq;
+       if (flags & MPIC_PRIMARY)
+               mpic->hc_irq.set_affinity = mpic_set_affinity;
+#ifdef CONFIG_SMP
+       mpic->hc_ipi.typename = name;
+       mpic->hc_ipi.enable = mpic_enable_ipi;
+       mpic->hc_ipi.disable = mpic_disable_ipi;
+       mpic->hc_ipi.end = mpic_end_ipi;
+#endif /* CONFIG_SMP */
+
+       mpic->flags = flags;
+       mpic->isu_size = isu_size;
+       mpic->irq_offset = irq_offset;
+       mpic->irq_count = irq_count;
+       mpic->ipi_offset = ipi_offset;
+       mpic->num_sources = 0; /* so far */
+       mpic->senses = senses;
+       mpic->senses_count = senses_count;
+
+       /* Map the global registers */
+       mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000);
+       mpic->tmregs = mpic->gregs + (MPIC_TIMER_BASE >> 2);
+       BUG_ON(mpic->gregs == NULL);
+
+       /* Reset */
+       if (flags & MPIC_WANTS_RESET) {
+               mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
+                          mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+                          | MPIC_GREG_GCONF_RESET);
+               while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+                      & MPIC_GREG_GCONF_RESET)
+                       mb();
+       }
+
+       /* Read feature register, calculate num CPUs and, for non-ISU
+        * MPICs, num sources as well. On ISU MPICs, sources are counted
+        * as ISUs are added
+        */
+       reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0);
+       mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK)
+                         >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
+       if (isu_size == 0)
+               mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+                                    >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
+
+       /* Map the per-CPU registers */
+       for (i = 0; i < mpic->num_cpus; i++) {
+               mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE +
+                                          i * MPIC_CPU_STRIDE, 0x1000);
+               BUG_ON(mpic->cpuregs[i] == NULL);
+       }
+
+       /* Initialize main ISU if none provided */
+       if (mpic->isu_size == 0) {
+               mpic->isu_size = mpic->num_sources;
+               mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE,
+                                       MPIC_IRQ_STRIDE * mpic->isu_size);
+               BUG_ON(mpic->isus[0] == NULL);
+       }
+       mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
+       mpic->isu_mask = (1 << mpic->isu_shift) - 1;
+
+       /* Display version */
+       switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) {
+       case 1:
+               vers = "1.0";
+               break;
+       case 2:
+               vers = "1.2";
+               break;
+       case 3:
+               vers = "1.3";
+               break;
+       default:
+               vers = "<unknown>";
+               break;
+       }
+       printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n",
+              name, vers, phys_addr, mpic->num_cpus);
+       printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size,
+              mpic->isu_shift, mpic->isu_mask);
+
+       mpic->next = mpics;
+       mpics = mpic;
+
+       if (flags & MPIC_PRIMARY)
+               mpic_primary = mpic;
+
+       return mpic;
+}
+
+void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
+                           unsigned long phys_addr)
+{
+       unsigned int isu_first = isu_num * mpic->isu_size;
+
+       BUG_ON(isu_num >= MPIC_MAX_ISU);
+
+       mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE * mpic->isu_size);
+       if ((isu_first + mpic->isu_size) > mpic->num_sources)
+               mpic->num_sources = isu_first + mpic->isu_size;
+}
+
+void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler,
+                              void *data)
+{
+       struct mpic *mpic = mpic_find(irq, NULL);
+       unsigned long flags;
+
+       /* Synchronization here is a bit dodgy, so don't try to replace cascade
+        * interrupts on the fly too often ... but normally it's set up at boot.
+        */
+       spin_lock_irqsave(&mpic_lock, flags);
+       if (mpic->cascade)             
+               mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset);
+       mpic->cascade = NULL;
+       wmb();
+       mpic->cascade_vec = irq - mpic->irq_offset;
+       mpic->cascade_data = data;
+       wmb();
+       mpic->cascade = handler;
+       mpic_enable_irq(irq);
+       spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+void __init mpic_init(struct mpic *mpic)
+{
+       int i;
+
+       BUG_ON(mpic->num_sources == 0);
+
+       printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources);
+
+       /* Set current processor priority to max */
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+
+       /* Initialize timers: just disable them all */
+       for (i = 0; i < 4; i++) {
+               mpic_write(mpic->tmregs,
+                          i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0);
+               mpic_write(mpic->tmregs,
+                          i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI,
+                          MPIC_VECPRI_MASK |
+                          (MPIC_VEC_TIMER_0 + i));
+       }
+
+       /* Initialize IPIs to our reserved vectors and mark them disabled for now */
+       mpic_test_broken_ipi(mpic);
+       for (i = 0; i < 4; i++) {
+               mpic_ipi_write(i,
+                              MPIC_VECPRI_MASK |
+                              (10 << MPIC_VECPRI_PRIORITY_SHIFT) |
+                              (MPIC_VEC_IPI_0 + i));
+#ifdef CONFIG_SMP
+               if (!(mpic->flags & MPIC_PRIMARY))
+                       continue;
+               irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU;
+               irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi;
+               
+#endif /* CONFIG_SMP */
+       }
+
+       /* Initialize interrupt sources */
+       if (mpic->irq_count == 0)
+               mpic->irq_count = mpic->num_sources;
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+       /* Do the ioapic fixups on U3 broken mpic */
+       DBG("MPIC flags: %x\n", mpic->flags);
+       if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
+               mpic_scan_ioapics(mpic);
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+       for (i = 0; i < mpic->num_sources; i++) {
+               /* start with vector = source number, and masked */
+               u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
+               int level = 0;
+               
+               /* if it's an IPI, we skip it */
+               if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) &&
+                   (mpic->irq_offset + i) <  (mpic->ipi_offset + i + 4))
+                       continue;
+
+               /* do senses munging */
+               if (mpic->senses && i < mpic->senses_count) {
+                       if (mpic->senses[i] & IRQ_SENSE_LEVEL)
+                               vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+                       if (mpic->senses[i] & IRQ_POLARITY_POSITIVE)
+                               vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+               } else
+                       vecpri |= MPIC_VECPRI_SENSE_LEVEL;
+
+               /* remember if it was a level interrupts */
+               level = (vecpri & MPIC_VECPRI_SENSE_LEVEL);
+
+               /* deal with broken U3 */
+               if (mpic->flags & MPIC_BROKEN_U3) {
+#ifdef CONFIG_MPIC_BROKEN_U3
+                       if (mpic_is_ht_interrupt(mpic, i)) {
+                               vecpri &= ~(MPIC_VECPRI_SENSE_MASK |
+                                           MPIC_VECPRI_POLARITY_MASK);
+                               vecpri |= MPIC_VECPRI_POLARITY_POSITIVE;
+                       }
+#else
+                       printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n");
+#endif
+               }
+
+               DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri,
+                   (level != 0));
+
+               /* init hw */
+               mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
+               mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+                              1 << get_hard_smp_processor_id(boot_cpuid));
+
+               /* init linux descriptors */
+               if (i < mpic->irq_count) {
+                       irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0;
+                       irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq;
+               }
+       }
+       
+       /* Init spurrious vector */
+       mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS);
+
+       /* Disable 8259 passthrough */
+       mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
+                  mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+                  | MPIC_GREG_GCONF_8259_PTHROU_DIS);
+
+       /* Set current processor priority to 0 */
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+}
+
+
+
+void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
+{
+       int is_ipi;
+       struct mpic *mpic = mpic_find(irq, &is_ipi);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&mpic_lock, flags);
+       if (is_ipi) {
+               reg = mpic_ipi_read(irq - mpic->ipi_offset) & MPIC_VECPRI_PRIORITY_MASK;
+               mpic_ipi_write(irq - mpic->ipi_offset,
+                              reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
+       } else {
+               reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI)
+                       & MPIC_VECPRI_PRIORITY_MASK;
+               mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI,
+                              reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
+       }
+       spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+unsigned int mpic_irq_get_priority(unsigned int irq)
+{
+       int is_ipi;
+       struct mpic *mpic = mpic_find(irq, &is_ipi);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&mpic_lock, flags);
+       if (is_ipi)
+               reg = mpic_ipi_read(irq - mpic->ipi_offset);
+       else
+               reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI);
+       spin_unlock_irqrestore(&mpic_lock, flags);
+       return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT;
+}
+
+void mpic_setup_this_cpu(void)
+{
+#ifdef CONFIG_SMP
+       struct mpic *mpic = mpic_primary;
+       unsigned long flags;
+#ifdef CONFIG_IRQ_ALL_CPUS
+       u32 msk = 1 << hard_smp_processor_id();
+       unsigned int i;
+#endif
+
+       BUG_ON(mpic == NULL);
+
+       DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
+
+       spin_lock_irqsave(&mpic_lock, flags);
+
+#ifdef CONFIG_IRQ_ALL_CPUS
+       /* let the mpic know we want intrs. default affinity is 0xffffffff
+        * until changed via /proc. That's how it's done on x86. If we want
+        * it differently, then we should make sure we also change the default
+        * values of irq_affinity in irq.c.
+        */
+       for (i = 0; i < mpic->num_sources ; i++)
+               mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+                       mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk);
+#endif /* CONFIG_IRQ_ALL_CPUS */
+
+       /* Set current processor priority to 0 */
+       mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+
+       spin_unlock_irqrestore(&mpic_lock, flags);
+#endif /* CONFIG_SMP */
+}
+
+void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
+{
+       struct mpic *mpic = mpic_primary;
+
+       BUG_ON(mpic == NULL);
+
+       DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
+
+       mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
+                      mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
+}
+
+int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
+{
+       u32 irq;
+
+       irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+       DBG("%s: get_one_irq(): %d\n", mpic->name, irq);
+
+       if (mpic->cascade && irq == mpic->cascade_vec) {
+               DBG("%s: cascading ...\n", mpic->name);
+               irq = mpic->cascade(regs, mpic->cascade_data);
+               mpic_eoi(mpic);
+               return irq;
+       }
+       if (unlikely(irq == MPIC_VEC_SPURRIOUS))
+               return -1;
+       if (irq < MPIC_VEC_IPI_0) 
+               return irq + mpic->irq_offset;
+               DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0);
+       return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset;
+}
+
+int mpic_get_irq(struct pt_regs *regs)
+{
+       struct mpic *mpic = mpic_primary;
+
+       BUG_ON(mpic == NULL);
+
+       return mpic_get_one_irq(mpic, regs);
+}
+
+
+#ifdef CONFIG_SMP
+void mpic_request_ipis(void)
+{
+       struct mpic *mpic = mpic_primary;
+
+       BUG_ON(mpic == NULL);
+       
+       printk("requesting IPIs ... \n");
+
+       /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
+       request_irq(mpic->ipi_offset+0, mpic_ipi_action, SA_INTERRUPT,
+                   "IPI0 (call function)", mpic);
+       request_irq(mpic->ipi_offset+1, mpic_ipi_action, SA_INTERRUPT,
+                  "IPI1 (reschedule)", mpic);
+       request_irq(mpic->ipi_offset+2, mpic_ipi_action, SA_INTERRUPT,
+                  "IPI2 (unused)", mpic);
+       request_irq(mpic->ipi_offset+3, mpic_ipi_action, SA_INTERRUPT,
+                  "IPI3 (debugger break)", mpic);
+
+       printk("IPIs requested... \n");
+}
+#endif /* CONFIG_SMP */
diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h
new file mode 100644 (file)
index 0000000..571b3c9
--- /dev/null
@@ -0,0 +1,267 @@
+#include <linux/irq.h>
+
+/*
+ * Global registers
+ */
+
+#define MPIC_GREG_BASE                 0x01000
+
+#define MPIC_GREG_FEATURE_0            0x00000
+#define                MPIC_GREG_FEATURE_LAST_SRC_MASK         0x07ff0000
+#define                MPIC_GREG_FEATURE_LAST_SRC_SHIFT        16
+#define                MPIC_GREG_FEATURE_LAST_CPU_MASK         0x00001f00
+#define                MPIC_GREG_FEATURE_LAST_CPU_SHIFT        8
+#define                MPIC_GREG_FEATURE_VERSION_MASK          0xff
+#define MPIC_GREG_FEATURE_1            0x00010
+#define MPIC_GREG_GLOBAL_CONF_0                0x00020
+#define                MPIC_GREG_GCONF_RESET                   0x80000000
+#define                MPIC_GREG_GCONF_8259_PTHROU_DIS         0x20000000
+#define                MPIC_GREG_GCONF_BASE_MASK               0x000fffff
+#define MPIC_GREG_GLOBAL_CONF_1                0x00030
+#define MPIC_GREG_VENDOR_0             0x00040
+#define MPIC_GREG_VENDOR_1             0x00050
+#define MPIC_GREG_VENDOR_2             0x00060
+#define MPIC_GREG_VENDOR_3             0x00070
+#define MPIC_GREG_VENDOR_ID            0x00080
+#define        MPIC_GREG_VENDOR_ID_STEPPING_MASK       0x00ff0000
+#define        MPIC_GREG_VENDOR_ID_STEPPING_SHIFT      16
+#define        MPIC_GREG_VENDOR_ID_DEVICE_ID_MASK      0x0000ff00
+#define        MPIC_GREG_VENDOR_ID_DEVICE_ID_SHIFT     8
+#define        MPIC_GREG_VENDOR_ID_VENDOR_ID_MASK      0x000000ff
+#define MPIC_GREG_PROCESSOR_INIT       0x00090
+#define MPIC_GREG_IPI_VECTOR_PRI_0     0x000a0
+#define MPIC_GREG_IPI_VECTOR_PRI_1     0x000b0
+#define MPIC_GREG_IPI_VECTOR_PRI_2     0x000c0
+#define MPIC_GREG_IPI_VECTOR_PRI_3     0x000d0
+#define MPIC_GREG_SPURIOUS             0x000e0
+#define MPIC_GREG_TIMER_FREQ           0x000f0
+
+/*
+ *
+ * Timer registers
+ */
+#define MPIC_TIMER_BASE                        0x01100
+#define MPIC_TIMER_STRIDE              0x40
+
+#define MPIC_TIMER_CURRENT_CNT         0x00000
+#define MPIC_TIMER_BASE_CNT            0x00010
+#define MPIC_TIMER_VECTOR_PRI          0x00020
+#define MPIC_TIMER_DESTINATION         0x00030
+
+/*
+ * Per-Processor registers
+ */
+
+#define MPIC_CPU_THISBASE              0x00000
+#define MPIC_CPU_BASE                  0x20000
+#define MPIC_CPU_STRIDE                        0x01000
+
+#define MPIC_CPU_IPI_DISPATCH_0                0x00040
+#define MPIC_CPU_IPI_DISPATCH_1                0x00050
+#define MPIC_CPU_IPI_DISPATCH_2                0x00060
+#define MPIC_CPU_IPI_DISPATCH_3                0x00070
+#define MPIC_CPU_CURRENT_TASK_PRI      0x00080
+#define        MPIC_CPU_TASKPRI_MASK                   0x0000000f
+#define MPIC_CPU_WHOAMI                        0x00090
+#define        MPIC_CPU_WHOAMI_MASK                    0x0000001f
+#define MPIC_CPU_INTACK                        0x000a0
+#define MPIC_CPU_EOI                   0x000b0
+
+/*
+ * Per-source registers
+ */
+
+#define MPIC_IRQ_BASE                  0x10000
+#define MPIC_IRQ_STRIDE                        0x00020
+#define MPIC_IRQ_VECTOR_PRI            0x00000
+#define        MPIC_VECPRI_MASK                        0x80000000
+#define        MPIC_VECPRI_ACTIVITY                    0x40000000      /* Read Only */
+#define        MPIC_VECPRI_PRIORITY_MASK               0x000f0000
+#define        MPIC_VECPRI_PRIORITY_SHIFT              16
+#define        MPIC_VECPRI_VECTOR_MASK                 0x000007ff
+#define        MPIC_VECPRI_POLARITY_POSITIVE           0x00800000
+#define        MPIC_VECPRI_POLARITY_NEGATIVE           0x00000000
+#define        MPIC_VECPRI_POLARITY_MASK               0x00800000
+#define        MPIC_VECPRI_SENSE_LEVEL                 0x00400000
+#define        MPIC_VECPRI_SENSE_EDGE                  0x00000000
+#define        MPIC_VECPRI_SENSE_MASK                  0x00400000
+#define MPIC_IRQ_DESTINATION           0x00010
+
+#define MPIC_MAX_IRQ_SOURCES   2048
+#define MPIC_MAX_CPUS          32
+#define MPIC_MAX_ISU           32
+
+/*
+ * Special vector numbers (internal use only)
+ */
+#define MPIC_VEC_SPURRIOUS     255
+#define MPIC_VEC_IPI_3         254
+#define MPIC_VEC_IPI_2         253
+#define MPIC_VEC_IPI_1         252
+#define MPIC_VEC_IPI_0         251
+
+/* unused */
+#define MPIC_VEC_TIMER_3       250
+#define MPIC_VEC_TIMER_2       249
+#define MPIC_VEC_TIMER_1       248
+#define MPIC_VEC_TIMER_0       247
+
+/* Type definition of the cascade handler */
+typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data);
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+/* Fixup table entry */
+struct mpic_irq_fixup
+{
+       u8 __iomem      *base;
+       unsigned int   irq;
+};
+#endif /* CONFIG_MPIC_BROKEN_U3 */
+
+
+/* The instance data of a given MPIC */
+struct mpic
+{
+       /* The "linux" controller struct */
+       hw_irq_controller       hc_irq;
+#ifdef CONFIG_SMP
+       hw_irq_controller       hc_ipi;
+#endif
+       const char              *name;
+       /* Flags */
+       unsigned int            flags;
+       /* How many irq sources in a given ISU */
+       unsigned int            isu_size;
+       unsigned int            isu_shift;
+       unsigned int            isu_mask;
+       /* Offset of irq vector numbers */
+       unsigned int            irq_offset;     
+       unsigned int            irq_count;
+       /* Offset of ipi vector numbers */
+       unsigned int            ipi_offset;
+       /* Number of sources */
+       unsigned int            num_sources;
+       /* Number of CPUs */
+       unsigned int            num_cpus;
+       /* cascade handler */
+       mpic_cascade_t          cascade;
+       void                    *cascade_data;
+       unsigned int            cascade_vec;
+       /* senses array */
+       unsigned char           *senses;
+       unsigned int            senses_count;
+
+#ifdef CONFIG_MPIC_BROKEN_U3
+       /* The fixup table */
+       struct mpic_irq_fixup   *fixups;
+       spinlock_t              fixup_lock;
+#endif
+
+       /* The various ioremap'ed bases */
+       volatile u32 __iomem    *gregs;
+       volatile u32 __iomem    *tmregs;
+       volatile u32 __iomem    *cpuregs[MPIC_MAX_CPUS];
+       volatile u32 __iomem    *isus[MPIC_MAX_ISU];
+
+       /* link */
+       struct mpic             *next;
+};
+
+/* This is the primary controller, only that one has IPIs and
+ * has afinity control. A non-primary MPIC always uses CPU0
+ * registers only
+ */
+#define MPIC_PRIMARY                   0x00000001
+/* Set this for a big-endian MPIC */
+#define MPIC_BIG_ENDIAN                        0x00000002
+/* Broken U3 MPIC */
+#define MPIC_BROKEN_U3                 0x00000004
+/* Broken IPI registers (autodetected) */
+#define MPIC_BROKEN_IPI                        0x00000008
+/* MPIC wants a reset */
+#define MPIC_WANTS_RESET               0x00000010
+
+/* Allocate the controller structure and setup the linux irq descs
+ * for the range if interrupts passed in. No HW initialization is
+ * actually performed.
+ * 
+ * @phys_addr: physial base address of the MPIC
+ * @flags:     flags, see constants above
+ * @isu_size:  number of interrupts in an ISU. Use 0 to use a
+ *              standard ISU-less setup (aka powermac)
+ * @irq_offset: first irq number to assign to this mpic
+ * @irq_count:  number of irqs to use with this mpic IRQ sources. Pass 0
+ *             to match the number of sources
+ * @ipi_offset: first irq number to assign to this mpic IPI sources,
+ *             used only on primary mpic
+ * @senses:    array of sense values
+ * @senses_num: number of entries in the array
+ *
+ * Note about the sense array. If none is passed, all interrupts are
+ * setup to be level negative unless MPIC_BROKEN_U3 is set in which
+ * case they are edge positive (and the array is ignored anyway).
+ * The values in the array start at the first source of the MPIC,
+ * that is senses[0] correspond to linux irq "irq_offset".
+ */
+extern struct mpic *mpic_alloc(unsigned long phys_addr,
+                              unsigned int flags,
+                              unsigned int isu_size,
+                              unsigned int irq_offset,
+                              unsigned int irq_count,
+                              unsigned int ipi_offset,
+                              unsigned char *senses,
+                              unsigned int senses_num,
+                              const char *name);
+
+/* Assign ISUs, to call before mpic_init()
+ *
+ * @mpic:      controller structure as returned by mpic_alloc()
+ * @isu_num:   ISU number
+ * @phys_addr: physical address of the ISU
+ */
+extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
+                           unsigned long phys_addr);
+
+/* Initialize the controller. After this has been called, none of the above
+ * should be called again for this mpic
+ */
+extern void mpic_init(struct mpic *mpic);
+
+/* Setup a cascade. Currently, only one cascade is supported this
+ * way, though you can always do a normal request_irq() and add
+ * other cascades this way. You should call this _after_ having
+ * added all the ISUs
+ *
+ * @irq_no:    "linux" irq number of the cascade (that is offset'ed vector)
+ * @handler:   cascade handler function
+ */
+extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder,
+                              void *data);
+
+/*
+ * All of the following functions must only be used after the
+ * ISUs have been assigned and the controller fully initialized
+ * with mpic_init()
+ */
+
+
+/* Change/Read the priority of an interrupt. Default is 8 for irqs and
+ * 10 for IPIs. You can call this on both IPIs and IRQ numbers, but the
+ * IPI number is then the offset'ed (linux irq number mapped to the IPI)
+ */
+extern void mpic_irq_set_priority(unsigned int irq, unsigned int pri);
+extern unsigned int mpic_irq_get_priority(unsigned int irq);
+
+/* Setup a non-boot CPU */
+extern void mpic_setup_this_cpu(void);
+
+/* Request IPIs on primary mpic */
+extern void mpic_request_ipis(void);
+
+/* Send an IPI (non offseted number 0..3) */
+extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask);
+
+/* Fetch interrupt from a given mpic */
+extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs);
+/* This one gets to the primary mpic */
+extern int mpic_get_irq(struct pt_regs *regs);
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
new file mode 100644 (file)
index 0000000..80e0289
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ *  linux/arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified by PPC64 Team, 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.
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <linux/version.h>
+#include <linux/adb.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/naca.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+
+#include "i8259.h"
+#include "open_pic.h"
+#include <asm/xics.h>
+#include <asm/ppcdebug.h>
+#include <asm/cputable.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+extern void pSeries_init_openpic(void);
+
+extern void find_and_init_phbs(void);
+extern void pSeries_final_fixup(void);
+
+extern void pSeries_get_boot_time(struct rtc_time *rtc_time);
+extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
+extern int  pSeries_set_rtc_time(struct rtc_time *rtc_time);
+extern void find_udbg_vterm(void);
+extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void); /* from head.S */
+int fwnmi_active;  /* TRUE if an FWNMI handler is present */
+
+unsigned long  virtPython0Facilities = 0;  // python0 facility area (memory mapped io) (64-bit format) VIRTUAL address.
+
+extern unsigned long loops_per_jiffy;
+
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
+
+void pSeries_get_cpuinfo(struct seq_file *m)
+{
+       struct device_node *root;
+       const char *model = "";
+
+       root = of_find_node_by_path("/");
+       if (root)
+               model = get_property(root, "model", NULL);
+       seq_printf(m, "machine\t\t: CHRP %s\n", model);
+       of_node_put(root);
+}
+
+/* Initialize firmware assisted non-maskable interrupts if
+ * the firmware supports this feature.
+ *
+ */
+static void __init fwnmi_init(void)
+{
+       int ret;
+       int ibm_nmi_register = rtas_token("ibm,nmi-register");
+       if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
+               return;
+       ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
+                       __pa((unsigned long)SystemReset_FWNMI),
+                       __pa((unsigned long)MachineCheck_FWNMI));
+       if (ret == 0)
+               fwnmi_active = 1;
+}
+
+static void __init pSeries_setup_arch(void)
+{
+       struct device_node *root;
+       unsigned int *opprop;
+
+       /* Fixup ppc_md depending on the type of interrupt controller */
+       if (naca->interrupt_controller == IC_OPEN_PIC) {
+               ppc_md.init_IRQ       = pSeries_init_openpic; 
+               ppc_md.get_irq        = openpic_get_irq;
+       } else {
+               ppc_md.init_IRQ       = xics_init_IRQ;
+               ppc_md.get_irq        = xics_get_irq;
+       }
+
+#ifdef CONFIG_SMP
+       smp_init_pSeries();
+#endif
+       /* openpic global configuration register (64-bit format). */
+       /* openpic Interrupt Source Unit pointer (64-bit format). */
+       /* python0 facility area (mmio) (64-bit format) REAL address. */
+
+       /* init to some ~sane value until calibrate_delay() runs */
+       loops_per_jiffy = 50000000;
+
+       if (ROOT_DEV == 0) {
+               printk("No ramdisk, default root is /dev/sda2\n");
+               ROOT_DEV = Root_SDA2;
+       }
+
+       fwnmi_init();
+
+       /* Find and initialize PCI host bridges */
+       /* iSeries needs to be done much later. */
+       eeh_init();
+       find_and_init_phbs();
+
+       /* Find the Open PIC if present */
+       root = of_find_node_by_path("/");
+       opprop = (unsigned int *) get_property(root,
+                               "platform-open-pic", NULL);
+       if (opprop != 0) {
+               int n = prom_n_addr_cells(root);
+               unsigned long openpic;
+
+               for (openpic = 0; n > 0; --n)
+                       openpic = (openpic << 32) + *opprop++;
+               printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic);
+               OpenPIC_Addr = __ioremap(openpic, 0x40000, _PAGE_NO_CACHE);
+       }
+       of_node_put(root);
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+
+       pSeries_nvram_init();
+}
+
+static int __init pSeries_init_panel(void)
+{
+       /* Manually leave the kernel version on the panel. */
+       ppc_md.progress("Linux ppc64\n", 0);
+       ppc_md.progress(UTS_RELEASE, 0);
+
+       return 0;
+}
+arch_initcall(pSeries_init_panel);
+
+
+
+void __init pSeries_find_serial_port(void)
+{
+       struct device_node *np;
+       unsigned long encode_phys_size = 32;
+       u32 *sizeprop;
+
+       struct isa_reg_property {
+               u32 space;
+               u32 address;
+               u32 size;
+       };
+       struct pci_reg_property {
+               struct pci_address addr;
+               u32 size_hi;
+               u32 size_lo;
+       };                                                                        
+
+       DBG(" -> pSeries_find_serial_port()\n");
+
+       naca->serialPortAddr = 0;
+
+       np = of_find_node_by_path("/");
+       if (!np)
+               return;
+       sizeprop = (u32 *)get_property(np, "#size-cells", NULL);
+       if (sizeprop != NULL)
+               encode_phys_size = (*sizeprop) << 5;
+       
+       for (np = NULL; (np = of_find_node_by_type(np, "serial"));) {
+               struct device_node *isa, *pci;
+               struct isa_reg_property *reg;
+               union pci_range *rangesp;
+               char *typep;
+
+               typep = (char *)get_property(np, "ibm,aix-loc", NULL);
+               if ((typep == NULL) || (typep && strcmp(typep, "S1")))
+                       continue;
+
+               reg = (struct isa_reg_property *)get_property(np, "reg", NULL); 
+
+               isa = of_get_parent(np);
+               if (!isa) {
+                       DBG("no isa parent found\n");
+                       break;
+               }
+               pci = of_get_parent(isa);
+               if (!pci) {
+                       DBG("no pci parent found\n");
+                       break;
+               }
+
+               rangesp = (union pci_range *)get_property(pci, "ranges", NULL);
+
+               if ( encode_phys_size == 32 )
+                       naca->serialPortAddr = rangesp->pci32.phys+reg->address;
+               else {
+                       naca->serialPortAddr =
+                               ((((unsigned long)rangesp->pci64.phys_hi) << 32)
+                               |
+                       (rangesp->pci64.phys_lo)) + reg->address;
+               }
+               break;
+       }
+
+       DBG(" <- pSeries_find_serial_port()\n");
+}
+
+
+/* Build up the firmware_features bitmask field
+ * using contents of device-tree/ibm,hypertas-functions.
+ * Ultimately this functionality may be moved into prom.c prom_init().
+ */
+void __init fw_feature_init(void)
+{
+       struct device_node * dn;
+       char * hypertas;
+       unsigned int len;
+
+       DBG(" -> fw_feature_init()\n");
+
+       cur_cpu_spec->firmware_features = 0;
+       dn = of_find_node_by_path("/rtas");
+       if (dn == NULL) {
+               printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n");
+               goto no_rtas;
+       }
+
+       hypertas = get_property(dn, "ibm,hypertas-functions", &len);
+       if (hypertas) {
+               while (len > 0){
+                       int i, hypertas_len;
+                       /* check value against table of strings */
+                       for(i=0; i < FIRMWARE_MAX_FEATURES ;i++) {
+                               if ((firmware_features_table[i].name) &&
+                                   (strcmp(firmware_features_table[i].name,hypertas))==0) {
+                                       /* we have a match */
+                                       cur_cpu_spec->firmware_features |= 
+                                               (firmware_features_table[i].val);
+                                       break;
+                               } 
+                       }
+                       hypertas_len = strlen(hypertas);
+                       len -= hypertas_len +1;
+                       hypertas+= hypertas_len +1;
+               }
+       }
+
+       of_node_put(dn);
+ no_rtas:
+       printk(KERN_INFO "firmware_features = 0x%lx\n", 
+              cur_cpu_spec->firmware_features);
+
+       DBG(" <- fw_feature_init()\n");
+}
+
+
+static  void __init pSeries_discover_pic(void)
+{
+       struct device_node *np;
+       char *typep;
+
+       /*
+        * Setup interrupt mapping options that are needed for finish_device_tree
+        * to properly parse the OF interrupt tree & do the virtual irq mapping
+        */
+       __irq_offset_value = NUM_ISA_INTERRUPTS;
+       naca->interrupt_controller = IC_INVALID;
+       for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) {
+               typep = (char *)get_property(np, "compatible", NULL);
+               if (strstr(typep, "open-pic"))
+                       naca->interrupt_controller = IC_OPEN_PIC;
+               else if (strstr(typep, "ppc-xicp"))
+                       naca->interrupt_controller = IC_PPC_XIC;
+               else
+                       printk("initialize_naca: failed to recognize"
+                              " interrupt-controller\n");
+               break;
+       }
+}
+
+/*
+ * Early initialization.  Relocation is on but do not reference unbolted pages
+ */
+static void __init pSeries_init_early(void)
+{
+       void *comport;
+       int iommu_off = 0;
+
+       DBG(" -> pSeries_init_early()\n");
+
+       fw_feature_init();
+       
+       if (systemcfg->platform & PLATFORM_LPAR)
+               hpte_init_lpar();
+       else {
+               hpte_init_native();
+               iommu_off = (of_chosen &&
+                            get_property(of_chosen, "linux,iommu-off", NULL));
+       }
+
+       pSeries_find_serial_port();
+
+       if (systemcfg->platform & PLATFORM_LPAR)
+               find_udbg_vterm();
+       else if (naca->serialPortAddr) {
+               /* Map the uart for udbg. */
+               comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
+               udbg_init_uart(comport);
+
+               ppc_md.udbg_putc = udbg_putc;
+               ppc_md.udbg_getc = udbg_getc;
+               ppc_md.udbg_getc_poll = udbg_getc_poll;
+               DBG("Hello World !\n");
+       }
+
+
+       if (iommu_off)
+               pci_dma_init_direct();
+       else
+               tce_init_pSeries();
+
+       pSeries_discover_pic();
+
+       DBG(" <- pSeries_init_early()\n");
+}
+
+
+static void pSeries_progress(char *s, unsigned short hex)
+{
+       struct device_node *root;
+       int width, *p;
+       char *os;
+       static int display_character, set_indicator;
+       static int max_width;
+       static spinlock_t progress_lock = SPIN_LOCK_UNLOCKED;
+       static int pending_newline = 0;  /* did last write end with unprinted newline? */
+
+       if (!rtas.base)
+               return;
+
+       if (max_width == 0) {
+               if ((root = find_path_device("/rtas")) &&
+                    (p = (unsigned int *)get_property(root,
+                                                      "ibm,display-line-length",
+                                                      NULL)))
+                       max_width = *p;
+               else
+                       max_width = 0x10;
+               display_character = rtas_token("display-character");
+               set_indicator = rtas_token("set-indicator");
+       }
+
+       if (display_character == RTAS_UNKNOWN_SERVICE) {
+               /* use hex display if available */
+               if (set_indicator != RTAS_UNKNOWN_SERVICE)
+                       rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex);
+               return;
+       }
+
+       spin_lock(&progress_lock);
+
+       /*
+        * Last write ended with newline, but we didn't print it since
+        * it would just clear the bottom line of output. Print it now
+        * instead.
+        *
+        * If no newline is pending, print a CR to start output at the
+        * beginning of the line.
+        */
+       if (pending_newline) {
+               rtas_call(display_character, 1, 1, NULL, '\r');
+               rtas_call(display_character, 1, 1, NULL, '\n');
+               pending_newline = 0;
+       } else {
+               rtas_call(display_character, 1, 1, NULL, '\r');
+       }
+       width = max_width;
+       os = s;
+       while (*os) {
+               if (*os == '\n' || *os == '\r') {
+                       /* Blank to end of line. */
+                       while (width-- > 0)
+                               rtas_call(display_character, 1, 1, NULL, ' ');
+                       /* If newline is the last character, save it
+                        * until next call to avoid bumping up the
+                        * display output.
+                        */
+                       if (*os == '\n' && !os[1]) {
+                               pending_newline = 1;
+                               spin_unlock(&progress_lock);
+                               return;
+                       }
+                       /* RTAS wants CR-LF, not just LF */
+                       if (*os == '\n') {
+                               rtas_call(display_character, 1, 1, NULL, '\r');
+                               rtas_call(display_character, 1, 1, NULL, '\n');
+                       } else {
+                               /* CR might be used to re-draw a line, so we'll
+                                * leave it alone and not add LF.
+                                */
+                               rtas_call(display_character, 1, 1, NULL, *os);
+                       }
+                       width = max_width;
+               } else {
+                       width--;
+                       rtas_call(display_character, 1, 1, NULL, *os);
+               }
+               os++;
+               /* if we overwrite the screen length */
+               if (width <= 0)
+                       while ((*os != 0) && (*os != '\n') && (*os != '\r'))
+                               os++;
+       }
+       /* Blank to end of line. */
+       while (width-- > 0)
+               rtas_call(display_character, 1, 1, NULL, ' ');
+
+       spin_unlock(&progress_lock);
+}
+
+extern void setup_default_decr(void);
+
+/* Some sane defaults: 125 MHz timebase, 1GHz processor */
+#define DEFAULT_TB_FREQ                125000000UL
+#define DEFAULT_PROC_FREQ      (DEFAULT_TB_FREQ * 8)
+
+static void __init pSeries_calibrate_decr(void)
+{
+       struct device_node *cpu;
+       struct div_result divres;
+       unsigned int *fp;
+       int node_found;
+
+       /*
+        * The cpu node should have a timebase-frequency property
+        * to tell us the rate at which the decrementer counts.
+        */
+       cpu = of_find_node_by_type(NULL, "cpu");
+
+       ppc_tb_freq = DEFAULT_TB_FREQ;          /* hardcoded default */
+       node_found = 0;
+       if (cpu != 0) {
+               fp = (unsigned int *)get_property(cpu, "timebase-frequency",
+                                                 NULL);
+               if (fp != 0) {
+                       node_found = 1;
+                       ppc_tb_freq = *fp;
+               }
+       }
+       if (!node_found)
+               printk(KERN_ERR "WARNING: Estimating decrementer frequency "
+                               "(not found)\n");
+
+       ppc_proc_freq = DEFAULT_PROC_FREQ;
+       node_found = 0;
+       if (cpu != 0) {
+               fp = (unsigned int *)get_property(cpu, "clock-frequency",
+                                                 NULL);
+               if (fp != 0) {
+                       node_found = 1;
+                       ppc_proc_freq = *fp;
+               }
+       }
+       if (!node_found)
+               printk(KERN_ERR "WARNING: Estimating processor frequency "
+                               "(not found)\n");
+
+       of_node_put(cpu);
+
+       printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+              ppc_tb_freq/1000000, ppc_tb_freq%1000000);
+       printk(KERN_INFO "time_init: processor frequency   = %lu.%.6lu MHz\n",
+              ppc_proc_freq/1000000, ppc_proc_freq%1000000);
+
+       tb_ticks_per_jiffy = ppc_tb_freq / HZ;
+       tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
+       tb_ticks_per_usec = ppc_tb_freq / 1000000;
+       tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
+       div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres);
+       tb_to_xs = divres.result_low;
+
+       setup_default_decr();
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+extern struct machdep_calls pSeries_md;
+
+static int __init pSeries_probe(int platform)
+{
+       if (platform != PLATFORM_PSERIES &&
+           platform != PLATFORM_PSERIES_LPAR)
+               return 0;
+
+       /* if we have some ppc_md fixups for LPAR to do, do
+        * it here ...
+        */
+
+       return 1;
+}
+
+struct machdep_calls __initdata pSeries_md = {
+       .probe                  = pSeries_probe,
+       .setup_arch             = pSeries_setup_arch,
+       .init_early             = pSeries_init_early,
+       .get_cpuinfo            = pSeries_get_cpuinfo,
+       .log_error              = pSeries_log_error,
+       .pcibios_fixup          = pSeries_final_fixup,
+       .restart                = rtas_restart,
+       .power_off              = rtas_power_off,
+       .halt                   = rtas_halt,
+       .panic                  = rtas_os_term,
+       .get_boot_time          = pSeries_get_boot_time,
+       .get_rtc_time           = pSeries_get_rtc_time,
+       .set_rtc_time           = pSeries_set_rtc_time,
+       .calibrate_decr         = pSeries_calibrate_decr,
+       .progress               = pSeries_progress,
+};
diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c
new file mode 100644 (file)
index 0000000..6eba926
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * SMP support for pSeries machines.
+ *
+ * Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
+ *
+ * Plus various changes from other IBM teams...
+ *
+ *      This 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.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/cpu.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
+#include <asm/time.h>
+#include <asm/ppcdebug.h>
+#include <asm/machdep.h>
+#include <asm/xics.h>
+#include <asm/cputable.h>
+#include <asm/system.h>
+#include <asm/rtas.h>
+#include <asm/plpar_wrappers.h>
+
+#include "mpic.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+extern void pseries_secondary_smp_init(unsigned long); 
+
+/* Get state of physical CPU.
+ * Return codes:
+ *     0       - The processor is in the RTAS stopped state
+ *     1       - stop-self is in progress
+ *     2       - The processor is not in the RTAS stopped state
+ *     -1      - Hardware Error
+ *     -2      - Hardware Busy, Try again later.
+ */
+static int query_cpu_stopped(unsigned int pcpu)
+{
+       int cpu_status;
+       int status, qcss_tok;
+
+       qcss_tok = rtas_token("query-cpu-stopped-state");
+       if (qcss_tok == RTAS_UNKNOWN_SERVICE)
+               return -1;
+       status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu);
+       if (status != 0) {
+               printk(KERN_ERR
+                      "RTAS query-cpu-stopped-state failed: %i\n", status);
+               return status;
+       }
+
+       return cpu_status;
+}
+
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+int __cpu_disable(void)
+{
+       /* FIXME: go put this in a header somewhere */
+       extern void xics_migrate_irqs_away(void);
+
+       systemcfg->processorCount--;
+
+       /*fix boot_cpuid here*/
+       if (smp_processor_id() == boot_cpuid)
+               boot_cpuid = any_online_cpu(cpu_online_map);
+
+       /* FIXME: abstract this to not be platform specific later on */
+       xics_migrate_irqs_away();
+       return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+       int tries;
+       int cpu_status;
+       unsigned int pcpu = get_hard_smp_processor_id(cpu);
+
+       for (tries = 0; tries < 25; tries++) {
+               cpu_status = query_cpu_stopped(pcpu);
+               if (cpu_status == 0 || cpu_status == -1)
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(HZ/5);
+       }
+       if (cpu_status != 0) {
+               printk("Querying DEAD? cpu %i (%i) shows %i\n",
+                      cpu, pcpu, cpu_status);
+       }
+
+       /* Isolation and deallocation are definatly done by
+        * drslot_chrp_cpu.  If they were not they would be
+        * done here.  Change isolate state to Isolate and
+        * change allocation-state to Unusable.
+        */
+       paca[cpu].cpu_start = 0;
+}
+
+/* Search all cpu device nodes for an offline logical cpu.  If a
+ * device node has a "ibm,my-drc-index" property (meaning this is an
+ * LPAR), paranoid-check whether we own the cpu.  For each "thread"
+ * of a cpu, if it is offline and has the same hw index as before,
+ * grab that in preference.
+ */
+static unsigned int find_physical_cpu_to_start(unsigned int old_hwindex)
+{
+       struct device_node *np = NULL;
+       unsigned int best = -1U;
+
+       while ((np = of_find_node_by_type(np, "cpu"))) {
+               int nr_threads, len;
+               u32 *index = (u32 *)get_property(np, "ibm,my-drc-index", NULL);
+               u32 *tid = (u32 *)
+                       get_property(np, "ibm,ppc-interrupt-server#s", &len);
+
+               if (!tid)
+                       tid = (u32 *)get_property(np, "reg", &len);
+
+               if (!tid)
+                       continue;
+
+               /* If there is a drc-index, make sure that we own
+                * the cpu.
+                */
+               if (index) {
+                       int state;
+                       int rc = rtas_get_sensor(9003, *index, &state);
+                       if (rc != 0 || state != 1)
+                               continue;
+               }
+
+               nr_threads = len / sizeof(u32);
+
+               while (nr_threads--) {
+                       if (0 == query_cpu_stopped(tid[nr_threads])) {
+                               best = tid[nr_threads];
+                               if (best == old_hwindex)
+                                       goto out;
+                       }
+               }
+       }
+out:
+       of_node_put(np);
+       return best;
+}
+
+/**
+ * smp_startup_cpu() - start the given cpu
+ *
+ * At boot time, there is nothing to do.  At run-time, call RTAS with
+ * the appropriate start location, if the cpu is in the RTAS stopped
+ * state.
+ *
+ * Returns:
+ *     0       - failure
+ *     1       - success
+ */
+static inline int __devinit smp_startup_cpu(unsigned int lcpu)
+{
+       int status;
+       unsigned long start_here = __pa((u32)*((unsigned long *)
+                                              pseries_secondary_smp_init));
+       unsigned int pcpu;
+
+       /* At boot time the cpus are already spinning in hold
+        * loops, so nothing to do. */
+       if (system_state < SYSTEM_RUNNING)
+               return 1;
+
+       pcpu = find_physical_cpu_to_start(get_hard_smp_processor_id(lcpu));
+       if (pcpu == -1U) {
+               printk(KERN_INFO "No more cpus available, failing\n");
+               return 0;
+       }
+
+       /* Fixup atomic count: it exited inside IRQ handler. */
+       paca[lcpu].__current->thread_info->preempt_count        = 0;
+
+       /* At boot this is done in prom.c. */
+       paca[lcpu].hw_cpu_id = pcpu;
+
+       status = rtas_call(rtas_token("start-cpu"), 3, 1, NULL,
+                          pcpu, start_here, lcpu);
+       if (status != 0) {
+               printk(KERN_ERR "start-cpu failed: %i\n", status);
+               return 0;
+       }
+       return 1;
+}
+#else /* ... CONFIG_HOTPLUG_CPU */
+static inline int __devinit smp_startup_cpu(unsigned int lcpu)
+{
+       return 1;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static inline void smp_xics_do_message(int cpu, int msg)
+{
+       set_bit(msg, &xics_ipi_message[cpu].value);
+       mb();
+       xics_cause_IPI(cpu);
+}
+
+static void smp_xics_message_pass(int target, int msg)
+{
+       unsigned int i;
+
+       if (target < NR_CPUS) {
+               smp_xics_do_message(target, msg);
+       } else {
+               for_each_online_cpu(i) {
+                       if (target == MSG_ALL_BUT_SELF
+                           && i == smp_processor_id())
+                               continue;
+                       smp_xics_do_message(i, msg);
+               }
+       }
+}
+
+extern void xics_request_IPIs(void);
+
+static int __init smp_xics_probe(void)
+{
+       xics_request_IPIs();
+
+       return cpus_weight(cpu_possible_map);
+}
+
+static void __devinit smp_xics_setup_cpu(int cpu)
+{
+       if (cpu != boot_cpuid)
+               xics_setup_cpu();
+}
+
+static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long timebase = 0;
+
+static void __devinit pSeries_give_timebase(void)
+{
+       spin_lock(&timebase_lock);
+       rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL);
+       timebase = get_tb();
+       spin_unlock(&timebase_lock);
+
+       while (timebase)
+               barrier();
+       rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL);
+}
+
+static void __devinit pSeries_take_timebase(void)
+{
+       while (!timebase)
+               barrier();
+       spin_lock(&timebase_lock);
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       timebase = 0;
+       spin_unlock(&timebase_lock);
+}
+
+static void __devinit pSeries_late_setup_cpu(int cpu)
+{
+       extern unsigned int default_distrib_server;
+
+       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+               vpa_init(cpu); 
+       }
+
+#ifdef CONFIG_IRQ_ALL_CPUS
+       /* Put the calling processor into the GIQ.  This is really only
+        * necessary from a secondary thread as the OF start-cpu interface
+        * performs this function for us on primary threads.
+        */
+       /* TODO: 9005 is #defined in rtas-proc.c -- move to a header */
+       rtas_set_indicator(9005, default_distrib_server, 1);
+#endif
+}
+
+
+void __devinit smp_pSeries_kick_cpu(int nr)
+{
+       BUG_ON(nr < 0 || nr >= NR_CPUS);
+
+       if (!smp_startup_cpu(nr))
+               return;
+
+       /*
+        * The processor is currently spinning, waiting for the
+        * cpu_start field to become non-zero After we set cpu_start,
+        * the processor will continue on to secondary_start
+        */
+       paca[nr].cpu_start = 1;
+}
+
+static struct smp_ops_t pSeries_mpic_smp_ops = {
+       .message_pass   = smp_mpic_message_pass,
+       .probe          = smp_mpic_probe,
+       .kick_cpu       = smp_pSeries_kick_cpu,
+       .setup_cpu      = smp_mpic_setup_cpu,
+       .late_setup_cpu = pSeries_late_setup_cpu,
+};
+
+static struct smp_ops_t pSeries_xics_smp_ops = {
+       .message_pass   = smp_xics_message_pass,
+       .probe          = smp_xics_probe,
+       .kick_cpu       = smp_pSeries_kick_cpu,
+       .setup_cpu      = smp_xics_setup_cpu,
+       .late_setup_cpu = pSeries_late_setup_cpu,
+};
+
+/* This is called very early */
+void __init smp_init_pSeries(void)
+{
+       int ret, i;
+
+       DBG(" -> smp_init_pSeries()\n");
+
+       if (naca->interrupt_controller == IC_OPEN_PIC)
+               smp_ops = &pSeries_mpic_smp_ops;
+       else
+               smp_ops = &pSeries_xics_smp_ops;
+
+       /* Start secondary threads on SMT systems; primary threads
+        * are already in the running state.
+        */
+       for_each_present_cpu(i) {
+               if (query_cpu_stopped(get_hard_smp_processor_id(i)) == 0) {
+                       printk("%16.16x : starting thread\n", i);
+                       DBG("%16.16x : starting thread\n", i);
+                       rtas_call(rtas_token("start-cpu"), 3, 1, &ret,
+                                 get_hard_smp_processor_id(i),
+                                 __pa((u32)*((unsigned long *)
+                                             pseries_secondary_smp_init)),
+                                 i);
+               }
+       }
+
+       if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
+               vpa_init(boot_cpuid);
+
+       /* Non-lpar has additional take/give timebase */
+       if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
+               smp_ops->give_timebase = pSeries_give_timebase;
+               smp_ops->take_timebase = pSeries_take_timebase;
+       }
+
+       DBG(" <- smp_init_pSeries()\n");
+}
+
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
new file mode 100644 (file)
index 0000000..f62bda7
--- /dev/null
@@ -0,0 +1,1714 @@
+/*
+ * 
+ *
+ * Procedures for interfacing to Open Firmware.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com 
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG_PROM
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/initrd.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/abs_addr.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/naca.h>
+#include <asm/pci.h>
+#include <asm/iommu.h>
+#include <asm/bootinfo.h>
+#include <asm/ppcdebug.h>
+#include <asm/btext.h>
+#include <asm/sections.h>
+#include <asm/machdep.h>
+#include "open_pic.h"
+
+#ifdef CONFIG_LOGO_LINUX_CLUT224
+#include <linux/linux_logo.h>
+extern const struct linux_logo logo_linux_clut224;
+#endif
+
+/*
+ * Properties whose value is longer than this get excluded from our
+ * copy of the device tree. This value does need to be big enough to
+ * ensure that we don't lose things like the interrupt-map property
+ * on a PCI-PCI bridge.
+ */
+#define MAX_PROPERTY_LENGTH    (1UL * 1024 * 1024)
+
+/*
+ * Eventually bump that one up
+ */
+#define DEVTREE_CHUNK_SIZE     0x100000
+
+/*
+ * This is the size of the local memory reserve map that gets copied
+ * into the boot params passed to the kernel. That size is totally
+ * flexible as the kernel just reads the list until it encounters an
+ * entry with size 0, so it can be changed without breaking binary
+ * compatibility
+ */
+#define MEM_RESERVE_MAP_SIZE   8
+
+/*
+ * prom_init() is called very early on, before the kernel text
+ * and data have been mapped to KERNELBASE.  At this point the code
+ * is running at whatever address it has been loaded at, so
+ * references to extern and static variables must be relocated
+ * explicitly.  The procedure reloc_offset() returns the address
+ * we're currently running at minus the address we were linked at.
+ * (Note that strings count as static variables.)
+ *
+ * Because OF may have mapped I/O devices into the area starting at
+ * KERNELBASE, particularly on CHRP machines, we can't safely call
+ * OF once the kernel has been mapped to KERNELBASE.  Therefore all
+ * OF calls should be done within prom_init(), and prom_init()
+ * and all routines called within it must be careful to relocate
+ * references as necessary.
+ *
+ * Note that the bss is cleared *after* prom_init runs, so we have
+ * to make sure that any static or extern variables it accesses
+ * are put in the data segment.
+ */
+
+
+#define PROM_BUG() do {                                                \
+        prom_printf("kernel BUG at %s line 0x%x!\n",           \
+                   RELOC(__FILE__), __LINE__);                 \
+        __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR);      \
+} while (0)
+
+#ifdef DEBUG_PROM
+#define prom_debug(x...)       prom_printf(x)
+#else
+#define prom_debug(x...)
+#endif
+
+
+typedef u32 prom_arg_t;
+
+struct prom_args {
+        u32 service;
+        u32 nargs;
+        u32 nret;
+        prom_arg_t args[10];
+        prom_arg_t *rets;     /* Pointer to return values in args[16]. */
+};
+
+struct prom_t {
+       unsigned long entry;
+       ihandle root;
+       ihandle chosen;
+       int cpu;
+       ihandle stdout;
+       ihandle disp_node;
+       struct prom_args args;
+       unsigned long version;
+       unsigned long root_size_cells;
+       unsigned long root_addr_cells;
+};
+
+struct pci_reg_property {
+       struct pci_address addr;
+       u32 size_hi;
+       u32 size_lo;
+};
+
+struct mem_map_entry {
+       u64     base;
+       u64     size;
+};
+
+typedef u32 cell_t;
+
+extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
+
+extern unsigned long reloc_offset(void);
+extern void enter_prom(struct prom_args *args, unsigned long entry);
+extern void copy_and_flush(unsigned long dest, unsigned long src,
+                          unsigned long size, unsigned long offset);
+
+extern unsigned long klimit;
+
+//int global_width = 640, global_height = 480, global_depth = 8, global_pitch;
+//unsigned global_address;
+/* prom structure */
+static struct prom_t __initdata prom;
+
+#define PROM_SCRATCH_SIZE 256
+
+static char __initdata of_stdout_device[256];
+static char __initdata prom_scratch[PROM_SCRATCH_SIZE];
+
+static unsigned long __initdata dt_header_start;
+static unsigned long __initdata dt_struct_start, dt_struct_end;
+static unsigned long __initdata dt_string_start, dt_string_end;
+
+static unsigned long __initdata prom_initrd_start, prom_initrd_end;
+
+static int __initdata iommu_force_on;
+static int __initdata ppc64_iommu_off;
+static int __initdata of_platform;
+
+static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
+
+static unsigned long __initdata alloc_top;
+static unsigned long __initdata alloc_top_high;
+static unsigned long __initdata alloc_bottom;
+static unsigned long __initdata rmo_top;
+static unsigned long __initdata ram_top;
+
+static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
+static int __initdata mem_reserve_cnt;
+
+static cell_t __initdata regbuf[1024];
+
+
+#define MAX_CPU_THREADS 2
+
+/* TO GO */
+#ifdef CONFIG_HMT
+struct {
+       unsigned int pir;
+       unsigned int threadid;
+} hmt_thread_data[NR_CPUS];
+#endif /* CONFIG_HMT */
+
+/*
+ * This are used in calls to call_prom.  The 4th and following
+ * arguments to call_prom should be 32-bit values.  64 bit values
+ * are truncated to 32 bits (and fortunately don't get interpreted
+ * as two arguments).
+ */
+#define ADDR(x)                (u32) ((unsigned long)(x) - offset)
+
+/* This is the one and *ONLY* place where we actually call open
+ * firmware from, since we need to make sure we're running in 32b
+ * mode when we do.  We switch back to 64b mode upon return.
+ */
+
+#define PROM_ERROR     (-1)
+
+static int __init call_prom(const char *service, int nargs, int nret, ...)
+{
+       int i;
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       va_list list;
+
+       _prom->args.service = ADDR(service);
+       _prom->args.nargs = nargs;
+       _prom->args.nret = nret;
+       _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]);
+
+       va_start(list, nret);
+       for (i=0; i < nargs; i++)
+               _prom->args.args[i] = va_arg(list, prom_arg_t);
+       va_end(list);
+
+       for (i=0; i < nret ;i++)
+               _prom->args.rets[i] = 0;
+
+       enter_prom(&_prom->args, _prom->entry);
+
+       return (nret > 0) ? _prom->args.rets[0] : 0;
+}
+
+
+static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
+                               unsigned long align)
+{
+       return (unsigned int)call_prom("claim", 3, 1,
+                                      (prom_arg_t)virt, (prom_arg_t)size,
+                                      (prom_arg_t)align);
+}
+
+static void __init prom_print(const char *msg)
+{
+       const char *p, *q;
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+
+       if (_prom->stdout == 0)
+               return;
+
+       for (p = msg; *p != 0; p = q) {
+               for (q = p; *q != 0 && *q != '\n'; ++q)
+                       ;
+               if (q > p)
+                       call_prom("write", 3, 1, _prom->stdout, p, q - p);
+               if (*q == 0)
+                       break;
+               ++q;
+               call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2);
+       }
+}
+
+
+static void __init prom_print_hex(unsigned long val)
+{
+       unsigned long offset = reloc_offset();
+       int i, nibbles = sizeof(val)*2;
+       char buf[sizeof(val)*2+1];
+       struct prom_t *_prom = PTRRELOC(&prom);
+
+       for (i = nibbles-1;  i >= 0;  i--) {
+               buf[i] = (val & 0xf) + '0';
+               if (buf[i] > '9')
+                       buf[i] += ('a'-'0'-10);
+               val >>= 4;
+       }
+       buf[nibbles] = '\0';
+       call_prom("write", 3, 1, _prom->stdout, buf, nibbles);
+}
+
+
+static void __init prom_printf(const char *format, ...)
+{
+       unsigned long offset = reloc_offset();
+       const char *p, *q, *s;
+       va_list args;
+       unsigned long v;
+       struct prom_t *_prom = PTRRELOC(&prom);
+
+       va_start(args, format);
+       for (p = PTRRELOC(format); *p != 0; p = q) {
+               for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
+                       ;
+               if (q > p)
+                       call_prom("write", 3, 1, _prom->stdout, p, q - p);
+               if (*q == 0)
+                       break;
+               if (*q == '\n') {
+                       ++q;
+                       call_prom("write", 3, 1, _prom->stdout,
+                                 ADDR("\r\n"), 2);
+                       continue;
+               }
+               ++q;
+               if (*q == 0)
+                       break;
+               switch (*q) {
+               case 's':
+                       ++q;
+                       s = va_arg(args, const char *);
+                       prom_print(s);
+                       break;
+               case 'x':
+                       ++q;
+                       v = va_arg(args, unsigned long);
+                       prom_print_hex(v);
+                       break;
+               }
+       }
+}
+
+
+static void __init __attribute__((noreturn)) prom_panic(const char *reason)
+{
+       unsigned long offset = reloc_offset();
+
+       prom_print(PTRRELOC(reason));
+       /* ToDo: should put up an SRC here */
+       call_prom("exit", 0, 0);
+
+       for (;;)                        /* should never get here */
+               ;
+}
+
+
+static int __init prom_next_node(phandle *nodep)
+{
+       phandle node;
+
+       if ((node = *nodep) != 0
+           && (*nodep = call_prom("child", 1, 1, node)) != 0)
+               return 1;
+       if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+               return 1;
+       for (;;) {
+               if ((node = call_prom("parent", 1, 1, node)) == 0)
+                       return 0;
+               if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+                       return 1;
+       }
+}
+
+static int __init prom_getprop(phandle node, const char *pname,
+                              void *value, size_t valuelen)
+{
+       unsigned long offset = reloc_offset();
+
+       return call_prom("getprop", 4, 1, node, ADDR(pname),
+                        (u32)(unsigned long) value, (u32) valuelen);
+}
+
+static int __init prom_getproplen(phandle node, const char *pname)
+{
+       unsigned long offset = reloc_offset();
+
+       return call_prom("getproplen", 2, 1, node, ADDR(pname));
+}
+
+static int __init prom_setprop(phandle node, const char *pname,
+                              void *value, size_t valuelen)
+{
+       unsigned long offset = reloc_offset();
+
+       return call_prom("setprop", 4, 1, node, ADDR(pname),
+                        (u32)(unsigned long) value, (u32) valuelen);
+}
+
+
+/*
+ * Early parsing of the command line passed to the kernel, used for
+ * the options that affect the iommu
+ */
+static void __init early_cmdline_parse(void)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       char *opt, *p;
+       int l = 0;
+
+       RELOC(prom_cmd_line[0]) = 0;
+       p = RELOC(prom_cmd_line);
+       if ((long)_prom->chosen > 0)
+               l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
+#ifdef CONFIG_CMDLINE
+       if (l == 0) /* dbl check */
+               strlcpy(RELOC(prom_cmd_line),
+                       RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));
+#endif /* CONFIG_CMDLINE */
+       prom_printf("command line: %s\n", RELOC(prom_cmd_line));
+
+       opt = strstr(RELOC(prom_cmd_line), RELOC("iommu="));
+       if (opt) {
+               prom_printf("iommu opt is: %s\n", opt);
+               opt += 6;
+               while (*opt && *opt == ' ')
+                       opt++;
+               if (!strncmp(opt, RELOC("off"), 3))
+                       RELOC(ppc64_iommu_off) = 1;
+               else if (!strncmp(opt, RELOC("force"), 5))
+                       RELOC(iommu_force_on) = 1;
+       }
+}
+
+/*
+ * Memory allocation strategy... our layout is normally:
+ *
+ *  at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd
+ *  might end up beeing before the kernel though. We assume this won't override
+ *  the final kernel at 0, we have no provision to handle that in this version,
+ *  but it should hopefully never happen.
+ *
+ *  alloc_top is set to the top of RMO, eventually shrink down if the TCEs overlap
+ *  alloc_bottom is set to the top of kernel/initrd
+ *
+ *  from there, allocations are done that way : rtas is allocated topmost, and
+ *  the device-tree is allocated from the bottom. We try to grow the device-tree
+ *  allocation as we progress. If we can't, then we fail, we don't currently have
+ *  a facility to restart elsewhere, but that shouldn't be necessary neither
+ *
+ *  Note that calls to reserve_mem have to be done explicitely, memory allocated
+ *  with either alloc_up or alloc_down isn't automatically reserved.
+ */
+
+
+/*
+ * Allocates memory in the RMO upward from the kernel/initrd
+ *
+ * When align is 0, this is a special case, it means to allocate in place
+ * at the current location of alloc_bottom or fail (that is basically
+ * extending the previous allocation). Used for the device-tree flattening
+ */
+static unsigned long __init alloc_up(unsigned long size, unsigned long align)
+{
+       unsigned long offset = reloc_offset();
+       unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align);
+       unsigned long addr = 0;
+
+       prom_debug("alloc_up(%x, %x)\n", size, align);
+       if (RELOC(ram_top) == 0)
+               prom_panic("alloc_up() called with mem not initialized\n");
+
+       if (align)
+               base = _ALIGN_UP(RELOC(alloc_bottom), align);
+       else
+               base = RELOC(alloc_bottom);
+
+       for(; (base + size) <= RELOC(alloc_top); 
+           base = _ALIGN_UP(base + 0x100000, align)) {
+               prom_debug("    trying: 0x%x\n\r", base);
+               addr = (unsigned long)prom_claim(base, size, 0);
+               if ((int)addr != PROM_ERROR)
+                       break;
+               addr = 0;
+               if (align == 0)
+                       break;
+       }
+       if (addr == 0)
+               return 0;
+       RELOC(alloc_bottom) = addr;
+
+       prom_debug(" -> %x\n", addr);
+       prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));
+       prom_debug("  alloc_top    : %x\n", RELOC(alloc_top));
+       prom_debug("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
+       prom_debug("  rmo_top      : %x\n", RELOC(rmo_top));
+       prom_debug("  ram_top      : %x\n", RELOC(ram_top));
+
+       return addr;
+}
+
+/*
+ * Allocates memory downard, either from top of RMO, or if highmem
+ * is set, from the top of RAM. Note that this one doesn't handle
+ * failures. In does claim memory if highmem is not set.
+ */
+static unsigned long __init alloc_down(unsigned long size, unsigned long align,
+                                      int highmem)
+{
+       unsigned long offset = reloc_offset();
+       unsigned long base, addr = 0;
+
+       prom_debug("alloc_down(%x, %x, %s)\n", size, align,
+                  highmem ? RELOC("(high)") : RELOC("(low)"));
+       if (RELOC(ram_top) == 0)
+               prom_panic("alloc_down() called with mem not initialized\n");
+
+       if (highmem) {
+               /* Carve out storage for the TCE table. */
+               addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align);
+               if (addr <= RELOC(alloc_bottom))
+                       return 0;
+               else {
+                       /* Will we bump into the RMO ? If yes, check out that we
+                        * didn't overlap existing allocations there, if we did,
+                        * we are dead, we must be the first in town !
+                        */
+                       if (addr < RELOC(rmo_top)) {
+                               /* Good, we are first */
+                               if (RELOC(alloc_top) == RELOC(rmo_top))
+                                       RELOC(alloc_top) = RELOC(rmo_top) = addr;
+                               else
+                                       return 0;
+                       }
+                       RELOC(alloc_top_high) = addr;
+               }
+               goto bail;
+       }
+
+       base = _ALIGN_DOWN(RELOC(alloc_top) - size, align);
+       for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align))  {
+               prom_debug("    trying: 0x%x\n\r", base);
+               addr = (unsigned long)prom_claim(base, size, 0);
+               if ((int)addr != PROM_ERROR)
+                       break;
+               addr = 0;
+       }
+       if (addr == 0)
+               return 0;
+       RELOC(alloc_top) = addr;
+
+ bail:
+       prom_debug(" -> %x\n", addr);
+       prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));
+       prom_debug("  alloc_top    : %x\n", RELOC(alloc_top));
+       prom_debug("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
+       prom_debug("  rmo_top      : %x\n", RELOC(rmo_top));
+       prom_debug("  ram_top      : %x\n", RELOC(ram_top));
+
+       return addr;
+}
+
+/*
+ * Parse a "reg" cell
+ */
+static unsigned long __init prom_next_cell(int s, cell_t **cellp)
+{
+       cell_t *p = *cellp;
+       unsigned long r = 0;
+
+       /* Ignore more than 2 cells */
+       while (s > 2) {
+               p++;
+               s--;
+       }
+       while (s) {
+               r <<= 32;
+               r |= *(p++);
+               s--;
+       }
+
+       *cellp = p;
+       return r;
+}
+
+/*
+ * Very dumb function for adding to the memory reserve list, but
+ * we don't need anything smarter at this point
+ *
+ * XXX Eventually check for collisions. They should NEVER happen
+ * if problems seem to show up, it would be a good start to track
+ * them down.
+ */
+static void reserve_mem(unsigned long base, unsigned long size)
+{
+       unsigned long offset = reloc_offset();
+       unsigned long top = base + size;
+       unsigned long cnt = RELOC(mem_reserve_cnt);
+
+       if (size == 0)
+               return;
+
+       /* We need to always keep one empty entry so that we
+        * have our terminator with "size" set to 0 since we are
+        * dumb and just copy this entire array to the boot params
+        */
+       base = _ALIGN_DOWN(base, PAGE_SIZE);
+       top = _ALIGN_UP(top, PAGE_SIZE);
+       size = top - base;
+
+       if (cnt >= (MEM_RESERVE_MAP_SIZE - 1))
+               prom_panic("Memory reserve map exhausted !\n");
+       RELOC(mem_reserve_map)[cnt].base = base;
+       RELOC(mem_reserve_map)[cnt].size = size;
+       RELOC(mem_reserve_cnt) = cnt + 1;
+}
+
+/*
+ * Initialize memory allocation mecanism, parse "memory" nodes and
+ * obtain that way the top of memory and RMO to setup out local allocator
+ */
+static void __init prom_init_mem(void)
+{
+       phandle node;
+       char *path, type[64];
+       unsigned int plen;
+       cell_t *p, *endp;
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+
+       /*
+        * We iterate the memory nodes to find
+        * 1) top of RMO (first node)
+        * 2) top of memory
+        */
+       prom_debug("root_addr_cells: %x\n", (long)_prom->root_addr_cells);
+       prom_debug("root_size_cells: %x\n", (long)_prom->root_size_cells);
+
+       prom_debug("scanning memory:\n");
+       path = RELOC(prom_scratch);
+
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               prom_getprop(node, "device_type", type, sizeof(type));
+
+               if (strcmp(type, RELOC("memory")))
+                       continue;
+       
+               plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
+               if (plen > sizeof(regbuf)) {
+                       prom_printf("memory node too large for buffer !\n");
+                       plen = sizeof(regbuf);
+               }
+               p = RELOC(regbuf);
+               endp = p + (plen / sizeof(cell_t));
+
+#ifdef DEBUG_PROM
+               memset(path, 0, PROM_SCRATCH_SIZE);
+               call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+               prom_debug("  node %s :\n", path);
+#endif /* DEBUG_PROM */
+
+               while ((endp - p) >= (_prom->root_addr_cells + _prom->root_size_cells)) {
+                       unsigned long base, size;
+
+                       base = prom_next_cell(_prom->root_addr_cells, &p);
+                       size = prom_next_cell(_prom->root_size_cells, &p);
+
+                       if (size == 0)
+                               continue;
+                       prom_debug("    %x %x\n", base, size);
+                       if (base == 0)
+                               RELOC(rmo_top) = size;
+                       if ((base + size) > RELOC(ram_top))
+                               RELOC(ram_top) = base + size;
+               }
+       }
+
+       /* Setup our top/bottom alloc points, that is top of RMO or top of
+        * segment 0 when running non-LPAR
+        */
+       if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
+               RELOC(alloc_top) = RELOC(rmo_top);
+       else
+               RELOC(alloc_top) = min(0x40000000ul, RELOC(ram_top));
+       RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000);
+       RELOC(alloc_top_high) = RELOC(ram_top);
+
+       /* Check if we have an initrd after the kernel, if we do move our bottom
+        * point to after it
+        */
+       if (RELOC(prom_initrd_start)) {
+               if ((RELOC(prom_initrd_start) + RELOC(prom_initrd_end))
+                   > RELOC(alloc_bottom))
+                       RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
+       }
+
+       prom_printf("memory layout at init:\n");
+       prom_printf("  alloc_bottom : %x\n", RELOC(alloc_bottom));
+       prom_printf("  alloc_top    : %x\n", RELOC(alloc_top));
+       prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
+       prom_printf("  rmo_top      : %x\n", RELOC(rmo_top));
+       prom_printf("  ram_top      : %x\n", RELOC(ram_top));
+}
+
+
+/*
+ * Allocate room for and instanciate RTAS
+ */
+static void __init prom_instantiate_rtas(void)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       phandle prom_rtas;
+       u64 base, entry = 0;
+        u32 size;
+
+       prom_debug("prom_instantiate_rtas: start...\n");
+
+       prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
+       if (prom_rtas != (phandle) -1) {
+               prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size));
+               if (size != 0) {
+                       base = alloc_down(size, PAGE_SIZE, 0);
+                       if (base == 0) {
+                               prom_printf("RTAS allocation failed !\n");
+                               return;
+                       }
+                       prom_printf("instantiating rtas at 0x%x", base);
+
+                       prom_rtas = call_prom("open", 1, 1, ADDR("/rtas"));
+                       prom_printf("...");
+
+                       if (call_prom("call-method", 3, 2,
+                                     ADDR("instantiate-rtas"),
+                                     prom_rtas, base) != PROM_ERROR) {
+                               entry = (long)_prom->args.rets[1];
+                       }
+                       if (entry == 0) {
+                               prom_printf(" failed\n");
+                               return;
+                       }
+                       prom_printf(" done\n");
+
+                       reserve_mem(base, size);
+               }
+
+               prom_setprop(_prom->chosen, "linux,rtas-base", &base, sizeof(base));
+               prom_setprop(_prom->chosen, "linux,rtas-entry", &entry, sizeof(entry));
+               prom_setprop(_prom->chosen, "linux,rtas-size", &size, sizeof(size));
+
+               prom_debug("rtas base     = 0x%x\n", base);
+               prom_debug("rtas entry    = 0x%x\n", entry);
+               prom_debug("rtas size     = 0x%x\n", (long)size);
+       }
+       prom_debug("prom_instantiate_rtas: end...\n");
+}
+
+
+/*
+ * Allocate room for and initialize TCE tables
+ */
+static void __init prom_initialize_tce_table(void)
+{
+       phandle node;
+       ihandle phb_node;
+       unsigned long offset = reloc_offset();
+       char compatible[64], type[64], model[64];
+       char *path = RELOC(prom_scratch);
+       u64 base, vbase, align;
+       u32 minalign, minsize;
+       u64 tce_entry, *tce_entryp;
+       u64 local_alloc_top, local_alloc_bottom;
+       u64 i;
+
+       if (RELOC(ppc64_iommu_off))
+               return;
+
+       prom_debug("starting prom_initialize_tce_table\n");
+
+       /* Cache current top of allocs so we reserve a single block */
+       local_alloc_top = RELOC(alloc_top_high);
+       local_alloc_bottom = local_alloc_top;
+
+       /* Search all nodes looking for PHBs. */
+       for (node = 0; prom_next_node(&node); ) {
+               compatible[0] = 0;
+               type[0] = 0;
+               model[0] = 0;
+               prom_getprop(node, "compatible",
+                            compatible, sizeof(compatible));
+               prom_getprop(node, "device_type", type, sizeof(type));
+               prom_getprop(node, "model", model, sizeof(model));
+
+               if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL))
+                       continue;
+
+               /* Keep the old logic in tack to avoid regression. */
+               if (compatible[0] != 0) {
+                       if ((strstr(compatible, RELOC("python")) == NULL) &&
+                           (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
+                           (strstr(compatible, RELOC("Winnipeg")) == NULL))
+                               continue;
+               } else if (model[0] != 0) {
+                       if ((strstr(model, RELOC("ython")) == NULL) &&
+                           (strstr(model, RELOC("peedwagon")) == NULL) &&
+                           (strstr(model, RELOC("innipeg")) == NULL))
+                               continue;
+               }
+
+               if (prom_getprop(node, "tce-table-minalign", &minalign,
+                                sizeof(minalign)) == PROM_ERROR)
+                       minalign = 0;
+               if (prom_getprop(node, "tce-table-minsize", &minsize,
+                                sizeof(minsize)) == PROM_ERROR)
+                       minsize = 4UL << 20;
+
+               /*
+                * Even though we read what OF wants, we just set the table
+                * size to 4 MB.  This is enough to map 2GB of PCI DMA space.
+                * By doing this, we avoid the pitfalls of trying to DMA to
+                * MMIO space and the DMA alias hole.
+                *
+                * On POWER4, firmware sets the TCE region by assuming
+                * each TCE table is 8MB. Using this memory for anything
+                * else will impact performance, so we always allocate 8MB.
+                * Anton
+                */
+               if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
+                       minsize = 8UL << 20;
+               else
+                       minsize = 4UL << 20;
+
+               /* Align to the greater of the align or size */
+               align = max(minalign, minsize);
+               base = alloc_down(minsize, align, 1);
+               if (base == 0)
+                       prom_panic("ERROR, cannot find space for TCE table.\n");
+               if (base < local_alloc_bottom)
+                       local_alloc_bottom = base;
+
+               vbase = (unsigned long)abs_to_virt(base);
+
+               /* Save away the TCE table attributes for later use. */
+               prom_setprop(node, "linux,tce-base", &vbase, sizeof(vbase));
+               prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize));
+               prom_setprop(node, "linux,has-tce-table", NULL, 0);
+
+               /* It seems OF doesn't null-terminate the path :-( */
+               memset(path, 0, sizeof(path));
+               /* Call OF to setup the TCE hardware */
+               if (call_prom("package-to-path", 3, 1, node,
+                             path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) {
+                       prom_printf("package-to-path failed\n");
+               }
+
+               prom_debug("TCE table: %s\n", path);
+               prom_debug("\tnode = 0x%x\n", node);
+               prom_debug("\tbase = 0x%x\n", vbase);
+               prom_debug("\tsize = 0x%x\n", minsize);
+
+               /* Initialize the table to have a one-to-one mapping
+                * over the allocated size.
+                */
+               tce_entryp = (unsigned long *)base;
+               for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
+                       tce_entry = (i << PAGE_SHIFT);
+                       tce_entry |= 0x3;
+                       *tce_entryp = tce_entry;
+               }
+
+               prom_printf("opening PHB %s", path);
+               phb_node = call_prom("open", 1, 1, path);
+               if ( (long)phb_node <= 0)
+                       prom_printf("... failed\n");
+               else
+                       prom_printf("... done\n");
+
+               call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"),
+                         phb_node, -1, minsize,
+                         (u32) base, (u32) (base >> 32));
+               call_prom("close", 1, 0, phb_node);
+       }
+
+       reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
+
+       /* Flag the first invalid entry */
+       prom_debug("ending prom_initialize_tce_table\n");
+}
+
+/*
+ * With CHRP SMP we need to use the OF to start the other
+ * processors so we can't wait until smp_boot_cpus (the OF is
+ * trashed by then) so we have to put the processors into
+ * a holding pattern controlled by the kernel (not OF) before
+ * we destroy the OF.
+ *
+ * This uses a chunk of low memory, puts some holding pattern
+ * code there and sends the other processors off to there until
+ * smp_boot_cpus tells them to do something.  The holding pattern
+ * checks that address until its cpu # is there, when it is that
+ * cpu jumps to __secondary_start().  smp_boot_cpus() takes care
+ * of setting those values.
+ *
+ * We also use physical address 0x4 here to tell when a cpu
+ * is in its holding pattern code.
+ *
+ * Fixup comment... DRENG / PPPBBB - Peter
+ *
+ * -- Cort
+ */
+static void __init prom_hold_cpus(void)
+{
+       unsigned long i;
+       unsigned int reg;
+       phandle node;
+       unsigned long offset = reloc_offset();
+       char type[64];
+       int cpuid = 0;
+       unsigned int interrupt_server[MAX_CPU_THREADS];
+       unsigned int cpu_threads, hw_cpu_num;
+       int propsize;
+       extern void __secondary_hold(void);
+       extern unsigned long __secondary_hold_spinloop;
+       extern unsigned long __secondary_hold_acknowledge;
+       unsigned long *spinloop
+               = (void *)virt_to_abs(&__secondary_hold_spinloop);
+       unsigned long *acknowledge
+               = (void *)virt_to_abs(&__secondary_hold_acknowledge);
+       unsigned long secondary_hold
+               = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold));
+       struct prom_t *_prom = PTRRELOC(&prom);
+
+       prom_debug("prom_hold_cpus: start...\n");
+       prom_debug("    1) spinloop       = 0x%x\n", (unsigned long)spinloop);
+       prom_debug("    1) *spinloop      = 0x%x\n", *spinloop);
+       prom_debug("    1) acknowledge    = 0x%x\n",
+                  (unsigned long)acknowledge);
+       prom_debug("    1) *acknowledge   = 0x%x\n", *acknowledge);
+       prom_debug("    1) secondary_hold = 0x%x\n", secondary_hold);
+
+       /* Set the common spinloop variable, so all of the secondary cpus
+        * will block when they are awakened from their OF spinloop.
+        * This must occur for both SMP and non SMP kernels, since OF will
+        * be trashed when we move the kernel.
+        */
+       *spinloop = 0;
+
+#ifdef CONFIG_HMT
+       for (i=0; i < NR_CPUS; i++) {
+               RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
+       }
+#endif
+       /* look for cpus */
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               prom_getprop(node, "device_type", type, sizeof(type));
+               if (strcmp(type, RELOC("cpu")) != 0)
+                       continue;
+
+               /* Skip non-configured cpus. */
+               prom_getprop(node, "status", type, sizeof(type));
+               if (strcmp(type, RELOC("okay")) != 0)
+                       continue;
+
+               reg = -1;
+               prom_getprop(node, "reg", &reg, sizeof(reg));
+
+               prom_debug("\ncpuid        = 0x%x\n", cpuid);
+               prom_debug("cpu hw idx   = 0x%x\n", reg);
+
+               /* Init the acknowledge var which will be reset by
+                * the secondary cpu when it awakens from its OF
+                * spinloop.
+                */
+               *acknowledge = (unsigned long)-1;
+
+               propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s",
+                                       &interrupt_server,
+                                       sizeof(interrupt_server));
+               if (propsize < 0) {
+                       /* no property.  old hardware has no SMT */
+                       cpu_threads = 1;
+                       interrupt_server[0] = reg; /* fake it with phys id */
+               } else {
+                       /* We have a threaded processor */
+                       cpu_threads = propsize / sizeof(u32);
+                       if (cpu_threads > MAX_CPU_THREADS) {
+                               prom_printf("SMT: too many threads!\n"
+                                           "SMT: found %x, max is %x\n",
+                                           cpu_threads, MAX_CPU_THREADS);
+                               cpu_threads = 1; /* ToDo: panic? */
+                       }
+               }
+
+               hw_cpu_num = interrupt_server[0];
+               if (hw_cpu_num != _prom->cpu) {
+                       /* Primary Thread of non-boot cpu */
+                       prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg);
+                       call_prom("start-cpu", 3, 0, node,
+                                 secondary_hold, cpuid);
+
+                       for ( i = 0 ; (i < 100000000) && 
+                             (*acknowledge == ((unsigned long)-1)); i++ ) ;
+
+                       if (*acknowledge == cpuid) {
+                               prom_printf("done\n");
+                               /* We have to get every CPU out of OF,
+                                * even if we never start it. */
+                               if (cpuid >= NR_CPUS)
+                                       goto next;
+                       } else {
+                               prom_printf("failed: %x\n", *acknowledge);
+                       }
+               }
+#ifdef CONFIG_SMP
+               else
+                       prom_printf("%x : boot cpu     %x\n", cpuid, reg);
+#endif
+next:
+#ifdef CONFIG_SMP
+               /* Init paca for secondary threads.   They start later. */
+               for (i=1; i < cpu_threads; i++) {
+                       cpuid++;
+                       if (cpuid >= NR_CPUS)
+                               continue;
+               }
+#endif /* CONFIG_SMP */
+               cpuid++;
+       }
+#ifdef CONFIG_HMT
+       /* Only enable HMT on processors that provide support. */
+       if (__is_processor(PV_PULSAR) || 
+           __is_processor(PV_ICESTAR) ||
+           __is_processor(PV_SSTAR)) {
+               prom_printf("    starting secondary threads\n");
+
+               for (i = 0; i < NR_CPUS; i += 2) {
+                       if (!cpu_online(i))
+                               continue;
+
+                       if (i == 0) {
+                               unsigned long pir = mfspr(SPRN_PIR);
+                               if (__is_processor(PV_PULSAR)) {
+                                       RELOC(hmt_thread_data)[i].pir = 
+                                               pir & 0x1f;
+                               } else {
+                                       RELOC(hmt_thread_data)[i].pir = 
+                                               pir & 0x3ff;
+                               }
+                       }
+               }
+       } else {
+               prom_printf("Processor is not HMT capable\n");
+       }
+#endif
+
+       if (cpuid > NR_CPUS)
+               prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS)
+                           ") exceeded: ignoring extras\n");
+
+       prom_debug("prom_hold_cpus: end...\n");
+}
+
+
+static void __init prom_init_client_services(unsigned long pp)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+
+       /* Get a handle to the prom entry point before anything else */
+       _prom->entry = pp;
+
+       /* Init default value for phys size */
+       _prom->root_size_cells = 1;
+       _prom->root_addr_cells = 2;
+
+       /* get a handle for the stdout device */
+       _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
+       if ((long)_prom->chosen <= 0)
+               prom_panic("cannot find chosen"); /* msg won't be printed :( */
+
+       /* get device tree root */
+       _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
+       if ((long)_prom->root <= 0)
+               prom_panic("cannot find device tree root"); /* msg won't be printed :( */
+}
+
+static void __init prom_init_stdout(void)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       char *path = RELOC(of_stdout_device);
+       char type[16];
+       u32 val;
+
+       if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0)
+               prom_panic("cannot find stdout");
+
+       _prom->stdout = val;
+
+       /* Get the full OF pathname of the stdout device */
+       memset(path, 0, 256);
+       call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
+       val = call_prom("instance-to-package", 1, 1, _prom->stdout);
+       prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val));
+       prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
+       prom_setprop(_prom->chosen, "linux,stdout-path",
+                    RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1);
+
+       /* If it's a display, note it */
+       memset(type, 0, sizeof(type));
+       prom_getprop(val, "device_type", type, sizeof(type));
+       if (strcmp(type, RELOC("display")) == 0) {
+               _prom->disp_node = val;
+               prom_setprop(val, "linux,boot-display", NULL, 0);
+       }
+}
+
+static int __init prom_find_machine_type(void)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       char compat[256];
+       int len, i = 0;
+       phandle rtas;
+
+       len = prom_getprop(_prom->root, "compatible",
+                          compat, sizeof(compat)-1);
+       if (len > 0) {
+               compat[len] = 0;
+               while (i < len) {
+                       char *p = &compat[i];
+                       int sl = strlen(p);
+                       if (sl == 0)
+                               break;
+                       if (strstr(p, RELOC("Power Macintosh")) ||
+                           strstr(p, RELOC("MacRISC4")))
+                               return PLATFORM_POWERMAC;
+                       i += sl + 1;
+               }
+       }
+       /* Default to pSeries. We need to know if we are running LPAR */
+       rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
+       if (rtas != (phandle) -1) {
+               unsigned long x;
+               x = prom_getproplen(rtas, "ibm,hypertas-functions");
+               if (x != PROM_ERROR) {
+                       prom_printf("Hypertas detected, assuming LPAR !\n");
+                       return PLATFORM_PSERIES_LPAR;
+               }
+       }
+       return PLATFORM_PSERIES;
+}
+
+static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+       unsigned long offset = reloc_offset();
+
+       return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r);
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF will probably fall over if we do that
+ * we've taken over the MMU.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static unsigned long __init prom_check_displays(void)
+{
+       unsigned long offset = reloc_offset();
+       struct prom_t *_prom = PTRRELOC(&prom);
+       char type[16], *path;
+       phandle node;
+       ihandle ih;
+       int i;
+
+       static unsigned char default_colors[] = {
+               0x00, 0x00, 0x00,
+               0x00, 0x00, 0xaa,
+               0x00, 0xaa, 0x00,
+               0x00, 0xaa, 0xaa,
+               0xaa, 0x00, 0x00,
+               0xaa, 0x00, 0xaa,
+               0xaa, 0xaa, 0x00,
+               0xaa, 0xaa, 0xaa,
+               0x55, 0x55, 0x55,
+               0x55, 0x55, 0xff,
+               0x55, 0xff, 0x55,
+               0x55, 0xff, 0xff,
+               0xff, 0x55, 0x55,
+               0xff, 0x55, 0xff,
+               0xff, 0xff, 0x55,
+               0xff, 0xff, 0xff
+       };
+       const unsigned char *clut;
+
+       prom_printf("Looking for displays\n");
+       for (node = 0; prom_next_node(&node); ) {
+               memset(type, 0, sizeof(type));
+               prom_getprop(node, "device_type", type, sizeof(type));
+               if (strcmp(type, RELOC("display")) != 0)
+                       continue;
+
+               /* It seems OF doesn't null-terminate the path :-( */
+               path = RELOC(prom_scratch);
+               memset(path, 0, PROM_SCRATCH_SIZE);
+
+               /*
+                * leave some room at the end of the path for appending extra
+                * arguments
+                */
+               if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0)
+                       continue;
+               prom_printf("found display   : %s, opening ... ", path);
+               
+               ih = call_prom("open", 1, 1, path);
+               if (ih == (ihandle)0 || ih == (ihandle)-1) {
+                       prom_printf("failed\n");
+                       continue;
+               }
+
+               /* Success */
+               prom_printf("done\n");
+               prom_setprop(node, "linux,opened", NULL, 0);
+
+               /*
+                * stdout wasn't a display node, pick the first we can find
+                * for btext
+                */
+               if (_prom->disp_node == 0)
+                       _prom->disp_node = node;
+
+               /* Setup a useable color table when the appropriate
+                * method is available. Should update this to set-colors */
+               clut = RELOC(default_colors);
+               for (i = 0; i < 32; i++, clut += 3)
+                       if (prom_set_color(ih, i, clut[0], clut[1],
+                                          clut[2]) != 0)
+                               break;
+
+#ifdef CONFIG_LOGO_LINUX_CLUT224
+               clut = PTRRELOC(RELOC(logo_linux_clut224.clut));
+               for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3)
+                       if (prom_set_color(ih, i + 32, clut[0], clut[1],
+                                          clut[2]) != 0)
+                               break;
+#endif /* CONFIG_LOGO_LINUX_CLUT224 */
+       }
+}
+
+
+/* Return (relocated) pointer to this much memory: moves initrd if reqd. */
+static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
+                             unsigned long needed, unsigned long align)
+{
+       unsigned long offset = reloc_offset();
+       void *ret;
+
+       *mem_start = _ALIGN(*mem_start, align);
+       while ((*mem_start + needed) > *mem_end) {
+               unsigned long room, chunk;
+
+               prom_debug("Chunk exhausted, claiming more at %x...\n",
+                          RELOC(alloc_bottom));
+               room = RELOC(alloc_top) - RELOC(alloc_bottom);
+               if (room > DEVTREE_CHUNK_SIZE)
+                       room = DEVTREE_CHUNK_SIZE;
+               if (room < PAGE_SIZE)
+                       prom_panic("No memory for flatten_device_tree (no room)");
+               chunk = alloc_up(room, 0);
+               if (chunk == 0)
+                       prom_panic("No memory for flatten_device_tree (claim failed)");
+               *mem_end = RELOC(alloc_top);
+       }
+
+       ret = (void *)*mem_start;
+       *mem_start += needed;
+
+       return ret;
+}
+
+#define dt_push_token(token, mem_start, mem_end) \
+       do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0)
+
+static unsigned long __init dt_find_string(char *str)
+{
+       unsigned long offset = reloc_offset();
+       char *s, *os;
+
+       s = os = (char *)RELOC(dt_string_start);
+       s += 4;
+       while (s <  (char *)RELOC(dt_string_end)) {
+               if (strcmp(s, str) == 0)
+                       return s - os;
+               s += strlen(s) + 1;
+       }
+       return 0;
+}
+
+static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
+                                        unsigned long *mem_end)
+{
+       unsigned long offset = reloc_offset();
+       char *prev_name, *namep, *sstart;
+       unsigned long soff;
+       phandle child;
+
+       sstart =  (char *)RELOC(dt_string_start);
+
+       /* get and store all property names */
+       prev_name = RELOC("");
+       for (;;) {
+               
+               /* 32 is max len of name including nul. */
+               namep = make_room(mem_start, mem_end, 32, 1);
+               if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) {
+                       /* No more nodes: unwind alloc */
+                       *mem_start = (unsigned long)namep;
+                       break;
+               }
+               soff = dt_find_string(namep);
+               if (soff != 0) {
+                       *mem_start = (unsigned long)namep;
+                       namep = sstart + soff;
+               } else {
+                       /* Trim off some if we can */
+                       *mem_start = (unsigned long)namep + strlen(namep) + 1;
+                       RELOC(dt_string_end) = *mem_start;
+               }
+               prev_name = namep;
+       }
+
+       /* do all our children */
+       child = call_prom("child", 1, 1, node);
+       while (child != (phandle)0) {
+               scan_dt_build_strings(child, mem_start, mem_end);
+               child = call_prom("peer", 1, 1, child);
+       }
+}
+
+static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
+                                       unsigned long *mem_end)
+{
+       int l, align;
+       phandle child;
+       char *namep, *prev_name, *sstart;
+       unsigned long soff;
+       unsigned char *valp;
+       unsigned long offset = reloc_offset();
+       char pname[32];
+       char *path;
+
+       path = RELOC(prom_scratch);
+
+       dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
+
+       /* get the node's full name */
+       namep = (char *)*mem_start;
+       l = call_prom("package-to-path", 3, 1, node,
+                     namep, *mem_end - *mem_start);
+       if (l >= 0) {
+               /* Didn't fit?  Get more room. */
+               if (l+1 > *mem_end - *mem_start) {
+                       namep = make_room(mem_start, mem_end, l+1, 1);
+                       call_prom("package-to-path", 3, 1, node, namep, l);
+               }
+               namep[l] = '\0';
+               *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
+       }
+
+       /* get it again for debugging */
+       memset(path, 0, PROM_SCRATCH_SIZE);
+       call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+
+       /* get and store all properties */
+       prev_name = RELOC("");
+       sstart = (char *)RELOC(dt_string_start);
+       for (;;) {
+               if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0)
+                       break;
+
+               /* find string offset */
+               soff = dt_find_string(pname);
+               if (soff == 0) {
+                       prom_printf("WARNING: Can't find string index for <%s>, node %s\n",
+                                   pname, path);
+                       break;
+               }
+               prev_name = sstart + soff;
+
+               /* get length */
+               l = call_prom("getproplen", 2, 1, node, pname);
+
+               /* sanity checks */
+               if (l < 0)
+                       continue;
+               if (l > MAX_PROPERTY_LENGTH) {
+                       prom_printf("WARNING: ignoring large property ");
+                       /* It seems OF doesn't null-terminate the path :-( */
+                       prom_printf("[%s] ", path);
+                       prom_printf("%s length 0x%x\n", pname, l);
+                       continue;
+               }
+
+               /* push property head */
+               dt_push_token(OF_DT_PROP, mem_start, mem_end);
+               dt_push_token(l, mem_start, mem_end);
+               dt_push_token(soff, mem_start, mem_end);
+
+               /* push property content */
+               align = (l >= 8) ? 8 : 4;
+               valp = make_room(mem_start, mem_end, l, align);
+               call_prom("getprop", 4, 1, node, pname, valp, l);
+               *mem_start = _ALIGN(*mem_start, 4);
+       }
+
+       /* Add a "linux,phandle" property. */
+       soff = dt_find_string(RELOC("linux,phandle"));
+       if (soff == 0)
+               prom_printf("WARNING: Can't find string index for <linux-phandle>"
+                           " node %s\n", path);
+       else {
+               dt_push_token(OF_DT_PROP, mem_start, mem_end);
+               dt_push_token(4, mem_start, mem_end);
+               dt_push_token(soff, mem_start, mem_end);
+               valp = make_room(mem_start, mem_end, 4, 4);
+               *(u32 *)valp = node;
+       }
+
+       /* do all our children */
+       child = call_prom("child", 1, 1, node);
+       while (child != (phandle)0) {
+               scan_dt_build_struct(child, mem_start, mem_end);
+               child = call_prom("peer", 1, 1, child);
+       }
+
+       dt_push_token(OF_DT_END_NODE, mem_start, mem_end);
+}
+
+static void __init flatten_device_tree(void)
+{
+       phandle root;
+       unsigned long offset = reloc_offset();
+       unsigned long mem_start, mem_end, room;
+       struct boot_param_header *hdr;
+       char *namep;
+       u64 *rsvmap;
+
+       /*
+        * Check how much room we have between alloc top & bottom (+/- a
+        * few pages), crop to 4Mb, as this is our "chuck" size
+        */
+       room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000;
+       if (room > DEVTREE_CHUNK_SIZE)
+               room = DEVTREE_CHUNK_SIZE;
+       prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom));
+
+       /* Now try to claim that */
+       mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
+       if (mem_start == 0)
+               prom_panic("Can't allocate initial device-tree chunk\n");
+       mem_end = RELOC(alloc_top);
+
+       /* Get root of tree */
+       root = call_prom("peer", 1, 1, (phandle)0);
+       if (root == (phandle)0)
+               prom_panic ("couldn't get device tree root\n");
+
+       /* Build header and make room for mem rsv map */ 
+       mem_start = _ALIGN(mem_start, 4);
+       hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4);
+       RELOC(dt_header_start) = (unsigned long)hdr;
+       rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
+
+       /* Start of strings */
+       mem_start = PAGE_ALIGN(mem_start);
+       RELOC(dt_string_start) = mem_start;
+       mem_start += 4; /* hole */
+
+       /* Add "linux,phandle" in there, we'll need it */
+       namep = make_room(&mem_start, &mem_end, 16, 1);
+       strcpy(namep, RELOC("linux,phandle"));
+       mem_start = (unsigned long)namep + strlen(namep) + 1;
+       RELOC(dt_string_end) = mem_start;
+
+       /* Build string array */
+       prom_printf("Building dt strings...\n"); 
+       scan_dt_build_strings(root, &mem_start, &mem_end);
+
+       /* Build structure */
+       mem_start = PAGE_ALIGN(mem_start);
+       RELOC(dt_struct_start) = mem_start;
+       prom_printf("Building dt structure...\n"); 
+       scan_dt_build_struct(root, &mem_start, &mem_end);
+       dt_push_token(OF_DT_END, &mem_start, &mem_end);
+       RELOC(dt_struct_end) = PAGE_ALIGN(mem_start);
+
+       /* Finish header */
+       hdr->magic = OF_DT_HEADER;
+       hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
+       hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
+       hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
+       hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
+       hdr->version = OF_DT_VERSION;
+       hdr->last_comp_version = 1;
+
+       /* Reserve the whole thing and copy the reserve map in, we
+        * also bump mem_reserve_cnt to cause further reservations to
+        * fail since it's too late.
+        */
+       reserve_mem(RELOC(dt_header_start), hdr->totalsize);
+       memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
+
+#ifdef DEBUG_PROM
+       {
+               int i;
+               prom_printf("reserved memory map:\n");
+               for (i = 0; i < RELOC(mem_reserve_cnt); i++)
+                       prom_printf("  %x - %x\n", RELOC(mem_reserve_map)[i].base,
+                                   RELOC(mem_reserve_map)[i].size);
+       }
+#endif
+       RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
+
+       prom_printf("Device tree strings 0x%x -> 0x%x\n",
+                   RELOC(dt_string_start), RELOC(dt_string_end)); 
+       prom_printf("Device tree struct  0x%x -> 0x%x\n",
+                   RELOC(dt_struct_start), RELOC(dt_struct_end));
+
+ }
+
+static void __init prom_find_boot_cpu(void)
+{
+       unsigned long offset = reloc_offset();
+               struct prom_t *_prom = PTRRELOC(&prom);
+       u32 getprop_rval;
+       ihandle prom_cpu;
+       phandle cpu_pkg;
+
+       if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
+               prom_panic("cannot find boot cpu");
+
+       cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
+
+       prom_setprop(cpu_pkg, "linux,boot-cpu", NULL, 0);
+       prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval));
+       _prom->cpu = getprop_rval;
+
+       prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu);
+}
+
+static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       unsigned long offset = reloc_offset();
+               struct prom_t *_prom = PTRRELOC(&prom);
+
+       if ( r3 && r4 && r4 != 0xdeadbeef) {
+               u64 val;
+
+               RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
+               RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
+
+               val = (u64)RELOC(prom_initrd_start);
+               prom_setprop(_prom->chosen, "linux,initrd-start", &val, sizeof(val));
+               val = (u64)RELOC(prom_initrd_end);
+               prom_setprop(_prom->chosen, "linux,initrd-end", &val, sizeof(val));
+
+               reserve_mem(RELOC(prom_initrd_start),
+                           RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
+
+               prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start));
+               prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end));
+       }
+#endif /* CONFIG_BLK_DEV_INITRD */
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+
+unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
+                              unsigned long r6, unsigned long r7)
+{      
+       unsigned long offset = reloc_offset();
+               struct prom_t *_prom = PTRRELOC(&prom);
+       unsigned long phys = KERNELBASE - offset;
+       u32 getprop_rval;
+       
+       /*
+        * First zero the BSS
+        */
+       memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start);
+
+       /*
+        * Init interface to Open Firmware, get some node references,
+        * like /chosen
+        */
+       prom_init_client_services(pp);
+
+       /*
+        * Init prom stdout device
+        */
+       prom_init_stdout();
+       prom_debug("klimit=0x%x\n", RELOC(klimit));
+       prom_debug("offset=0x%x\n", offset);
+
+       /*
+        * Reserve kernel in reserve map
+        */
+       reserve_mem(0, __pa(RELOC(klimit)));
+
+       /*
+        * Check for an initrd
+        */
+       prom_check_initrd(r3, r4);
+
+       /*
+        * Get default machine type. At this point, we do not differenciate
+        * between pSeries SMP and pSeries LPAR
+        */
+       RELOC(of_platform) = prom_find_machine_type();
+       getprop_rval = RELOC(of_platform);
+       prom_setprop(_prom->chosen, "linux,platform",
+                    &getprop_rval, sizeof(getprop_rval));
+
+       /*
+        * On pSeries, copy the CPU hold code
+        */
+               if (RELOC(of_platform) & PLATFORM_PSERIES)
+                       copy_and_flush(0, KERNELBASE - offset, 0x100, 0);
+
+       /*
+        * Get memory cells format
+        */
+       getprop_rval = 1;
+       prom_getprop(_prom->root, "#size-cells",
+                    &getprop_rval, sizeof(getprop_rval));
+       _prom->root_size_cells = getprop_rval;
+       getprop_rval = 2;
+       prom_getprop(_prom->root, "#address-cells",
+                    &getprop_rval, sizeof(getprop_rval));
+       _prom->root_addr_cells = getprop_rval;
+
+       /*
+        * Do early parsing of command line
+        */
+       early_cmdline_parse();
+
+       /*
+        * Initialize memory management within prom_init
+        */
+       prom_init_mem();
+
+       /*
+        * Determine which cpu is actually running right _now_
+        */
+       prom_find_boot_cpu();
+
+       /* 
+        * Initialize display devices
+        */
+       prom_check_displays();
+
+       /*
+        * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else
+        * that uses the allocator, we need to make sure we get the top of memory
+        * available for us here...
+        */
+       if (RELOC(of_platform) == PLATFORM_PSERIES)
+               prom_initialize_tce_table();
+
+       /*
+        * On non-powermacs, try to instantiate RTAS and puts all CPUs
+        * in spin-loops. PowerMacs don't have a working RTAS and use
+        * a different way to spin CPUs
+        */
+       if (RELOC(of_platform) != PLATFORM_POWERMAC) {
+               prom_instantiate_rtas();
+               prom_hold_cpus();
+       }
+
+       /*
+        * Fill in some infos for use by the kernel later on
+        */
+       if (RELOC(ppc64_iommu_off))
+               prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0);
+       if (RELOC(iommu_force_on))
+               prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0);
+
+       /*
+        * Now finally create the flattened device-tree
+        */
+               prom_printf("copying OF device tree ...\n");
+               flatten_device_tree();
+
+       /*
+        * Call OF "quiesce" method to shut down pending DMA's from
+        * devices etc...
+        */
+       prom_printf("Calling quiesce ...\n");
+       call_prom("quiesce", 0, 0);
+
+       /*
+        * And finally, call the kernel passing it the flattened device
+        * tree and NULL as r5, thus triggering the new entry point which
+        * is common to us and kexec
+        */
+       prom_printf("returning from prom_init\n");
+       prom_debug("->dt_header_start=0x%x\n", RELOC(dt_header_start));
+       prom_debug("->phys=0x%x\n", phys);
+
+       __start(RELOC(dt_header_start), phys, 0);
+
+       return 0;
+}
+
diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c
new file mode 100644 (file)
index 0000000..2bb0b39
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * arch/ppc64/kernel/u3_iommu.c
+ *
+ * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation
+ *
+ * Based on pSeries_iommu.c:
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation
+ *
+ * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu.
+ *
+ * 
+ * This 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/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/ppcdebug.h>
+#include <asm/iommu.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/abs_addr.h>
+#include <asm/cacheflush.h>
+#include <asm/lmb.h>
+
+#include "pci.h"
+
+extern int iommu_force_on;
+
+/* physical base of DART registers */
+#define DART_BASE        0xf8033000UL
+
+/* Offset from base to control register */
+#define DARTCNTL   0
+/* Offset from base to exception register */
+#define DARTEXCP   0x10
+/* Offset from base to TLB tag registers */
+#define DARTTAG    0x1000
+
+
+/* Control Register fields */
+
+/* base address of table (pfn) */
+#define DARTCNTL_BASE_MASK    0xfffff
+#define DARTCNTL_BASE_SHIFT   12
+
+#define DARTCNTL_FLUSHTLB     0x400
+#define DARTCNTL_ENABLE       0x200
+
+/* size of table in pages */
+#define DARTCNTL_SIZE_MASK    0x1ff
+#define DARTCNTL_SIZE_SHIFT   0
+
+/* DART table fields */
+#define DARTMAP_VALID   0x80000000
+#define DARTMAP_RPNMASK 0x00ffffff
+
+/* Physical base address and size of the DART table */
+unsigned long dart_tablebase; /* exported to htab_initialize */
+static unsigned long dart_tablesize;
+
+/* Virtual base address of the DART table */
+static u32 *dart_vbase;
+
+/* Mapped base address for the dart */
+static unsigned int *dart; 
+
+/* Dummy val that entries are set to when unused */
+static unsigned int dart_emptyval;
+
+static struct iommu_table iommu_table_u3;
+static int dart_dirty;
+
+#define DBG(...)
+
+static inline void dart_tlb_invalidate_all(void)
+{
+       unsigned long l = 0;
+       unsigned int reg;
+       unsigned long limit;
+
+       DBG("dart: flush\n");
+
+       /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the
+        * control register and wait for it to clear.
+        *
+        * Gotcha: Sometimes, the DART won't detect that the bit gets
+        * set. If so, clear it and set it again.
+        */ 
+
+       limit = 0;
+
+retry:
+       reg = in_be32((unsigned int *)dart+DARTCNTL);
+       reg |= DARTCNTL_FLUSHTLB;
+       out_be32((unsigned int *)dart+DARTCNTL, reg);
+
+       l = 0;
+       while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) &&
+               l < (1L<<limit)) {
+               l++;
+       }
+       if (l == (1L<<limit)) {
+               if (limit < 4) {
+                       limit++;
+                       reg = in_be32((unsigned int *)dart+DARTCNTL);
+                       reg &= ~DARTCNTL_FLUSHTLB;
+                       out_be32((unsigned int *)dart+DARTCNTL, reg);
+                       goto retry;
+               } else
+                       panic("U3-DART: TLB did not flush after waiting a long "
+                             "time. Buggy U3 ?");
+       }
+}
+
+static void dart_flush(struct iommu_table *tbl)
+{
+       if (dart_dirty)
+               dart_tlb_invalidate_all();
+       dart_dirty = 0;
+}
+
+static void dart_build(struct iommu_table *tbl, long index, 
+                      long npages, unsigned long uaddr,
+                      enum dma_data_direction direction)
+{
+       unsigned int *dp;
+       unsigned int rpn;
+
+       DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr);
+
+       dp = ((unsigned int*)tbl->it_base) + index;
+       
+       /* On U3, all memory is contigous, so we can move this
+        * out of the loop.
+        */
+       while (npages--) {
+               rpn = virt_to_abs(uaddr) >> PAGE_SHIFT;
+
+               *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
+
+               rpn++;
+               uaddr += PAGE_SIZE;
+       }
+
+       dart_dirty = 1;
+}
+
+
+static void dart_free(struct iommu_table *tbl, long index, long npages)
+{
+       unsigned int *dp;
+       
+       /* We don't worry about flushing the TLB cache. The only drawback of
+        * not doing it is that we won't catch buggy device drivers doing
+        * bad DMAs, but then no 32-bit architecture ever does either.
+        */
+
+       DBG("dart: free at: %lx, %lx\n", index, npages);
+
+       dp  = ((unsigned int *)tbl->it_base) + index;
+               
+       while (npages--)
+               *(dp++) = dart_emptyval;
+}
+
+
+static int dart_init(struct device_node *dart_node)
+{
+       unsigned int regword;
+       unsigned int i;
+       unsigned long tmp;
+       struct page *p;
+
+       if (dart_tablebase == 0 || dart_tablesize == 0) {
+               printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n");
+               return -ENODEV;
+       }
+
+       /* Make sure nothing from the DART range remains in the CPU cache
+        * from a previous mapping that existed before the kernel took
+        * over
+        */
+       flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize);
+
+       /* Allocate a spare page to map all invalid DART pages. We need to do
+        * that to work around what looks like a problem with the HT bridge
+        * prefetching into invalid pages and corrupting data
+        */
+       tmp = __get_free_pages(GFP_ATOMIC, 1);
+       if (tmp == 0)
+               panic("U3-DART: Cannot allocate spare page !");
+       dart_emptyval = DARTMAP_VALID |
+               ((virt_to_abs(tmp) >> PAGE_SHIFT) & DARTMAP_RPNMASK);
+
+       /* Map in DART registers. FIXME: Use device node to get base address */
+       dart = ioremap(DART_BASE, 0x7000);
+       if (dart == NULL)
+               panic("U3-DART: Cannot map registers !");
+
+       /* Set initial control register contents: table base, 
+        * table size and enable bit
+        */
+       regword = DARTCNTL_ENABLE | 
+               ((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) |
+               (((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
+                                << DARTCNTL_SIZE_SHIFT);
+       p = virt_to_page(dart_tablebase);
+       dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
+
+       /* Fill initial table */
+       for (i = 0; i < dart_tablesize/4; i++)
+               dart_vbase[i] = dart_emptyval;
+
+       /* Initialize DART with table base and enable it. */
+       out_be32((unsigned int *)dart, regword);
+
+       /* Invalidate DART to get rid of possible stale TLBs */
+       dart_tlb_invalidate_all();
+
+       iommu_table_u3.it_busno = 0;
+       
+       /* Units of tce entries */
+       iommu_table_u3.it_offset = 0;
+       
+       /* Set the tce table size - measured in pages */
+       iommu_table_u3.it_size = dart_tablesize >> PAGE_SHIFT;
+
+       /* Initialize the common IOMMU code */
+       iommu_table_u3.it_base = (unsigned long)dart_vbase;
+       iommu_table_u3.it_index = 0;
+       iommu_table_u3.it_blocksize = 1;
+       iommu_table_u3.it_entrysize = sizeof(u32);
+       iommu_init_table(&iommu_table_u3);
+
+       /* Reserve the last page of the DART to avoid possible prefetch
+        * past the DART mapped area
+        */
+       set_bit(iommu_table_u3.it_mapsize - 1, iommu_table_u3.it_map);
+
+       printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n");
+
+       return 0;
+}
+
+void iommu_setup_u3(void)
+{
+       struct pci_dev *dev = NULL;
+       struct device_node *dn;
+
+       /* Find the DART in the device-tree */
+       dn = of_find_compatible_node(NULL, "dart", "u3-dart");
+       if (dn == NULL)
+               return;
+
+       /* Setup low level TCE operations for the core IOMMU code */
+       ppc_md.tce_build = dart_build;
+       ppc_md.tce_free  = dart_free;
+       ppc_md.tce_flush = dart_flush;
+
+       /* Initialize the DART HW */
+       if (dart_init(dn))
+               return;
+
+       /* Setup pci_dma ops */
+       pci_iommu_init();
+
+       /* We only have one iommu table on the mac for now, which makes
+        * things simple. Setup all PCI devices to point to this table
+        */
+       while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               /* We must use pci_device_to_OF_node() to make sure that
+                * we get the real "final" pointer to the device in the
+                * pci_dev sysdata and not the temporary PHB one
+                */
+               struct device_node *dn = pci_device_to_OF_node(dev);
+               if (dn)
+                       dn->iommu_table = &iommu_table_u3;
+       }
+}
+
+void __init alloc_u3_dart_table(void)
+{
+       /* Only reserve DART space if machine has more than 2GB of RAM
+        * or if requested with iommu=on on cmdline.
+        */
+       if (lmb_end_of_DRAM() <= 0x80000000ull && !iommu_force_on)
+               return;
+
+       /* 512 pages (2MB) is max DART tablesize. */
+       dart_tablesize = 1UL << 21;
+       /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we
+        * will blow up an entire large page anyway in the kernel mapping
+        */
+       dart_tablebase = (unsigned long)
+               abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
+
+       printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase);
+}
diff --git a/arch/ppc64/lib/sstep.c b/arch/ppc64/lib/sstep.c
new file mode 100644 (file)
index 0000000..ce9ecc6
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Single-step support.
+ *
+ * Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM
+ *
+ * This 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/ptrace.h>
+#include <asm/sstep.h>
+#include <asm/processor.h>
+
+extern char SystemCall_common[];
+
+/* Bits in SRR1 that are copied from MSR */
+#define MSR_MASK       0xffffffff87c0ffff
+
+/*
+ * Determine whether a conditional branch instruction would branch.
+ */
+static int branch_taken(unsigned int instr, struct pt_regs *regs)
+{
+       unsigned int bo = (instr >> 21) & 0x1f;
+       unsigned int bi;
+
+       if ((bo & 4) == 0) {
+               /* decrement counter */
+               --regs->ctr;
+               if (((bo >> 1) & 1) ^ (regs->ctr == 0))
+                       return 0;
+       }
+       if ((bo & 0x10) == 0) {
+               /* check bit from CR */
+               bi = (instr >> 16) & 0x1f;
+               if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1))
+                       return 0;
+       }
+       return 1;
+}
+
+/*
+ * Emulate instructions that cause a transfer of control.
+ * Returns 1 if the step was emulated, 0 if not,
+ * or -1 if the instruction is one that should not be stepped,
+ * such as an rfid, or a mtmsrd that would clear MSR_RI.
+ */
+int emulate_step(struct pt_regs *regs, unsigned int instr)
+{
+       unsigned int opcode, rd;
+       unsigned long int imm;
+
+       opcode = instr >> 26;
+       switch (opcode) {
+       case 16:        /* bc */
+               imm = (signed short)(instr & 0xfffc);
+               if ((instr & 2) == 0)
+                       imm += regs->nip;
+               regs->nip += 4;
+               if ((regs->msr & MSR_SF) == 0)
+                       regs->nip &= 0xffffffffUL;
+               if (instr & 1)
+                       regs->link = regs->nip;
+               if (branch_taken(instr, regs))
+                       regs->nip = imm;
+               return 1;
+       case 17:        /* sc */
+               /*
+                * N.B. this uses knowledge about how the syscall
+                * entry code works.  If that is changed, this will
+                * need to be changed also.
+                */
+               regs->gpr[9] = regs->gpr[13];
+               regs->gpr[11] = regs->nip + 4;
+               regs->gpr[12] = regs->msr & MSR_MASK;
+               regs->gpr[13] = (unsigned long) get_paca();
+               regs->nip = (unsigned long) &SystemCall_common;
+               regs->msr = MSR_KERNEL;
+               return 1;
+       case 18:        /* b */
+               imm = instr & 0x03fffffc;
+               if (imm & 0x02000000)
+                       imm -= 0x04000000;
+               if ((instr & 2) == 0)
+                       imm += regs->nip;
+               if (instr & 1) {
+                       regs->link = regs->nip + 4;
+                       if ((regs->msr & MSR_SF) == 0)
+                               regs->link &= 0xffffffffUL;
+               }
+               if ((regs->msr & MSR_SF) == 0)
+                       imm &= 0xffffffffUL;
+               regs->nip = imm;
+               return 1;
+       case 19:
+               switch (instr & 0x7fe) {
+               case 0x20:      /* bclr */
+               case 0x420:     /* bcctr */
+                       imm = (instr & 0x400)? regs->ctr: regs->link;
+                       regs->nip += 4;
+                       if ((regs->msr & MSR_SF) == 0) {
+                               regs->nip &= 0xffffffffUL;
+                               imm &= 0xffffffffUL;
+                       }
+                       if (instr & 1)
+                               regs->link = regs->nip;
+                       if (branch_taken(instr, regs))
+                               regs->nip = imm;
+                       return 1;
+               case 0x24:      /* rfid, scary */
+                       return -1;
+               }
+       case 31:
+               rd = (instr >> 21) & 0x1f;
+               switch (instr & 0x7fe) {
+               case 0xa6:      /* mfmsr */
+                       regs->gpr[rd] = regs->msr & MSR_MASK;
+                       regs->nip += 4;
+                       if ((regs->msr & MSR_SF) == 0)
+                               regs->nip &= 0xffffffffUL;
+                       return 1;
+               case 0x164:     /* mtmsrd */
+                       /* only MSR_EE and MSR_RI get changed if bit 15 set */
+                       /* mtmsrd doesn't change MSR_HV and MSR_ME */
+                       imm = (instr & 0x10000)? 0x8002: 0xefffffffffffefffUL;
+                       imm = (regs->msr & MSR_MASK & ~imm)
+                               | (regs->gpr[rd] & imm);
+                       if ((imm & MSR_RI) == 0)
+                               /* can't step mtmsrd that would clear MSR_RI */
+                               return -1;
+                       regs->msr = imm;
+                       regs->nip += 4;
+                       if ((imm & MSR_SF) == 0)
+                               regs->nip &= 0xffffffffUL;
+                       return 1;
+               }
+       }
+       return 0;
+}
diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c
new file mode 100644 (file)
index 0000000..0d8c8ab
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * native hashtable management.
+ *
+ * SMP scalability work:
+ *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * 
+ * This 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/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+
+#include <asm/abs_addr.h>
+#include <asm/machdep.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/tlb.h>
+#include <asm/cputable.h>
+
+#define HPTE_LOCK_BIT 3
+
+static spinlock_t native_tlbie_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void native_lock_hpte(HPTE *hptep)
+{
+       unsigned long *word = &hptep->dw0.dword0;
+
+       while (1) {
+               if (!test_and_set_bit(HPTE_LOCK_BIT, word))
+                       break;
+               while(test_bit(HPTE_LOCK_BIT, word))
+                       cpu_relax();
+       }
+}
+
+static inline void native_unlock_hpte(HPTE *hptep)
+{
+       unsigned long *word = &hptep->dw0.dword0;
+
+       asm volatile("lwsync":::"memory");
+       clear_bit(HPTE_LOCK_BIT, word);
+}
+
+long native_hpte_insert(unsigned long hpte_group, unsigned long va,
+                       unsigned long prpn, int secondary,
+                       unsigned long hpteflags, int bolted, int large)
+{
+       unsigned long arpn = physRpn_to_absRpn(prpn);
+       HPTE *hptep = htab_data.htab + hpte_group;
+       Hpte_dword0 dw0;
+       HPTE lhpte;
+       int i;
+
+       for (i = 0; i < HPTES_PER_GROUP; i++) {
+               dw0 = hptep->dw0.dw0;
+
+               if (!dw0.v) {
+                       /* retry with lock held */
+                       native_lock_hpte(hptep);
+                       dw0 = hptep->dw0.dw0;
+                       if (!dw0.v)
+                               break;
+                       native_unlock_hpte(hptep);
+               }
+
+               hptep++;
+       }
+
+       if (i == HPTES_PER_GROUP)
+               return -1;
+
+       lhpte.dw1.dword1      = 0;
+       lhpte.dw1.dw1.rpn     = arpn;
+       lhpte.dw1.flags.flags = hpteflags;
+
+       lhpte.dw0.dword0      = 0;
+       lhpte.dw0.dw0.avpn    = va >> 23;
+       lhpte.dw0.dw0.h       = secondary;
+       lhpte.dw0.dw0.bolted  = bolted;
+       lhpte.dw0.dw0.v       = 1;
+
+       if (large) {
+               lhpte.dw0.dw0.l = 1;
+               lhpte.dw0.dw0.avpn &= ~0x1UL;
+       }
+
+       hptep->dw1.dword1 = lhpte.dw1.dword1;
+
+       /* Guarantee the second dword is visible before the valid bit */
+       __asm__ __volatile__ ("eieio" : : : "memory");
+
+       /*
+        * Now set the first dword including the valid bit
+        * NOTE: this also unlocks the hpte
+        */
+       hptep->dw0.dword0 = lhpte.dw0.dword0;
+
+       __asm__ __volatile__ ("ptesync" : : : "memory");
+
+       return i | (secondary << 3);
+}
+
+static long native_hpte_remove(unsigned long hpte_group)
+{
+       HPTE *hptep;
+       Hpte_dword0 dw0;
+       int i;
+       int slot_offset;
+
+       /* pick a random entry to start at */
+       slot_offset = mftb() & 0x7;
+
+       for (i = 0; i < HPTES_PER_GROUP; i++) {
+               hptep = htab_data.htab + hpte_group + slot_offset;
+               dw0 = hptep->dw0.dw0;
+
+               if (dw0.v && !dw0.bolted) {
+                       /* retry with lock held */
+                       native_lock_hpte(hptep);
+                       dw0 = hptep->dw0.dw0;
+                       if (dw0.v && !dw0.bolted)
+                               break;
+                       native_unlock_hpte(hptep);
+               }
+
+               slot_offset++;
+               slot_offset &= 0x7;
+       }
+
+       if (i == HPTES_PER_GROUP)
+               return -1;
+
+       /* Invalidate the hpte. NOTE: this also unlocks it */
+       hptep->dw0.dword0 = 0;
+
+       return i;
+}
+
+static inline void set_pp_bit(unsigned long pp, HPTE *addr)
+{
+       unsigned long old;
+       unsigned long *p = &addr->dw1.dword1;
+
+       __asm__ __volatile__(
+       "1:     ldarx   %0,0,%3\n\
+               rldimi  %0,%2,0,61\n\
+               stdcx.  %0,0,%3\n\
+               bne     1b"
+       : "=&r" (old), "=m" (*p)
+       : "r" (pp), "r" (p), "m" (*p)
+       : "cc");
+}
+
+/*
+ * Only works on small pages. Yes its ugly to have to check each slot in
+ * the group but we only use this during bootup.
+ */
+static long native_hpte_find(unsigned long vpn)
+{
+       HPTE *hptep;
+       unsigned long hash;
+       unsigned long i, j;
+       long slot;
+       Hpte_dword0 dw0;
+
+       hash = hpt_hash(vpn, 0);
+
+       for (j = 0; j < 2; j++) {
+               slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+               for (i = 0; i < HPTES_PER_GROUP; i++) {
+                       hptep = htab_data.htab + slot;
+                       dw0 = hptep->dw0.dw0;
+
+                       if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+                           (dw0.h == j)) {
+                               /* HPTE matches */
+                               if (j)
+                                       slot = -slot;
+                               return slot;
+                       }
+                       ++slot;
+               }
+               hash = ~hash;
+       }
+
+       return -1;
+}
+
+static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
+                                unsigned long va, int large, int local)
+{
+       HPTE *hptep = htab_data.htab + slot;
+       Hpte_dword0 dw0;
+       unsigned long avpn = va >> 23;
+       int ret = 0;
+
+       if (large)
+               avpn &= ~0x1UL;
+
+       native_lock_hpte(hptep);
+
+       dw0 = hptep->dw0.dw0;
+
+       /* Even if we miss, we need to invalidate the TLB */
+       if ((dw0.avpn != avpn) || !dw0.v) {
+               native_unlock_hpte(hptep);
+               ret = -1;
+       } else {
+               set_pp_bit(newpp, hptep);
+               native_unlock_hpte(hptep);
+       }
+
+       /* Ensure it is out of the tlb too */
+       if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) {
+               tlbiel(va);
+       } else {
+               int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+
+               if (lock_tlbie)
+                       spin_lock(&native_tlbie_lock);
+               tlbie(va, large);
+               if (lock_tlbie)
+                       spin_unlock(&native_tlbie_lock);
+       }
+
+       return ret;
+}
+
+/*
+ * Update the page protection bits. Intended to be used to create
+ * guard pages for kernel data structures on pages which are bolted
+ * in the HPT. Assumes pages being operated on will not be stolen.
+ * Does not work on large pages.
+ *
+ * No need to lock here because we should be the only user.
+ */
+static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
+{
+       unsigned long vsid, va, vpn, flags;
+       long slot;
+       HPTE *hptep;
+       int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+
+       vsid = get_kernel_vsid(ea);
+       va = (vsid << 28) | (ea & 0x0fffffff);
+       vpn = va >> PAGE_SHIFT;
+
+       slot = native_hpte_find(vpn);
+       if (slot == -1)
+               panic("could not find page to bolt\n");
+       hptep = htab_data.htab + slot;
+
+       set_pp_bit(newpp, hptep);
+
+       /* Ensure it is out of the tlb too */
+       if (lock_tlbie)
+               spin_lock_irqsave(&native_tlbie_lock, flags);
+       tlbie(va, 0);
+       if (lock_tlbie)
+               spin_unlock_irqrestore(&native_tlbie_lock, flags);
+}
+
+static void native_hpte_invalidate(unsigned long slot, unsigned long va,
+                                   int large, int local)
+{
+       HPTE *hptep = htab_data.htab + slot;
+       Hpte_dword0 dw0;
+       unsigned long avpn = va >> 23;
+       unsigned long flags;
+       int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+
+       if (large)
+               avpn &= ~0x1UL;
+
+       local_irq_save(flags);
+       native_lock_hpte(hptep);
+
+       dw0 = hptep->dw0.dw0;
+
+       /* Even if we miss, we need to invalidate the TLB */
+       if ((dw0.avpn != avpn) || !dw0.v) {
+               native_unlock_hpte(hptep);
+       } else {
+               /* Invalidate the hpte. NOTE: this also unlocks it */
+               hptep->dw0.dword0 = 0;
+       }
+
+       /* Invalidate the tlb */
+       if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) {
+               tlbiel(va);
+       } else {
+               if (lock_tlbie)
+                       spin_lock(&native_tlbie_lock);
+               tlbie(va, large);
+               if (lock_tlbie)
+                       spin_unlock(&native_tlbie_lock);
+       }
+       local_irq_restore(flags);
+}
+
+static void native_flush_hash_range(unsigned long context,
+                                   unsigned long number, int local)
+{
+       unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn;
+       int i, j;
+       HPTE *hptep;
+       Hpte_dword0 dw0;
+       struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+
+       /* XXX fix for large ptes */
+       unsigned long large = 0;
+
+       local_irq_save(flags);
+
+       j = 0;
+       for (i = 0; i < number; i++) {
+               if ((batch->addr[i] >= USER_START) &&
+                   (batch->addr[i] <= USER_END))
+                       vsid = get_vsid(context, batch->addr[i]);
+               else
+                       vsid = get_kernel_vsid(batch->addr[i]);
+
+               va = (vsid << 28) | (batch->addr[i] & 0x0fffffff);
+               batch->vaddr[j] = va;
+               if (large)
+                       vpn = va >> HPAGE_SHIFT;
+               else
+                       vpn = va >> PAGE_SHIFT;
+               hash = hpt_hash(vpn, large);
+               secondary = (pte_val(batch->pte[i]) & _PAGE_SECONDARY) >> 15;
+               if (secondary)
+                       hash = ~hash;
+               slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+               slot += (pte_val(batch->pte[i]) & _PAGE_GROUP_IX) >> 12;
+
+               hptep = htab_data.htab + slot;
+
+               avpn = va >> 23;
+               if (large)
+                       avpn &= ~0x1UL;
+
+               native_lock_hpte(hptep);
+
+               dw0 = hptep->dw0.dw0;
+
+               /* Even if we miss, we need to invalidate the TLB */
+               if ((dw0.avpn != avpn) || !dw0.v) {
+                       native_unlock_hpte(hptep);
+               } else {
+                       /* Invalidate the hpte. NOTE: this also unlocks it */
+                       hptep->dw0.dword0 = 0;
+               }
+
+               j++;
+       }
+
+       if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) {
+               asm volatile("ptesync":::"memory");
+
+               for (i = 0; i < j; i++)
+                       __tlbiel(batch->vaddr[i]);
+
+               asm volatile("ptesync":::"memory");
+       } else {
+               int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);
+
+               if (lock_tlbie)
+                       spin_lock(&native_tlbie_lock);
+
+               asm volatile("ptesync":::"memory");
+
+               for (i = 0; i < j; i++)
+                       __tlbie(batch->vaddr[i], 0);
+
+               asm volatile("eieio; tlbsync; ptesync":::"memory");
+
+               if (lock_tlbie)
+                       spin_unlock(&native_tlbie_lock);
+       }
+
+       local_irq_restore(flags);
+}
+
+void hpte_init_native(void)
+{
+#ifdef CONFIG_PPC_PSERIES
+       struct device_node *root;
+       const char *model;
+#endif /* CONFIG_PPC_PSERIES */
+
+       ppc_md.hpte_invalidate  = native_hpte_invalidate;
+       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;
+
+#ifdef CONFIG_PPC_PSERIES
+       /* Disable TLB batching on nighthawk */
+       root = of_find_node_by_path("/");
+       if (root) {
+               model = get_property(root, "model", NULL);
+               if (!strcmp(model, "CHRP IBM,9076-N81")) {
+                       of_node_put(root);
+                       goto bail;
+               }
+               of_node_put(root);
+       }
+#endif /* CONFIG_PPC_PSERIES */
+
+       ppc_md.flush_hash_range = native_flush_hash_range;
+ bail:
+       htab_finish_init();
+}
diff --git a/arch/ppc64/mm/stab.c b/arch/ppc64/mm/stab.c
new file mode 100644 (file)
index 0000000..9b4fe8a
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * PowerPC64 Segment Translation Support.
+ *
+ * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
+ *    Copyright (c) 2001 Dave Engebretsen
+ *
+ * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ *      This 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 <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/paca.h>
+#include <asm/naca.h>
+#include <asm/cputable.h>
+
+/* Both the segment table and SLB code uses the following cache */
+#define NR_STAB_CACHE_ENTRIES 8
+DEFINE_PER_CPU(long, stab_cache_ptr);
+DEFINE_PER_CPU(long, stab_cache[NR_STAB_CACHE_ENTRIES]);
+
+/*
+ * Create a segment table entry for the given esid/vsid pair.
+ */
+static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
+{
+       unsigned long esid_data, vsid_data;
+       unsigned long entry, group, old_esid, castout_entry, i;
+       unsigned int global_entry;
+       struct stab_entry *ste, *castout_ste;
+       unsigned long kernel_segment = (esid << SID_SHIFT) >= KERNELBASE;
+
+       vsid_data = vsid << STE_VSID_SHIFT;
+       esid_data = esid << SID_SHIFT | STE_ESID_KP | STE_ESID_V;
+       if (! kernel_segment)
+               esid_data |= STE_ESID_KS;
+
+       /* Search the primary group first. */
+       global_entry = (esid & 0x1f) << 3;
+       ste = (struct stab_entry *)(stab | ((esid & 0x1f) << 7));
+
+       /* Find an empty entry, if one exists. */
+       for (group = 0; group < 2; group++) {
+               for (entry = 0; entry < 8; entry++, ste++) {
+                       if (!(ste->esid_data & STE_ESID_V)) {
+                               ste->vsid_data = vsid_data;
+                               asm volatile("eieio":::"memory");
+                               ste->esid_data = esid_data;
+                               return (global_entry | entry);
+                       }
+               }
+               /* Now search the secondary group. */
+               global_entry = ((~esid) & 0x1f) << 3;
+               ste = (struct stab_entry *)(stab | (((~esid) & 0x1f) << 7));
+       }
+
+       /*
+        * Could not find empty entry, pick one with a round robin selection.
+        * Search all entries in the two groups.
+        */
+       castout_entry = get_paca()->stab_rr;
+       for (i = 0; i < 16; i++) {
+               if (castout_entry < 8) {
+                       global_entry = (esid & 0x1f) << 3;
+                       ste = (struct stab_entry *)(stab | ((esid & 0x1f) << 7));
+                       castout_ste = ste + castout_entry;
+               } else {
+                       global_entry = ((~esid) & 0x1f) << 3;
+                       ste = (struct stab_entry *)(stab | (((~esid) & 0x1f) << 7));
+                       castout_ste = ste + (castout_entry - 8);
+               }
+
+               /* Dont cast out the first kernel segment */
+               if ((castout_ste->esid_data & ESID_MASK) != KERNELBASE)
+                       break;
+
+               castout_entry = (castout_entry + 1) & 0xf;
+       }
+
+       get_paca()->stab_rr = (castout_entry + 1) & 0xf;
+
+       /* Modify the old entry to the new value. */
+
+       /* Force previous translations to complete. DRENG */
+       asm volatile("isync" : : : "memory");
+
+       old_esid = castout_ste->esid_data >> SID_SHIFT;
+       castout_ste->esid_data = 0;             /* Invalidate old entry */
+
+       asm volatile("sync" : : : "memory");    /* Order update */
+
+       castout_ste->vsid_data = vsid_data;
+       asm volatile("eieio" : : : "memory");   /* Order update */
+       castout_ste->esid_data = esid_data;
+
+       asm volatile("slbie  %0" : : "r" (old_esid << SID_SHIFT));
+       /* Ensure completion of slbie */
+       asm volatile("sync" : : : "memory");
+
+       return (global_entry | (castout_entry & 0x7));
+}
+
+/*
+ * Allocate a segment table entry for the given ea and mm
+ */
+static int __ste_allocate(unsigned long ea, struct mm_struct *mm)
+{
+       unsigned long vsid;
+       unsigned char stab_entry;
+       unsigned long offset;
+
+       /* Kernel or user address? */
+       if (ea >= KERNELBASE) {
+               vsid = get_kernel_vsid(ea);
+       } else {
+               if ((ea >= TASK_SIZE_USER64) || (! mm))
+                       return 1;
+
+               vsid = get_vsid(mm->context.id, ea);
+       }
+
+       stab_entry = make_ste(get_paca()->stab_addr, GET_ESID(ea), vsid);
+
+       if (ea < KERNELBASE) {
+               offset = __get_cpu_var(stab_cache_ptr);
+               if (offset < NR_STAB_CACHE_ENTRIES)
+                       __get_cpu_var(stab_cache[offset++]) = stab_entry;
+               else
+                       offset = NR_STAB_CACHE_ENTRIES+1;
+               __get_cpu_var(stab_cache_ptr) = offset;
+
+               /* Order update */
+               asm volatile("sync":::"memory");
+       }
+
+       return 0;
+}
+
+int ste_allocate(unsigned long ea)
+{
+       return __ste_allocate(ea, current->mm);
+}
+
+/*
+ * Do the segment table work for a context switch: flush all user
+ * entries from the table, then preload some probably useful entries
+ * for the new task
+ */
+void switch_stab(struct task_struct *tsk, struct mm_struct *mm)
+{
+       struct stab_entry *stab = (struct stab_entry *) get_paca()->stab_addr;
+       struct stab_entry *ste;
+       unsigned long offset = __get_cpu_var(stab_cache_ptr);
+       unsigned long pc = KSTK_EIP(tsk);
+       unsigned long stack = KSTK_ESP(tsk);
+       unsigned long unmapped_base;
+
+       /* Force previous translations to complete. DRENG */
+       asm volatile("isync" : : : "memory");
+
+       if (offset <= NR_STAB_CACHE_ENTRIES) {
+               int i;
+
+               for (i = 0; i < offset; i++) {
+                       ste = stab + __get_cpu_var(stab_cache[i]);
+                       ste->esid_data = 0; /* invalidate entry */
+               }
+       } else {
+               unsigned long entry;
+
+               /* Invalidate all entries. */
+               ste = stab;
+
+               /* Never flush the first entry. */
+               ste += 1;
+               for (entry = 1;
+                    entry < (PAGE_SIZE / sizeof(struct stab_entry));
+                    entry++, ste++) {
+                       unsigned long ea;
+                       ea = ste->esid_data & ESID_MASK;
+                       if (ea < KERNELBASE) {
+                               ste->esid_data = 0;
+                       }
+               }
+       }
+
+       asm volatile("sync; slbia; sync":::"memory");
+
+       __get_cpu_var(stab_cache_ptr) = 0;
+
+       /* Now preload some entries for the new task */
+       if (test_tsk_thread_flag(tsk, TIF_32BIT))
+               unmapped_base = TASK_UNMAPPED_BASE_USER32;
+       else
+               unmapped_base = TASK_UNMAPPED_BASE_USER64;
+
+       __ste_allocate(pc, mm);
+
+       if (GET_ESID(pc) == GET_ESID(stack))
+               return;
+
+       __ste_allocate(stack, mm);
+
+       if ((GET_ESID(pc) == GET_ESID(unmapped_base))
+           || (GET_ESID(stack) == GET_ESID(unmapped_base)))
+               return;
+
+       __ste_allocate(unmapped_base, mm);
+
+       /* Order update */
+       asm volatile("sync" : : : "memory");
+}
+
+extern void slb_initialize(void);
+
+/*
+ * Build an entry for the base kernel segment and put it into
+ * the segment table or SLB.  All other segment table or SLB
+ * entries are faulted in.
+ */
+void stab_initialize(unsigned long stab)
+{
+       unsigned long vsid = get_kernel_vsid(KERNELBASE);
+
+       if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
+               slb_initialize();
+       } else {
+               asm volatile("isync; slbia; isync":::"memory");
+               make_ste(stab, GET_ESID(KERNELBASE), vsid);
+
+               /* Order update */
+               asm volatile("sync":::"memory");
+       }
+}
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
new file mode 100644 (file)
index 0000000..f53b6d5
--- /dev/null
@@ -0,0 +1,5 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+endmenu
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
new file mode 100644 (file)
index 0000000..79a4222
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  arch/s390/kernel/irq.c
+ *
+ *  S390 version
+ *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * This file contains interrupt related functions.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+
+/*
+ * show_interrupts is needed by /proc/interrupts.
+ */
+int show_interrupts(struct seq_file *p, void *v)
+{
+       static const char *intrclass_names[] = { "EXT", "I/O", };
+       int i = *(loff_t *) v, j;
+
+       if (i == 0) {
+               seq_puts(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) {
+               seq_printf(p, "%s: ", intrclass_names[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_putc(p, '\n');
+
+        }
+
+        return 0;
+}
+
+/*
+ * For compatibilty only. S/390 specific setup of interrupts et al. is done
+ * much later in init_channel_subsystem().
+ */
+void __init
+init_IRQ(void)
+{
+       /* nothing... */
+}
+
+/*
+ * Switch to the asynchronous interrupt stack for softirq execution.
+ */
+extern void __do_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+       unsigned long flags, old, new;
+
+       if (in_interrupt())
+               return;
+
+       local_irq_save(flags);
+
+       if (local_softirq_pending()) {
+               /* Get current stack pointer. */
+               asm volatile("la %0,0(15)" : "=a" (old));
+               /* Check against async. stack address range. */
+               new = S390_lowcore.async_stack;
+               if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) {
+                       /* Need to switch to the async. stack. */
+                       new -= STACK_FRAME_OVERHEAD;
+                       ((struct stack_frame *) new)->back_chain = old;
+
+                       asm volatile("   la    15,0(%0)\n"
+                                    "   basr  14,%2\n"
+                                    "   la    15,0(%1)\n"
+                                    : : "a" (new), "a" (old),
+                                        "a" (__do_softirq)
+                                    : "0", "1", "2", "3", "4", "5",
+                                      "cc", "memory" );
+               } else
+                       /* We are already on the async stack. */
+                       __do_softirq();
+       }
+
+       local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(do_softirq);
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
new file mode 100644 (file)
index 0000000..3fab181
--- /dev/null
@@ -0,0 +1,124 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config SH_STANDARD_BIOS
+       bool "Use LinuxSH standard BIOS"
+       help
+         Say Y here if your target has the gdb-sh-stub
+         package from www.m17n.org (or any conforming standard LinuxSH BIOS)
+         in FLASH or EPROM.  The kernel will use standard BIOS calls during
+         boot for various housekeeping tasks (including calls to read and
+         write characters to a system console, get a MAC address from an
+         on-board Ethernet interface, and shut down the hardware).  Note this
+         does not work with machines with an existing operating system in
+         mask ROM and no flash (WindowsCE machines fall in this category).
+         If unsure, say N.
+
+config EARLY_SCIF_CONSOLE
+       bool "Use early SCIF console"
+       depends on CPU_SH4
+
+config EARLY_PRINTK
+       bool "Early printk support"
+       depends on SH_STANDARD_BIOS || EARLY_SCIF_CONSOLE
+       help
+         Say Y here to redirect kernel printk messages to the serial port
+         used by the SH-IPL bootloader, starting very early in the boot
+         process and ending when the kernel's serial console is initialised.
+         This option is only useful porting the kernel to a new machine,
+         when the kernel may crash or hang before the serial console is
+         initialised. If unsure, say N.
+
+config KGDB
+       bool "Include KGDB kernel debugger"
+       help
+         Include in-kernel hooks for kgdb, the Linux kernel source level
+         debugger.  See <http://kgdb.sourceforge.net/> for more information.
+         Unless you are intending to debug the kernel, say N here.
+
+menu "KGDB configuration options"
+       depends on KGDB
+
+config MORE_COMPILE_OPTIONS
+       bool "Add any additional compile options"
+       help
+         If you want to add additional CFLAGS to the kernel build, enable this
+         option and then enter what you would like to add in the next question.
+         Note however that -g is already appended with the selection of KGDB.
+
+config COMPILE_OPTIONS
+       string "Additional compile arguments"
+       depends on MORE_COMPILE_OPTIONS
+
+config KGDB_NMI
+       bool "Enter KGDB on NMI"
+       default n
+
+config KGDB_THREAD
+       bool "Include KGDB thread support"
+       default y
+
+config SH_KGDB_CONSOLE
+       bool "Console messages through GDB"
+       default n
+
+config KGDB_SYSRQ
+       bool "Allow SysRq 'G' to enter KGDB"
+       default y
+
+config KGDB_KERNEL_ASSERTS
+       bool "Include KGDB kernel assertions"
+       default n
+
+comment "Serial port setup"
+
+config KGDB_DEFPORT
+       int "Port number (ttySCn)"
+       default "1"
+
+config KGDB_DEFBAUD
+       int "Baud rate"
+       default "115200"
+
+choice
+       prompt "Parity"
+       depends on KGDB
+       default KGDB_DEFPARITY_N
+
+config KGDB_DEFPARITY_N
+       bool "None"
+
+config KGDB_DEFPARITY_E
+       bool "Even"
+
+config KGDB_DEFPARITY_O
+       bool "Odd"
+
+endchoice
+
+choice
+       prompt "Data bits"
+       depends on KGDB
+       default KGDB_DEFBITS_8
+
+config KGDB_DEFBITS_8
+       bool "8"
+
+config KGDB_DEFBITS_7
+       bool "7"
+
+endchoice
+
+endmenu
+
+config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       default y if KGDB
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         and slower, but it will give very useful debugging information.
+         If you don't debug the kernel, you can say N, but we may not be able
+         to solve problems without frame pointers.
+
+endmenu
diff --git a/arch/sh/boards/renesas/edosk7705/Makefile b/arch/sh/boards/renesas/edosk7705/Makefile
new file mode 100644 (file)
index 0000000..7fccbf2
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the EDOSK7705 specific parts of the kernel
+#
+# 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).
+#
+
+obj-y   := setup.o io.o
+
diff --git a/arch/sh/boards/renesas/edosk7705/io.c b/arch/sh/boards/renesas/edosk7705/io.c
new file mode 100644 (file)
index 0000000..541cea2
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/io.c
+ *
+ * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routines for Hitachi EDOSK7705 board.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/edosk7705/io.h>
+#include <asm/addrspace.h>
+
+#define SMC_IOADDR     0xA2000000
+
+#define maybebadio(name,port) \
+  printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+        #name, (port), (__u32) __builtin_return_address(0))
+
+/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
+unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
+{
+     if (port >= 0x300 && port < 0x320) {
+         /* SMC91C96 registers are 4 byte aligned rather than the
+          * usual 2 byte!
+          */
+         return SMC_IOADDR + ( (port - 0x300) * 2);
+     }
+
+     maybebadio(sh_edosk7705_isa_port2addr, port);
+     return port;
+}
+
+/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
+ * registers causes problems. So we bit-shift the value and read / write
+ * in 2 byte chunks. Setting the low byte to 0 does not cause problems
+ * now as odd byte writes are only made on the bit mask / interrupt
+ * register. This may not be the case in future Mar-2003 SJD
+ */
+unsigned char sh_edosk7705_inb(unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320 && port & 0x01) {
+               return (volatile unsigned char)(generic_inw(port -1) >> 8);
+       }
+       return *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port);
+}
+
+unsigned int sh_edosk7705_inl(unsigned long port)
+{
+       return *(volatile unsigned long *)port;
+}
+
+void sh_edosk7705_outb(unsigned char value, unsigned long port)
+{
+       if (port >= 0x300 && port < 0x320 && port & 0x01) {
+               generic_outw(((unsigned short)value << 8), port -1);
+               return;
+       }
+       *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port) = value;
+}
+
+void sh_edosk7705_outl(unsigned int value, unsigned long port)
+{
+       *(volatile unsigned long *)port = value;
+}
+
+void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
+{
+       unsigned char *p = addr;
+       while (count--) *p++ = sh_edosk7705_inb(port);
+}
+
+void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count)
+{
+       unsigned long *p = (unsigned long*)addr;
+       while (count--)
+               *p++ = *(volatile unsigned long *)port;
+}
+
+void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+       unsigned char *p = (unsigned char*)addr;
+       while (count--) sh_edosk7705_outb(*p++, port);
+}
+
+void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+       unsigned long *p = (unsigned long*)addr;
+       while (count--) sh_edosk7705_outl(*p++, port);
+}
+
diff --git a/arch/sh/boards/renesas/edosk7705/setup.c b/arch/sh/boards/renesas/edosk7705/setup.c
new file mode 100644 (file)
index 0000000..8b6f0c2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000  Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/edosk7705/io.h>
+
+static void init_edosk7705(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_edosk7705 __initmv = {
+       .mv_nr_irqs             = 80,
+
+       .mv_inb                 = sh_edosk7705_inb,
+       .mv_inl                 = sh_edosk7705_inl,
+       .mv_outb                = sh_edosk7705_outb,
+       .mv_outl                = sh_edosk7705_outl,
+
+       .mv_inl_p               = sh_edosk7705_inl,
+       .mv_outl_p              = sh_edosk7705_outl,
+
+       .mv_insb                = sh_edosk7705_insb,
+       .mv_insl                = sh_edosk7705_insl,
+       .mv_outsb               = sh_edosk7705_outsb,
+       .mv_outsl               = sh_edosk7705_outsl,
+
+       .mv_isa_port2addr       = sh_edosk7705_isa_port2addr,
+       .mv_init_irq            = init_edosk7705,
+};
+ALIAS_MV(edosk7705)
+
+static void __init init_edosk7705(void)
+{
+       /* This is the Ethernet interrupt */
+       make_imask_irq(0x09);
+}
+
+const char *get_system_type(void)
+{
+       return "EDOSK7705";
+}
+
+void __init platform_setup(void)
+{
+       /* Nothing .. */
+}
+
diff --git a/arch/sh/boards/se/73180/Makefile b/arch/sh/boards/se/73180/Makefile
new file mode 100644 (file)
index 0000000..8f63886
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the 73180 SolutionEngine specific parts of the kernel
+#
+
+obj-y   := setup.o io.o irq.o
+
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/se/73180/io.c b/arch/sh/boards/se/73180/io.c
new file mode 100644 (file)
index 0000000..73648cb
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * arch/sh/boards/se/73180/io.c
+ *
+ * Copyright (C) 2003 YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/boards/se/7300/io.c
+ *
+ * I/O routine for SH-Mobile3 73180 SolutionEngine.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/mach/se73180.h>
+#include <asm/io.h>
+
+#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
+
+struct iop {
+       unsigned long start, end;
+       unsigned long base;
+       struct iop *(*check) (struct iop * p, unsigned long port);
+       unsigned char (*inb) (struct iop * p, unsigned long port);
+       unsigned short (*inw) (struct iop * p, unsigned long port);
+       void (*outb) (struct iop * p, unsigned char value, unsigned long port);
+       void (*outw) (struct iop * p, unsigned short value, unsigned long port);
+};
+
+struct iop *
+simple_check(struct iop *p, unsigned long port)
+{
+       if ((p->start <= port) && (port <= p->end))
+               return p;
+       else
+               badio(check, port);
+}
+
+struct iop *
+ide_check(struct iop *p, unsigned long port)
+{
+       if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
+               return p;
+       return NULL;
+}
+
+unsigned char
+simple_inb(struct iop *p, unsigned long port)
+{
+       return *(unsigned char *) (p->base + port);
+}
+
+unsigned short
+simple_inw(struct iop *p, unsigned long port)
+{
+       return *(unsigned short *) (p->base + port);
+}
+
+void
+simple_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+       *(unsigned char *) (p->base + port) = value;
+}
+
+void
+simple_outw(struct iop *p, unsigned short value, unsigned long port)
+{
+       *(unsigned short *) (p->base + port) = value;
+}
+
+unsigned char
+pcc_inb(struct iop *p, unsigned long port)
+{
+       unsigned long addr = p->base + port + 0x40000;
+       unsigned long v;
+
+       if (port & 1)
+               addr += 0x00400000;
+       v = *(volatile unsigned char *) addr;
+       return v;
+}
+
+void
+pcc_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+       unsigned long addr = p->base + port + 0x40000;
+
+       if (port & 1)
+               addr += 0x00400000;
+       *(volatile unsigned char *) addr = value;
+}
+
+unsigned char
+bad_inb(struct iop *p, unsigned long port)
+{
+       badio(inb, port);
+}
+
+void
+bad_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+       badio(inw, port);
+}
+
+/* MSTLANEX01 LAN at 0xb400:0000 */
+static struct iop laniop = {
+       .start = 0x300,
+       .end = 0x30f,
+       .base = 0xb4000000,
+       .check = simple_check,
+       .inb = simple_inb,
+       .inw = simple_inw,
+       .outb = simple_outb,
+       .outw = simple_outw,
+};
+
+/* NE2000 pc card NIC */
+static struct iop neiop = {
+       .start = 0x280,
+       .end = 0x29f,
+       .base = 0xb0600000 + 0x80,      /* soft 0x280 -> hard 0x300 */
+       .check = simple_check,
+       .inb = pcc_inb,
+       .inw = simple_inw,
+       .outb = pcc_outb,
+       .outw = simple_outw,
+};
+
+/* CF in CF slot */
+static struct iop cfiop = {
+       .base = 0xb0600000,
+       .check = ide_check,
+       .inb = pcc_inb,
+       .inw = simple_inw,
+       .outb = pcc_outb,
+       .outw = simple_outw,
+};
+
+static __inline__ struct iop *
+port2iop(unsigned long port)
+{
+       if (0) ;
+#if defined(CONFIG_SMC91111)
+       else if (laniop.check(&laniop, port))
+               return &laniop;
+#endif
+#if defined(CONFIG_NE2000)
+       else if (neiop.check(&neiop, port))
+               return &neiop;
+#endif
+#if defined(CONFIG_IDE)
+       else if (cfiop.check(&cfiop, port))
+               return &cfiop;
+#endif
+       else
+               return &neiop;  /* fallback */
+}
+
+static inline void
+delay(void)
+{
+       ctrl_inw(0xac000000);
+       ctrl_inw(0xac000000);
+}
+
+unsigned char
+sh73180se_inb(unsigned long port)
+{
+       struct iop *p = port2iop(port);
+       return (p->inb) (p, port);
+}
+
+unsigned char
+sh73180se_inb_p(unsigned long port)
+{
+       unsigned char v = sh73180se_inb(port);
+       delay();
+       return v;
+}
+
+unsigned short
+sh73180se_inw(unsigned long port)
+{
+       struct iop *p = port2iop(port);
+       return (p->inw) (p, port);
+}
+
+unsigned int
+sh73180se_inl(unsigned long port)
+{
+       badio(inl, port);
+}
+
+void
+sh73180se_outb(unsigned char value, unsigned long port)
+{
+       struct iop *p = port2iop(port);
+       (p->outb) (p, value, port);
+}
+
+void
+sh73180se_outb_p(unsigned char value, unsigned long port)
+{
+       sh73180se_outb(value, port);
+       delay();
+}
+
+void
+sh73180se_outw(unsigned short value, unsigned long port)
+{
+       struct iop *p = port2iop(port);
+       (p->outw) (p, value, port);
+}
+
+void
+sh73180se_outl(unsigned int value, unsigned long port)
+{
+       badio(outl, port);
+}
+
+void
+sh73180se_insb(unsigned long port, void *addr, unsigned long count)
+{
+       unsigned char *a = addr;
+       struct iop *p = port2iop(port);
+       while (count--)
+               *a++ = (p->inb) (p, port);
+}
+
+void
+sh73180se_insw(unsigned long port, void *addr, unsigned long count)
+{
+       unsigned short *a = addr;
+       struct iop *p = port2iop(port);
+       while (count--)
+               *a++ = (p->inw) (p, port);
+}
+
+void
+sh73180se_insl(unsigned long port, void *addr, unsigned long count)
+{
+       badio(insl, port);
+}
+
+void
+sh73180se_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+       unsigned char *a = (unsigned char *) addr;
+       struct iop *p = port2iop(port);
+       while (count--)
+               (p->outb) (p, *a++, port);
+}
+
+void
+sh73180se_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+       unsigned short *a = (unsigned short *) addr;
+       struct iop *p = port2iop(port);
+       while (count--)
+               (p->outw) (p, *a++, port);
+}
+
+void
+sh73180se_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+       badio(outsw, port);
+}
diff --git a/arch/sh/boards/se/73180/irq.c b/arch/sh/boards/se/73180/irq.c
new file mode 100644 (file)
index 0000000..70f04ca
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * arch/sh/boards/se/73180/irq.c
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/boards/se/7300/irq.c
+ *
+ * Modified for SH-Mobile SolutionEngine 73180 Support
+ *              by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/se73180.h>
+
+static int
+intreq2irq(int i)
+{
+       if (i == 5)
+               return 10;
+       return 32 + 7 - i;
+}
+
+static int
+irq2intreq(int irq)
+{
+       if (irq == 10)
+               return 5;
+       return 7 - (irq - 32);
+}
+
+static void
+disable_intreq_irq(unsigned int irq)
+{
+       ctrl_outb(1 << (7 - irq2intreq(irq)), INTMSK0);
+}
+
+static void
+enable_intreq_irq(unsigned int irq)
+{
+       ctrl_outb(1 << (7 - irq2intreq(irq)), INTMSKCLR0);
+}
+
+static void
+mask_and_ack_intreq_irq(unsigned int irq)
+{
+       disable_intreq_irq(irq);
+}
+
+static unsigned int
+startup_intreq_irq(unsigned int irq)
+{
+       enable_intreq_irq(irq);
+       return 0;
+}
+
+static void
+shutdown_intreq_irq(unsigned int irq)
+{
+       disable_intreq_irq(irq);
+}
+
+static void
+end_intreq_irq(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               enable_intreq_irq(irq);
+}
+
+static struct hw_interrupt_type intreq_irq_type = {
+       .typename = "intreq",
+       .startup = startup_intreq_irq,
+       .shutdown = shutdown_intreq_irq,
+       .enable = enable_intreq_irq,
+       .disable = disable_intreq_irq,
+       .ack = mask_and_ack_intreq_irq,
+       .end = end_intreq_irq
+};
+
+void
+make_intreq_irq(unsigned int irq)
+{
+       disable_irq_nosync(irq);
+       irq_desc[irq].handler = &intreq_irq_type;
+       disable_intreq_irq(irq);
+}
+
+int
+shmse_irq_demux(int irq)
+{
+       if (irq == IRQ5_IRQ)
+               return 10;
+       return irq;
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init
+init_73180se_IRQ(void)
+{
+       make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+
+       ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+       ctrl_outw(0x2000, 0xb07fffec);  /* mrshpc irq enable */
+       ctrl_outl(3 << ((7 - 5) * 4), INTC_INTPRI0);    /* irq5 pri=3 */
+       ctrl_outw(2 << ((7 - 5) * 2), INTC_ICR1);       /* low-level irq */
+       make_intreq_irq(10);
+
+       make_ipr_irq(VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8);
+
+       ctrl_outb(0x0f, INTC_IMCR5);    /* enable SCIF IRQ */
+
+       make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+       make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+       make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+       make_ipr_irq(IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+       make_ipr_irq(IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+                    IIC0_PRIORITY);
+       make_ipr_irq(IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+                    IIC0_PRIORITY);
+       make_ipr_irq(IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+       make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+       make_ipr_irq(SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY);
+
+       /* VIO interrupt */
+       make_ipr_irq(CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+       make_ipr_irq(BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+       make_ipr_irq(VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+
+       make_ipr_irq(LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY);
+       ctrl_outw(0x2000, PA_MRSHPC + 0x0c);    /* mrshpc irq enable */
+}
diff --git a/arch/sh/boards/se/73180/led.c b/arch/sh/boards/se/73180/led.c
new file mode 100644 (file)
index 0000000..1e8f1cf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * arch/sh/boards/se/73180/led.c
+ *
+ * Derived from arch/sh/boards/se/770x/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/mach/se73180.h>
+
+static void
+mach_led(int position, int value)
+{
+       volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+
+       if (value) {
+               *p |= (1 << LED_SHIFT);
+       } else {
+               *p &= ~(1 << LED_SHIFT);
+       }
+}
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void
+heartbeat_73180se(void)
+{
+       static unsigned int cnt = 0, period = 0;
+       volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+       static unsigned bit = 0, up = 1;
+
+       cnt += 1;
+       if (cnt < period) {
+               return;
+       }
+
+       cnt = 0;
+
+       /* Go through the points (roughly!):
+        * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+        */
+       period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT)));
+
+       if (up) {
+               if (bit == 7) {
+                       bit--;
+                       up = 0;
+               } else {
+                       bit++;
+               }
+       } else {
+               if (bit == 0) {
+                       bit++;
+                       up = 1;
+               } else {
+                       bit--;
+               }
+       }
+       *p = 1 << (bit + LED_SHIFT);
+
+}
diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c
new file mode 100644 (file)
index 0000000..07fa90c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * arch/sh/boards/se/73180/setup.c
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/setup_shmse.c
+ *
+ * Modified for 73180 SolutionEngine
+ *           by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/mach/io.h>
+
+void heartbeat_73180se(void);
+void init_73180se_IRQ(void);
+
+const char *
+get_system_type(void)
+{
+       return "SolutionEngine 73180";
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_73180se __initmv = {
+       .mv_nr_irqs = 108,
+       .mv_inb = sh73180se_inb,
+       .mv_inw = sh73180se_inw,
+       .mv_inl = sh73180se_inl,
+       .mv_outb = sh73180se_outb,
+       .mv_outw = sh73180se_outw,
+       .mv_outl = sh73180se_outl,
+
+       .mv_inb_p = sh73180se_inb_p,
+       .mv_inw_p = sh73180se_inw,
+       .mv_inl_p = sh73180se_inl,
+       .mv_outb_p = sh73180se_outb_p,
+       .mv_outw_p = sh73180se_outw,
+       .mv_outl_p = sh73180se_outl,
+
+       .mv_insb = sh73180se_insb,
+       .mv_insw = sh73180se_insw,
+       .mv_insl = sh73180se_insl,
+       .mv_outsb = sh73180se_outsb,
+       .mv_outsw = sh73180se_outsw,
+       .mv_outsl = sh73180se_outsl,
+
+       .mv_init_irq = init_73180se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+       .mv_heartbeat = heartbeat_73180se,
+#endif
+};
+
+ALIAS_MV(73180se)
+/*
+ * Initialize the board
+ */
+void __init
+platform_setup(void)
+{
+
+}
diff --git a/arch/sh/boards/sh03/Makefile b/arch/sh/boards/sh03/Makefile
new file mode 100644 (file)
index 0000000..321be50
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for the Interface (CTP/PCI-SH03) specific parts of the kernel
+#
+
+obj-y   := setup.o rtc.o
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/sh03/led.c b/arch/sh/boards/sh03/led.c
new file mode 100644 (file)
index 0000000..c851b0b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * linux/arch/sh/boards/sh03/led.c
+ *
+ * Copyright (C) 2004  Saito.K Interface Corporation.
+ *
+ * This file contains Interface CTP/PCI-SH03 specific LED code.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void heartbeat_sh03(void)
+{
+       static unsigned int cnt = 0, period = 0;
+       volatile unsigned char* p = (volatile unsigned char*)0xa0800000;
+       static unsigned bit = 0, up = 1;
+
+       cnt += 1;
+       if (cnt < period) {
+               return;
+       }
+
+       cnt = 0;
+
+       /* Go through the points (roughly!):
+        * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+        */
+       period = 110 - ( (300<<FSHIFT)/
+                        ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+       if (up) {
+               if (bit == 7) {
+                       bit--;
+                       up=0;
+               } else {
+                       bit ++;
+               }
+       } else {
+               if (bit == 0) {
+                       bit++;
+                       up=1;
+               } else {
+                       bit--;
+               }
+       }
+       *p = 1<<bit;
+
+}
diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c
new file mode 100644 (file)
index 0000000..e5881b1
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * linux/arch/sh/boards/sh03/rtc.c -- CTP/PCI-SH03 on-chip RTC support
+ *
+ *  Copyright (C) 2004  Saito.K & Jeanne(ksaito@interface.co.jp)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+
+#define RTC_BASE       0xb0000000
+#define RTC_SEC1       (RTC_BASE + 0)
+#define RTC_SEC10      (RTC_BASE + 1)
+#define RTC_MIN1       (RTC_BASE + 2)
+#define RTC_MIN10      (RTC_BASE + 3)
+#define RTC_HOU1       (RTC_BASE + 4)
+#define RTC_HOU10      (RTC_BASE + 5)
+#define RTC_WEE1       (RTC_BASE + 6)
+#define RTC_DAY1       (RTC_BASE + 7)
+#define RTC_DAY10      (RTC_BASE + 8)
+#define RTC_MON1       (RTC_BASE + 9)
+#define RTC_MON10      (RTC_BASE + 10)
+#define RTC_YEA1       (RTC_BASE + 11)
+#define RTC_YEA10      (RTC_BASE + 12)
+#define RTC_YEA100     (RTC_BASE + 13)
+#define RTC_YEA1000    (RTC_BASE + 14)
+#define RTC_CTL                (RTC_BASE + 15)
+#define RTC_BUSY       1
+#define RTC_STOP       2
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val)        ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+extern void (*rtc_get_time)(struct timespec *);
+extern int (*rtc_set_time)(const time_t);
+extern spinlock_t rtc_lock;
+
+unsigned long get_cmos_time(void)
+{
+       unsigned int year, mon, day, hour, min, sec;
+       int i;
+
+       spin_lock(&rtc_lock);
+ again:
+       for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+               if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
+                       break;
+       do {
+               sec  = (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10;
+               min  = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10;
+               hour = (ctrl_inb(RTC_HOU1) & 0xf) + (ctrl_inb(RTC_HOU10) & 0xf) * 10;
+               day  = (ctrl_inb(RTC_DAY1) & 0xf) + (ctrl_inb(RTC_DAY10) & 0xf) * 10;
+               mon  = (ctrl_inb(RTC_MON1) & 0xf) + (ctrl_inb(RTC_MON10) & 0xf) * 10;
+               year = (ctrl_inb(RTC_YEA1) & 0xf) + (ctrl_inb(RTC_YEA10) & 0xf) * 10
+                    + (ctrl_inb(RTC_YEA100 ) & 0xf) * 100
+                    + (ctrl_inb(RTC_YEA1000) & 0xf) * 1000;
+       } while (sec != (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10);
+       if (year == 0 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+           hour > 23 || min > 59 || sec > 59) {
+               printk(KERN_ERR
+                      "SH-03 RTC: invalid value, resetting to 1 Jan 2000\n");
+               printk("year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n",
+                      year, mon, day, hour, min, sec);
+
+               ctrl_outb(0, RTC_SEC1); ctrl_outb(0, RTC_SEC10);
+               ctrl_outb(0, RTC_MIN1); ctrl_outb(0, RTC_MIN10);
+               ctrl_outb(0, RTC_HOU1); ctrl_outb(0, RTC_HOU10);
+               ctrl_outb(6, RTC_WEE1);
+               ctrl_outb(1, RTC_DAY1); ctrl_outb(0, RTC_DAY10);
+               ctrl_outb(1, RTC_MON1); ctrl_outb(0, RTC_MON10);
+               ctrl_outb(0, RTC_YEA1); ctrl_outb(0, RTC_YEA10);
+               ctrl_outb(0, RTC_YEA100);
+               ctrl_outb(2, RTC_YEA1000);
+               ctrl_outb(0, RTC_CTL);
+               goto again;
+       }
+
+       spin_unlock(&rtc_lock);
+       return mktime(year, mon, day, hour, min, sec);
+}
+
+void sh03_rtc_gettimeofday(struct timespec *tv)
+{
+
+       tv->tv_sec = get_cmos_time();
+       tv->tv_nsec = 0;
+}
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+       int retval = 0;
+       int real_seconds, real_minutes, cmos_minutes;
+       int i;
+
+       /* gets recalled with irq locally disabled */
+       spin_lock(&rtc_lock);
+       for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+               if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
+                       break;
+       cmos_minutes = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10;
+       real_seconds = nowtime % 60;
+       real_minutes = nowtime / 60;
+       if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+               real_minutes += 30;             /* correct for half hour time zone */
+       real_minutes %= 60;
+
+       if (abs(real_minutes - cmos_minutes) < 30) {
+               BIN_TO_BCD(real_seconds);
+               BIN_TO_BCD(real_minutes);
+               ctrl_outb(real_seconds % 10, RTC_SEC1);
+               ctrl_outb(real_seconds / 10, RTC_SEC10);
+               ctrl_outb(real_minutes % 10, RTC_MIN1);
+               ctrl_outb(real_minutes / 10, RTC_MIN10);
+       } else {
+               printk(KERN_WARNING
+                      "set_rtc_mmss: can't update from %d to %d\n",
+                      cmos_minutes, real_minutes);
+               retval = -1;
+       }
+       spin_unlock(&rtc_lock);
+
+       return retval;
+}
+
+int sh03_rtc_settimeofday(const time_t secs)
+{
+       unsigned long nowtime = secs;
+
+       return set_rtc_mmss(nowtime);
+}
+
+void sh03_time_init(void)
+{
+       rtc_get_time = sh03_rtc_gettimeofday;
+       rtc_set_time = sh03_rtc_settimeofday;
+}
diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c
new file mode 100644 (file)
index 0000000..d2a08ca
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/sh/boards/sh03/setup.c
+ *
+ * Copyright (C) 2004  Interface Co.,Ltd. Saito.K
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/sh03/io.h>
+#include <asm/sh03/sh03.h>
+#include <asm/addrspace.h>
+#include "../../drivers/pci/pci-sh7751.h"
+
+extern void (*board_time_init)(void);
+
+const char *get_system_type(void)
+{
+       return "Interface CTP/PCI-SH03)";
+}
+
+void init_sh03_IRQ(void)
+{
+       ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+
+       make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
+       make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
+       make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
+       make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
+}
+
+extern void *cf_io_base;
+
+unsigned long sh03_isa_port2addr(unsigned long port)
+{
+       if (PXSEG(port))
+               return port;
+       /* CompactFlash (IDE) */
+       if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6)) {
+               return (unsigned long)cf_io_base + port;
+       }
+        return port + SH7751_PCI_IO_BASE;
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh03 __initmv = {
+       .mv_nr_irqs             = 48,
+       .mv_isa_port2addr       = sh03_isa_port2addr,
+       .mv_init_irq            = init_sh03_IRQ,
+
+#ifdef CONFIG_HEARTBEAT
+       .mv_heartbeat           = heartbeat_sh03,
+#endif
+};
+
+ALIAS_MV(sh03)
+
+/* arch/sh/boards/sh03/rtc.c */
+void sh03_time_init(void);
+
+int __init platform_setup(void)
+{
+       board_time_init = sh03_time_init;
+       return 0;
+}
diff --git a/arch/sh/boards/superh/microdev/Makefile b/arch/sh/boards/superh/microdev/Makefile
new file mode 100644 (file)
index 0000000..1387dd6
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the SuperH MicroDev specific parts of the kernel
+#
+
+obj-y   := setup.o irq.o io.o
+
+obj-$(CONFIG_HEARTBEAT)        += led.o
+
diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c
new file mode 100644 (file)
index 0000000..fe83b2c
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * linux/arch/sh/kernel/io_microdev.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ * Copyright (C) 2003, 2004 SuperH, Inc.
+ * Copyright (C) 2004 Paul Mundt
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/mach/io.h>
+
+       /*
+        *      we need to have a 'safe' address to re-direct all I/O requests
+        *      that we do not explicitly wish to handle. This safe address
+        *      must have the following properies:
+        *
+        *              * writes are ignored (no exception)
+        *              * reads are benign (no side-effects)
+        *              * accesses of width 1, 2 and 4-bytes are all valid.
+        *
+        *      The Processor Version Register (PVR) has these properties.
+        */
+#define        PVR     0xff000030      /* Processor Version Register */
+
+
+#define        IO_IDE2_BASE            0x170ul /* I/O base for SMSC FDC37C93xAPM IDE #2 */
+#define        IO_IDE1_BASE            0x1f0ul /* I/O base for SMSC FDC37C93xAPM IDE #1 */
+#define IO_ISP1161_BASE                0x290ul /* I/O port for Philips ISP1161x USB chip */
+#define IO_SERIAL2_BASE                0x2f8ul /* I/O base for SMSC FDC37C93xAPM Serial #2 */
+#define        IO_LAN91C111_BASE       0x300ul /* I/O base for SMSC LAN91C111 Ethernet chip */
+#define        IO_IDE2_MISC            0x376ul /* I/O misc for SMSC FDC37C93xAPM IDE #2 */
+#define IO_SUPERIO_BASE                0x3f0ul /* I/O base for SMSC FDC37C93xAPM SuperIO chip */
+#define        IO_IDE1_MISC            0x3f6ul /* I/O misc for SMSC FDC37C93xAPM IDE #1 */
+#define IO_SERIAL1_BASE                0x3f8ul /* I/O base for SMSC FDC37C93xAPM Serial #1 */
+
+#define        IO_ISP1161_EXTENT       0x04ul  /* I/O extent for Philips ISP1161x USB chip */
+#define        IO_LAN91C111_EXTENT     0x10ul  /* I/O extent for SMSC LAN91C111 Ethernet chip */
+#define        IO_SUPERIO_EXTENT       0x02ul  /* I/O extent for SMSC FDC37C93xAPM SuperIO chip */
+#define        IO_IDE_EXTENT           0x08ul  /* I/O extent for IDE Task Register set */
+#define IO_SERIAL_EXTENT       0x10ul
+
+#define        IO_LAN91C111_PHYS       0xa7500000ul    /* Physical address of SMSC LAN91C111 Ethernet chip */
+#define        IO_ISP1161_PHYS         0xa7700000ul    /* Physical address of Philips ISP1161x USB chip */
+#define        IO_SUPERIO_PHYS         0xa7800000ul    /* Physical address of SMSC FDC37C93xAPM SuperIO chip */
+
+#define PORT2ADDR(x) (microdev_isa_port2addr(x))
+
+
+static inline void delay(void)
+{
+#if defined(CONFIG_PCI)
+       /* System board present, just make a dummy SRAM access.  (CS0 will be
+          mapped to PCI memory, probably good to avoid it.) */
+       ctrl_inw(0xa6800000);
+#else
+       /* CS0 will be mapped to flash, ROM etc so safe to access it. */
+       ctrl_inw(0xa0000000);
+#endif
+}
+
+unsigned char microdev_inb(unsigned long port)
+{
+#ifdef CONFIG_PCI
+       if (port >= PCIBIOS_MIN_IO)
+               return microdev_pci_inb(port);
+#endif
+       return *(volatile unsigned char*)PORT2ADDR(port);
+}
+
+unsigned short microdev_inw(unsigned long port)
+{
+#ifdef CONFIG_PCI
+       if (port >= PCIBIOS_MIN_IO)
+               return microdev_pci_inw(port);
+#endif
+       return *(volatile unsigned short*)PORT2ADDR(port);
+}
+
+unsigned int microdev_inl(unsigned long port)
+{
+#ifdef CONFIG_PCI
+       if (port >= PCIBIOS_MIN_IO)
+               return microdev_pci_inl(port);
+#endif
+       return *(volatile unsigned int*)PORT2ADDR(port);
+}
+
+void microdev_outb(unsigned char b, unsigned long port)
+{
+#ifdef CONFIG_PCI
+       if (port >= PCIBIOS_MIN_IO) {
+               microdev_pci_outb(b, port);
+               return;
+       }
+#endif
+
+       /*
+        *      There is a board feature with the current SH4-202 MicroDev in
+        *      that the 2 byte enables (nBE0 and nBE1) are tied together (and
+        *      to the Chip Select Line (Ethernet_CS)). Due to this conectivity,
+        *      it is not possible to safely perform 8-bit writes to the
+        *      Ethernet registers, as 16-bits will be consumed from the Data
+        *      lines (corrupting the other byte).  Hence, this function is
+        *      written to impliment 16-bit read/modify/write for all byte-wide
+        *      acceses.
+        *
+        *      Note: there is no problem with byte READS (even or odd).
+        *
+        *                      Sean McGoogan - 16th June 2003.
+        */
+       if ((port >= IO_LAN91C111_BASE) &&
+           (port <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
+                       /*
+                        * Then are trying to perform a byte-write to the
+                        * LAN91C111.  This needs special care.
+                        */
+               if (port % 2 == 1) {    /* is the port odd ? */
+                       /* unset bit-0, i.e. make even */
+                       const unsigned long evenPort = port-1;
+                       unsigned short word;
+
+                       /*
+                        * do a 16-bit read/write to write to 'port',
+                        * preserving even byte.
+                        *
+                        *      Even addresses are bits 0-7
+                        *      Odd  addresses are bits 8-15
+                        */
+                       word = microdev_inw(evenPort);
+                       word = (word & 0xffu) | (b << 8);
+                       microdev_outw(word, evenPort);
+               } else {
+                       /* else, we are trying to do an even byte write */
+                       unsigned short word;
+
+                       /*
+                        * do a 16-bit read/write to write to 'port',
+                        * preserving odd byte.
+                        *
+                        *      Even addresses are bits 0-7
+                        *      Odd  addresses are bits 8-15
+                        */
+                       word = microdev_inw(port);
+                       word = (word & 0xff00u) | (b);
+                       microdev_outw(word, port);
+               }
+       } else {
+               *(volatile unsigned char*)PORT2ADDR(port) = b;
+       }
+}
+
+void microdev_outw(unsigned short b, unsigned long port)
+{
+#ifdef CONFIG_PCI
+       if (port >= PCIBIOS_MIN_IO) {
+               microdev_pci_outw(b, port);
+               return;
+       }
+#endif
+       *(volatile unsigned short*)PORT2ADDR(port) = b;
+}
+
+void microdev_outl(unsigned int b, unsigned long port)
+{
+#ifdef CONFIG_PCI
+       if (port >= PCIBIOS_MIN_IO) {
+               microdev_pci_outl(b, port);
+               return;
+       }
+#endif
+       *(volatile unsigned int*)PORT2ADDR(port) = b;
+}
+
+unsigned char microdev_inb_p(unsigned long port)
+{
+       unsigned char v = microdev_inb(port);
+       delay();
+       return v;
+}
+
+unsigned short microdev_inw_p(unsigned long port)
+{
+       unsigned short v = microdev_inw(port);
+       delay();
+       return v;
+}
+
+unsigned int microdev_inl_p(unsigned long port)
+{
+       unsigned int v = microdev_inl(port);
+       delay();
+       return v;
+}
+
+void microdev_outb_p(unsigned char b, unsigned long port)
+{
+       microdev_outb(b, port);
+       delay();
+}
+
+void microdev_outw_p(unsigned short b, unsigned long port)
+{
+       microdev_outw(b, port);
+       delay();
+}
+
+void microdev_outl_p(unsigned int b, unsigned long port)
+{
+       microdev_outl(b, port);
+       delay();
+}
+
+void microdev_insb(unsigned long port, void *buffer, unsigned long count)
+{
+       volatile unsigned char *port_addr;
+       unsigned char *buf = buffer;
+
+       port_addr = (volatile unsigned char *)PORT2ADDR(port);
+
+       while (count--)
+               *buf++ = *port_addr;
+}
+
+void microdev_insw(unsigned long port, void *buffer, unsigned long count)
+{
+       volatile unsigned short *port_addr;
+       unsigned short *buf = buffer;
+
+       port_addr = (volatile unsigned short *)PORT2ADDR(port);
+
+       while (count--)
+               *buf++ = *port_addr;
+}
+
+void microdev_insl(unsigned long port, void *buffer, unsigned long count)
+{
+       volatile unsigned long *port_addr;
+       unsigned int *buf = buffer;
+
+       port_addr = (volatile unsigned long *)PORT2ADDR(port);
+
+       while (count--)
+               *buf++ = *port_addr;
+}
+
+void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+       volatile unsigned char *port_addr;
+       const unsigned char *buf = buffer;
+
+       port_addr = (volatile unsigned char *)PORT2ADDR(port);
+
+       while (count--)
+               *port_addr = *buf++;
+}
+
+void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+       volatile unsigned short *port_addr;
+       const unsigned short *buf = buffer;
+
+       port_addr = (volatile unsigned short *)PORT2ADDR(port);
+
+       while (count--)
+               *port_addr = *buf++;
+}
+
+void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+       volatile unsigned long *port_addr;
+       const unsigned int *buf = buffer;
+
+       port_addr = (volatile unsigned long *)PORT2ADDR(port);
+
+       while (count--)
+               *port_addr = *buf++;
+}
+
+/*
+ * map I/O ports to memory-mapped addresses
+ */
+unsigned long microdev_isa_port2addr(unsigned long offset)
+{
+       unsigned long result;
+
+       if ((offset >= IO_LAN91C111_BASE) &&
+           (offset <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
+                       /*
+                        *      SMSC LAN91C111 Ethernet chip
+                        */
+               result = IO_LAN91C111_PHYS + offset - IO_LAN91C111_BASE;
+       } else if ((offset >= IO_SUPERIO_BASE) &&
+                  (offset <  IO_SUPERIO_BASE + IO_SUPERIO_EXTENT)) {
+                       /*
+                        *      SMSC FDC37C93xAPM SuperIO chip
+                        *
+                        *      Configuration Registers
+                        */
+               result = IO_SUPERIO_PHYS + (offset << 1);
+#if 0
+       } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
+                  offset == KBD_STATUS_REG) {
+                       /*
+                        *      SMSC FDC37C93xAPM SuperIO chip
+                        *
+                        *      PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
+                        */
+               result = IO_SUPERIO_PHYS + (offset << 1);
+#endif
+       } else if (((offset >= IO_IDE1_BASE) &&
+                   (offset <  IO_IDE1_BASE + IO_IDE_EXTENT)) ||
+                   (offset == IO_IDE1_MISC)) {
+                       /*
+                        *      SMSC FDC37C93xAPM SuperIO chip
+                        *
+                        *      IDE #1
+                        */
+               result = IO_SUPERIO_PHYS + (offset << 1);
+       } else if (((offset >= IO_IDE2_BASE) &&
+                   (offset <  IO_IDE2_BASE + IO_IDE_EXTENT)) ||
+                   (offset == IO_IDE2_MISC)) {
+                       /*
+                        *      SMSC FDC37C93xAPM SuperIO chip
+                        *
+                        *      IDE #2
+                        */
+               result = IO_SUPERIO_PHYS + (offset << 1);
+       } else if ((offset >= IO_SERIAL1_BASE) &&
+                  (offset <  IO_SERIAL1_BASE + IO_SERIAL_EXTENT)) {
+                       /*
+                        *      SMSC FDC37C93xAPM SuperIO chip
+                        *
+                        *      Serial #1
+                        */
+               result = IO_SUPERIO_PHYS + (offset << 1);
+       } else if ((offset >= IO_SERIAL2_BASE) &&
+                  (offset <  IO_SERIAL2_BASE + IO_SERIAL_EXTENT)) {
+                       /*
+                        *      SMSC FDC37C93xAPM SuperIO chip
+                        *
+                        *      Serial #2
+                        */
+               result = IO_SUPERIO_PHYS + (offset << 1);
+       } else if ((offset >= IO_ISP1161_BASE) &&
+                  (offset < IO_ISP1161_BASE + IO_ISP1161_EXTENT)) {
+                       /*
+                        *      Philips USB ISP1161x chip
+                        */
+               result = IO_ISP1161_PHYS + offset - IO_ISP1161_BASE;
+       } else {
+                       /*
+                        *      safe default.
+                        */
+               printk("Warning: unexpected port in %s( offset = 0x%lx )\n",
+                      __FUNCTION__, offset);
+               result = PVR;
+       }
+
+       return result;
+}
+
diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c
new file mode 100644 (file)
index 0000000..1298883
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * arch/sh/boards/superh/microdev/irq.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+
+#define NUM_EXTERNAL_IRQS 16   /* IRL0 .. IRL15 */
+
+
+static const struct {
+       unsigned char fpgaIrq;
+       unsigned char mapped;
+       const char *name;
+} fpgaIrqTable[NUM_EXTERNAL_IRQS] = {
+       { 0,                            0,      "unused"   },           /* IRQ #0       IRL=15  0x200  */
+       { MICRODEV_FPGA_IRQ_KEYBOARD,   1,      "keyboard" },           /* IRQ #1       IRL=14  0x220  */
+       { MICRODEV_FPGA_IRQ_SERIAL1,    1,      "Serial #1"},           /* IRQ #2       IRL=13  0x240  */
+       { MICRODEV_FPGA_IRQ_ETHERNET,   1,      "Ethernet" },           /* IRQ #3       IRL=12  0x260  */
+       { MICRODEV_FPGA_IRQ_SERIAL2,    0,      "Serial #2"},           /* IRQ #4       IRL=11  0x280  */
+       { 0,                            0,      "unused"   },           /* IRQ #5       IRL=10  0x2a0  */
+       { 0,                            0,      "unused"   },           /* IRQ #6       IRL=9   0x2c0  */
+       { MICRODEV_FPGA_IRQ_USB_HC,     1,      "USB"      },           /* IRQ #7       IRL=8   0x2e0  */
+       { MICRODEV_IRQ_PCI_INTA,        1,      "PCI INTA" },           /* IRQ #8       IRL=7   0x300  */
+       { MICRODEV_IRQ_PCI_INTB,        1,      "PCI INTB" },           /* IRQ #9       IRL=6   0x320  */
+       { MICRODEV_IRQ_PCI_INTC,        1,      "PCI INTC" },           /* IRQ #10      IRL=5   0x340  */
+       { MICRODEV_IRQ_PCI_INTD,        1,      "PCI INTD" },           /* IRQ #11      IRL=4   0x360  */
+       { MICRODEV_FPGA_IRQ_MOUSE,      1,      "mouse"    },           /* IRQ #12      IRL=3   0x380  */
+       { MICRODEV_FPGA_IRQ_IDE2,       1,      "IDE #2"   },           /* IRQ #13      IRL=2   0x3a0  */
+       { MICRODEV_FPGA_IRQ_IDE1,       1,      "IDE #1"   },           /* IRQ #14      IRL=1   0x3c0  */
+       { 0,                            0,      "unused"   },           /* IRQ #15      IRL=0   0x3e0  */
+};
+
+#if (MICRODEV_LINUX_IRQ_KEYBOARD != 1)
+#  error Inconsistancy in defining the IRQ# for Keyboard!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_ETHERNET != 3)
+#  error Inconsistancy in defining the IRQ# for Ethernet!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_USB_HC != 7)
+#  error Inconsistancy in defining the IRQ# for USB!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_MOUSE != 12)
+#  error Inconsistancy in defining the IRQ# for PS/2 Mouse!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_IDE2 != 13)
+#  error Inconsistancy in defining the IRQ# for secondary IDE!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_IDE1 != 14)
+#  error Inconsistancy in defining the IRQ# for primary IDE!
+#endif
+
+static void enable_microdev_irq(unsigned int irq);
+static void disable_microdev_irq(unsigned int irq);
+
+       /* shutdown is same as "disable" */
+#define shutdown_microdev_irq disable_microdev_irq
+
+static void mask_and_ack_microdev(unsigned int);
+static void end_microdev_irq(unsigned int irq);
+
+static unsigned int startup_microdev_irq(unsigned int irq)
+{
+       enable_microdev_irq(irq);
+       return 0;               /* never anything pending */
+}
+
+static struct hw_interrupt_type microdev_irq_type = {
+       "MicroDev-IRQ",
+       startup_microdev_irq,
+       shutdown_microdev_irq,
+       enable_microdev_irq,
+       disable_microdev_irq,
+       mask_and_ack_microdev,
+       end_microdev_irq
+};
+
+static void disable_microdev_irq(unsigned int irq)
+{
+       unsigned int flags;
+       unsigned int fpgaIrq;
+
+       if (irq >= NUM_EXTERNAL_IRQS) return;
+       if (!fpgaIrqTable[irq].mapped) return;
+
+       fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
+
+               /* disable interrupts */
+       local_irq_save(flags);
+
+               /* disable interupts on the FPGA INTC register */
+       ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
+
+               /* restore interrupts */
+       local_irq_restore(flags);
+}
+
+static void enable_microdev_irq(unsigned int irq)
+{
+       unsigned long priorityReg, priorities, pri;
+       unsigned int flags;
+       unsigned int fpgaIrq;
+
+
+       if (irq >= NUM_EXTERNAL_IRQS) return;
+       if (!fpgaIrqTable[irq].mapped) return;
+
+       pri = 15 - irq;
+
+       fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
+       priorityReg = MICRODEV_FPGA_INTPRI_REG(fpgaIrq);
+
+               /* disable interrupts */
+       local_irq_save(flags);
+
+               /* set priority for the interrupt */
+       priorities = ctrl_inl(priorityReg);
+       priorities &= ~MICRODEV_FPGA_INTPRI_MASK(fpgaIrq);
+       priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri);
+       ctrl_outl(priorities, priorityReg);
+
+               /* enable interupts on the FPGA INTC register */
+       ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
+
+               /* restore interrupts */
+       local_irq_restore(flags);
+}
+
+       /* This functions sets the desired irq handler to be a MicroDev type */
+static void __init make_microdev_irq(unsigned int irq)
+{
+       disable_irq_nosync(irq);
+       irq_desc[irq].handler = &microdev_irq_type;
+       disable_microdev_irq(irq);
+}
+
+static void mask_and_ack_microdev(unsigned int irq)
+{
+       disable_microdev_irq(irq);
+}
+
+static void end_microdev_irq(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+       {
+               enable_microdev_irq(irq);
+       }
+}
+
+extern void __init init_microdev_irq(void)
+{
+       int i;
+
+               /* disable interupts on the FPGA INTC register */
+       ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG);
+
+       for (i = 0; i < NUM_EXTERNAL_IRQS; i++)
+       {
+               make_microdev_irq(i);
+       }
+}
+
+extern void microdev_print_fpga_intc_status(void)
+{
+       volatile unsigned int * const intenb = (unsigned int*)MICRODEV_FPGA_INTENB_REG;
+       volatile unsigned int * const intdsb = (unsigned int*)MICRODEV_FPGA_INTDSB_REG;
+       volatile unsigned int * const intpria = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(0);
+       volatile unsigned int * const intprib = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(8);
+       volatile unsigned int * const intpric = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(16);
+       volatile unsigned int * const intprid = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(24);
+       volatile unsigned int * const intsrc = (unsigned int*)MICRODEV_FPGA_INTSRC_REG;
+       volatile unsigned int * const intreq = (unsigned int*)MICRODEV_FPGA_INTREQ_REG;
+
+       printk("-------------------------- microdev_print_fpga_intc_status() ------------------\n");
+       printk("FPGA_INTENB = 0x%08x\n", *intenb);
+       printk("FPGA_INTDSB = 0x%08x\n", *intdsb);
+       printk("FPGA_INTSRC = 0x%08x\n", *intsrc);
+       printk("FPGA_INTREQ = 0x%08x\n", *intreq);
+       printk("FPGA_INTPRI[3..0] = %08x:%08x:%08x:%08x\n", *intprid, *intpric, *intprib, *intpria);
+       printk("-------------------------------------------------------------------------------\n");
+}
+
+
diff --git a/arch/sh/boards/superh/microdev/led.c b/arch/sh/boards/superh/microdev/led.c
new file mode 100644 (file)
index 0000000..52a98e6
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/sh/kernel/led_microdev.c
+ *
+ * Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
+ * Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+
+#define LED_REGISTER 0xa6104d20
+
+static void mach_led_d9(int value)
+{
+       unsigned long reg;
+       reg = ctrl_inl(LED_REGISTER);
+       reg &= ~1;
+       reg |= (value & 1);
+       ctrl_outl(reg, LED_REGISTER);
+       return;
+}
+
+static void mach_led_d10(int value)
+{
+       unsigned long reg;
+       reg = ctrl_inl(LED_REGISTER);
+       reg &= ~2;
+       reg |= ((value & 1) << 1);
+       ctrl_outl(reg, LED_REGISTER);
+       return;
+}
+
+
+#ifdef CONFIG_HEARTBEAT
+#include <linux/sched.h>
+
+static unsigned char banner_table[] = {
+       0x11, 0x01, 0x11, 0x01, 0x11, 0x03,
+       0x11, 0x01, 0x11, 0x01, 0x13, 0x03,
+       0x11, 0x01, 0x13, 0x01, 0x13, 0x01, 0x11, 0x03,
+       0x11, 0x03,
+       0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
+       0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x07,
+       0x13, 0x01, 0x13, 0x03,
+       0x11, 0x01, 0x11, 0x03,
+       0x13, 0x01, 0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
+       0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
+       0x13, 0x01, 0x13, 0x01, 0x13, 0x03,
+       0x13, 0x01, 0x11, 0x01, 0x11, 0x03,
+       0x11, 0x03,
+       0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x13, 0x07,
+       0xff
+};
+
+static void banner(void)
+{
+       static int pos = 0;
+       static int count = 0;
+
+       if (count) {
+               count--;
+       } else {
+               int val = banner_table[pos];
+               if (val == 0xff) {
+                       pos = 0;
+                       val = banner_table[pos];
+               }
+               pos++;
+               mach_led_d10((val >> 4) & 1);
+               count = 10 * (val & 0xf);
+       }
+}
+
+/* From heartbeat_harp in the stboards directory */
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void microdev_heartbeat(void)
+{
+       static unsigned cnt = 0, period = 0, dist = 0;
+
+       if (cnt == 0 || cnt == dist)
+               mach_led_d9(1);
+       else if (cnt == 7 || cnt == dist+7)
+               mach_led_d9(0);
+
+       if (++cnt > period) {
+               cnt = 0;
+               /* The hyperbolic function below modifies the heartbeat period
+                * length in dependency of the current (5min) load. It goes
+                * through the points f(0)=126, f(1)=86, f(5)=51,
+                * f(inf)->30. */
+               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+               dist = period / 4;
+       }
+
+       banner();
+}
+
+#endif
diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c
new file mode 100644 (file)
index 0000000..c189199
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * arch/sh/boards/superh/microdev/setup.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ * Copyright (C) 2003, 2004 SuperH, Inc.
+ * Copyright (C) 2004 Paul Mundt
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/io.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+extern void microdev_heartbeat(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh4202_microdev __initmv = {
+       .mv_nr_irqs             = 72,           /* QQQ need to check this - use the MACRO */
+
+       .mv_inb                 = microdev_inb,
+       .mv_inw                 = microdev_inw,
+       .mv_inl                 = microdev_inl,
+       .mv_outb                = microdev_outb,
+       .mv_outw                = microdev_outw,
+       .mv_outl                = microdev_outl,
+
+       .mv_inb_p               = microdev_inb_p,
+       .mv_inw_p               = microdev_inw_p,
+       .mv_inl_p               = microdev_inl_p,
+       .mv_outb_p              = microdev_outb_p,
+       .mv_outw_p              = microdev_outw_p,
+       .mv_outl_p              = microdev_outl_p,
+
+       .mv_insb                = microdev_insb,
+       .mv_insw                = microdev_insw,
+       .mv_insl                = microdev_insl,
+       .mv_outsb               = microdev_outsb,
+       .mv_outsw               = microdev_outsw,
+       .mv_outsl               = microdev_outsl,
+
+       .mv_isa_port2addr       = microdev_isa_port2addr,
+
+       .mv_init_irq            = init_microdev_irq,
+
+#ifdef CONFIG_HEARTBEAT
+       .mv_heartbeat           = microdev_heartbeat,
+#endif
+};
+ALIAS_MV(sh4202_microdev)
+
+/****************************************************************************/
+
+
+       /*
+        * Setup for the SMSC FDC37C93xAPM
+        */
+#define SMSC_CONFIG_PORT_ADDR   (0x3F0)
+#define SMSC_INDEX_PORT_ADDR    SMSC_CONFIG_PORT_ADDR
+#define SMSC_DATA_PORT_ADDR     (SMSC_INDEX_PORT_ADDR + 1)
+
+#define SMSC_ENTER_CONFIG_KEY   0x55
+#define SMSC_EXIT_CONFIG_KEY    0xaa
+
+#define SMCS_LOGICAL_DEV_INDEX          0x07   /* Logical Device Number */
+#define SMSC_DEVICE_ID_INDEX    0x20   /* Device ID */
+#define SMSC_DEVICE_REV_INDEX   0x21   /* Device Revision */
+#define SMSC_ACTIVATE_INDEX     0x30   /* Activate */
+#define SMSC_PRIMARY_BASE_INDEX         0x60   /* Primary Base Address */
+#define SMSC_SECONDARY_BASE_INDEX 0x62 /* Secondary Base Address */
+#define SMSC_PRIMARY_INT_INDEX  0x70   /* Primary Interrupt Select */
+#define SMSC_SECONDARY_INT_INDEX 0x72  /* Secondary Interrupt Select */
+#define SMSC_HDCS0_INDEX        0xf0   /* HDCS0 Address Decoder */
+#define SMSC_HDCS1_INDEX        0xf1   /* HDCS1 Address Decoder */
+
+#define SMSC_IDE1_DEVICE       1       /* IDE #1 logical device */
+#define SMSC_IDE2_DEVICE       2       /* IDE #2 logical device */
+#define SMSC_PARALLEL_DEVICE   3       /* Parallel Port logical device */
+#define SMSC_SERIAL1_DEVICE    4       /* Serial #1 logical device */
+#define SMSC_SERIAL2_DEVICE    5       /* Serial #2 logical device */
+#define SMSC_KEYBOARD_DEVICE   7       /* Keyboard logical device */
+#define SMSC_CONFIG_REGISTERS  8       /* Configuration Registers (Aux I/O) */
+
+#define SMSC_READ_INDEXED(index) ({ \
+       outb((index), SMSC_INDEX_PORT_ADDR); \
+       inb(SMSC_DATA_PORT_ADDR); })
+#define SMSC_WRITE_INDEXED(val, index) ({ \
+       outb((index), SMSC_INDEX_PORT_ADDR); \
+       outb((val),   SMSC_DATA_PORT_ADDR); })
+
+#define        IDE1_PRIMARY_BASE       0x01f0  /* Task File Registe base for IDE #1 */
+#define        IDE1_SECONDARY_BASE     0x03f6  /* Miscellaneous AT registers for IDE #1 */
+#define        IDE2_PRIMARY_BASE       0x0170  /* Task File Registe base for IDE #2 */
+#define        IDE2_SECONDARY_BASE     0x0376  /* Miscellaneous AT registers for IDE #2 */
+
+#define SERIAL1_PRIMARY_BASE   0x03f8
+#define SERIAL2_PRIMARY_BASE   0x02f8
+
+#define        MSB(x)          ( (x) >> 8 )
+#define        LSB(x)          ( (x) & 0xff )
+
+       /* General-Purpose base address on CPU-board FPGA */
+#define        MICRODEV_FPGA_GP_BASE           0xa6100000ul
+
+       /* assume a Keyboard Controller is present */
+int microdev_kbd_controller_present = 1;
+
+const char *get_system_type(void)
+{
+       return "SH4-202 MicroDev";
+}
+
+static struct resource smc91x_resources[] = {
+       [0] = {
+               .start          = 0x300,
+               .end            = 0x300 + 0x0001000 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = MICRODEV_LINUX_IRQ_ETHERNET,
+               .end            = MICRODEV_LINUX_IRQ_ETHERNET,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device smc91x_device = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
+};
+
+static int __init smc91x_setup(void)
+{
+       return platform_device_register(&smc91x_device);
+}
+
+__initcall(smc91x_setup);
+
+       /*
+        * Initialize the board
+        */
+void __init platform_setup(void)
+{
+       int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
+       const int fpgaRevision = *fpgaRevisionRegister;
+       int * const CacheControlRegister = (int*)CCR;
+
+       printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
+               get_system_type(), fpgaRevision, *CacheControlRegister);
+}
+
+
+/****************************************************************************/
+
+
+       /*
+        * Setup for the SMSC FDC37C93xAPM
+        */
+static int __init smsc_superio_setup(void)
+{
+
+       unsigned char devid, devrev;
+
+               /* Initially the chip is in run state */
+               /* Put it into configuration state */
+       outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+               /* Read device ID info */
+       devid  = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
+       devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
+       if ( (devid==0x30) && (devrev==0x01) )
+       {
+               printk("SMSC FDC37C93xAPM SuperIO device detected\n");
+       }
+       else
+       {               /* not the device identity we expected */
+               printk("Not detected a SMSC FDC37C93xAPM SuperIO device (devid=0x%02x, rev=0x%02x)\n",
+                       devid, devrev);
+                       /* inform the keyboard driver that we have no keyboard controller */
+               microdev_kbd_controller_present = 0;
+                       /* little point in doing anything else in this functon */
+               return 0;
+       }
+
+               /* Select the keyboard device */
+       SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+               /* enable it */
+       SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+               /* enable the interrupts */
+       SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX);
+       SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX);
+
+               /* Select the Serial #1 device */
+       SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+               /* enable it */
+       SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+               /* program with port addresses */
+       SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+       SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+       SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
+               /* enable the interrupts */
+       SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX);
+
+               /* Select the Serial #2 device */
+       SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+               /* enable it */
+       SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+               /* program with port addresses */
+       SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+       SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+       SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
+               /* enable the interrupts */
+       SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX);
+
+               /* Select the IDE#1 device */
+       SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+               /* enable it */
+       SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+               /* program with port addresses */
+       SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+       SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+       SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
+       SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
+       SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX);
+       SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX);
+               /* select the interrupt */
+       SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX);
+
+               /* Select the IDE#2 device */
+       SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+               /* enable it */
+       SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+               /* program with port addresses */
+       SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+       SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+       SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
+       SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
+               /* select the interrupt */
+       SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX);
+
+               /* Select the configuration registers */
+       SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX);
+               /* enable the appropriate GPIO pins for IDE functionality:
+                * bit[0]   In/Out              1==input;  0==output
+                * bit[1]   Polarity            1==invert; 0==no invert
+                * bit[2]   Int Enb #1          1==Enable Combined IRQ #1; 0==disable
+                * bit[3:4] Function Select     00==original; 01==Alternate Function #1
+                */
+       SMSC_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */
+       SMSC_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */
+       SMSC_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */
+       SMSC_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */
+       SMSC_WRITE_INDEXED(0x08, 0xe8); /* GP20 = nIDE2_OE */
+
+               /* Exit the configuraton state */
+       outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+       return 0;
+}
+
+
+/* This is grotty, but, because kernel is always referenced on the link line
+ * before any devices, this is safe.
+ */
+__initcall(smsc_superio_setup);
diff --git a/arch/sh/configs/microdev_defconfig b/arch/sh/configs/microdev_defconfig
new file mode 100644 (file)
index 0000000..e76a93a
--- /dev/null
@@ -0,0 +1,680 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# 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=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+CONFIG_SH_SH4202_MICRODEV=y
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+CONFIG_CPU_SUBTYPE_SH4_202=y
+CONFIG_MMU=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200"
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_PREEMPT=y
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
+CONFIG_SH_PCLK_FREQ=65986048
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_ISA=y
+# CONFIG_PCI is not set
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=1
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_IDE_SH=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI 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 is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_UNIX is not set
+# 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 is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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=y
+# CONFIG_STNIC is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+CONFIG_SMC91X=y
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# 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
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA 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_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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=y
+# 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_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# 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=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se73180_defconfig b/arch/sh/configs/se73180_defconfig
new file mode 100644 (file)
index 0000000..1d5884d
--- /dev/null
@@ -0,0 +1,430 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+CONFIG_SH_73180_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+CONFIG_CPU_SUBTYPE_SH73180=y
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+CONFIG_MMU=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram"
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+# CONFIG_MEMORY_OVERRIDE is not set
+# CONFIG_SH_FPU is not set
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+# CONFIG_SH_PCLK_CALC is not set
+CONFIG_SH_PCLK_FREQ=27000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# SH initrd options
+#
+CONFIG_EMBEDDED_RAMDISK=y
+CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
+#
+# 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD 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
+#
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# 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
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SH_WDT 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_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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_FAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_SYSFS is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig
new file mode 100644 (file)
index 0000000..bf48af3
--- /dev/null
@@ -0,0 +1,645 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_IOSCHED_NOOP is not set
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System type
+#
+CONFIG_SH_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SH4 is not set
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+CONFIG_CPU_SUBTYPE_SH7705=y
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+CONFIG_SH7705_CACHE_32KB=y
+CONFIG_MMU=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+# CONFIG_CF_ENABLER is not set
+CONFIG_SH_RTC=y
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_ADC is not set
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_PREEMPT=y
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_SOLUTIONENGINE=y
+CONFIG_MTD_SUPERH_RESERVE=0x300000
+# CONFIG_MTD_MPC1211 is not set
+# CONFIG_MTD_RTS7751R2D is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD 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_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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_STNIC=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE 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 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=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 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 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# 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
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR 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_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 is not set
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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 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_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 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
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig
new file mode 100644 (file)
index 0000000..100d08f
--- /dev/null
@@ -0,0 +1,936 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+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=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+CONFIG_SH_SH03=y
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+CONFIG_MMU=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_CF_ENABLER=y
+CONFIG_CF_AREA5=y
+# CONFIG_CF_AREA6 is not set
+CONFIG_CF_BASE_ADDR=0xb4000000
+CONFIG_SH_RTC=y
+CONFIG_SH_FPU=y
+CONFIG_ZERO_PAGE_OFFSET=0x00004000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_PREEMPT=y
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_CALC=y
+CONFIG_SH_PCLK_FREQ=49876504
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_YENTA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PROBE=y
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=m
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# SH initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_IDE_SH=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_MEGARAID 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_DTC3280 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_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=m
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# 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_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# 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=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# 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_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_IPV6 is not set
+# CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER 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
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED 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=y
+# CONFIG_DUMMY is not set
+# 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=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_8139CP=y
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_NET_POCKET 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 is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# 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_NET_FC 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 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=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SH_WDT=m
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_RTC is not set
+CONFIG_SH03_RTC=y
+# 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_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS 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_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+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_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_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=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
new file mode 100644 (file)
index 0000000..5db5cb9
--- /dev/null
@@ -0,0 +1,61 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ *     IRQ functions
+ */
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev)
+{
+       int irq;
+
+       if (dev->bus->number == 0) {
+               switch (slot) {
+               case 4: return 5;       /* eth0       */
+               case 8: return 5;       /* eth1       */
+               case 6: return 2;       /* PCI bridge */
+               default:
+                       printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+                       return 2;
+               }
+       } else {
+               switch (pin) {
+               case 0:   irq =  2; break;
+               case 1:   irq =  2; break;
+               case 2:   irq =  2; break;
+               case 3:   irq =  2; break;
+               case 4:   irq =  2; break;
+               default:  irq = -1; break;
+               }
+       }
+       return irq;
+}
+
+static u8 __init sh03_no_swizzle(struct pci_dev *dev, u8 *pin)
+{
+       /* no swizzling */
+       return PCI_SLOT(dev->devfn);
+}
+
+static int sh03_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int irq = -1;
+
+       /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+       irq = pcibios_map_platform_irq(slot, pin, dev);
+       if( irq < 0 ) {
+               pr_debug("PCI: Error mapping IRQ on device %s\n", dev->slot_name);
+               return irq;
+       }
+
+       pr_debug("Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
+
+       return irq;
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+       pci_fixup_irqs(sh03_no_swizzle, sh03_pci_lookup_irq);
+}
diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c
new file mode 100644 (file)
index 0000000..df21997
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-sh03.c
+ *
+ * PCI initialization for the Interface CTP/PCI-SH03 board
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include "pci-sh7751.h"
+
+/*
+ * Description:  This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+   return 1;
+}
+
+static struct resource sh7751_io_resource = {
+       .name   = "SH03 IO",
+       .start  = SH7751_PCI_IO_BASE,
+       .end    = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
+       .flags  = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+       .name   = "SH03 mem",
+       .start  = SH7751_PCI_MEMORY_BASE,
+       .end    = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+       .flags  = IORESOURCE_MEM
+};
+
+extern struct pci_ops sh7751_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+       { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+       { NULL, NULL, NULL, 0, 0 },
+};
+
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..dc6725c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <asm/thread_info.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+       /* offsets into the thread_info struct */
+       DEFINE(TI_TASK,         offsetof(struct thread_info, task));
+       DEFINE(TI_EXEC_DOMAIN,  offsetof(struct thread_info, exec_domain));
+       DEFINE(TI_FLAGS,        offsetof(struct thread_info, flags));
+       DEFINE(TI_CPU,          offsetof(struct thread_info, cpu));
+       DEFINE(TI_PRE_COUNT,    offsetof(struct thread_info, preempt_count));
+       DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
+
+       return 0;
+}
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
new file mode 100644 (file)
index 0000000..f17a2a0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/sh/kernel/cpu/sh2/probe.c
+ *
+ * CPU Subtype Probing for SH-2.
+ *
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+       /*
+        * For now, assume SH7604 .. fix this later.
+        */
+       cpu_data->type                  = CPU_SH7604;
+       cpu_data->dcache.ways           = 4;
+       cpu_data->dcache.way_shift      = 6;
+       cpu_data->dcache.sets           = 64;
+       cpu_data->dcache.entry_shift    = 4;
+       cpu_data->dcache.linesz         = L1_CACHE_BYTES;
+       cpu_data->dcache.flags          = 0;
+
+       /*
+        * SH-2 doesn't have separate caches
+        */
+       cpu_data->dcache.flags |= SH_CACHE_COMBINED;
+       cpu_data->icache = cpu_data->dcache;
+
+       return 0;
+}
+
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
new file mode 100644 (file)
index 0000000..5cdc886
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * arch/sh/kernel/cpu/sh3/probe.c
+ *
+ * CPU Subtype Probing for SH-3.
+ *
+ * Copyright (C) 1999, 2000  Niibe Yutaka
+ * Copyright (C) 2002  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+       unsigned long addr0, addr1, data0, data1, data2, data3;
+
+       jump_to_P2();
+       /*
+        * Check if the entry shadows or not.
+        * When shadowed, it's 128-entry system.
+        * Otherwise, it's 256-entry system.
+        */
+       addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
+       addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
+
+       /* First, write back & invalidate */
+       data0  = ctrl_inl(addr0);
+       ctrl_outl(data0&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr0);
+       data1  = ctrl_inl(addr1);
+       ctrl_outl(data1&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr1);
+
+       /* Next, check if there's shadow or not */
+       data0 = ctrl_inl(addr0);
+       data0 ^= SH_CACHE_VALID;
+       ctrl_outl(data0, addr0);
+       data1 = ctrl_inl(addr1);
+       data2 = data1 ^ SH_CACHE_VALID;
+       ctrl_outl(data2, addr1);
+       data3 = ctrl_inl(addr0);
+
+       /* Lastly, invaliate them. */
+       ctrl_outl(data0&~SH_CACHE_VALID, addr0);
+       ctrl_outl(data2&~SH_CACHE_VALID, addr1);
+
+       back_to_P1();
+
+       cpu_data->dcache.ways           = 4;
+       cpu_data->dcache.entry_shift    = 4;
+       cpu_data->dcache.linesz         = L1_CACHE_BYTES;
+       cpu_data->dcache.flags          = 0;
+
+       /*
+        * 7709A/7729 has 16K cache (256-entry), while 7702 has only
+        * 2K(direct) 7702 is not supported (yet)
+        */
+       if (data0 == data1 && data2 == data3) { /* Shadow */
+               cpu_data->dcache.way_incr       = (1 << 11);
+               cpu_data->dcache.entry_mask     = 0x7f0;
+               cpu_data->dcache.sets           = 128;
+               cpu_data->type = CPU_SH7708;
+
+               cpu_data->flags |= CPU_HAS_MMU_PAGE_ASSOC;
+       } else {                                /* 7709A or 7729  */
+               cpu_data->dcache.way_incr       = (1 << 12);
+               cpu_data->dcache.entry_mask     = 0xff0;
+               cpu_data->dcache.sets           = 256;
+               cpu_data->type = CPU_SH7729;
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+               cpu_data->type = CPU_SH7705;
+
+#if defined(CONFIG_SH7705_CACHE_32KB)
+               cpu_data->dcache.way_incr       = (1 << 13);
+               cpu_data->dcache.entry_mask     = 0x1ff0;
+               cpu_data->dcache.sets           = 512;
+               ctrl_outl(CCR_CACHE_32KB, CCR3);
+#else
+               ctrl_outl(CCR_CACHE_16KB, CCR3);
+#endif
+#endif
+       }
+
+       /*
+        * SH-3 doesn't have separate caches
+        */
+       cpu_data->dcache.flags |= SH_CACHE_COMBINED;
+       cpu_data->icache = cpu_data->dcache;
+
+       return 0;
+}
+
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
new file mode 100644 (file)
index 0000000..42427b7
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * arch/sh/kernel/cpu/sh4/probe.c
+ *
+ * CPU Subtype Probing for SH-4.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004  Paul Mundt
+ * Copyright (C) 2003  Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+       unsigned long pvr, prr, cvr;
+       unsigned long size;
+
+       static unsigned long sizes[16] = {
+               [1] = (1 << 12),
+               [2] = (1 << 13),
+               [4] = (1 << 14),
+               [8] = (1 << 15),
+               [9] = (1 << 16)
+       };
+
+       pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
+       prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
+       cvr = (ctrl_inl(CCN_CVR));
+
+       /*
+        * Setup some sane SH-4 defaults for the icache
+        */
+       cpu_data->icache.way_incr       = (1 << 13);
+       cpu_data->icache.entry_shift    = 5;
+       cpu_data->icache.entry_mask     = 0x1fe0;
+       cpu_data->icache.sets           = 256;
+       cpu_data->icache.ways           = 1;
+       cpu_data->icache.linesz         = L1_CACHE_BYTES;
+
+       /*
+        * And again for the dcache ..
+        */
+       cpu_data->dcache.way_incr       = (1 << 14);
+       cpu_data->dcache.entry_shift    = 5;
+       cpu_data->dcache.entry_mask     = 0x3fe0;
+       cpu_data->dcache.sets           = 512;
+       cpu_data->dcache.ways           = 1;
+       cpu_data->dcache.linesz         = L1_CACHE_BYTES;
+
+       /* Set the FPU flag, virtually all SH-4's have one */
+       cpu_data->flags |= CPU_HAS_FPU;
+
+       /*
+        * Probe the underlying processor version/revision and
+        * adjust cpu_data setup accordingly.
+        */
+       switch (pvr) {
+       case 0x205:
+               cpu_data->type = CPU_SH7750;
+               cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+               break;
+       case 0x206:
+               cpu_data->type = CPU_SH7750S;
+               cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+               break;
+       case 0x1100:
+               cpu_data->type = CPU_SH7751;
+               break;
+       case 0x2000:
+               cpu_data->type = CPU_SH73180;
+               cpu_data->icache.ways = 4;
+               cpu_data->dcache.ways = 4;
+               cpu_data->flags &= ~CPU_HAS_FPU;
+               break;
+       case 0x8000:
+               cpu_data->type = CPU_ST40RA;
+               break;
+       case 0x8100:
+               cpu_data->type = CPU_ST40GX1;
+               break;
+       case 0x700:
+               cpu_data->type = CPU_SH4_501;
+               cpu_data->icache.ways = 2;
+               cpu_data->dcache.ways = 2;
+
+               /* No FPU on the SH4-500 series.. */
+               cpu_data->flags &= ~CPU_HAS_FPU;
+               break;
+       case 0x600:
+               cpu_data->type = CPU_SH4_202;
+               cpu_data->icache.ways = 2;
+               cpu_data->dcache.ways = 2;
+               break;
+       case 0x500 ... 0x501:
+               switch (prr) {
+                   case 0x10: cpu_data->type = CPU_SH7750R; break;
+                   case 0x11: cpu_data->type = CPU_SH7751R; break;
+                   case 0x50: cpu_data->type = CPU_SH7760;  break;
+               }
+
+               cpu_data->icache.ways = 2;
+               cpu_data->dcache.ways = 2;
+
+               break;
+       default:
+               cpu_data->type = CPU_SH_NONE;
+               break;
+       }
+
+       /*
+        * On anything that's not a direct-mapped cache, look to the CVR
+        * for I/D-cache specifics.
+        */
+       if (cpu_data->icache.ways > 1) {
+               size = sizes[(cvr >> 20) & 0xf];
+               cpu_data->icache.way_incr       = (size >> 1);
+               cpu_data->icache.sets           = (size >> 6);
+               cpu_data->icache.entry_mask     =
+                       (cpu_data->icache.way_incr - (1 << 5));
+       }
+
+       if (cpu_data->dcache.ways > 1) {
+               size = sizes[(cvr >> 16) & 0xf];
+               cpu_data->dcache.way_incr       = (size >> 1);
+               cpu_data->dcache.sets           = (size >> 6);
+               cpu_data->dcache.entry_mask     =
+                       (cpu_data->dcache.way_incr - (1 << 5));
+       }
+
+       return 0;
+}
+
diff --git a/arch/sh/lib/memcpy-sh4.S b/arch/sh/lib/memcpy-sh4.S
new file mode 100644 (file)
index 0000000..55f2274
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * "memcpy" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ * Copyright (c) 2002  STMicroelectronics Ltd
+ *   Modified from memcpy.S and micro-optimised for SH4
+ *   Stuart Menefy (stuart.menefy@st.com)
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/config.h>
+
+/*
+ * void *memcpy(void *dst, const void *src, size_t n);
+ *
+ * It is assumed that there is no overlap between src and dst.
+ * If there is an overlap, then the results are undefined.
+ */
+
+       !
+       !       GHIJ KLMN OPQR -->  ...G HIJK LMNO PQR.
+       !
+
+       ! Size is 16 or greater, and may have trailing bytes
+
+       .balign 32
+.Lcase1:
+       ! Read a long word and write a long word at once
+       ! At the start of each iteration, r7 contains last long load
+       add     #-1,r5          !  79 EX
+       mov     r4,r2           !   5 MT (0 cycles latency)
+
+       mov.l   @(r0,r5),r7     !  21 LS (2 cycles latency)
+       add     #-4,r5          !  50 EX
+
+       add     #7,r2           !  79 EX
+       !
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+       ! 6 cycles, 4 bytes per iteration
+3:     mov.l   @(r0,r5),r1     !  21 LS (latency=2)    ! NMLK
+       mov     r7, r3          !   5 MT (latency=0)    ! RQPO
+
+       cmp/hi  r2,r0           !  57 MT
+       shll16  r3              ! 103 EX
+
+       mov     r1,r6           !   5 MT (latency=0)
+       shll8   r3              ! 102 EX                ! Oxxx
+
+       shlr8   r6              ! 106 EX                ! xNML
+       mov     r1, r7          !   5 MT (latency=0)
+
+       or      r6,r3           !  82 EX                ! ONML
+       bt/s    3b              ! 109 BR
+
+        mov.l  r3,@-r0         !  30 LS
+#else
+3:     mov.l   @(r0,r5),r1     !  21 LS (latency=2)    ! KLMN
+       mov     r7,r3           !   5 MT (latency=0)    ! OPQR
+
+       cmp/hi  r2,r0           !  57 MT
+       shlr16  r3              ! 107 EX
+
+       shlr8   r3              ! 106 EX                ! xxxO
+       mov     r1,r6           !   5 MT (latency=0)
+
+       shll8   r6              ! 102 EX                ! LMNx
+       mov     r1,r7           !   5 MT (latency=0)
+
+       or      r6,r3           !  82 EX                ! LMNO
+       bt/s    3b              ! 109 BR
+
+        mov.l  r3,@-r0         !  30 LS
+#endif
+       ! Finally, copy a byte at once, if necessary
+
+       add     #4,r5           !  50 EX
+       cmp/eq  r4,r0           !  54 MT
+
+       add     #-6,r2          !  50 EX
+       bt      9f              ! 109 BR
+
+8:     cmp/hi  r2,r0           !  57 MT
+       mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+
+       bt/s    8b              ! 109 BR
+
+        mov.b  r1,@-r0         !  29 LS
+
+9:     rts
+        nop
+
+
+       !
+       !       GHIJ KLMN OPQR -->  .GHI JKLM NOPQ R...
+       !
+
+       ! Size is 16 or greater, and may have trailing bytes
+
+       .balign 32
+.Lcase3:
+       ! Read a long word and write a long word at once
+       ! At the start of each iteration, r7 contains last long load
+       add     #-3,r5          ! 79 EX
+       mov     r4,r2           !  5 MT (0 cycles latency)
+
+       mov.l   @(r0,r5),r7     ! 21 LS (2 cycles latency)
+       add     #-4,r5          ! 50 EX
+
+       add     #7,r2           !  79 EX
+       !
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+       ! 6 cycles, 4 bytes per iteration
+3:     mov.l   @(r0,r5),r1     !  21 LS (latency=2)    ! NMLK
+       mov     r7, r3          !   5 MT (latency=0)    ! RQPO
+
+       cmp/hi  r2,r0           !  57 MT
+       shll8   r3              ! 102 EX                ! QPOx
+
+       mov     r1,r6           !   5 MT (latency=0)
+       shlr16  r6              ! 107 EX
+
+       shlr8   r6              ! 106 EX                ! xxxN
+       mov     r1, r7          !   5 MT (latency=0)
+
+       or      r6,r3           !  82 EX                ! QPON
+       bt/s    3b              ! 109 BR
+
+        mov.l  r3,@-r0         !  30 LS
+#else
+3:     mov     r1,r3           ! OPQR
+       shlr8   r3              ! xOPQ
+       mov.l   @(r0,r5),r1     ! KLMN
+       mov     r1,r6
+       shll16  r6
+       shll8   r6              ! Nxxx
+       or      r6,r3           ! NOPQ
+       cmp/hi  r2,r0
+       bt/s    3b
+        mov.l  r3,@-r0
+#endif
+
+       ! Finally, copy a byte at once, if necessary
+
+       add     #6,r5           !  50 EX
+       cmp/eq  r4,r0           !  54 MT
+
+       add     #-6,r2          !  50 EX
+       bt      9f              ! 109 BR
+
+8:     cmp/hi  r2,r0           !  57 MT
+       mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+
+       bt/s    8b              ! 109 BR
+
+        mov.b  r1,@-r0         !  29 LS
+
+9:     rts
+        nop
+
+ENTRY(memcpy)
+
+       ! Calculate the invariants which will be used in the remainder
+       ! of the code:
+       !
+       !      r4   -->  [ ...  ] DST             [ ...  ] SRC
+       !                [ ...  ]                 [ ...  ]
+       !                  :                        :
+       !      r0   -->  [ ...  ]       r0+r5 --> [ ...  ]
+       !
+       !
+
+       ! Short circuit the common case of src, dst and len being 32 bit aligned
+       ! and test for zero length move
+
+       mov     r6, r0          !   5 MT (0 cycle latency)
+       or      r4, r0          !  82 EX
+
+       or      r5, r0          !  82 EX
+       tst     r6, r6          !  86 MT
+
+       bt/s    99f             ! 111 BR                (zero len)
+        tst    #3, r0          !  87 MT
+
+       mov     r4, r0          !   5 MT (0 cycle latency)
+       add     r6, r0          !  49 EX
+
+       mov     #16, r1         !   6 EX
+       bt/s    .Lcase00        ! 111 BR                (aligned)
+
+        sub    r4, r5          !  75 EX
+
+       ! Arguments are not nicely long word aligned or zero len.
+       ! Check for small copies, and if so do a simple byte at a time copy.
+       !
+       ! Deciding on an exact value of 'small' is not easy, as the point at which
+       ! using the optimised routines become worthwhile varies (these are the
+       ! cycle counts for differnet sizes using byte-at-a-time vs. optimised):
+       !       size    byte-at-time    long    word    byte
+       !       16      42              39-40   46-50   50-55
+       !       24      58              43-44   54-58   62-67
+       !       36      82              49-50   66-70   80-85
+       ! However the penalty for getting it 'wrong' is much higher for long word
+       ! aligned data (and this is more common), so use a value of 16.
+
+       cmp/gt  r6,r1           !  56 MT
+
+       add     #-1,r5          !  50 EX
+       bf/s    6f              ! 108 BR                (not small)
+
+        mov    r5, r3          !   5 MT (latency=0)
+       shlr    r6              ! 104 EX
+
+       mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+       bf/s    4f              ! 111 BR
+
+        add    #-1,r3          !  50 EX
+       tst     r6, r6          !  86 MT
+
+       bt/s    98f             ! 110 BR
+        mov.b  r1,@-r0         !  29 LS
+
+       ! 4 cycles, 2 bytes per iteration
+3:     mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+
+4:     mov.b   @(r0,r3),r2     !  20 LS (latency=2)
+       dt      r6              !  67 EX
+
+       mov.b   r1,@-r0         !  29 LS
+       bf/s    3b              ! 111 BR
+
+        mov.b  r2,@-r0         !  29 LS
+98:
+       rts
+        nop
+
+99:    rts
+        mov    r4, r0
+
+       ! Size is not small, so its worthwhile looking for optimisations.
+       ! First align destination to a long word boundary.
+       !
+       ! r5 = normal value -1
+
+6:     tst     #3, r0          !  87 MT
+        mov    #3, r3          !   6 EX
+
+       bt/s    2f              ! 111 BR
+        and    r0,r3           !  78 EX
+
+       ! 3 cycles, 1 byte per iteration
+1:     dt      r3              !  67 EX
+       mov.b   @(r0,r5),r1     !  19 LS (latency=2)
+
+       add     #-1, r6         !  79 EX
+       bf/s    1b              ! 109 BR
+
+        mov.b  r1,@-r0         !  28 LS
+
+2:     add     #1, r5          !  79 EX
+
+       ! Now select the appropriate bulk transfer code based on relative
+       ! alignment of src and dst.
+
+       mov     r0, r3          !   5 MT (latency=0)
+
+       mov     r5, r0          !   5 MT (latency=0)
+       tst     #1, r0          !  87 MT
+
+       bf/s    1f              ! 111 BR
+        mov    #64, r7         !   6 EX
+
+       ! bit 0 clear
+
+       cmp/ge  r7, r6          !  55 MT
+
+       bt/s    2f              ! 111 BR
+        tst    #2, r0          !  87 MT
+
+       ! small
+       bt/s    .Lcase0
+        mov    r3, r0
+
+       bra     .Lcase2
+        nop
+
+       ! big
+2:     bt/s    .Lcase0b
+        mov    r3, r0
+
+       bra     .Lcase2b
+        nop
+
+       ! bit 0 set
+1:     tst     #2, r0          ! 87 MT
+
+       bt/s    .Lcase1
+        mov    r3, r0
+
+       bra     .Lcase3
+        nop
+
+
+       !
+       !       GHIJ KLMN OPQR -->  GHIJ KLMN OPQR
+       !
+
+       ! src, dst and size are all long word aligned
+       ! size is non-zero
+
+       .balign 32
+.Lcase00:
+       mov     #64, r1         !   6 EX
+       mov     r5, r3          !   5 MT (latency=0)
+
+       cmp/gt  r6, r1          !  56 MT
+       add     #-4, r5         !  50 EX
+
+       bf      .Lcase00b       ! 108 BR                (big loop)
+       shlr2   r6              ! 105 EX
+
+       shlr    r6              ! 104 EX
+       mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+       bf/s    4f              ! 111 BR
+        add    #-8, r3         !  50 EX
+
+       tst     r6, r6          !  86 MT
+       bt/s    5f              ! 110 BR
+
+        mov.l  r1,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r3), r2   !  21 LS (latency=2)
+       dt      r6              !  67 EX
+
+       mov.l   r1, @-r0        !  30 LS
+       bf/s    3b              ! 109 BR
+
+        mov.l  r2, @-r0        !  30 LS
+
+5:     rts
+        nop
+
+
+       ! Size is 16 or greater and less than 64, but may have trailing bytes
+
+       .balign 32
+.Lcase0:
+       add     #-4, r5         !  50 EX
+       mov     r4, r7          !   5 MT (latency=0)
+
+       mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+       mov     #4, r2          !   6 EX
+
+       add     #11, r7         !  50 EX
+       tst     r2, r6          !  86 MT
+
+       mov     r5, r3          !   5 MT (latency=0)
+       bt/s    4f              ! 111 BR
+
+        add    #-4, r3         !  50 EX
+       mov.l   r1,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r3), r2   !  21 LS (latency=2)
+       cmp/hi  r7, r0
+
+       mov.l   r1, @-r0        !  30 LS
+       bt/s    3b              ! 109 BR
+
+        mov.l  r2, @-r0        !  30 LS
+
+       ! Copy the final 0-3 bytes
+
+       add     #3,r5           !  50 EX
+
+       cmp/eq  r0, r4          !  54 MT
+       add     #-10, r7        !  50 EX
+
+       bt      9f              ! 110 BR
+
+       ! 3 cycles, 1 byte per iteration
+1:     mov.b   @(r0,r5),r1     !  19 LS
+       cmp/hi  r7,r0           !  57 MT
+
+       bt/s    1b              ! 111 BR
+        mov.b  r1,@-r0         !  28 LS
+
+9:     rts
+        nop
+
+       ! Size is at least 64 bytes, so will be going round the big loop at least once.
+       !
+       !   r2 = rounded up r4
+       !   r3 = rounded down r0
+
+       .balign 32
+.Lcase0b:
+       add     #-4, r5         !  50 EX
+
+.Lcase00b:
+       mov     r0, r3          !   5 MT (latency=0)
+       mov     #(~0x1f), r1    !   6 EX
+
+       and     r1, r3          !  78 EX
+       mov     r4, r2          !   5 MT (latency=0)
+
+       cmp/eq  r3, r0          !  54 MT
+       add     #0x1f, r2       !  50 EX
+
+       bt/s    1f              ! 110 BR
+        and    r1, r2          !  78 EX
+
+       ! copy initial words until cache line aligned
+
+       mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+       tst     #4, r0          !  87 MT
+
+       mov     r5, r6          !   5 MT (latency=0)
+       add     #-4, r6         !  50 EX
+
+       bt/s    4f              ! 111 BR
+        add    #8, r3          !  50 EX
+
+       tst     #0x18, r0       !  87 MT
+
+       bt/s    1f              ! 109 BR
+        mov.l  r1,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r6), r7   !  21 LS (latency=2)
+       cmp/eq  r3, r0          !  54 MT
+
+       mov.l   r1, @-r0        !  30 LS
+       bf/s    3b              ! 109 BR
+
+        mov.l  r7, @-r0        !  30 LS
+
+       ! Copy the cache line aligned blocks
+       !
+       ! In use: r0, r2, r4, r5
+       ! Scratch: r1, r3, r6, r7
+       !
+       ! We could do this with the four scratch registers, but if src
+       ! and dest hit the same cache line, this will thrash, so make
+       ! use of additional registers.
+       !
+       ! We also need r0 as a temporary (for movca), so 'undo' the invariant:
+       !   r5:  src (was r0+r5)
+       !   r1:  dest (was r0)
+       ! this can be reversed at the end, so we don't need to save any extra
+       ! state.
+       !
+1:     mov.l   r8, @-r15       !  30 LS
+       add     r0, r5          !  49 EX
+
+       mov.l   r9, @-r15       !  30 LS
+       mov     r0, r1          !   5 MT (latency=0)
+
+       mov.l   r10, @-r15      !  30 LS
+       add     #-0x1c, r5      !  50 EX
+
+       mov.l   r11, @-r15      !  30 LS
+
+       ! 16 cycles, 32 bytes per iteration
+2:     mov.l   @(0x00,r5),r0   ! 18 LS (latency=2)
+       add     #-0x20, r1      ! 50 EX
+       mov.l   @(0x04,r5),r3   ! 18 LS (latency=2)
+       mov.l   @(0x08,r5),r6   ! 18 LS (latency=2)
+       mov.l   @(0x0c,r5),r7   ! 18 LS (latency=2)
+       mov.l   @(0x10,r5),r8   ! 18 LS (latency=2)
+       mov.l   @(0x14,r5),r9   ! 18 LS (latency=2)
+       mov.l   @(0x18,r5),r10  ! 18 LS (latency=2)
+       mov.l   @(0x1c,r5),r11  ! 18 LS (latency=2)
+       movca.l r0,@r1          ! 40 LS (latency=3-7)
+       mov.l   r3,@(0x04,r1)   ! 33 LS
+       mov.l   r6,@(0x08,r1)   ! 33 LS
+       mov.l   r7,@(0x0c,r1)   ! 33 LS
+
+       mov.l   r8,@(0x10,r1)   ! 33 LS
+       add     #-0x20, r5      ! 50 EX
+
+       mov.l   r9,@(0x14,r1)   ! 33 LS
+       cmp/eq  r2,r1           ! 54 MT
+
+       mov.l   r10,@(0x18,r1)  !  33 LS
+       bf/s    2b              ! 109 BR
+
+        mov.l  r11,@(0x1c,r1)  !  33 LS
+
+       mov     r1, r0          !   5 MT (latency=0)
+
+       mov.l   @r15+, r11      !  15 LS
+       sub     r1, r5          !  75 EX
+
+       mov.l   @r15+, r10      !  15 LS
+       cmp/eq  r4, r0          !  54 MT
+
+       bf/s    1f              ! 109 BR
+        mov.l   @r15+, r9      !  15 LS
+
+       rts
+1:      mov.l  @r15+, r8       !  15 LS
+       sub     r4, r1          !  75 EX                (len remaining)
+
+       ! number of trailing bytes is non-zero
+       !
+       ! invariants restored (r5 already decremented by 4)
+       ! also r1=num bytes remaining
+
+       mov     #4, r2          !   6 EX
+       mov     r4, r7          !   5 MT (latency=0)
+
+       add     #0x1c, r5       !  50 EX                (back to -4)
+       cmp/hs  r2, r1          !  58 MT
+
+       bf/s    5f              ! 108 BR
+        add     #11, r7        !  50 EX
+
+       mov.l   @(r0, r5), r6   !  21 LS (latency=2)
+       tst     r2, r1          !  86 MT
+
+       mov     r5, r3          !   5 MT (latency=0)
+       bt/s    4f              ! 111 BR
+
+        add    #-4, r3         !  50 EX
+       cmp/hs  r2, r1          !  58 MT
+
+       bt/s    5f              ! 111 BR
+        mov.l  r6,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r6   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r3), r2   !  21 LS (latency=2)
+       cmp/hi  r7, r0
+
+       mov.l   r6, @-r0        !  30 LS
+       bt/s    3b              ! 109 BR
+
+        mov.l  r2, @-r0        !  30 LS
+
+       ! Copy the final 0-3 bytes
+
+5:     cmp/eq  r0, r4          !  54 MT
+       add     #-10, r7        !  50 EX
+
+       bt      9f              ! 110 BR
+       add     #3,r5           !  50 EX
+
+       ! 3 cycles, 1 byte per iteration
+1:     mov.b   @(r0,r5),r1     !  19 LS
+       cmp/hi  r7,r0           !  57 MT
+
+       bt/s    1b              ! 111 BR
+        mov.b  r1,@-r0         !  28 LS
+
+9:     rts
+        nop
+
+       !
+       !       GHIJ KLMN OPQR -->  ..GH IJKL MNOP QR..
+       !
+
+       .balign 32
+.Lcase2:
+       ! Size is 16 or greater and less then 64, but may have trailing bytes
+
+2:     mov     r5, r6          !   5 MT (latency=0)
+       add     #-2,r5          !  50 EX
+
+       mov     r4,r2           !   5 MT (latency=0)
+       add     #-4,r6          !  50 EX
+
+       add     #7,r2           !  50 EX
+3:     mov.w   @(r0,r5),r1     !  20 LS (latency=2)
+
+       mov.w   @(r0,r6),r3     !  20 LS (latency=2)
+       cmp/hi  r2,r0           !  57 MT
+
+       mov.w   r1,@-r0         !  29 LS
+       bt/s    3b              ! 111 BR
+
+        mov.w  r3,@-r0         !  29 LS
+
+       bra     10f
+        nop
+
+
+       .balign 32
+.Lcase2b:
+       ! Size is at least 64 bytes, so will be going round the big loop at least once.
+       !
+       !   r2 = rounded up r4
+       !   r3 = rounded down r0
+
+       mov     r0, r3          !   5 MT (latency=0)
+       mov     #(~0x1f), r1    !   6 EX
+
+       and     r1, r3          !  78 EX
+       mov     r4, r2          !   5 MT (latency=0)
+
+       cmp/eq  r3, r0          !  54 MT
+       add     #0x1f, r2       !  50 EX
+
+       add     #-2, r5         !  50 EX
+       bt/s    1f              ! 110 BR
+        and    r1, r2          !  78 EX
+
+       ! Copy a short word one at a time until we are cache line aligned
+       !   Normal values: r0, r2, r3, r4
+       !   Unused: r1, r6, r7
+       !   Mod: r5 (=r5-2)
+       !
+       add     #2, r3          !  50 EX
+
+2:     mov.w   @(r0,r5),r1     !  20 LS (latency=2)
+       cmp/eq  r3,r0           !  54 MT
+
+       bf/s    2b              ! 111 BR
+
+        mov.w  r1,@-r0         !  29 LS
+
+       ! Copy the cache line aligned blocks
+       !
+       ! In use: r0, r2, r4, r5 (=r5-2)
+       ! Scratch: r1, r3, r6, r7
+       !
+       ! We could do this with the four scratch registers, but if src
+       ! and dest hit the same cache line, this will thrash, so make
+       ! use of additional registers.
+       !
+       ! We also need r0 as a temporary (for movca), so 'undo' the invariant:
+       !   r5:  src (was r0+r5)
+       !   r1:  dest (was r0)
+       ! this can be reversed at the end, so we don't need to save any extra
+       ! state.
+       !
+1:     mov.l   r8, @-r15       !  30 LS
+       add     r0, r5          !  49 EX
+
+       mov.l   r9, @-r15       !  30 LS
+       mov     r0, r1          !   5 MT (latency=0)
+
+       mov.l   r10, @-r15      !  30 LS
+       add     #-0x1e, r5      !  50 EX
+
+       mov.l   r11, @-r15      !  30 LS
+
+       mov.l   r12, @-r15      !  30 LS
+
+       ! 17 cycles, 32 bytes per iteration
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+2:     mov.w   @r5+, r0        !  14 LS (latency=2)            ..JI
+       add     #-0x20, r1      !  50 EX
+
+       mov.l   @r5+, r3        !  15 LS (latency=2)            NMLK
+
+       mov.l   @r5+, r6        !  15 LS (latency=2)            RQPO
+       shll16  r0              ! 103 EX                        JI..
+
+       mov.l   @r5+, r7        !  15 LS (latency=2)
+       xtrct   r3, r0          !  48 EX                        LKJI
+
+       mov.l   @r5+, r8        !  15 LS (latency=2)
+       xtrct   r6, r3          !  48 EX                        PONM
+
+       mov.l   @r5+, r9        !  15 LS (latency=2)
+       xtrct   r7, r6          !  48 EX
+
+       mov.l   @r5+, r10       !  15 LS (latency=2)
+       xtrct   r8, r7          !  48 EX
+
+       mov.l   @r5+, r11       !  15 LS (latency=2)
+       xtrct   r9, r8          !  48 EX
+
+       mov.w   @r5+, r12       !  15 LS (latency=2)
+       xtrct   r10, r9         !  48 EX
+
+       movca.l r0,@r1          !  40 LS (latency=3-7)
+       xtrct   r11, r10        !  48 EX
+
+       mov.l   r3, @(0x04,r1)  !  33 LS
+       xtrct   r12, r11        !  48 EX
+
+       mov.l   r6, @(0x08,r1)  !  33 LS
+
+       mov.l   r7, @(0x0c,r1)  !  33 LS
+
+       mov.l   r8, @(0x10,r1)  !  33 LS
+       add     #-0x40, r5      !  50 EX
+
+       mov.l   r9, @(0x14,r1)  !  33 LS
+       cmp/eq  r2,r1           !  54 MT
+
+       mov.l   r10, @(0x18,r1) !  33 LS
+       bf/s    2b              ! 109 BR
+
+        mov.l  r11, @(0x1c,r1) !  33 LS
+#else
+2:     mov.w   @(0x1e,r5), r0  !  17 LS (latency=2)
+       add     #-2, r5         !  50 EX
+
+       mov.l   @(0x1c,r5), r3  !  18 LS (latency=2)
+       add     #-4, r1         !  50 EX
+
+       mov.l   @(0x18,r5), r6  !  18 LS (latency=2)
+       shll16  r0              ! 103 EX
+
+       mov.l   @(0x14,r5), r7  !  18 LS (latency=2)
+       xtrct   r3, r0          !  48 EX
+
+       mov.l   @(0x10,r5), r8  !  18 LS (latency=2)
+       xtrct   r6, r3          !  48 EX
+
+       mov.l   @(0x0c,r5), r9  !  18 LS (latency=2)
+       xtrct   r7, r6          !  48 EX
+
+       mov.l   @(0x08,r5), r10 !  18 LS (latency=2)
+       xtrct   r8, r7          !  48 EX
+
+       mov.l   @(0x04,r5), r11 !  18 LS (latency=2)
+       xtrct   r9, r8          !  48 EX
+
+       mov.w   @(0x02,r5), r12 !  18 LS (latency=2)
+       xtrct   r10, r9         !  48 EX
+
+       movca.l r0,@r1          !  40 LS (latency=3-7)
+       add     #-0x1c, r1      !  50 EX
+
+       mov.l   r3, @(0x1c,r1)  !  33 LS
+       xtrct   r11, r10        !  48 EX
+
+       mov.l   r6, @(0x18,r1)  !  33 LS
+       xtrct   r12, r11        !  48 EX
+
+       mov.l   r7, @(0x14,r1)  !  33 LS
+
+       mov.l   r8, @(0x10,r1)  !  33 LS
+       add     #-0x3e, r5      !  50 EX
+
+       mov.l   r9, @(0x0c,r1)  !  33 LS
+       cmp/eq  r2,r1           !  54 MT
+
+       mov.l   r10, @(0x08,r1) !  33 LS
+       bf/s    2b              ! 109 BR
+
+        mov.l  r11, @(0x04,r1) !  33 LS
+#endif
+
+       mov.l   @r15+, r12
+       mov     r1, r0          !   5 MT (latency=0)
+
+       mov.l   @r15+, r11      !  15 LS
+       sub     r1, r5          !  75 EX
+
+       mov.l   @r15+, r10      !  15 LS
+       cmp/eq  r4, r0          !  54 MT
+
+       bf/s    1f              ! 109 BR
+        mov.l   @r15+, r9      !  15 LS
+
+       rts
+1:      mov.l  @r15+, r8       !  15 LS
+
+       add     #0x1e, r5       !  50 EX
+
+       ! Finish off a short word at a time
+       ! r5 must be invariant - 2
+10:    mov     r4,r2           !   5 MT (latency=0)
+       add     #1,r2           !  50 EX
+
+       cmp/hi  r2, r0          !  57 MT
+       bf/s    1f              ! 109 BR
+
+        add    #2, r2          !  50 EX
+
+3:     mov.w   @(r0,r5),r1     !  20 LS
+       cmp/hi  r2,r0           !  57 MT
+
+       bt/s    3b              ! 109 BR
+
+        mov.w  r1,@-r0         !  29 LS
+1:
+
+       !
+       ! Finally, copy the last byte if necessary
+       cmp/eq  r4,r0           !  54 MT
+       bt/s    9b
+        add    #1,r5
+       mov.b   @(r0,r5),r1
+       rts
+        mov.b  r1,@-r0
+
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
new file mode 100644 (file)
index 0000000..3a0508b
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * arch/sh/mm/cache-sh7705.c
+ *
+ * Copyright (C) 1999, 2000  Niibe Yutaka
+ * Copyright (C) 2004  Alex Song
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+
+/* The 32KB cache on the SH7705 suffers from the same synonym problem
+ * as SH4 CPUs */
+
+#define __pte_offset(address) \
+               ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \
+               __pte_offset(address))
+
+static inline void cache_wback_all(void)
+{
+       unsigned long ways, waysize, addrstart;
+
+       ways = cpu_data->dcache.ways;
+       waysize = cpu_data->dcache.sets;
+       waysize <<= cpu_data->dcache.entry_shift;
+
+       addrstart = CACHE_OC_ADDRESS_ARRAY;
+
+       do {
+               unsigned long addr;
+
+               for (addr = addrstart;
+                    addr < addrstart + waysize;
+                    addr += cpu_data->dcache.linesz) {
+                       unsigned long data;
+                       int v = SH_CACHE_UPDATED | SH_CACHE_VALID;
+
+                       data = ctrl_inl(addr);
+
+                       if ((data & v) == v)
+                               ctrl_outl(data & ~v, addr);
+
+               }
+
+               addrstart += cpu_data->dcache.way_incr;
+       } while (--ways);
+}
+
+/*
+ * Write back the range of D-cache, and purge the I-cache.
+ *
+ * Called from kernel/module.c:sys_init_module and routine for a.out format.
+ */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+       __flush_wback_region((void *)start, end - start);
+}
+
+
+/*
+ * Writeback&Invalidate the D-cache of the page
+ */
+static void __flush_dcache_page(unsigned long phys)
+{
+       unsigned long ways, waysize, addrstart;
+       unsigned long flags;
+
+       phys |= SH_CACHE_VALID;
+
+       /*
+        * Here, phys is the physical address of the page. We check all the
+        * tags in the cache for those with the same page number as this page
+        * (by masking off the lowest 2 bits of the 19-bit tag; these bits are
+        * derived from the offset within in the 4k page). Matching valid
+        * entries are invalidated.
+        *
+        * Since 2 bits of the cache index are derived from the virtual page
+        * number, knowing this would reduce the number of cache entries to be
+        * searched by a factor of 4. However this function exists to deal with
+        * potential cache aliasing, therefore the optimisation is probably not
+        * possible.
+        */
+       local_irq_save(flags);
+       jump_to_P2();
+
+       ways = cpu_data->dcache.ways;
+       waysize = cpu_data->dcache.sets;
+       waysize <<= cpu_data->dcache.entry_shift;
+
+       addrstart = CACHE_OC_ADDRESS_ARRAY;
+
+       do {
+               unsigned long addr;
+
+               for (addr = addrstart;
+                    addr < addrstart + waysize;
+                    addr += cpu_data->dcache.linesz) {
+                       unsigned long data;
+
+                       data = ctrl_inl(addr) & (0x1ffffC00 | SH_CACHE_VALID);
+                       if (data == phys) {
+                               data &= ~(SH_CACHE_VALID | SH_CACHE_UPDATED);
+                               ctrl_outl(data, addr);
+                       }
+               }
+
+               addrstart += cpu_data->dcache.way_incr;
+       } while (--ways);
+
+       back_to_P1();
+       local_irq_restore(flags);
+}
+
+
+/*
+ * Write back & invalidate the D-cache of the page.
+ * (To avoid "alias" issues)
+ */
+void flush_dcache_page(struct page *page)
+{
+       if (test_bit(PG_mapped, &page->flags))
+               __flush_dcache_page(PHYSADDR(page_address(page)));
+}
+
+void flush_cache_all(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       jump_to_P2();
+
+       cache_wback_all();
+       back_to_P1();
+       local_irq_restore(flags);
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+       /* Is there any good way? */
+       /* XXX: possibly call flush_cache_range for each vm area */
+       flush_cache_all();
+}
+
+/*
+ * Write back and invalidate D-caches.
+ *
+ * START, END: Virtual Address (U0 address)
+ *
+ * NOTE: We need to flush the _physical_ page entry.
+ * Flushing the cache lines for U0 only isn't enough.
+ * We need to flush for P1 too, which may contain aliases.
+ */
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+                      unsigned long end)
+{
+
+       /*
+        * We could call flush_cache_page for the pages of these range,
+        * but it's not efficient (scan the caches all the time...).
+        *
+        * We can't use A-bit magic, as there's the case we don't have
+        * valid entry on TLB.
+        */
+       flush_cache_all();
+}
+
+/*
+ * Write back and invalidate I/D-caches for the page.
+ *
+ * ADDRESS: Virtual Address (U0 address)
+ */
+void flush_cache_page(struct vm_area_struct *vma, unsigned long address)
+{
+       pgd_t *dir;
+       pmd_t *pmd;
+       pte_t *pte;
+       pte_t entry;
+       unsigned long phys;
+
+       dir = pgd_offset(vma->vm_mm, address);
+       pmd = pmd_offset(dir, address);
+       if (pmd_none(*pmd) || pmd_bad(*pmd))
+               return;
+       pte = pte_offset(pmd, address);
+       entry = *pte;
+       if (pte_none(entry) || !pte_present(entry))
+               return;
+
+       phys = pte_val(entry)&PTE_PHYS_MASK;
+       __flush_dcache_page(phys);
+}
+
+/*
+ * This is called when a page-cache page is about to be mapped into a
+ * user process' address space.  It offers an opportunity for a
+ * port to ensure d-cache/i-cache coherency if necessary.
+ *
+ * Not entirely sure why this is necessary on SH3 with 32K cache but
+ * without it we get occasional "Memory fault" when loading a program.
+ */
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+       __flush_purge_region(page_address(page), PAGE_SIZE);
+}
+
diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c
new file mode 100644 (file)
index 0000000..4a6eea8
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * arch/sh/mm/pg-sh7705.c
+ *
+ * Copyright (C) 1999, 2000  Niibe Yutaka
+ * Copyright (C) 2004  Alex Song
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/addrspace.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+
+static inline void __flush_purge_virtual_region(void *p1, void *virt, int size)
+{
+       unsigned long v;
+       unsigned long begin, end;
+       unsigned long p1_begin;
+
+
+       begin = L1_CACHE_ALIGN((unsigned long)virt);
+       end = L1_CACHE_ALIGN((unsigned long)virt + size);
+
+       p1_begin = (unsigned long)p1 & ~(L1_CACHE_BYTES - 1);
+
+       /* do this the slow way as we may not have TLB entries
+        * for virt yet. */
+       for (v = begin; v < end; v += L1_CACHE_BYTES) {
+               unsigned long p;
+               unsigned long ways, addr;
+
+               p = __pa(p1_begin);
+
+               ways = cpu_data->dcache.ways;
+               addr = CACHE_OC_ADDRESS_ARRAY;
+
+               do {
+                       unsigned long data;
+
+                       addr |= (v & cpu_data->dcache.entry_mask);
+
+                       data = ctrl_inl(addr);
+                       if ((data & CACHE_PHYSADDR_MASK) ==
+                              (p & CACHE_PHYSADDR_MASK)) {
+                               data &= ~(SH_CACHE_UPDATED|SH_CACHE_VALID);
+                               ctrl_outl(data, addr);
+                       }
+
+                       addr += cpu_data->dcache.way_incr;
+               } while (--ways);
+
+               p1_begin += L1_CACHE_BYTES;
+       }
+}
+
+/*
+ * clear_user_page
+ * @to: P1 address
+ * @address: U0 address to be mapped
+ */
+void clear_user_page(void *to, unsigned long address, struct page *pg)
+{
+       struct page *page = virt_to_page(to);
+
+       __set_bit(PG_mapped, &page->flags);
+       if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) {
+               clear_page(to);
+               __flush_wback_region(to, PAGE_SIZE);
+       } else {
+               __flush_purge_virtual_region(to,
+                                            (void *)(address & 0xfffff000),
+                                            PAGE_SIZE);
+               clear_page(to);
+               __flush_wback_region(to, PAGE_SIZE);
+       }
+}
+
+/*
+ * copy_user_page
+ * @to: P1 address
+ * @from: P1 address
+ * @address: U0 address to be mapped
+ */
+void copy_user_page(void *to, void *from, unsigned long address, struct page *pg)
+{
+       struct page *page = virt_to_page(to);
+
+
+       __set_bit(PG_mapped, &page->flags);
+       if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) {
+               copy_page(to, from);
+               __flush_wback_region(to, PAGE_SIZE);
+       } else {
+               __flush_purge_virtual_region(to,
+                                            (void *)(address & 0xfffff000),
+                                            PAGE_SIZE);
+               copy_page(to, from);
+               __flush_wback_region(to, PAGE_SIZE);
+       }
+}
+
+/*
+ * For SH7705, we have our own implementation for ptep_get_and_clear
+ * Copied from pg-sh4.c
+ */
+inline pte_t ptep_get_and_clear(pte_t *ptep)
+{
+       pte_t pte = *ptep;
+
+       pte_clear(ptep);
+       if (!pte_not_present(pte)) {
+               unsigned long pfn = pte_pfn(pte);
+               if (pfn_valid(pfn)) {
+                       struct page *page = pfn_to_page(pfn);
+                       struct address_space *mapping = page_mapping(page);
+                       if (!mapping || !mapping_writably_mapped(mapping))
+                               __clear_bit(PG_mapped, &page->flags);
+               }
+       }
+
+       return pte;
+}
+
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c
new file mode 100644 (file)
index 0000000..de09ba7
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * arch/sh/oprofile/op_model_sh7750.c
+ *
+ * OProfile support for SH7750/SH7750S Performance Counters
+ *
+ * Copyright (C) 2003, 2004  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/oprofile.h>
+#include <linux/profile.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define PM_CR_BASE     0xff000084      /* 16-bit */
+#define PM_CTR_BASE    0xff100004      /* 32-bit */
+
+#define PMCR1          (PM_CR_BASE  + 0x00)
+#define PMCR2          (PM_CR_BASE  + 0x04)
+#define PMCTR1H                (PM_CTR_BASE + 0x00)
+#define PMCTR1L                (PM_CTR_BASE + 0x04)
+#define PMCTR2H                (PM_CTR_BASE + 0x08)
+#define PMCTR2L                (PM_CTR_BASE + 0x0c)
+
+#define PMCR_PMM_MASK  0x0000003f
+
+#define PMCR_CLKF      0x00000100
+#define PMCR_PMCLR     0x00002000
+#define PMCR_PMST      0x00004000
+#define PMCR_PMEN      0x00008000
+
+#define PMCR_ENABLE    (PMCR_PMST | PMCR_PMEN)
+
+/*
+ * SH7750/SH7750S have 2 perf counters
+ */
+#define NR_CNTRS       2
+
+extern const char *get_cpu_subtype(void);
+
+struct op_counter_config {
+       unsigned long enabled;
+       unsigned long event;
+       unsigned long count;
+
+       /* Dummy values for userspace tool compliance */
+       unsigned long kernel;
+       unsigned long user;
+       unsigned long unit_mask;
+};
+
+static struct op_counter_config ctr[NR_CNTRS];
+
+/*
+ * There are a number of events supported by each counter (33 in total).
+ * Since we have 2 counters, each counter will take the event code as it
+ * corresponds to the PMCR PMM setting. Each counter can be configured
+ * independently.
+ *
+ *     Event Code      Description
+ *     ----------      -----------
+ *
+ *     0x01            Operand read access
+ *     0x02            Operand write access
+ *     0x03            UTLB miss
+ *     0x04            Operand cache read miss
+ *     0x05            Operand cache write miss
+ *     0x06            Instruction fetch (w/ cache)
+ *     0x07            Instruction TLB miss
+ *     0x08            Instruction cache miss
+ *     0x09            All operand accesses
+ *     0x0a            All instruction accesses
+ *     0x0b            OC RAM operand access
+ *     0x0d            On-chip I/O space access
+ *     0x0e            Operand access (r/w)
+ *     0x0f            Operand cache miss (r/w)
+ *     0x10            Branch instruction
+ *     0x11            Branch taken
+ *     0x12            BSR/BSRF/JSR
+ *     0x13            Instruction execution
+ *     0x14            Instruction execution in parallel
+ *     0x15            FPU Instruction execution
+ *     0x16            Interrupt
+ *     0x17            NMI
+ *     0x18            trapa instruction execution
+ *     0x19            UBCA match
+ *     0x1a            UBCB match
+ *     0x21            Instruction cache fill
+ *     0x22            Operand cache fill
+ *     0x23            Elapsed time
+ *     0x24            Pipeline freeze by I-cache miss
+ *     0x25            Pipeline freeze by D-cache miss
+ *     0x27            Pipeline freeze by branch instruction
+ *     0x28            Pipeline freeze by CPU register
+ *     0x29            Pipeline freeze by FPU
+ *
+ * Unfortunately we don't have a native exception or interrupt for counter
+ * overflow (although since these counters can run for 16.3 days without
+ * overflowing, it's not really necessary).
+ *
+ * OProfile on the other hand likes to have samples taken periodically, so
+ * for now we just piggyback the timer interrupt to get the expected
+ * behavior.
+ */
+
+static int sh7750_timer_notify(struct notifier_block *self,
+                              unsigned long val, void *data)
+{
+       struct pt_regs *regs = data;
+       unsigned long pc;
+
+       pc = instruction_pointer(regs);
+       oprofile_add_sample(pc, !user_mode(regs), 0, smp_processor_id());
+
+       return 0;
+}
+
+static struct notifier_block sh7750_timer_notifier = {
+       .notifier_call          = sh7750_timer_notify,
+};
+
+static u64 sh7750_read_counter(int counter)
+{
+       u32 hi, lo;
+
+       hi = (counter == 0) ? ctrl_inl(PMCTR1H) : ctrl_inl(PMCTR2H);
+       lo = (counter == 0) ? ctrl_inl(PMCTR1L) : ctrl_inl(PMCTR2L);
+
+       return (u64)((u64)(hi & 0xffff) << 32) | lo;
+}
+
+/*
+ * Files will be in a path like:
+ *
+ *  /<oprofilefs mount point>/<counter number>/<file>
+ *
+ * So when dealing with <file>, we look to the parent dentry for the counter
+ * number.
+ */
+static inline int to_counter(struct file *file)
+{
+       const unsigned char *name = file->f_dentry->d_parent->d_name.name;
+
+       return (int)simple_strtol(name, NULL, 10);
+}
+
+/*
+ * XXX: We have 48-bit counters, so we're probably going to want something
+ * more along the lines of oprofilefs_ullong_to_user().. Truncating to
+ * unsigned long works fine for now though, as long as we don't attempt to
+ * profile for too horribly long.
+ */
+static ssize_t sh7750_read_count(struct file *file, char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       int counter = to_counter(file);
+       u64 val = sh7750_read_counter(counter);
+
+       return oprofilefs_ulong_to_user((unsigned long)val, buf, count, ppos);
+}
+
+static ssize_t sh7750_write_count(struct file *file, const char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       int counter = to_counter(file);
+       unsigned long val;
+
+       if (oprofilefs_ulong_from_user(&val, buf, count))
+               return -EFAULT;
+
+       /*
+        * Any write will clear the counter, although only 0 should be
+        * written for this purpose, as we do not support setting the
+        * counter to an arbitrary value.
+        */
+       WARN_ON(val != 0);
+
+       if (counter == 0) {
+               ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1);
+       } else {
+               ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2);
+       }
+
+       return count;
+}
+
+static struct file_operations count_fops = {
+       .read           = sh7750_read_count,
+       .write          = sh7750_write_count,
+};
+
+static int sh7750_perf_counter_create_files(struct super_block *sb, struct dentry *root)
+{
+       int i;
+
+       for (i = 0; i < NR_CNTRS; i++) {
+               struct dentry *dir;
+               char buf[3];
+
+               snprintf(buf, sizeof(buf), "%d", i);
+               dir = oprofilefs_mkdir(sb, root, buf);
+
+               oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
+               oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
+               oprofilefs_create_file(sb, dir, "count", &count_fops);
+
+               /* Dummy entries */
+               oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
+               oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
+               oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
+       }
+
+       return 0;
+}
+
+static int sh7750_perf_counter_start(void)
+{
+       u16 pmcr;
+
+       /* Enable counter 1 */
+       if (ctr[0].enabled) {
+               pmcr = ctrl_inw(PMCR1);
+               WARN_ON(pmcr & PMCR_PMEN);
+
+               pmcr &= ~PMCR_PMM_MASK;
+               pmcr |= ctr[0].event;
+               ctrl_outw(pmcr | PMCR_ENABLE, PMCR1);
+       }
+
+       /* Enable counter 2 */
+       if (ctr[1].enabled) {
+               pmcr = ctrl_inw(PMCR2);
+               WARN_ON(pmcr & PMCR_PMEN);
+
+               pmcr &= ~PMCR_PMM_MASK;
+               pmcr |= ctr[1].event;
+               ctrl_outw(pmcr | PMCR_ENABLE, PMCR2);
+       }
+
+       return register_profile_notifier(&sh7750_timer_notifier);
+}
+
+static void sh7750_perf_counter_stop(void)
+{
+       ctrl_outw(ctrl_inw(PMCR1) & ~PMCR_PMEN, PMCR1);
+       ctrl_outw(ctrl_inw(PMCR2) & ~PMCR_PMEN, PMCR2);
+
+       unregister_profile_notifier(&sh7750_timer_notifier);
+}
+
+static struct oprofile_operations sh7750_perf_counter_ops = {
+       .create_files   = sh7750_perf_counter_create_files,
+       .start          = sh7750_perf_counter_start,
+       .stop           = sh7750_perf_counter_stop,
+};
+
+int __init oprofile_arch_init(struct oprofile_operations **ops)
+{
+       if (!(cpu_data->flags & CPU_HAS_PERF_COUNTER))
+               return -ENODEV;
+
+       sh7750_perf_counter_ops.cpu_type = (char *)get_cpu_subtype();
+       *ops = &sh7750_perf_counter_ops;
+
+       printk(KERN_INFO "oprofile: using SH-4 (%s) performance monitoring.\n",
+              sh7750_perf_counter_ops.cpu_type);
+
+       /* Clear the counters */
+       ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1);
+       ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2);
+
+       return 0;
+}
+
+void oprofile_arch_exit(void)
+{
+}
+
diff --git a/arch/sh/tools/gen-mach-types b/arch/sh/tools/gen-mach-types
new file mode 100644 (file)
index 0000000..bb2b822
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/awk
+#
+# Awk script to generate include/asm-sh/machtypes.h
+# Heavily based on arch/arm/tools/gen-mach-types
+#
+BEGIN  { nr = 0 }
+/^#/   { next }
+/^[    ]*$/ { next }
+
+NF == 2 {
+         mach[nr] = $1;
+         config[nr] = "CONFIG_"$2;
+         nr++;
+       }
+
+END    {
+         printf("/*\n");
+         printf(" * Automagically generated, don't touch.\n");
+         printf(" */\n");
+         printf("#ifndef __ASM_SH_MACHTYPES_H\n");
+         printf("#define __ASM_SH_MACHTYPES_H\n");
+         printf("\n");
+         printf("#include <linux/config.h>\n");
+         printf("\n");
+         printf("/*\n");
+         printf(" * We'll use the following MACH_xxx defs for placeholders for the time\n");
+         printf(" * being .. these will all go away once sh_machtype is assigned per-board.\n");
+         printf(" *\n");
+         printf(" * For now we leave things the way they are for backwards compatibility.\n");
+         printf(" */\n");
+         printf("\n");
+         printf("/* Mach types */\n");
+
+         for (i = 0; i < nr; i++) {
+             printf("#ifdef %s\n", config[i]);
+             printf("  #define MACH_%s\t\t1\n", mach[i]);
+             printf("#else\n");
+             printf("  #define MACH_%s\t\t0\n", mach[i]);
+             printf("#endif\n");
+           }
+
+         printf("\n");
+         printf("/* Machtype checks */\n");
+         for (i = 0; i < nr; i++)
+             printf("#define mach_is_%s()\t\t\t(MACH_%s)\n",
+                tolower(mach[i]), mach[i]);
+         printf("\n");
+         printf("#endif /* __ASM_SH_MACHTYPES_H */\n");
+       }
diff --git a/arch/sh64/Kconfig.debug b/arch/sh64/Kconfig.debug
new file mode 100644 (file)
index 0000000..530b3c6
--- /dev/null
@@ -0,0 +1,37 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+       bool "Early SCIF console support"
+
+config DEBUG_KERNEL_WITH_GDB_STUB
+       bool "GDB Stub kernel debug"
+
+config SH64_PROC_TLB
+       bool "Debug: report TLB fill/purge activity through /proc/tlb"
+       depends on PROC_FS
+
+config SH64_PROC_ASIDS
+       bool "Debug: report ASIDs through /proc/asids"
+       depends on PROC_FS
+
+config SH64_SR_WATCH
+       bool "Debug: set SR.WATCH to enable hardware watchpoints and trace"
+
+config SH_ALPHANUMERIC
+       bool "Enable debug outputs to on-board alphanumeric display"
+
+config SH_NO_BSS_INIT
+       bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)"
+
+config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       default y if KGDB
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         and slower, but it will give very useful debugging information.
+         If you don't debug the kernel, you can say N, but we may not be able
+         to solve problems without frame pointers.
+
+endmenu
diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug
new file mode 100644 (file)
index 0000000..120f6b5
--- /dev/null
@@ -0,0 +1,14 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_STACK_USAGE
+       bool "Enable stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+endmenu
diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug
new file mode 100644 (file)
index 0000000..cd8d39f
--- /dev/null
@@ -0,0 +1,54 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_STACK_USAGE
+       bool "Enable stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+config KPROBES
+       bool "Kprobes"
+       depends on DEBUG_KERNEL
+       help
+         Kprobes allows you to trap at almost any kernel address and
+         execute a callback function.  register_kprobe() establishes
+         a probepoint and specifies the callback.  Kprobes is useful
+         for kernel debugging, non-intrusive instrumentation and testing.
+         If in doubt, say "N".
+
+config DEBUG_DCFLUSH
+       bool "D-cache flush debugging"
+       depends on DEBUG_KERNEL
+
+config STACK_DEBUG
+       depends on DEBUG_KERNEL
+       bool "Stack Overflow Detection Support"
+
+config DEBUG_BOOTMEM
+       depends on DEBUG_KERNEL
+       bool "Debug BOOTMEM initialization"
+
+# We have a custom atomic_dec_and_lock() implementation but it's not
+# compatible with spinlock debugging so we need to fall back on
+# the generic version in that case.
+config HAVE_DEC_LOCK
+       bool
+       depends on SMP && !DEBUG_SPINLOCK
+       default y
+
+config MCOUNT
+       bool
+       depends on STACK_DEBUG
+       default y
+
+config FRAME_POINTER
+       bool
+       depends on MCOUNT
+       default y
+
+endmenu
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
new file mode 100644 (file)
index 0000000..bc5cc1d
--- /dev/null
@@ -0,0 +1,373 @@
+/* arch/sparc64/kernel/kprobes.c
+ *
+ * Copyright (C) 2004 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+
+#include <asm/kdebug.h>
+#include <asm/signal.h>
+
+/* We do not have hardware single-stepping on sparc64.
+ * So we implement software single-stepping with breakpoint
+ * traps.  The top-level scheme is similar to that used
+ * in the x86 kprobes implementation.
+ *
+ * In the kprobe->insn[] array we store the original
+ * instruction at index zero and a break instruction at
+ * index one.
+ *
+ * When we hit a kprobe we:
+ * - Run the pre-handler
+ * - Remember "regs->tnpc" and interrupt level stored in
+ *   "regs->tstate" so we can restore them later
+ * - Disable PIL interrupts
+ * - Set regs->tpc to point to kprobe->insn[0]
+ * - Set regs->tnpc to point to kprobe->insn[1]
+ * - Mark that we are actively in a kprobe
+ *
+ * At this point we wait for the second breakpoint at
+ * kprobe->insn[1] to hit.  When it does we:
+ * - Run the post-handler
+ * - Set regs->tpc to "remembered" regs->tnpc stored above,
+ *   restore the PIL interrupt level in "regs->tstate" as well
+ * - Make any adjustments necessary to regs->tnpc in order
+ *   to handle relative branches correctly.  See below.
+ * - Mark that we are no longer actively in a kprobe.
+ */
+
+void arch_prepare_kprobe(struct kprobe *p)
+{
+       p->insn[0] = *p->addr;
+       p->insn[1] = BREAKPOINT_INSTRUCTION_2;
+}
+
+/* kprobe_status settings */
+#define KPROBE_HIT_ACTIVE      0x00000001
+#define KPROBE_HIT_SS          0x00000002
+
+static struct kprobe *current_kprobe;
+static unsigned long current_kprobe_orig_tnpc;
+static unsigned long current_kprobe_orig_tstate_pil;
+static unsigned int kprobe_status;
+
+static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+       current_kprobe_orig_tnpc = regs->tnpc;
+       current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
+       regs->tstate |= TSTATE_PIL;
+
+       regs->tpc = (unsigned long) &p->insn[0];
+       regs->tnpc = (unsigned long) &p->insn[1];
+}
+
+static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
+{
+       *p->addr = p->opcode;
+       flushi(p->addr);
+
+       regs->tpc = (unsigned long) p->addr;
+       regs->tnpc = current_kprobe_orig_tnpc;
+       regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+                       current_kprobe_orig_tstate_pil);
+}
+
+static int kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p;
+       void *addr = (void *) regs->tpc;
+       int ret = 0;
+
+       preempt_disable();
+
+       if (kprobe_running()) {
+               /* We *are* holding lock here, so this is safe.
+                * Disarm the probe we just hit, and ignore it.
+                */
+               p = get_kprobe(addr);
+               if (p) {
+                       disarm_kprobe(p, regs);
+                       ret = 1;
+               } else {
+                       p = current_kprobe;
+                       if (p->break_handler && p->break_handler(p, regs))
+                               goto ss_probe;
+               }
+               /* If it's not ours, can't be delete race, (we hold lock). */
+               goto no_kprobe;
+       }
+
+       lock_kprobes();
+       p = get_kprobe(addr);
+       if (!p) {
+               unlock_kprobes();
+               if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) {
+                       /*
+                        * The breakpoint instruction was removed right
+                        * after we hit it.  Another cpu has removed
+                        * either a probepoint or a debugger breakpoint
+                        * at this address.  In either case, no further
+                        * handling of this interrupt is appropriate.
+                        */
+                       ret = 1;
+               }
+               /* Not one of ours: let kernel handle it */
+               goto no_kprobe;
+       }
+
+       kprobe_status = KPROBE_HIT_ACTIVE;
+       current_kprobe = p;
+       if (p->pre_handler(p, regs))
+               return 1;
+
+ss_probe:
+       prepare_singlestep(p, regs);
+       kprobe_status = KPROBE_HIT_SS;
+       return 1;
+
+no_kprobe:
+       preempt_enable_no_resched();
+       return ret;
+}
+
+/* If INSN is a relative control transfer instruction,
+ * return the corrected branch destination value.
+ *
+ * The original INSN location was REAL_PC, it actually
+ * executed at PC and produced destination address NPC.
+ */
+static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc,
+                                    unsigned long pc, unsigned long npc)
+{
+       /* Branch not taken, no mods necessary.  */
+       if (npc == pc + 0x4UL)
+               return real_pc + 0x4UL;
+
+       /* The three cases are call, branch w/prediction,
+        * and traditional branch.
+        */
+       if ((insn & 0xc0000000) == 0x40000000 ||
+           (insn & 0xc1c00000) == 0x00400000 ||
+           (insn & 0xc1c00000) == 0x00800000) {
+               /* The instruction did all the work for us
+                * already, just apply the offset to the correct
+                * instruction location.
+                */
+               return (real_pc + (npc - pc));
+       }
+
+       return real_pc + 0x4UL;
+}
+
+/* If INSN is an instruction which writes it's PC location
+ * into a destination register, fix that up.
+ */
+static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
+{
+       unsigned long *slot = NULL;
+
+       /* Simplest cast is call, which always uses %o7 */
+       if ((insn & 0xc0000000) == 0x40000000) {
+               slot = &regs->u_regs[UREG_I7];
+       }
+
+       /* Jmpl encodes the register inside of the opcode */
+       if ((insn & 0xc1f80000) == 0x81c00000) {
+               unsigned long rd = ((insn >> 25) & 0x1f);
+
+               if (rd <= 15) {
+                       slot = &regs->u_regs[rd];
+               } else {
+                       /* Hard case, it goes onto the stack. */
+                       flushw_all();
+
+                       rd -= 16;
+                       slot = (unsigned long *)
+                               (regs->u_regs[UREG_FP] + STACK_BIAS);
+                       slot += rd;
+               }
+       }
+       if (slot != NULL)
+               *slot = real_pc;
+}
+
+/*
+ * Called after single-stepping.  p->addr is the address of the
+ * instruction whose first byte has been replaced by the breakpoint
+ * instruction.  To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction.  The address of this
+ * copy is p->insn.
+ *
+ * This function prepares to return from the post-single-step
+ * breakpoint trap.
+ */
+static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+{
+       u32 insn = p->insn[0];
+
+       regs->tpc = current_kprobe_orig_tnpc;
+       regs->tnpc = relbranch_fixup(insn,
+                                    (unsigned long) p->addr,
+                                    (unsigned long) &p->insn[0],
+                                    regs->tnpc);
+       retpc_fixup(regs, insn, (unsigned long) p->addr);
+
+       regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+                       current_kprobe_orig_tstate_pil);
+}
+
+static inline int post_kprobe_handler(struct pt_regs *regs)
+{
+       if (!kprobe_running())
+               return 0;
+
+       if (current_kprobe->post_handler)
+               current_kprobe->post_handler(current_kprobe, regs, 0);
+
+       resume_execution(current_kprobe, regs);
+
+       unlock_kprobes();
+       preempt_enable_no_resched();
+
+       return 1;
+}
+
+/* Interrupts disabled, kprobe_lock held. */
+static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       if (current_kprobe->fault_handler
+           && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
+               return 1;
+
+       if (kprobe_status & KPROBE_HIT_SS) {
+               resume_execution(current_kprobe, regs);
+
+               unlock_kprobes();
+               preempt_enable_no_resched();
+       }
+       return 0;
+}
+
+/*
+ * Wrapper routine to for handling exceptions.
+ */
+int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
+                            void *data)
+{
+       struct die_args *args = (struct die_args *)data;
+       switch (val) {
+       case DIE_DEBUG:
+               if (kprobe_handler(args->regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_DEBUG_2:
+               if (post_kprobe_handler(args->regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_GPF:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_PAGE_FAULT:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
+{
+       BUG_ON(trap_level != 0x170 && trap_level != 0x171);
+
+       if (user_mode(regs)) {
+               local_irq_enable();
+               bad_trap(regs, trap_level);
+               return;
+       }
+
+       /* trap_level == 0x170 --> ta 0x70
+        * trap_level == 0x171 --> ta 0x71
+        */
+       if (notify_die((trap_level == 0x170) ? DIE_DEBUG : DIE_DEBUG_2,
+                      (trap_level == 0x170) ? "debug" : "debug_2",
+                      regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP)
+               bad_trap(regs, trap_level);
+}
+
+/* Jprobes support.  */
+static struct pt_regs jprobe_saved_regs;
+static struct pt_regs *jprobe_saved_regs_location;
+static struct sparc_stackf jprobe_saved_stack;
+
+int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+       jprobe_saved_regs_location = regs;
+       memcpy(&jprobe_saved_regs, regs, sizeof(*regs));
+
+       /* Save a whole stack frame, this gets arguments
+        * pushed onto the stack after using up all the
+        * arg registers.
+        */
+       memcpy(&jprobe_saved_stack,
+              (char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
+              sizeof(jprobe_saved_stack));
+
+       regs->tpc  = (unsigned long) jp->entry;
+       regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
+       regs->tstate |= TSTATE_PIL;
+
+       return 1;
+}
+
+void jprobe_return(void)
+{
+       preempt_enable_no_resched();
+       __asm__ __volatile__(
+               ".globl jprobe_return_trap_instruction\n"
+"jprobe_return_trap_instruction:\n\t"
+               "ta 0x70");
+}
+
+extern void jprobe_return_trap_instruction(void);
+
+extern void __show_regs(struct pt_regs * regs);
+
+int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       u32 *addr = (u32 *) regs->tpc;
+
+       if (addr == (u32 *) jprobe_return_trap_instruction) {
+               if (jprobe_saved_regs_location != regs) {
+                       printk("JPROBE: Current regs (%p) does not match "
+                              "saved regs (%p).\n",
+                              regs, jprobe_saved_regs_location);
+                       printk("JPROBE: Saved registers\n");
+                       __show_regs(jprobe_saved_regs_location);
+                       printk("JPROBE: Current registers\n");
+                       __show_regs(regs);
+                       BUG();
+               }
+               /* Restore old register state.  Do pt_regs
+                * first so that UREG_FP is the original one for
+                * the stack frame restore.
+                */
+               memcpy(regs, &jprobe_saved_regs, sizeof(*regs));
+
+               memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
+                      &jprobe_saved_stack,
+                      sizeof(jprobe_saved_stack));
+
+               return 1;
+       }
+       return 0;
+}
diff --git a/arch/sparc64/lib/U1copy_from_user.S b/arch/sparc64/lib/U1copy_from_user.S
new file mode 100644 (file)
index 0000000..93146a8
--- /dev/null
@@ -0,0 +1,33 @@
+/* U1copy_from_user.S: UltraSparc-I/II/IIi/IIe optimized copy from userspace.
+ *
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
+ */
+
+#define EX_LD(x)               \
+98:    x;                      \
+       .section .fixup;        \
+       .align 4;               \
+99:    retl;                   \
+        mov    1, %o0;         \
+       .section __ex_table;    \
+       .align 4;               \
+       .word 98b, 99b;         \
+       .text;                  \
+       .align 4;
+
+#define FUNC_NAME              ___copy_from_user
+#define LOAD(type,addr,dest)   type##a [addr] %asi, dest
+#define LOAD_BLK(addr,dest)    ldda [addr] ASI_BLK_AIUS, dest
+#define EX_RETVAL(x)           0
+
+       /* Writing to %asi is _expensive_ so we hardcode it.
+        * Reading %asi to check for KERNEL_DS is comparatively
+        * cheap.
+        */
+#define PREAMBLE                                       \
+       rd              %asi, %g1;                      \
+       cmp             %g1, ASI_AIUS;                  \
+       bne,pn          %icc, memcpy_user_stub;         \
+        nop;                                           \
+
+#include "U1memcpy.S"
diff --git a/arch/sparc64/lib/U1copy_to_user.S b/arch/sparc64/lib/U1copy_to_user.S
new file mode 100644 (file)
index 0000000..1fccc52
--- /dev/null
@@ -0,0 +1,33 @@
+/* U1copy_to_user.S: UltraSparc-I/II/IIi/IIe optimized copy to userspace.
+ *
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
+ */
+
+#define EX_ST(x)               \
+98:    x;                      \
+       .section .fixup;        \
+       .align 4;               \
+99:    retl;                   \
+        mov    1, %o0;         \
+       .section __ex_table;    \
+       .align 4;               \
+       .word 98b, 99b;         \
+       .text;                  \
+       .align 4;
+
+#define FUNC_NAME              ___copy_to_user
+#define STORE(type,src,addr)   type##a src, [addr] ASI_AIUS
+#define STORE_BLK(src,addr)    stda src, [addr] ASI_BLK_AIUS
+#define EX_RETVAL(x)           0
+
+       /* Writing to %asi is _expensive_ so we hardcode it.
+        * Reading %asi to check for KERNEL_DS is comparatively
+        * cheap.
+        */
+#define PREAMBLE                                       \
+       rd              %asi, %g1;                      \
+       cmp             %g1, ASI_AIUS;                  \
+       bne,pn          %icc, memcpy_user_stub;         \
+        nop;                                           \
+
+#include "U1memcpy.S"
diff --git a/arch/sparc64/lib/U1memcpy.S b/arch/sparc64/lib/U1memcpy.S
new file mode 100644 (file)
index 0000000..06a5bd2
--- /dev/null
@@ -0,0 +1,555 @@
+/* U1memcpy.S: UltraSPARC-I/II/IIi/IIe optimized memcpy.
+ *
+ * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#else
+#define ASI_BLK_P 0xf0
+#define FPRS_FEF  0x04
+#ifdef MEMCPY_DEBUG
+#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs; \
+                clr %g1; clr %g2; clr %g3; subcc %g0, %g0, %g0;
+#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#else
+#define VISEntry rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExit and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#endif
+#endif
+
+#ifndef EX_LD
+#define EX_LD(x)       x
+#endif
+
+#ifndef EX_ST
+#define EX_ST(x)       x
+#endif
+
+#ifndef EX_RETVAL
+#define EX_RETVAL(x)   x
+#endif
+
+#ifndef LOAD
+#define LOAD(type,addr,dest)   type [addr], dest
+#endif
+
+#ifndef LOAD_BLK
+#define LOAD_BLK(addr,dest)    ldda [addr] ASI_BLK_P, dest
+#endif
+
+#ifndef STORE
+#define STORE(type,src,addr)   type src, [addr]
+#endif
+
+#ifndef STORE_BLK
+#define STORE_BLK(src,addr)    stda src, [addr] ASI_BLK_P
+#endif
+
+#ifndef FUNC_NAME
+#define FUNC_NAME      memcpy
+#endif
+
+#ifndef PREAMBLE
+#define PREAMBLE
+#endif
+
+#ifndef XCC
+#define XCC xcc
+#endif
+
+#define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9)          \
+       faligndata              %f1, %f2, %f48;                 \
+       faligndata              %f2, %f3, %f50;                 \
+       faligndata              %f3, %f4, %f52;                 \
+       faligndata              %f4, %f5, %f54;                 \
+       faligndata              %f5, %f6, %f56;                 \
+       faligndata              %f6, %f7, %f58;                 \
+       faligndata              %f7, %f8, %f60;                 \
+       faligndata              %f8, %f9, %f62;
+
+#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)   \
+       EX_LD(LOAD_BLK(%src, %fdest));                          \
+       EX_ST(STORE_BLK(%fsrc, %dest));                         \
+       add                     %src, 0x40, %src;               \
+       subcc                   %len, 0x40, %len;               \
+       be,pn                   %xcc, jmptgt;                   \
+        add                    %dest, 0x40, %dest;             \
+
+#define LOOP_CHUNK1(src, dest, len, branch_dest)               \
+       MAIN_LOOP_CHUNK(src, dest, f0,  f48, len, branch_dest)
+#define LOOP_CHUNK2(src, dest, len, branch_dest)               \
+       MAIN_LOOP_CHUNK(src, dest, f16, f48, len, branch_dest)
+#define LOOP_CHUNK3(src, dest, len, branch_dest)               \
+       MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
+
+#define STORE_SYNC(dest, fsrc)                         \
+       EX_ST(STORE_BLK(%fsrc, %dest));                 \
+       add                     %dest, 0x40, %dest;
+
+#define STORE_JUMP(dest, fsrc, target)                 \
+       EX_ST(STORE_BLK(%fsrc, %dest));                 \
+       add                     %dest, 0x40, %dest;     \
+       ba,pt                   %xcc, target;
+
+#define FINISH_VISCHUNK(dest, f0, f1, left)    \
+       subcc                   %left, 8, %left;\
+       bl,pn                   %xcc, 95f;      \
+        faligndata             %f0, %f1, %f48; \
+       EX_ST(STORE(std, %f48, %dest));         \
+       add                     %dest, 8, %dest;
+
+#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)       \
+       subcc                   %left, 8, %left;        \
+       bl,pn                   %xcc, 95f;              \
+        fsrc1                  %f0, %f1;
+
+#define UNEVEN_VISCHUNK(dest, f0, f1, left)            \
+       UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)        \
+       ba,a,pt                 %xcc, 93f;
+
+       .register       %g2,#scratch
+       .register       %g3,#scratch
+
+       .text
+       .align          64
+
+       .globl          FUNC_NAME
+       .type           FUNC_NAME,#function
+FUNC_NAME:             /* %o0=dst, %o1=src, %o2=len */
+       PREAMBLE
+       mov             %o0, %g5
+       cmp             %o2, 0
+       be,pn           %XCC, 85f
+        or             %o0, %o1, %o3
+       cmp             %o2, 16
+       blu,a,pn        %XCC, 80f
+        or             %o3, %o2, %o3
+
+       cmp             %o2, (5 * 64)
+       blu,pt          %XCC, 70f
+        andcc          %o3, 0x7, %g0
+
+       /* Clobbers o5/g1/g2/g3/g7/icc/xcc.  */
+       VISEntry
+
+       /* Is 'dst' already aligned on an 64-byte boundary? */
+       andcc           %o0, 0x3f, %g2
+       be,pt           %XCC, 2f
+
+       /* Compute abs((dst & 0x3f) - 0x40) into %g2.  This is the number
+        * of bytes to copy to make 'dst' 64-byte aligned.  We pre-
+        * subtract this from 'len'.
+        */
+        sub            %o0, %o1, %o4
+       sub             %g2, 0x40, %g2
+       sub             %g0, %g2, %g2
+       sub             %o2, %g2, %o2
+       andcc           %g2, 0x7, %g1
+       be,pt           %icc, 2f
+        and            %g2, 0x38, %g2
+
+1:     subcc           %g1, 0x1, %g1
+       EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
+       EX_ST(STORE(stb, %o3, %o1 + %o4))
+       bgu,pt          %XCC, 1b
+        add            %o1, 0x1, %o1
+
+       add             %o1, %o4, %o0
+
+2:     cmp             %g2, 0x0
+       and             %o1, 0x7, %g1
+       be,pt           %icc, 3f
+        alignaddr      %o1, %g0, %o1
+
+       EX_LD(LOAD(ldd, %o1, %f4))
+1:     EX_LD(LOAD(ldd, %o1 + 0x8, %f6))
+       add             %o1, 0x8, %o1
+       subcc           %g2, 0x8, %g2
+       faligndata      %f4, %f6, %f0
+       EX_ST(STORE(std, %f0, %o0))
+       be,pn           %icc, 3f
+        add            %o0, 0x8, %o0
+
+       EX_LD(LOAD(ldd, %o1 + 0x8, %f4))
+       add             %o1, 0x8, %o1
+       subcc           %g2, 0x8, %g2
+       faligndata      %f6, %f4, %f0
+       EX_ST(STORE(std, %f0, %o0))
+       bne,pt          %icc, 1b
+        add            %o0, 0x8, %o0
+
+       /* Destination is 64-byte aligned.  */
+3:     
+       membar            #LoadStore | #StoreStore | #StoreLoad
+
+       subcc           %o2, 0x40, %o4
+       add             %o1, %g1, %g1
+       andncc          %o4, (0x40 - 1), %o4
+       srl             %g1, 3, %g2
+       sub             %o2, %o4, %g3
+       andn            %o1, (0x40 - 1), %o1
+       and             %g2, 7, %g2
+       andncc          %g3, 0x7, %g3
+       fmovd           %f0, %f2
+       sub             %g3, 0x8, %g3
+       sub             %o2, %o4, %o2
+
+       add             %g1, %o4, %g1
+       subcc           %o2, %g3, %o2
+
+       EX_LD(LOAD_BLK(%o1, %f0))
+       add             %o1, 0x40, %o1
+       add             %g1, %g3, %g1
+       EX_LD(LOAD_BLK(%o1, %f16))
+       add             %o1, 0x40, %o1
+       sub             %o4, 0x80, %o4
+       EX_LD(LOAD_BLK(%o1, %f32))
+       add             %o1, 0x40, %o1
+
+       /* There are 8 instances of the unrolled loop,
+        * one for each possible alignment of the
+        * source buffer.  Each loop instance is 452
+        * bytes.
+        */
+       sll             %g2, 3, %o3
+       sub             %o3, %g2, %o3
+       sllx            %o3, 4, %o3
+       add             %o3, %g2, %o3
+       sllx            %o3, 2, %g2
+1:     rd              %pc, %o3
+       add             %o3, %lo(1f - 1b), %o3
+       jmpl            %o3 + %g2, %g0
+        nop
+
+       .align          64
+1:     FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
+       STORE_JUMP(o0, f48, 40f) membar #Sync
+2:     FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
+       STORE_JUMP(o0, f48, 48f) membar #Sync
+3:     FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
+       STORE_JUMP(o0, f48, 56f) membar #Sync
+
+1:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
+       STORE_JUMP(o0, f48, 41f) membar #Sync
+2:     FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
+       STORE_JUMP(o0, f48, 49f) membar #Sync
+3:     FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
+       STORE_JUMP(o0, f48, 57f) membar #Sync
+
+1:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
+       STORE_JUMP(o0, f48, 42f) membar #Sync
+2:     FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
+       STORE_JUMP(o0, f48, 50f) membar #Sync
+3:     FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
+       STORE_JUMP(o0, f48, 58f) membar #Sync
+
+1:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6) 
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
+       STORE_JUMP(o0, f48, 43f) membar #Sync
+2:     FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
+       STORE_JUMP(o0, f48, 51f) membar #Sync
+3:     FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
+       STORE_JUMP(o0, f48, 59f) membar #Sync
+
+1:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
+       STORE_JUMP(o0, f48, 44f) membar #Sync
+2:     FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
+       STORE_JUMP(o0, f48, 52f) membar #Sync
+3:     FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
+       STORE_JUMP(o0, f48, 60f) membar #Sync
+
+1:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
+       STORE_JUMP(o0, f48, 45f) membar #Sync
+2:     FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
+       STORE_JUMP(o0, f48, 53f) membar #Sync
+3:     FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
+       STORE_JUMP(o0, f48, 61f) membar #Sync
+
+1:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
+       STORE_JUMP(o0, f48, 46f) membar #Sync
+2:     FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
+       STORE_JUMP(o0, f48, 54f) membar #Sync
+3:     FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
+       STORE_JUMP(o0, f48, 62f) membar #Sync
+
+1:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
+       LOOP_CHUNK1(o1, o0, o4, 1f)
+       FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
+       LOOP_CHUNK2(o1, o0, o4, 2f)
+       FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
+       LOOP_CHUNK3(o1, o0, o4, 3f)
+       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
+       FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
+       STORE_JUMP(o0, f48, 47f) membar #Sync
+2:     FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
+       STORE_JUMP(o0, f48, 55f) membar #Sync
+3:     FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
+       STORE_SYNC(o0, f48) membar #Sync
+       FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
+       STORE_JUMP(o0, f48, 63f) membar #Sync
+
+40:    FINISH_VISCHUNK(o0, f0,  f2,  g3)
+41:    FINISH_VISCHUNK(o0, f2,  f4,  g3)
+42:    FINISH_VISCHUNK(o0, f4,  f6,  g3)
+43:    FINISH_VISCHUNK(o0, f6,  f8,  g3)
+44:    FINISH_VISCHUNK(o0, f8,  f10, g3)
+45:    FINISH_VISCHUNK(o0, f10, f12, g3)
+46:    FINISH_VISCHUNK(o0, f12, f14, g3)
+47:    UNEVEN_VISCHUNK(o0, f14, f0,  g3)
+48:    FINISH_VISCHUNK(o0, f16, f18, g3)
+49:    FINISH_VISCHUNK(o0, f18, f20, g3)
+50:    FINISH_VISCHUNK(o0, f20, f22, g3)
+51:    FINISH_VISCHUNK(o0, f22, f24, g3)
+52:    FINISH_VISCHUNK(o0, f24, f26, g3)
+53:    FINISH_VISCHUNK(o0, f26, f28, g3)
+54:    FINISH_VISCHUNK(o0, f28, f30, g3)
+55:    UNEVEN_VISCHUNK(o0, f30, f0,  g3)
+56:    FINISH_VISCHUNK(o0, f32, f34, g3)
+57:    FINISH_VISCHUNK(o0, f34, f36, g3)
+58:    FINISH_VISCHUNK(o0, f36, f38, g3)
+59:    FINISH_VISCHUNK(o0, f38, f40, g3)
+60:    FINISH_VISCHUNK(o0, f40, f42, g3)
+61:    FINISH_VISCHUNK(o0, f42, f44, g3)
+62:    FINISH_VISCHUNK(o0, f44, f46, g3)
+63:    UNEVEN_VISCHUNK_LAST(o0, f46, f0,  g3)
+
+93:    EX_LD(LOAD(ldd, %o1, %f2))
+       add             %o1, 8, %o1
+       subcc           %g3, 8, %g3
+       faligndata      %f0, %f2, %f8
+       EX_ST(STORE(std, %f8, %o0))
+       bl,pn           %xcc, 95f
+        add            %o0, 8, %o0
+       EX_LD(LOAD(ldd, %o1, %f0))
+       add             %o1, 8, %o1
+       subcc           %g3, 8, %g3
+       faligndata      %f2, %f0, %f8
+       EX_ST(STORE(std, %f8, %o0))
+       bge,pt          %xcc, 93b
+        add            %o0, 8, %o0
+
+95:    brz,pt          %o2, 2f
+        mov            %g1, %o1
+
+1:     EX_LD(LOAD(ldub, %o1, %o3))
+       add             %o1, 1, %o1
+       subcc           %o2, 1, %o2
+       EX_ST(STORE(stb, %o3, %o0))
+       bne,pt          %xcc, 1b
+        add            %o0, 1, %o0
+
+2:     membar          #StoreLoad | #StoreStore
+       VISExit
+       retl
+        mov            EX_RETVAL(%g5), %o0
+
+       .align          64
+70:    /* 16 < len <= (5 * 64) */
+       bne,pn          %XCC, 75f
+        sub            %o0, %o1, %o3
+
+72:    andn            %o2, 0xf, %o4
+       and             %o2, 0xf, %o2
+1:     EX_LD(LOAD(ldx, %o1 + 0x00, %o5))
+       EX_LD(LOAD(ldx, %o1 + 0x08, %g1))
+       subcc           %o4, 0x10, %o4
+       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       add             %o1, 0x8, %o1
+       EX_ST(STORE(stx, %g1, %o1 + %o3))
+       bgu,pt          %XCC, 1b
+        add            %o1, 0x8, %o1
+73:    andcc           %o2, 0x8, %g0
+       be,pt           %XCC, 1f
+        nop
+       EX_LD(LOAD(ldx, %o1, %o5))
+       sub             %o2, 0x8, %o2
+       EX_ST(STORE(stx, %o5, %o1 + %o3))
+       add             %o1, 0x8, %o1
+1:     andcc           %o2, 0x4, %g0
+       be,pt           %XCC, 1f
+        nop
+       EX_LD(LOAD(lduw, %o1, %o5))
+       sub             %o2, 0x4, %o2
+       EX_ST(STORE(stw, %o5, %o1 + %o3))
+       add             %o1, 0x4, %o1
+1:     cmp             %o2, 0
+       be,pt           %XCC, 85f
+        nop
+       ba,pt           %xcc, 90f
+        nop
+
+75:    andcc           %o0, 0x7, %g1
+       sub             %g1, 0x8, %g1
+       be,pn           %icc, 2f
+        sub            %g0, %g1, %g1
+       sub             %o2, %g1, %o2
+
+1:     EX_LD(LOAD(ldub, %o1, %o5))
+       subcc           %g1, 1, %g1
+       EX_ST(STORE(stb, %o5, %o1 + %o3))
+       bgu,pt          %icc, 1b
+        add            %o1, 1, %o1
+
+2:     add             %o1, %o3, %o0
+       andcc           %o1, 0x7, %g1
+       bne,pt          %icc, 8f
+        sll            %g1, 3, %g1
+
+       cmp             %o2, 16
+       bgeu,pt         %icc, 72b
+        nop
+       ba,a,pt         %xcc, 73b
+
+8:     mov             64, %o3
+       andn            %o1, 0x7, %o1
+       EX_LD(LOAD(ldx, %o1, %g2))
+       sub             %o3, %g1, %o3
+       andn            %o2, 0x7, %o4
+       sllx            %g2, %g1, %g2
+1:     EX_LD(LOAD(ldx, %o1 + 0x8, %g3))
+       subcc           %o4, 0x8, %o4
+       add             %o1, 0x8, %o1
+       srlx            %g3, %o3, %o5
+       or              %o5, %g2, %o5
+       EX_ST(STORE(stx, %o5, %o0))
+       add             %o0, 0x8, %o0
+       bgu,pt          %icc, 1b
+        sllx           %g3, %g1, %g2
+
+       srl             %g1, 3, %g1
+       andcc           %o2, 0x7, %o2
+       be,pn           %icc, 85f
+        add            %o1, %g1, %o1
+       ba,pt           %xcc, 90f
+        sub            %o0, %o1, %o3
+
+       .align          64
+80:    /* 0 < len <= 16 */
+       andcc           %o3, 0x3, %g0
+       bne,pn          %XCC, 90f
+        sub            %o0, %o1, %o3
+
+1:     EX_LD(LOAD(lduw, %o1, %g1))
+       subcc           %o2, 4, %o2
+       EX_ST(STORE(stw, %g1, %o1 + %o3))
+       bgu,pt          %XCC, 1b
+        add            %o1, 4, %o1
+
+85:    retl
+        mov            EX_RETVAL(%g5), %o0
+
+       .align          32
+90:    EX_LD(LOAD(ldub, %o1, %g1))
+       subcc           %o2, 1, %o2
+       EX_ST(STORE(stb, %g1, %o1 + %o3))
+       bgu,pt          %XCC, 90b
+        add            %o1, 1, %o1
+       retl
+        mov            EX_RETVAL(%g5), %o0
+
+       .size           FUNC_NAME, .-FUNC_NAME
diff --git a/arch/sparc64/lib/U3patch.S b/arch/sparc64/lib/U3patch.S
new file mode 100644 (file)
index 0000000..e2b6c5e
--- /dev/null
@@ -0,0 +1,32 @@
+/* U3patch.S: Patch Ultra-I routines with Ultra-III variant.
+ *
+ * Copyright (C) 2004 David S. Miller <davem@redhat.com>
+ */
+
+#define BRANCH_ALWAYS  0x10680000
+#define NOP            0x01000000
+#define ULTRA3_DO_PATCH(OLD, NEW)      \
+       sethi   %hi(NEW), %g1; \
+       or      %g1, %lo(NEW), %g1; \
+       sethi   %hi(OLD), %g2; \
+       or      %g2, %lo(OLD), %g2; \
+       sub     %g1, %g2, %g1; \
+       sethi   %hi(BRANCH_ALWAYS), %g3; \
+       srl     %g1, 2, %g1; \
+       or      %g3, %lo(BRANCH_ALWAYS), %g3; \
+       or      %g3, %g1, %g3; \
+       stw     %g3, [%g2]; \
+       sethi   %hi(NOP), %g3; \
+       or      %g3, %lo(NOP), %g3; \
+       stw     %g3, [%g2 + 0x4]; \
+       flush   %g2;
+
+       .globl  cheetah_patch_copyops
+       .type   cheetah_patch_copyops,#function
+cheetah_patch_copyops:
+       ULTRA3_DO_PATCH(memcpy, U3memcpy)
+       ULTRA3_DO_PATCH(___copy_from_user, U3copy_from_user)
+       ULTRA3_DO_PATCH(___copy_to_user, U3copy_to_user)
+       retl
+        nop
+       .size   cheetah_patch_copyops,.-cheetah_patch_copyops
diff --git a/arch/sparc64/lib/copy_in_user.S b/arch/sparc64/lib/copy_in_user.S
new file mode 100644 (file)
index 0000000..816076c
--- /dev/null
@@ -0,0 +1,119 @@
+/* copy_in_user.S: Copy from userspace to userspace.
+ *
+ * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/asi.h>
+
+#define XCC xcc
+
+#define EX(x,y)                        \
+98:    x,y;                    \
+       .section .fixup;        \
+       .align 4;               \
+99:    retl;                   \
+        mov 1, %o0;            \
+       .section __ex_table;    \
+       .align 4;               \
+       .word 98b, 99b;         \
+       .text;                  \
+       .align 4;
+
+       .register       %g2,#scratch
+       .register       %g3,#scratch
+
+       .text
+       .align  32
+
+       /* Don't try to get too fancy here, just nice and
+        * simple.  This is predominantly used for well aligned
+        * small copies in the compat layer.  It is also used
+        * to copy register windows around during thread cloning.
+        */
+
+       .globl          ___copy_in_user
+       .type           ___copy_in_user,#function
+___copy_in_user:       /* %o0=dst, %o1=src, %o2=len */
+       /* Writing to %asi is _expensive_ so we hardcode it.
+        * Reading %asi to check for KERNEL_DS is comparatively
+        * cheap.
+        */
+       rd              %asi, %g1
+       cmp             %g1, ASI_AIUS
+       bne,pn          %icc, memcpy_user_stub
+        nop
+
+       cmp             %o2, 0
+       be,pn           %XCC, 85f
+        or             %o0, %o1, %o3
+       cmp             %o2, 16
+       bleu,a,pn       %XCC, 80f
+        or             %o3, %o2, %o3
+
+       /* 16 < len <= 64 */
+       andcc           %o3, 0x7, %g0
+       bne,pn          %XCC, 90f
+        sub            %o0, %o1, %o3
+
+       andn            %o2, 0x7, %o4
+       and             %o2, 0x7, %o2
+1:     subcc           %o4, 0x8, %o4
+       EX(ldxa [%o1] %asi, %o5)
+       EX(stxa %o5, [%o1 + %o3] ASI_AIUS)
+       bgu,pt          %XCC, 1b
+        add            %o1, 0x8, %o1
+       andcc           %o2, 0x4, %g0
+       be,pt           %XCC, 1f
+        nop
+       sub             %o2, 0x4, %o2
+       EX(lduwa [%o1] %asi, %o5)
+       EX(stwa %o5, [%o1 + %o3] ASI_AIUS)
+       add             %o1, 0x4, %o1
+1:     cmp             %o2, 0
+       be,pt           %XCC, 85f
+        nop
+       ba,pt           %xcc, 90f
+        nop
+
+80:    /* 0 < len <= 16 */
+       andcc           %o3, 0x3, %g0
+       bne,pn          %XCC, 90f
+        sub            %o0, %o1, %o3
+
+82:
+       subcc           %o2, 4, %o2
+       EX(lduwa [%o1] %asi, %g1)
+       EX(stwa %g1, [%o1 + %o3] ASI_AIUS)
+       bgu,pt          %XCC, 82b
+        add            %o1, 4, %o1
+
+85:    retl
+        clr            %o0
+
+       .align  32
+90:
+       subcc           %o2, 1, %o2
+       EX(lduba [%o1] %asi, %g1)
+       EX(stba %g1, [%o1 + %o3] ASI_AIUS)
+       bgu,pt          %XCC, 90b
+        add            %o1, 1, %o1
+       retl
+        clr            %o0
+
+       .size           ___copy_in_user, .-___copy_in_user
+
+       /* Act like copy_{to,in}_user(), ie. return zero instead
+        * of original destination pointer.  This is invoked when
+        * copy_{to,in}_user() finds that %asi is kernel space.
+        */
+       .globl          memcpy_user_stub
+       .type           memcpy_user_stub,#function
+memcpy_user_stub:
+       save            %sp, -192, %sp
+       mov             %i0, %o0
+       mov             %i1, %o1
+       call            memcpy
+        mov            %i2, %o2
+       ret
+        restore        %g0, %g0, %o0
+       .size           memcpy_user_stub, .-memcpy_user_stub
diff --git a/arch/sparc64/lib/delay.c b/arch/sparc64/lib/delay.c
new file mode 100644 (file)
index 0000000..f55f528
--- /dev/null
@@ -0,0 +1,49 @@
+/* delay.c: Delay loops for sparc64
+ *
+ * Copyright (C) 2004 David S. Miller <davem@redhat.com>
+ *
+ * Based heavily upon x86 variant which is:
+ *     Copyright (C) 1993 Linus Torvalds
+ *     Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/delay.h>
+
+void __delay(unsigned long loops)
+{
+       __asm__ __volatile__(
+"      b,pt    %%xcc, 1f\n"
+"       cmp    %0, 0\n"
+"      .align  32\n"
+"1:\n"
+"      bne,pt  %%xcc, 1b\n"
+"       subcc  %0, 1, %0\n"
+       : "=&r" (loops)
+       : "0" (loops)
+       : "cc");
+}
+
+/* We used to multiply by HZ after shifting down by 32 bits
+ * but that runs into problems for higher values of HZ and
+ * slow cpus.
+ */
+void __const_udelay(unsigned long n)
+{
+       n *= 4;
+
+       n *= (cpu_data(smp_processor_id()).udelay_val * (HZ/4));
+       n >>= 32;
+
+       __delay(n + 1);
+}
+
+void __udelay(unsigned long n)
+{
+       __const_udelay(n * 0x10c7UL);
+}
+
+
+void __ndelay(unsigned long n)
+{
+       __const_udelay(n * 0x5UL);
+}
diff --git a/arch/sparc64/lib/iomap.c b/arch/sparc64/lib/iomap.c
new file mode 100644 (file)
index 0000000..ac556db
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Implement the sparc64 iomap interfaces
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+/* Create a virtual mapping cookie for an IO port range */
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       return (void __iomem *) (unsigned long) port;
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+       /* Nothing to do */
+}
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len || !start)
+               return NULL;
+       if (maxlen && len > maxlen)
+               len = maxlen;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+               return ioremap_nocache(start, len);
+       }
+       /* What? */
+       return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+{
+       /* nothing to do */
+}
+EXPORT_SYMBOL(pci_iomap);
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/sparc64/lib/memmove.S b/arch/sparc64/lib/memmove.S
new file mode 100644 (file)
index 0000000..ca8781d
--- /dev/null
@@ -0,0 +1,33 @@
+/* memmove.S: Simple memmove implementation.
+ *
+ * Copyright (C) 1997, 2004 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+       .text
+       .align          32
+       .globl          memmove
+       .type           memmove,#function
+memmove:
+       mov             %o0, %g1
+       cmp             %o0, %o1
+       blu,pt          %xcc, memcpy
+        sub            %o0, %o1, %g5
+       add             %o1, %o2, %g3
+       cmp             %g3, %o0
+       bleu,pt         %xcc, memcpy
+        add            %o1, %o2, %g5
+       add             %o0, %o2, %o5
+
+       sub             %g5, 1, %o1
+       sub             %o5, 1, %o0
+1:     ldub            [%o1], %g5
+       subcc           %o2, 1, %o2
+       sub             %o1, 1, %o1
+       stb             %g5, [%o0]
+       bne,pt          %icc, 1b
+        sub            %o0, 1, %o0
+
+       retl
+        mov            %g1, %o0
+       .size           memmove, .-memmove
diff --git a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c
new file mode 100644 (file)
index 0000000..58ec560
--- /dev/null
@@ -0,0 +1,68 @@
+/* user_fixup.c: Fix up user copy faults.
+ *
+ * Copyright (C) 2004 David S. Miller <davem@redhat.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+
+/* Calculating the exact fault address when using
+ * block loads and stores can be very complicated.
+ * Instead of trying to be clever and handling all
+ * of the cases, just fix things up simply here.
+ */
+
+unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
+{
+       char *dst = to;
+       const char __user *src = from;
+
+       while (size--) {
+               if (__get_user(*dst, src))
+                       break;
+               dst++;
+               src++;
+       }
+
+       if (size)
+               memset(dst, 0, size);
+
+       return size;
+}
+
+unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size)
+{
+       char __user *dst = to;
+       const char *src = from;
+
+       while (size--) {
+               if (__put_user(*src, dst))
+                       break;
+               dst++;
+               src++;
+       }
+
+       return size;
+}
+
+unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size)
+{
+       char __user *dst = to;
+       char __user *src = from;
+
+       while (size--) {
+               char tmp;
+
+               if (__get_user(tmp, src))
+                       break;
+               if (__put_user(tmp, dst))
+                       break;
+               dst++;
+               src++;
+       }
+
+       return size;
+}
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
new file mode 100644 (file)
index 0000000..a2d5830
--- /dev/null
@@ -0,0 +1,43 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config FRAME_POINTER
+       bool
+       default y if DEBUG_INFO
+
+config PT_PROXY
+       bool "Enable ptrace proxy"
+       depends on XTERM_CHAN && DEBUG_INFO
+       help
+       This option enables a debugging interface which allows gdb to debug
+       the kernel without needing to actually attach to kernel threads.
+       If you want to do kernel debugging, say Y here; otherwise say N.
+
+config GPROF
+       bool "Enable gprof support"
+       depends on DEBUG_INFO
+       help
+        This allows profiling of a User-Mode Linux kernel with the gprof
+        utility.
+
+        See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+        details.
+
+        If you're involved in UML kernel development and want to use gprof,
+        say Y.  If you're unsure, say N.
+
+config GCOV
+       bool "Enable gcov support"
+       depends on DEBUG_INFO
+       help
+        This option allows developers to retrieve coverage data from a UML
+        session.
+
+        See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+        details.
+
+        If you're involved in UML kernel development and want to use gcov,
+        say Y.  If you're unsure, say N.
+
+endmenu
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
new file mode 100644 (file)
index 0000000..705df73
--- /dev/null
@@ -0,0 +1 @@
+ARCH_USER_CFLAGS := -D__x86_64__
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
new file mode 100644 (file)
index 0000000..ce251f0
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __COW_SYS_H__
+#define __COW_SYS_H__
+
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "user.h"
+
+static inline void *cow_malloc(int size)
+{
+       return(um_kmalloc(size));
+}
+
+static inline void cow_free(void *ptr)
+{
+       kfree(ptr);
+}
+
+#define cow_printf printk
+
+static inline char *cow_strdup(char *str)
+{
+       return(uml_strdup(str));
+}
+
+static inline int cow_seek_file(int fd, __u64 offset)
+{
+       return(os_seek_file(fd, offset));
+}
+
+static inline int cow_file_size(char *file, __u64 *size_out)
+{
+       return(os_file_size(file, size_out));
+}
+
+static inline int cow_write_file(int fd, char *buf, int size)
+{
+       return(os_write_file(fd, buf, size));
+}
+
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
new file mode 100644 (file)
index 0000000..ee16421
--- /dev/null
@@ -0,0 +1,171 @@
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_FORMAT(ELF_FORMAT)
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+SECTIONS
+{
+  . = START + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  __binary_start = .;
+  . = ALIGN(4096);             /* Init code and data */
+  _stext = .;
+  __init_begin = .;
+  .init.text : {
+       _sinittext = .;
+       *(.init.text)
+       _einittext = .;
+  }
+
+  . = ALIGN(4096);
+
+  /* Read-only sections, merged into text segment: */
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata    : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss      : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           : {
+    KEEP (*(.init))
+  } =0x90909090
+  .plt            : { *(.plt) }
+  .text           : {
+    *(.text)
+    SCHED_TEXT
+    *(.stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x90909090
+  .fini           : {
+    KEEP (*(.fini))
+  } =0x90909090
+
+  .kstrtab : { *(.kstrtab) }
+
+  #include "asm/common.lds.S"
+
+  init.data : { *(.init.data) }
+
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  .preinit_array     : { *(.preinit_array) }
+  .init_array     : { *(.init_array) }
+  .fini_array     : { *(.fini_array) }
+  .data           : {
+    . = ALIGN(KERNEL_STACK_SIZE);              /* init_task */
+    *(.data.init_task)
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  .ctors          : {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          : {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .got            : { *(.got.plt) *(.got) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            : {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  }
+  _end = .;
+  PROVIDE (end = .);
+   /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .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) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+}
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
new file mode 100644 (file)
index 0000000..e1fd2c5
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <asm/page.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "signal_user.h"
+#include "user.h"
+#include "init.h"
+#include "mode.h"
+#include "choose-mode.h"
+#include "uml-config.h"
+
+/* Set in set_stklim, which is called from main and __wrap_malloc.
+ * __wrap_malloc only calls it if main hasn't started.
+ */
+unsigned long stacksizelim;
+
+/* Set in main */
+char *linux_prog;
+
+#define PGD_BOUND (4 * 1024 * 1024)
+#define STACKSIZE (8 * 1024 * 1024)
+#define THREAD_NAME_LEN (256)
+
+static void set_stklim(void)
+{
+       struct rlimit lim;
+
+       if(getrlimit(RLIMIT_STACK, &lim) < 0){
+               perror("getrlimit");
+               exit(1);
+       }
+       if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
+               lim.rlim_cur = STACKSIZE;
+               if(setrlimit(RLIMIT_STACK, &lim) < 0){
+                       perror("setrlimit");
+                       exit(1);
+               }
+       }
+       stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
+}
+
+static __init void do_uml_initcalls(void)
+{
+       initcall_t *call;
+
+       call = &__uml_initcall_start;
+       while (call < &__uml_initcall_end){;
+               (*call)();
+               call++;
+       }
+}
+
+static void last_ditch_exit(int sig)
+{
+       CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
+       signal(SIGINT, SIG_DFL);
+       signal(SIGTERM, SIG_DFL);
+       signal(SIGHUP, SIG_DFL);
+       uml_cleanup();
+       exit(1);
+}
+
+extern int uml_exitcode;
+
+int main(int argc, char **argv, char **envp)
+{
+       char **new_argv;
+       sigset_t mask;
+       int ret, i;
+
+       /* Enable all signals except SIGIO - in some environments, we can
+        * enter with some signals blocked
+        */
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGIO);
+       if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
+               perror("sigprocmask");
+               exit(1);
+       }
+
+#ifdef UML_CONFIG_MODE_TT
+       /* Allocate memory for thread command lines */
+       if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
+
+               char padding[THREAD_NAME_LEN] = {
+                       [ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0'
+               };
+
+               new_argv = malloc((argc + 2) * sizeof(char*));
+               if(!new_argv) {
+                       perror("Allocating extended argv");
+                       exit(1);
+               }
+
+               new_argv[0] = argv[0];
+               new_argv[1] = padding;
+
+               for(i = 2; i <= argc; i++)
+                       new_argv[i] = argv[i - 1];
+               new_argv[argc + 1] = NULL;
+
+               execvp(new_argv[0], new_argv);
+               perror("execing with extended args");
+               exit(1);
+       }
+#endif
+
+       linux_prog = argv[0];
+
+       set_stklim();
+
+       new_argv = malloc((argc + 1) * sizeof(char *));
+       if(new_argv == NULL){
+               perror("Mallocing argv");
+               exit(1);
+       }
+       for(i=0;i<argc;i++){
+               new_argv[i] = strdup(argv[i]);
+               if(new_argv[i] == NULL){
+                       perror("Mallocing an arg");
+                       exit(1);
+               }
+       }
+       new_argv[argc] = NULL;
+
+       set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+       set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+       set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+
+       do_uml_initcalls();
+       ret = linux_main(argc, argv);
+
+       /* Reboot */
+       if(ret){
+               int err;
+
+               printf("\n");
+
+               /* Let any pending signals fire, then disable them.  This
+                * ensures that they won't be delivered after the exec, when
+                * they are definitely not expected.
+                */
+               unblock_signals();
+               disable_timer();
+               err = deactivate_all_fds();
+               if(err)
+                       printf("deactivate_all_fds failed, errno = %d\n",
+                              -err);
+
+               execvp(new_argv[0], new_argv);
+               perror("Failed to exec kernel");
+               ret = 1;
+       }
+       printf("\n");
+       return(uml_exitcode);
+}
+
+#define CAN_KMALLOC() \
+       (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1))
+
+extern void *__real_malloc(int);
+
+void *__wrap_malloc(int size)
+{
+       void *ret;
+
+       if(!CAN_KMALLOC())
+               return(__real_malloc(size));
+       else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/
+               ret = um_kmalloc(size);
+       else ret = um_vmalloc(size);
+
+       /* glibc people insist that if malloc fails, errno should be
+        * set by malloc as well. So we do.
+        */
+       if(ret == NULL)
+               errno = ENOMEM;
+
+       return(ret);
+}
+
+void *__wrap_calloc(int n, int size)
+{
+       void *ptr = __wrap_malloc(n * size);
+
+       if(ptr == NULL) return(NULL);
+       memset(ptr, 0, n * size);
+       return(ptr);
+}
+
+extern void __real_free(void *);
+
+extern unsigned long high_physmem;
+
+void __wrap_free(void *ptr)
+{
+       unsigned long addr = (unsigned long) ptr;
+
+       /* We need to know how the allocation happened, so it can be correctly
+        * freed.  This is done by seeing what region of memory the pointer is
+        * in -
+        *      physical memory - kmalloc/kfree
+        *      kernel virtual memory - vmalloc/vfree
+        *      anywhere else - malloc/free
+        * If kmalloc is not yet possible, then the kernel memory regions
+        * may not be set up yet, and the variables not initialized.  So,
+        * free is called.
+        *
+        * CAN_KMALLOC is checked because it would be bad to free a buffer
+        * with kmalloc/vmalloc after they have been turned off during
+        * shutdown.
+        */
+
+       if((addr >= uml_physmem) && (addr < high_physmem)){
+               if(CAN_KMALLOC())
+                       kfree(ptr);
+       }
+       else if((addr >= start_vm) && (addr < end_vm)){
+               if(CAN_KMALLOC())
+                       vfree(ptr);
+       }
+       else __real_free(ptr);
+}
+
+/*
+ * 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/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
new file mode 100644 (file)
index 0000000..4cd60d7
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MMU_H
+#define __SKAS_MMU_H
+
+struct mmu_context_skas {
+       int mm_fd;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
new file mode 100644 (file)
index 0000000..f198388
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_SKAS_H__
+#define __MODE_SKAS_H__
+
+#include <sysdep/ptrace.h>
+
+extern unsigned long exec_regs[];
+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 int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs,
+                                 void *from_ptr);
+extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp,
+                               union uml_pt_regs *regs,
+                               unsigned long fault_addr, int fault_type);
+extern void sig_handler_common_skas(int sig, void *sc_ptr);
+extern void halt_skas(void);
+extern void reboot_skas(void);
+extern void kill_off_processes_skas(void);
+extern int is_skas_winch(int pid, int fd, void *data);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h
new file mode 100644 (file)
index 0000000..94c5649
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_MODE_KERN_H__
+#define __SKAS_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+
+extern void flush_thread_skas(void);
+extern void *switch_to_skas(void *prev, void *next);
+extern void start_thread_skas(struct pt_regs *regs, unsigned long eip,
+                             unsigned long esp);
+extern int copy_thread_skas(int nr, unsigned long clone_flags,
+                           unsigned long sp, unsigned long stack_top,
+                           struct task_struct *p, struct pt_regs *regs);
+extern void release_thread_skas(struct task_struct *task);
+extern void exit_thread_skas(void);
+extern void initial_thread_cb_skas(void (*proc)(void *), void *arg);
+extern void init_idle_skas(void);
+extern void flush_tlb_kernel_range_skas(unsigned long start,
+                                       unsigned long end);
+extern void flush_tlb_kernel_vm_skas(void);
+extern void __flush_tlb_one_skas(unsigned long addr);
+extern void flush_tlb_range_skas(struct vm_area_struct *vma,
+                                unsigned long start, unsigned long end);
+extern void flush_tlb_mm_skas(struct mm_struct *mm);
+extern void force_flush_all_skas(void);
+extern long execute_syscall_skas(void *r);
+extern void before_mem_skas(unsigned long unused);
+extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
+                                        unsigned long *task_size_out);
+extern int start_uml_skas(void);
+extern int external_pid_skas(struct task_struct *task);
+extern int thread_pid_skas(struct task_struct *task);
+
+#define kmem_end_skas (host_task_size - 1024 * 1024)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
new file mode 100644 (file)
index 0000000..da9c52c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SKAS_UACCESS_H
+#define __SKAS_UACCESS_H
+
+#include "asm/errno.h"
+
+#define access_ok_skas(type, addr, size) \
+       ((segment_eq(get_fs(), KERNEL_DS)) || \
+        (((unsigned long) (addr) < TASK_SIZE) && \
+         ((unsigned long) (addr) + (size) <= TASK_SIZE)))
+
+static inline int verify_area_skas(int type, const void * addr,
+                                  unsigned long size)
+{
+       return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern int copy_from_user_skas(void *to, const void *from, int n);
+extern int copy_to_user_skas(void *to, const void *from, int n);
+extern int strncpy_from_user_skas(char *dst, const char *src, int count);
+extern int __clear_user_skas(void *mem, int len);
+extern int clear_user_skas(void *mem, int len);
+extern int strnlen_user_skas(const void *str, int len);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
new file mode 100644 (file)
index 0000000..0440510
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MMU_H
+#define __TT_MMU_H
+
+struct mmu_context_tt {
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
new file mode 100644 (file)
index 0000000..fb5cfd3
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_TT_H__
+#define __MODE_TT_H__
+
+#include "sysdep/ptrace.h"
+
+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 int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data);
+extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr,
+                             void *data);
+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);
+extern void halt_tt(void);
+extern int is_tracer_winch(int pid, int fd, void *data);
+extern void kill_off_processes_tt(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
new file mode 100644 (file)
index 0000000..28aaab3
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MODE_KERN_H__
+#define __TT_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+
+extern void *switch_to_tt(void *prev, void *next);
+extern void flush_thread_tt(void);
+extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
+                          unsigned long esp);
+extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+                         unsigned long stack_top, struct task_struct *p,
+                         struct pt_regs *regs);
+extern void release_thread_tt(struct task_struct *task);
+extern void exit_thread_tt(void);
+extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
+extern void init_idle_tt(void);
+extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_vm_tt(void);
+extern void __flush_tlb_one_tt(unsigned long addr);
+extern void flush_tlb_range_tt(struct vm_area_struct *vma,
+                              unsigned long start, unsigned long end);
+extern void flush_tlb_mm_tt(struct mm_struct *mm);
+extern void force_flush_all_tt(void);
+extern long execute_syscall_tt(void *r);
+extern void before_mem_tt(unsigned long brk_start);
+extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
+                                      unsigned long *task_size_out);
+extern int start_uml_tt(void);
+extern int external_pid_tt(struct task_struct *task);
+extern int thread_pid_tt(struct task_struct *task);
+
+#define kmem_end_tt (host_task_size - ABOVE_KMEM)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
new file mode 100644 (file)
index 0000000..f0bad01
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_UACCESS_H
+#define __TT_UACCESS_H
+
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/errno.h"
+#include "asm/current.h"
+#include "asm/a.out.h"
+#include "uml_uaccess.h"
+
+#define ABOVE_KMEM (16 * 1024 * 1024)
+
+extern unsigned long end_vm;
+extern unsigned long uml_physmem;
+
+#define under_task_size(addr, size) \
+       (((unsigned long) (addr) < TASK_SIZE) && \
+         (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define is_stack(addr, size) \
+       (((unsigned long) (addr) < STACK_TOP) && \
+        ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
+        (((unsigned long) (addr) + (size)) <= STACK_TOP))
+
+#define access_ok_tt(type, addr, size) \
+       ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
+         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
+          (under_task_size(addr, size) || is_stack(addr, size))))
+
+static inline int verify_area_tt(int type, const void * addr,
+                                unsigned long size)
+{
+       return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern unsigned long get_fault_addr(void);
+
+extern int __do_copy_from_user(void *to, const void *from, int n,
+                              void **fault_addr, void **fault_catcher);
+extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+                                 void **fault_addr, void **fault_catcher);
+extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+                          void **fault_catcher);
+extern int __do_strnlen_user(const char *str, unsigned long n,
+                            void **fault_addr, void **fault_catcher);
+
+extern int copy_from_user_tt(void *to, const void *from, int n);
+extern int copy_to_user_tt(void *to, const void *from, int n);
+extern int strncpy_from_user_tt(char *dst, const char *src, int count);
+extern int __clear_user_tt(void *mem, int len);
+extern int clear_user_tt(void *mem, int len);
+extern int strnlen_user_tt(const void *str, int len);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
new file mode 100644 (file)
index 0000000..89ed329
--- /dev/null
@@ -0,0 +1,96 @@
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_FORMAT(ELF_FORMAT)
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+SECTIONS
+{
+  . = START + SIZEOF_HEADERS;
+
+  __binary_start = .;
+#ifdef MODE_TT
+  .thread_private : {
+    __start_thread_private = .;
+    errno = .;
+    . += 4;
+    arch/um/kernel/tt/unmap_fin.o (.data)
+    __end_thread_private = .;
+  }
+  . = ALIGN(4096);
+  .remap : { arch/um/kernel/tt/unmap_fin.o (.text) }
+#endif
+
+  . = ALIGN(4096);             /* Init code and data */
+  _stext = .;
+  __init_begin = .;
+  .init.text : {
+       _sinittext = .;
+       *(.init.text)
+       _einittext = .;
+  }
+  . = ALIGN(4096);
+  .text      :
+  {
+    *(.text)
+    SCHED_TEXT
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  }
+
+  #include "asm/common.lds.S"
+
+  init.data : { *(init.data) }
+  .data    :
+  {
+    . = ALIGN(KERNEL_STACK_SIZE);              /* init_task */
+    *(.data.init_task)
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  . = ALIGN(0x1000);
+  .sbss      :
+  {
+   __bss_start = .;
+   PROVIDE(_bss_start = .);
+   *(.sbss)
+   *(.scommon)
+  }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
new file mode 100644 (file)
index 0000000..cf30a39
--- /dev/null
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <sys/time.h>
+
+unsigned long long os_usecs(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+/*
+ * 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/v850/Kconfig.debug b/arch/v850/Kconfig.debug
new file mode 100644 (file)
index 0000000..4acfb9c
--- /dev/null
@@ -0,0 +1,10 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config NO_KERNEL_MSG
+       bool "Suppress Kernel BUG Messages"
+       help
+         Do not output any debug BUG messages within the kernel.
+
+endmenu
diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug
new file mode 100644 (file)
index 0000000..2ba7f5a
--- /dev/null
@@ -0,0 +1,59 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+# !SMP for now because the context switch early causes GPF in segment reloading
+# and the GS base checking does the wrong thing then, causing a hang.
+config CHECKING
+       bool "Additional run-time checks"
+       depends on DEBUG_KERNEL && !SMP
+       help
+         Enables some internal consistency checks for kernel debugging.
+         You should normally say N.
+
+config INIT_DEBUG
+       bool "Debug __init statements"
+       depends on DEBUG_KERNEL
+       help
+         Fill __init and __initdata at the end of boot. This helps debugging
+         illegal uses of __init and __initdata after initialization.
+
+config SCHEDSTATS
+       bool "Collect scheduler statistics"
+       depends on DEBUG_KERNEL && PROC_FS
+       help
+         If you say Y here, additional code will be inserted into the
+         scheduler and related routines to collect statistics about
+         scheduler behavior and provide them in /proc/schedstat.  These
+         stats may be useful for both tuning and debugging the scheduler
+         If you aren't debugging the scheduler or trying to tune a specific
+         application, you can say N to avoid the very slight overhead
+         this adds.
+
+config IOMMU_DEBUG
+       depends on GART_IOMMU && DEBUG_KERNEL
+       bool "Enable IOMMU debugging"
+       help
+         Force the IOMMU to on even when you have less than 4GB of
+        memory and add debugging code. On overflow always panic. And
+        allow to enable IOMMU leak tracing. Can be disabled at boot
+        time with iommu=noforce. This will also enable scatter gather
+        list merging.  Currently not recommended for production
+        code. When you use it make sure you have a big enough
+        IOMMU/AGP aperture.  Most of the options enabled by this can
+        be set more finegrained using the iommu= command line
+        options. See Documentation/x86_64/boot-options.txt for more
+        details.
+
+config IOMMU_LEAK
+       bool "IOMMU leak tracing"
+       depends on DEBUG_KERNEL
+       depends on IOMMU_DEBUG
+       help
+         Add a simple leak tracer to the IOMMU code. This is useful when you
+        are debugging a buggy device driver that leaks IOMMU mappings.
+
+#config X86_REMOTE_DEBUG
+#       bool "kgdb debugging stub"
+
+endmenu
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
new file mode 100644 (file)
index 0000000..9aa5cb6
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2004 James Cleverdon, IBM.
+ * Subject to the GNU Public License, v.2
+ *
+ * Generic APIC sub-arch probe layer.
+ *
+ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+ * James Cleverdon.
+ */
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/smp.h>
+#include <asm/ipi.h>
+
+/* which logical CPU number maps to which CPU (physical APIC ID) */
+u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+EXPORT_SYMBOL(x86_cpu_to_apicid);
+u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+
+extern struct genapic apic_cluster;
+extern struct genapic apic_flat;
+
+struct genapic *genapic = &apic_flat;
+
+
+/*
+ * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
+ */
+void __init clustered_apic_check(void)
+{
+       long i;
+       u8 clusters, max_cluster;
+       u8 id;
+       u8 cluster_cnt[NUM_APIC_CLUSTERS];
+
+       memset(cluster_cnt, 0, sizeof(cluster_cnt));
+
+       for (i = 0; i < NR_CPUS; i++) {
+               id = bios_cpu_apicid[i];
+               if (id != BAD_APICID)
+                       cluster_cnt[APIC_CLUSTERID(id)]++;
+       }
+
+       clusters = 0;
+       max_cluster = 0;
+       for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
+               if (cluster_cnt[i] > 0) {
+                       ++clusters;
+                       if (cluster_cnt[i] > max_cluster)
+                               max_cluster = cluster_cnt[i];
+               }
+       }
+
+       /*
+        * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode,
+        * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical
+        * else physical mode.
+        * (We don't use lowest priority delivery + HW APIC IRQ steering, so
+        * can ignore the clustered logical case and go straight to physical.)
+        */
+       if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster)
+               genapic = &apic_flat;
+       else
+               genapic = &apic_cluster;
+
+       printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
+}
+
+/* Same for both flat and clustered. */
+
+void send_IPI_self(int vector)
+{
+       __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
+}
diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c
new file mode 100644 (file)
index 0000000..9703da7
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2004 James Cleverdon, IBM.
+ * Subject to the GNU Public License, v.2
+ *
+ * Clustered APIC subarch code.  Up to 255 CPUs, physical delivery.
+ * (A more realistic maximum is around 230 CPUs.)
+ *
+ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+ * James Cleverdon.
+ */
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <asm/smp.h>
+#include <asm/ipi.h>
+
+
+/*
+ * Set up the logical destination ID.
+ *
+ * Intel recommends to set DFR, LDR and TPR before enabling
+ * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+ * document number 292116).  So here it goes...
+ */
+static void cluster_init_apic_ldr(void)
+{
+       unsigned long val, id;
+       long i, count;
+       u8 lid;
+       u8 my_id = hard_smp_processor_id();
+       u8 my_cluster = APIC_CLUSTER(my_id);
+
+       /* Create logical APIC IDs by counting CPUs already in cluster. */
+       for (count = 0, i = NR_CPUS; --i >= 0; ) {
+               lid = x86_cpu_to_log_apicid[i];
+               if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster)
+                       ++count;
+       }
+       /*
+        * We only have a 4 wide bitmap in cluster mode.  There's no way
+        * to get above 60 CPUs and still give each one it's own bit.
+        * But, we're using physical IRQ delivery, so we don't care.
+        * Use bit 3 for the 4th through Nth CPU in each cluster.
+        */
+       if (count >= XAPIC_DEST_CPUS_SHIFT)
+               count = 3;
+       id = my_cluster | (1UL << count);
+       x86_cpu_to_log_apicid[smp_processor_id()] = id;
+       apic_write_around(APIC_DFR, APIC_DFR_CLUSTER);
+       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+       val |= SET_APIC_LOGICAL_ID(id);
+       apic_write_around(APIC_LDR, val);
+}
+
+/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
+
+static cpumask_t cluster_target_cpus(void)
+{
+       return cpumask_of_cpu(0);
+}
+
+static void cluster_send_IPI_mask(cpumask_t mask, int vector)
+{
+       send_IPI_mask_sequence(mask, vector);
+}
+
+static void cluster_send_IPI_allbutself(int vector)
+{
+       cpumask_t mask = cpu_online_map;
+       cpu_clear(smp_processor_id(), mask);
+
+       if (!cpus_empty(mask))
+               cluster_send_IPI_mask(mask, vector);
+}
+
+static void cluster_send_IPI_all(int vector)
+{
+       cluster_send_IPI_mask(cpu_online_map, vector);
+}
+
+static int cluster_apic_id_registered(void)
+{
+       return 1;
+}
+
+static unsigned int cluster_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+       int cpu;
+
+       /*
+        * We're using fixed IRQ delivery, can only return one phys APIC ID.
+        * May as well be the first.
+        */
+       cpu = first_cpu(cpumask);
+       if ((unsigned)cpu < NR_CPUS)
+               return x86_cpu_to_apicid[cpu];
+       else
+               return BAD_APICID;
+}
+
+/* cpuid returns the value latched in the HW at reset, not the APIC ID
+ * register's value.  For any box whose BIOS changes APIC IDs, like
+ * clustered APIC systems, we must use hard_smp_processor_id.
+ *
+ * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
+ */
+static unsigned int phys_pkg_id(int index_msb)
+{
+       return hard_smp_processor_id() >> index_msb;
+}
+
+struct genapic apic_cluster = {
+       .name = "clustered",
+       .int_delivery_mode = dest_Fixed,
+       .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
+       .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_FIXED,
+       .target_cpus = cluster_target_cpus,
+       .apic_id_registered = cluster_apic_id_registered,
+       .init_apic_ldr = cluster_init_apic_ldr,
+       .send_IPI_all = cluster_send_IPI_all,
+       .send_IPI_allbutself = cluster_send_IPI_allbutself,
+       .send_IPI_mask = cluster_send_IPI_mask,
+       .cpu_mask_to_apicid = cluster_cpu_mask_to_apicid,
+       .phys_pkg_id = phys_pkg_id,
+};
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
new file mode 100644 (file)
index 0000000..b4cbbad
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2004 James Cleverdon, IBM.
+ * Subject to the GNU Public License, v.2
+ *
+ * Flat APIC subarch code.  Maximum 8 CPUs, logical delivery.
+ *
+ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+ * James Cleverdon.
+ */
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <asm/smp.h>
+#include <asm/ipi.h>
+
+
+static cpumask_t flat_target_cpus(void)
+{
+       return cpu_online_map;
+}
+
+/*
+ * Set up the logical destination ID.
+ *
+ * Intel recommends to set DFR, LDR and TPR before enabling
+ * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
+ * document number 292116).  So here it goes...
+ */
+static void flat_init_apic_ldr(void)
+{
+       unsigned long val;
+       unsigned long num, id;
+
+       num = smp_processor_id();
+       id = 1UL << num;
+       x86_cpu_to_log_apicid[num] = id;
+       apic_write_around(APIC_DFR, APIC_DFR_FLAT);
+       val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+       val |= SET_APIC_LOGICAL_ID(id);
+       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];
+       unsigned long cfg;
+       unsigned long flags;
+
+       local_save_flags(flags);
+       local_irq_disable();
+
+       /*
+        * Wait for idle.
+        */
+       apic_wait_icr_idle();
+
+       /*
+        * prepare target chip field
+        */
+       cfg = __prepare_ICR2(mask);
+       apic_write_around(APIC_ICR2, cfg);
+
+       /*
+        * program the ICR
+        */
+       cfg = __prepare_ICR(0, vector, APIC_DEST_LOGICAL);
+
+       /*
+        * Send the IPI. The write to APIC_ICR fires this off.
+        */
+       apic_write_around(APIC_ICR, cfg);
+       local_irq_restore(flags);
+}
+
+static int flat_apic_id_registered(void)
+{
+       return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
+}
+
+static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+       return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
+}
+
+static unsigned int phys_pkg_id(int index_msb)
+{
+       u32 ebx;
+
+       ebx = cpuid_ebx(1);
+       return ((ebx >> 24) & 0xFF) >> index_msb;
+}
+
+struct genapic apic_flat =  {
+       .name = "flat",
+       .int_delivery_mode = dest_LowestPrio,
+       .int_dest_mode = (APIC_DEST_LOGICAL != 0),
+       .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
+       .target_cpus = flat_target_cpus,
+       .apic_id_registered = flat_apic_id_registered,
+       .init_apic_ldr = flat_init_apic_ldr,
+       .send_IPI_all = flat_send_IPI_all,
+       .send_IPI_allbutself = flat_send_IPI_allbutself,
+       .send_IPI_mask = flat_send_IPI_mask,
+       .cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
+       .phys_pkg_id = phys_pkg_id,
+};
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
new file mode 100644 (file)
index 0000000..dfef312
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ *  Kernel Probes (KProbes)
+ *  arch/x86_64/kernel/kprobes.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ *
+ * 2002-Oct    Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
+ *             Probes initial implementation ( includes contributions from
+ *             Rusty Russell).
+ * 2004-July   Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
+ *             interface to access function arguments.
+ * 2004-Oct    Jim Keniston <kenistoj@us.ibm.com> and Prasanna S Panchamukhi
+ *             <prasanna@in.ibm.com> adapted for x86_64
+ */
+
+#include <linux/config.h>
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/preempt.h>
+#include <linux/vmalloc.h>
+
+#include <asm/pgtable.h>
+#include <asm/kdebug.h>
+
+/* kprobe_status settings */
+#define KPROBE_HIT_ACTIVE      0x00000001
+#define KPROBE_HIT_SS          0x00000002
+
+static struct kprobe *current_kprobe;
+static unsigned long kprobe_status, kprobe_old_rflags, kprobe_saved_rflags;
+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 */
+static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
+
+/*
+ * returns non-zero if opcode modifies the interrupt flag.
+ */
+static inline int is_IF_modifier(kprobe_opcode_t *insn)
+{
+       switch (*insn) {
+       case 0xfa:              /* cli */
+       case 0xfb:              /* sti */
+       case 0xcf:              /* iret/iretd */
+       case 0x9d:              /* popf/popfd */
+               return 1;
+       }
+
+       if (*insn  >= 0x40 && *insn <= 0x4f && *++insn == 0xcf)
+               return 1;
+       return 0;
+}
+
+int arch_prepare_kprobe(struct kprobe *p)
+{
+       /* insn: must be on special executable page on x86_64. */
+       p->ainsn.insn = get_insn_slot();
+       if (!p->ainsn.insn) {
+               return -ENOMEM;
+       }
+       memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
+       return 0;
+}
+
+void arch_remove_kprobe(struct kprobe *p)
+{
+       free_insn_slot(p->ainsn.insn);
+}
+
+static inline void disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
+{
+       *p->addr = p->opcode;
+       regs->rip = (unsigned long)p->addr;
+}
+
+static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+       regs->eflags |= TF_MASK;
+       regs->eflags &= ~IF_MASK;
+
+       regs->rip = (unsigned long)p->ainsn.insn;
+}
+
+/*
+ * Interrupts are disabled on entry as trap3 is an interrupt gate and they
+ * remain disabled thorough out this function.
+ */
+int kprobe_handler(struct pt_regs *regs)
+{
+       struct kprobe *p;
+       int ret = 0;
+       kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->rip - sizeof(kprobe_opcode_t));
+
+       /* We're in an interrupt, but this is clear and BUG()-safe. */
+       preempt_disable();
+
+       /* Check we're not actually recursing */
+       if (kprobe_running()) {
+               /* We *are* holding lock here, so this is safe.
+                  Disarm the probe we just hit, and ignore it. */
+               p = get_kprobe(addr);
+               if (p) {
+                       disarm_kprobe(p, regs);
+                       ret = 1;
+               } else {
+                       p = current_kprobe;
+                       if (p->break_handler && p->break_handler(p, regs)) {
+                               goto ss_probe;
+                       }
+               }
+               /* If it's not ours, can't be delete race, (we hold lock). */
+               goto no_kprobe;
+       }
+
+       lock_kprobes();
+       p = get_kprobe(addr);
+       if (!p) {
+               unlock_kprobes();
+               if (*addr != BREAKPOINT_INSTRUCTION) {
+                       /*
+                        * The breakpoint instruction was removed right
+                        * after we hit it.  Another cpu has removed
+                        * either a probepoint or a debugger breakpoint
+                        * at this address.  In either case, no further
+                        * handling of this interrupt is appropriate.
+                        */
+                       ret = 1;
+               }
+               /* Not one of ours: let kernel handle it */
+               goto no_kprobe;
+       }
+
+       kprobe_status = KPROBE_HIT_ACTIVE;
+       current_kprobe = p;
+       kprobe_saved_rflags = kprobe_old_rflags
+           = (regs->eflags & (TF_MASK | IF_MASK));
+       if (is_IF_modifier(p->ainsn.insn))
+               kprobe_saved_rflags &= ~IF_MASK;
+
+       if (p->pre_handler(p, regs)) {
+               /* handler has already set things up, so skip ss setup */
+               return 1;
+       }
+
+      ss_probe:
+       prepare_singlestep(p, regs);
+       kprobe_status = KPROBE_HIT_SS;
+       return 1;
+
+      no_kprobe:
+       preempt_enable_no_resched();
+       return ret;
+}
+
+/*
+ * Called after single-stepping.  p->addr is the address of the
+ * instruction whose first byte has been replaced by the "int 3"
+ * instruction.  To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction.  The address of this
+ * copy is p->ainsn.insn.
+ *
+ * This function prepares to return from the post-single-step
+ * interrupt.  We have to fix up the stack as follows:
+ *
+ * 0) Except in the case of absolute or indirect jump or call instructions,
+ * the new rip is relative to the copied instruction.  We need to make
+ * it relative to the original instruction.
+ *
+ * 1) If the single-stepped instruction was pushfl, then the TF and IF
+ * flags are set in the just-pushed eflags, and may need to be cleared.
+ *
+ * 2) If the single-stepped instruction was a call, the return address
+ * that is atop the stack is the address following the copied instruction.
+ * We need to make it the address following the original instruction.
+ */
+static void resume_execution(struct kprobe *p, struct pt_regs *regs)
+{
+       unsigned long *tos = (unsigned long *)regs->rsp;
+       unsigned long next_rip = 0;
+       unsigned long copy_rip = (unsigned long)p->ainsn.insn;
+       unsigned long orig_rip = (unsigned long)p->addr;
+       kprobe_opcode_t *insn = p->ainsn.insn;
+
+       /*skip the REX prefix*/
+       if (*insn >= 0x40 && *insn <= 0x4f)
+               insn++;
+
+       switch (*insn) {
+       case 0x9c:              /* pushfl */
+               *tos &= ~(TF_MASK | IF_MASK);
+               *tos |= kprobe_old_rflags;
+               break;
+       case 0xe8:              /* call relative - Fix return addr */
+               *tos = orig_rip + (*tos - copy_rip);
+               break;
+       case 0xff:
+               if ((*insn & 0x30) == 0x10) {
+                       /* call absolute, indirect */
+                       /* Fix return addr; rip is correct. */
+                       next_rip = regs->rip;
+                       *tos = orig_rip + (*tos - copy_rip);
+               } else if (((*insn & 0x31) == 0x20) ||  /* jmp near, absolute indirect */
+                          ((*insn & 0x31) == 0x21)) {  /* jmp far, absolute indirect */
+                       /* rip is correct. */
+                       next_rip = regs->rip;
+               }
+               break;
+       case 0xea:              /* jmp absolute -- rip is correct */
+               next_rip = regs->rip;
+               break;
+       default:
+               break;
+       }
+
+       regs->eflags &= ~TF_MASK;
+       if (next_rip) {
+               regs->rip = next_rip;
+       } else {
+               regs->rip = orig_rip + (regs->rip - copy_rip);
+       }
+}
+
+/*
+ * Interrupts are disabled on entry as trap1 is an interrupt gate and they
+ * remain disabled thoroughout this function.  And we hold kprobe lock.
+ */
+int post_kprobe_handler(struct pt_regs *regs)
+{
+       if (!kprobe_running())
+               return 0;
+
+       if (current_kprobe->post_handler)
+               current_kprobe->post_handler(current_kprobe, regs, 0);
+
+       resume_execution(current_kprobe, regs);
+       regs->eflags |= kprobe_saved_rflags;
+
+       unlock_kprobes();
+       preempt_enable_no_resched();
+
+       /*
+        * if somebody else is singlestepping across a probe point, eflags
+        * will have TF set, in which case, continue the remaining processing
+        * of do_debug, as if this is not a probe hit.
+        */
+       if (regs->eflags & TF_MASK)
+               return 0;
+
+       return 1;
+}
+
+/* Interrupts disabled, kprobe_lock held. */
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+       if (current_kprobe->fault_handler
+           && current_kprobe->fault_handler(current_kprobe, regs, trapnr))
+               return 1;
+
+       if (kprobe_status & KPROBE_HIT_SS) {
+               resume_execution(current_kprobe, regs);
+               regs->eflags |= kprobe_old_rflags;
+
+               unlock_kprobes();
+               preempt_enable_no_resched();
+       }
+       return 0;
+}
+
+/*
+ * Wrapper routine for handling exceptions.
+ */
+int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
+                            void *data)
+{
+       struct die_args *args = (struct die_args *)data;
+       switch (val) {
+       case DIE_INT3:
+               if (kprobe_handler(args->regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_DEBUG:
+               if (post_kprobe_handler(args->regs))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_GPF:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       case DIE_PAGE_FAULT:
+               if (kprobe_running() &&
+                   kprobe_fault_handler(args->regs, args->trapnr))
+                       return NOTIFY_STOP;
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+       unsigned long addr;
+
+       jprobe_saved_regs = *regs;
+       jprobe_saved_rsp = (long *) regs->rsp;
+       addr = (unsigned long)jprobe_saved_rsp;
+       /*
+        * As Linus pointed out, gcc assumes that the callee
+        * owns the argument space and could overwrite it, e.g.
+        * tailcall optimization. So, to be absolutely safe
+        * we also save and restore enough stack bytes to cover
+        * the argument area.
+        */
+       memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr));
+       regs->eflags &= ~IF_MASK;
+       regs->rip = (unsigned long)(jp->entry);
+       return 1;
+}
+
+void jprobe_return(void)
+{
+       preempt_enable_no_resched();
+       asm volatile ("       xchg   %%rbx,%%rsp     \n"
+                     "       int3                      \n"
+                     "       .globl jprobe_return_end  \n"
+                     "       jprobe_return_end:        \n"
+                     "       nop                       \n"::"b"
+                     (jprobe_saved_rsp):"memory");
+}
+
+int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+       u8 *addr = (u8 *) (regs->rip - 1);
+       unsigned long stack_addr = (unsigned long)jprobe_saved_rsp;
+       struct jprobe *jp = container_of(p, struct jprobe, kp);
+
+       if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
+               if ((long *)regs->rsp != jprobe_saved_rsp) {
+                       struct pt_regs *saved_regs =
+                           container_of(jprobe_saved_rsp, struct pt_regs, rsp);
+                       printk("current rsp %p does not match saved rsp %p\n",
+                              (long *)regs->rsp, jprobe_saved_rsp);
+                       printk("Saved registers for jprobe %p\n", jp);
+                       show_registers(saved_regs);
+                       printk("Current registers\n");
+                       show_registers(regs);
+                       BUG();
+               }
+               *regs = jprobe_saved_regs;
+               memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack,
+                      MIN_STACK_SIZE(stack_addr));
+               return 1;
+       }
+       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 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_ATOMIC);
+       if (!kip) {
+               return NULL;
+       }
+       kip->insns = (kprobe_opcode_t*) __vmalloc(PAGE_SIZE,
+               GFP_ATOMIC|__GFP_HIGHMEM, __pgprot(__PAGE_KERNEL_EXEC));
+       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)
+{
+       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 {
+                                       vfree(kip->insns);
+                                       kfree(kip);
+                               }
+                       }
+                       return;
+               }
+       }
+}
diff --git a/arch/x86_64/lib/bitops.c b/arch/x86_64/lib/bitops.c
new file mode 100644 (file)
index 0000000..6060dd9
--- /dev/null
@@ -0,0 +1,140 @@
+#include <linux/module.h>
+#include <asm/bitops.h>
+
+#undef find_first_zero_bit
+#undef find_next_zero_bit
+#undef find_first_bit
+#undef find_next_bit
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+inline long find_first_zero_bit(const unsigned long * addr, unsigned long size)
+{
+       long d0, d1, d2;
+       long res;
+
+       if (!size)
+               return 0;
+       asm volatile(
+               "  repe; scasq\n"
+               "  je 1f\n"
+               "  xorq -8(%%rdi),%%rax\n"
+               "  subq $8,%%rdi\n"
+               "  bsfq %%rax,%%rdx\n"
+               "1:  subq %[addr],%%rdi\n"
+               "  shlq $3,%%rdi\n"
+               "  addq %%rdi,%%rdx"
+               :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+               :"0" (0ULL), "1" ((size + 63) >> 6), "2" (addr), "3" (-1ULL),
+                [addr] "r" (addr) : "memory");
+       return res;
+}
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+long find_next_zero_bit (const unsigned long * addr, long size, long offset)
+{
+       unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
+       unsigned long set = 0;
+       unsigned long res, bit = offset&63;
+
+       if (bit) {
+               /*
+                * Look for zero in first word
+                */
+               asm("bsfq %1,%0\n\t"
+                   "cmoveq %2,%0"
+                   : "=r" (set)
+                   : "r" (~(*p >> bit)), "r"(64L));
+               if (set < (64 - bit))
+                       return set + offset;
+               set = 64 - bit;
+               p++;
+       }
+       /*
+        * No zero yet, search remaining full words for a zero
+        */
+       res = find_first_zero_bit ((const unsigned long *)p,
+                                  size - 64 * (p - (unsigned long *) addr));
+       return (offset + set + res);
+}
+
+static inline long
+__find_first_bit(const unsigned long * addr, unsigned long size)
+{
+       long d0, d1;
+       long res;
+
+       asm volatile(
+               "   repe; scasq\n"
+               "   jz 1f\n"
+               "   subq $8,%%rdi\n"
+               "   bsfq (%%rdi),%%rax\n"
+               "1: subq %[addr],%%rdi\n"
+               "   shlq $3,%%rdi\n"
+               "   addq %%rdi,%%rax"
+               :"=a" (res), "=&c" (d0), "=&D" (d1)
+               :"0" (0ULL),
+                "1" ((size + 63) >> 6), "2" (addr),
+                [addr] "r" (addr) : "memory");
+       return res;
+}
+
+/**
+ * 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.
+ */
+long find_first_bit(const unsigned long * addr, unsigned long size)
+{
+       return __find_first_bit(addr,size);
+}
+
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+long find_next_bit(const unsigned long * addr, long size, long offset)
+{
+       const unsigned long * p = addr + (offset >> 6);
+       unsigned long set = 0, bit = offset & 63, res;
+
+       if (bit) {
+               /*
+                * Look for nonzero in the first 64 bits:
+                */
+               asm("bsfq %1,%0\n\t"
+                   "cmoveq %2,%0\n\t"
+                   : "=r" (set)
+                   : "r" (*p >> bit), "r" (64L));
+               if (set < (64 - bit))
+                       return set + offset;
+               set = 64 - bit;
+               p++;
+       }
+       /*
+        * No set bit yet, search remaining full words for a bit
+        */
+       res = __find_first_bit (p, size - 64 * (p - addr));
+       return (offset + set + res);
+}
+
+EXPORT_SYMBOL(find_next_bit);
+EXPORT_SYMBOL(find_first_bit);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/x86_64/pci/Makefile-BUS b/arch/x86_64/pci/Makefile-BUS
new file mode 100644 (file)
index 0000000..291985f
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Makefile for X86_64 specific PCI routines
+#
+# Reuse the i386 PCI subsystem
+#
+CFLAGS += -I arch/i386/pci
+
+obj-y          := i386.o
+obj-$(CONFIG_PCI_DIRECT)+= direct.o
+obj-y          += fixup.o
+obj-$(CONFIG_ACPI_PCI) += acpi.o
+obj-y                  += legacy.o irq.o common.o
+# mmconfig has a 64bit special
+obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
+
+direct-y += ../../i386/pci/direct.o
+acpi-y   += ../../i386/pci/acpi.o
+legacy-y += ../../i386/pci/legacy.o
+irq-y    += ../../i386/pci/irq.o
+common-y += ../../i386/pci/common.o
+fixup-y  += ../../i386/pci/fixup.o
+i386-y  += ../../i386/pci/i386.o
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
new file mode 100644 (file)
index 0000000..d1c728a
--- /dev/null
@@ -0,0 +1,74 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/mpspec.h>
+#include <linux/cpumask.h>
+
+/*
+ * This discovers the pcibus <-> node mapping on AMD K8.
+ *
+ * RED-PEN need to call this again on PCI hotplug
+ * RED-PEN empty cpus get reported wrong
+ */
+
+#define NODE_ID_REGISTER 0x60
+#define NODE_ID(dword) (dword & 0x07)
+#define LDT_BUS_NUMBER_REGISTER_0 0x94
+#define LDT_BUS_NUMBER_REGISTER_1 0xB4
+#define LDT_BUS_NUMBER_REGISTER_2 0xD4
+#define NR_LDT_BUS_NUMBER_REGISTERS 3
+#define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
+#define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
+#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
+
+/**
+ * fill_mp_bus_to_cpumask()
+ * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
+ * Registers found in the K8 northbridge
+ */
+__init static int
+fill_mp_bus_to_cpumask(void)
+{
+       struct pci_dev *nb_dev = NULL;
+       int i, j;
+       u32 ldtbus, nid;
+       static int lbnr[3] = {
+               LDT_BUS_NUMBER_REGISTER_0,
+               LDT_BUS_NUMBER_REGISTER_1,
+               LDT_BUS_NUMBER_REGISTER_2
+       };
+
+       while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                       PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
+               pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
+
+               for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
+                       pci_read_config_dword(nb_dev, lbnr[i], &ldtbus);
+                       /*
+                        * if there are no busses hanging off of the current
+                        * ldt link then both the secondary and subordinate
+                        * bus number fields are set to 0.
+                        */
+                       if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
+                               && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
+                               for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
+                                    j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
+                                    j++)
+                                       pci_bus_to_cpumask[j] =
+                                               node_to_cpumask(NODE_ID(nid));
+                       }
+               }
+       }
+
+       /* quick sanity check */
+       for (i = 0; i < 256; i++) {
+               if (cpus_empty(pci_bus_to_cpumask[i])) {
+                       printk(KERN_ERR
+                              "k8-bus.c: bus %i has empty cpu mask\n", i);
+                       pci_bus_to_cpumask[i] = CPU_MASK_ALL;
+               }
+       }
+
+       return 0;
+}
+
+fs_initcall(fill_mp_bus_to_cpumask);
diff --git a/crypto/anubis.c b/crypto/anubis.c
new file mode 100644 (file)
index 0000000..3925eb0
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * Cryptographic API.
+ *
+ * Anubis Algorithm
+ *
+ * The Anubis algorithm was developed by Paulo S. L. M. Barreto and
+ * Vincent Rijmen.
+ *
+ * See
+ *
+ *     P.S.L.M. Barreto, V. Rijmen,
+ *     ``The Anubis block cipher,''
+ *     NESSIE submission, 2000.
+ *
+ * This software implements the "tweaked" version of Anubis.
+ * Only the S-box and (consequently) the rounds constants have been
+ * changed.
+ *
+ * The original authors have disclaimed all copyright interest in this
+ * code and thus put it in the public domain. The subsequent authors
+ * have put this under the GNU General Public License.
+ *
+ * By Aaron Grothe ajgrothe@yahoo.com, October 28, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+#define ANUBIS_MIN_KEY_SIZE    16
+#define ANUBIS_MAX_KEY_SIZE    40
+#define ANUBIS_BLOCK_SIZE      16
+#define ANUBIS_MAX_N           10
+#define ANUBIS_MAX_ROUNDS      (8 + ANUBIS_MAX_N)
+
+struct anubis_ctx {
+       int key_len; // in bits
+       int R;
+       u32 E[ANUBIS_MAX_ROUNDS + 1][4];
+       u32 D[ANUBIS_MAX_ROUNDS + 1][4];
+};
+
+static const u32 T0[256] = {
+       0xba69d2bbU, 0x54a84de5U, 0x2f5ebce2U, 0x74e8cd25U,
+       0x53a651f7U, 0xd3bb6bd0U, 0xd2b96fd6U, 0x4d9a29b3U,
+       0x50a05dfdU, 0xac458acfU, 0x8d070e09U, 0xbf63c6a5U,
+       0x70e0dd3dU, 0x52a455f1U, 0x9a29527bU, 0x4c982db5U,
+       0xeac98f46U, 0xd5b773c4U, 0x97336655U, 0xd1bf63dcU,
+       0x3366ccaaU, 0x51a259fbU, 0x5bb671c7U, 0xa651a2f3U,
+       0xdea15ffeU, 0x48903dadU, 0xa84d9ad7U, 0x992f5e71U,
+       0xdbab4be0U, 0x3264c8acU, 0xb773e695U, 0xfce5d732U,
+       0xe3dbab70U, 0x9e214263U, 0x913f7e41U, 0x9b2b567dU,
+       0xe2d9af76U, 0xbb6bd6bdU, 0x4182199bU, 0x6edca579U,
+       0xa557aef9U, 0xcb8b0b80U, 0x6bd6b167U, 0x95376e59U,
+       0xa15fbee1U, 0xf3fbeb10U, 0xb17ffe81U, 0x0204080cU,
+       0xcc851792U, 0xc49537a2U, 0x1d3a744eU, 0x14285078U,
+       0xc39b2bb0U, 0x63c69157U, 0xdaa94fe6U, 0x5dba69d3U,
+       0x5fbe61dfU, 0xdca557f2U, 0x7dfae913U, 0xcd871394U,
+       0x7ffee11fU, 0x5ab475c1U, 0x6cd8ad75U, 0x5cb86dd5U,
+       0xf7f3fb08U, 0x264c98d4U, 0xffe3db38U, 0xedc79354U,
+       0xe8cd874aU, 0x9d274e69U, 0x6fdea17fU, 0x8e010203U,
+       0x19326456U, 0xa05dbae7U, 0xf0fde71aU, 0x890f1e11U,
+       0x0f1e3c22U, 0x070e1c12U, 0xaf4386c5U, 0xfbebcb20U,
+       0x08102030U, 0x152a547eU, 0x0d1a342eU, 0x04081018U,
+       0x01020406U, 0x64c88d45U, 0xdfa35bf8U, 0x76ecc529U,
+       0x79f2f90bU, 0xdda753f4U, 0x3d7af48eU, 0x162c5874U,
+       0x3f7efc82U, 0x376edcb2U, 0x6ddaa973U, 0x3870e090U,
+       0xb96fdeb1U, 0x73e6d137U, 0xe9cf834cU, 0x356ad4beU,
+       0x55aa49e3U, 0x71e2d93bU, 0x7bf6f107U, 0x8c050a0fU,
+       0x72e4d531U, 0x880d1a17U, 0xf6f1ff0eU, 0x2a54a8fcU,
+       0x3e7cf884U, 0x5ebc65d9U, 0x274e9cd2U, 0x468c0589U,
+       0x0c183028U, 0x65ca8943U, 0x68d0bd6dU, 0x61c2995bU,
+       0x03060c0aU, 0xc19f23bcU, 0x57ae41efU, 0xd6b17fceU,
+       0xd9af43ecU, 0x58b07dcdU, 0xd8ad47eaU, 0x66cc8549U,
+       0xd7b37bc8U, 0x3a74e89cU, 0xc88d078aU, 0x3c78f088U,
+       0xfae9cf26U, 0x96316253U, 0xa753a6f5U, 0x982d5a77U,
+       0xecc59752U, 0xb86ddab7U, 0xc7933ba8U, 0xae4182c3U,
+       0x69d2b96bU, 0x4b9631a7U, 0xab4b96ddU, 0xa94f9ed1U,
+       0x67ce814fU, 0x0a14283cU, 0x478e018fU, 0xf2f9ef16U,
+       0xb577ee99U, 0x224488ccU, 0xe5d7b364U, 0xeec19f5eU,
+       0xbe61c2a3U, 0x2b56acfaU, 0x811f3e21U, 0x1224486cU,
+       0x831b362dU, 0x1b366c5aU, 0x0e1c3824U, 0x23468ccaU,
+       0xf5f7f304U, 0x458a0983U, 0x214284c6U, 0xce811f9eU,
+       0x499239abU, 0x2c58b0e8U, 0xf9efc32cU, 0xe6d1bf6eU,
+       0xb671e293U, 0x2850a0f0U, 0x172e5c72U, 0x8219322bU,
+       0x1a34685cU, 0x8b0b161dU, 0xfee1df3eU, 0x8a09121bU,
+       0x09122436U, 0xc98f038cU, 0x87132635U, 0x4e9c25b9U,
+       0xe1dfa37cU, 0x2e5cb8e4U, 0xe4d5b762U, 0xe0dda77aU,
+       0xebcb8b40U, 0x903d7a47U, 0xa455aaffU, 0x1e3c7844U,
+       0x85172e39U, 0x60c09d5dU, 0x00000000U, 0x254a94deU,
+       0xf4f5f702U, 0xf1ffe31cU, 0x94356a5fU, 0x0b162c3aU,
+       0xe7d3bb68U, 0x75eac923U, 0xefc39b58U, 0x3468d0b8U,
+       0x3162c4a6U, 0xd4b577c2U, 0xd0bd67daU, 0x86112233U,
+       0x7efce519U, 0xad478ec9U, 0xfde7d334U, 0x2952a4f6U,
+       0x3060c0a0U, 0x3b76ec9aU, 0x9f234665U, 0xf8edc72aU,
+       0xc6913faeU, 0x13264c6aU, 0x060c1814U, 0x050a141eU,
+       0xc59733a4U, 0x11224466U, 0x77eec12fU, 0x7cf8ed15U,
+       0x7af4f501U, 0x78f0fd0dU, 0x366cd8b4U, 0x1c387048U,
+       0x3972e496U, 0x59b279cbU, 0x18306050U, 0x56ac45e9U,
+       0xb37bf68dU, 0xb07dfa87U, 0x244890d8U, 0x204080c0U,
+       0xb279f28bU, 0x9239724bU, 0xa35bb6edU, 0xc09d27baU,
+       0x44880d85U, 0x62c49551U, 0x10204060U, 0xb475ea9fU,
+       0x84152a3fU, 0x43861197U, 0x933b764dU, 0xc2992fb6U,
+       0x4a9435a1U, 0xbd67cea9U, 0x8f030605U, 0x2d5ab4eeU,
+       0xbc65caafU, 0x9c254a6fU, 0x6ad4b561U, 0x40801d9dU,
+       0xcf831b98U, 0xa259b2ebU, 0x801d3a27U, 0x4f9e21bfU,
+       0x1f3e7c42U, 0xca890f86U, 0xaa4992dbU, 0x42841591U,
+};
+
+static const u32 T1[256] = {
+       0x69babbd2U, 0xa854e54dU, 0x5e2fe2bcU, 0xe87425cdU,
+       0xa653f751U, 0xbbd3d06bU, 0xb9d2d66fU, 0x9a4db329U,
+       0xa050fd5dU, 0x45accf8aU, 0x078d090eU, 0x63bfa5c6U,
+       0xe0703dddU, 0xa452f155U, 0x299a7b52U, 0x984cb52dU,
+       0xc9ea468fU, 0xb7d5c473U, 0x33975566U, 0xbfd1dc63U,
+       0x6633aaccU, 0xa251fb59U, 0xb65bc771U, 0x51a6f3a2U,
+       0xa1defe5fU, 0x9048ad3dU, 0x4da8d79aU, 0x2f99715eU,
+       0xabdbe04bU, 0x6432acc8U, 0x73b795e6U, 0xe5fc32d7U,
+       0xdbe370abU, 0x219e6342U, 0x3f91417eU, 0x2b9b7d56U,
+       0xd9e276afU, 0x6bbbbdd6U, 0x82419b19U, 0xdc6e79a5U,
+       0x57a5f9aeU, 0x8bcb800bU, 0xd66b67b1U, 0x3795596eU,
+       0x5fa1e1beU, 0xfbf310ebU, 0x7fb181feU, 0x04020c08U,
+       0x85cc9217U, 0x95c4a237U, 0x3a1d4e74U, 0x28147850U,
+       0x9bc3b02bU, 0xc6635791U, 0xa9dae64fU, 0xba5dd369U,
+       0xbe5fdf61U, 0xa5dcf257U, 0xfa7d13e9U, 0x87cd9413U,
+       0xfe7f1fe1U, 0xb45ac175U, 0xd86c75adU, 0xb85cd56dU,
+       0xf3f708fbU, 0x4c26d498U, 0xe3ff38dbU, 0xc7ed5493U,
+       0xcde84a87U, 0x279d694eU, 0xde6f7fa1U, 0x018e0302U,
+       0x32195664U, 0x5da0e7baU, 0xfdf01ae7U, 0x0f89111eU,
+       0x1e0f223cU, 0x0e07121cU, 0x43afc586U, 0xebfb20cbU,
+       0x10083020U, 0x2a157e54U, 0x1a0d2e34U, 0x08041810U,
+       0x02010604U, 0xc864458dU, 0xa3dff85bU, 0xec7629c5U,
+       0xf2790bf9U, 0xa7ddf453U, 0x7a3d8ef4U, 0x2c167458U,
+       0x7e3f82fcU, 0x6e37b2dcU, 0xda6d73a9U, 0x703890e0U,
+       0x6fb9b1deU, 0xe67337d1U, 0xcfe94c83U, 0x6a35bed4U,
+       0xaa55e349U, 0xe2713bd9U, 0xf67b07f1U, 0x058c0f0aU,
+       0xe47231d5U, 0x0d88171aU, 0xf1f60effU, 0x542afca8U,
+       0x7c3e84f8U, 0xbc5ed965U, 0x4e27d29cU, 0x8c468905U,
+       0x180c2830U, 0xca654389U, 0xd0686dbdU, 0xc2615b99U,
+       0x06030a0cU, 0x9fc1bc23U, 0xae57ef41U, 0xb1d6ce7fU,
+       0xafd9ec43U, 0xb058cd7dU, 0xadd8ea47U, 0xcc664985U,
+       0xb3d7c87bU, 0x743a9ce8U, 0x8dc88a07U, 0x783c88f0U,
+       0xe9fa26cfU, 0x31965362U, 0x53a7f5a6U, 0x2d98775aU,
+       0xc5ec5297U, 0x6db8b7daU, 0x93c7a83bU, 0x41aec382U,
+       0xd2696bb9U, 0x964ba731U, 0x4babdd96U, 0x4fa9d19eU,
+       0xce674f81U, 0x140a3c28U, 0x8e478f01U, 0xf9f216efU,
+       0x77b599eeU, 0x4422cc88U, 0xd7e564b3U, 0xc1ee5e9fU,
+       0x61bea3c2U, 0x562bfaacU, 0x1f81213eU, 0x24126c48U,
+       0x1b832d36U, 0x361b5a6cU, 0x1c0e2438U, 0x4623ca8cU,
+       0xf7f504f3U, 0x8a458309U, 0x4221c684U, 0x81ce9e1fU,
+       0x9249ab39U, 0x582ce8b0U, 0xeff92cc3U, 0xd1e66ebfU,
+       0x71b693e2U, 0x5028f0a0U, 0x2e17725cU, 0x19822b32U,
+       0x341a5c68U, 0x0b8b1d16U, 0xe1fe3edfU, 0x098a1b12U,
+       0x12093624U, 0x8fc98c03U, 0x13873526U, 0x9c4eb925U,
+       0xdfe17ca3U, 0x5c2ee4b8U, 0xd5e462b7U, 0xdde07aa7U,
+       0xcbeb408bU, 0x3d90477aU, 0x55a4ffaaU, 0x3c1e4478U,
+       0x1785392eU, 0xc0605d9dU, 0x00000000U, 0x4a25de94U,
+       0xf5f402f7U, 0xfff11ce3U, 0x35945f6aU, 0x160b3a2cU,
+       0xd3e768bbU, 0xea7523c9U, 0xc3ef589bU, 0x6834b8d0U,
+       0x6231a6c4U, 0xb5d4c277U, 0xbdd0da67U, 0x11863322U,
+       0xfc7e19e5U, 0x47adc98eU, 0xe7fd34d3U, 0x5229f6a4U,
+       0x6030a0c0U, 0x763b9aecU, 0x239f6546U, 0xedf82ac7U,
+       0x91c6ae3fU, 0x26136a4cU, 0x0c061418U, 0x0a051e14U,
+       0x97c5a433U, 0x22116644U, 0xee772fc1U, 0xf87c15edU,
+       0xf47a01f5U, 0xf0780dfdU, 0x6c36b4d8U, 0x381c4870U,
+       0x723996e4U, 0xb259cb79U, 0x30185060U, 0xac56e945U,
+       0x7bb38df6U, 0x7db087faU, 0x4824d890U, 0x4020c080U,
+       0x79b28bf2U, 0x39924b72U, 0x5ba3edb6U, 0x9dc0ba27U,
+       0x8844850dU, 0xc4625195U, 0x20106040U, 0x75b49feaU,
+       0x15843f2aU, 0x86439711U, 0x3b934d76U, 0x99c2b62fU,
+       0x944aa135U, 0x67bda9ceU, 0x038f0506U, 0x5a2deeb4U,
+       0x65bcafcaU, 0x259c6f4aU, 0xd46a61b5U, 0x80409d1dU,
+       0x83cf981bU, 0x59a2ebb2U, 0x1d80273aU, 0x9e4fbf21U,
+       0x3e1f427cU, 0x89ca860fU, 0x49aadb92U, 0x84429115U,
+};
+
+static const u32 T2[256] = {
+       0xd2bbba69U, 0x4de554a8U, 0xbce22f5eU, 0xcd2574e8U,
+       0x51f753a6U, 0x6bd0d3bbU, 0x6fd6d2b9U, 0x29b34d9aU,
+       0x5dfd50a0U, 0x8acfac45U, 0x0e098d07U, 0xc6a5bf63U,
+       0xdd3d70e0U, 0x55f152a4U, 0x527b9a29U, 0x2db54c98U,
+       0x8f46eac9U, 0x73c4d5b7U, 0x66559733U, 0x63dcd1bfU,
+       0xccaa3366U, 0x59fb51a2U, 0x71c75bb6U, 0xa2f3a651U,
+       0x5ffedea1U, 0x3dad4890U, 0x9ad7a84dU, 0x5e71992fU,
+       0x4be0dbabU, 0xc8ac3264U, 0xe695b773U, 0xd732fce5U,
+       0xab70e3dbU, 0x42639e21U, 0x7e41913fU, 0x567d9b2bU,
+       0xaf76e2d9U, 0xd6bdbb6bU, 0x199b4182U, 0xa5796edcU,
+       0xaef9a557U, 0x0b80cb8bU, 0xb1676bd6U, 0x6e599537U,
+       0xbee1a15fU, 0xeb10f3fbU, 0xfe81b17fU, 0x080c0204U,
+       0x1792cc85U, 0x37a2c495U, 0x744e1d3aU, 0x50781428U,
+       0x2bb0c39bU, 0x915763c6U, 0x4fe6daa9U, 0x69d35dbaU,
+       0x61df5fbeU, 0x57f2dca5U, 0xe9137dfaU, 0x1394cd87U,
+       0xe11f7ffeU, 0x75c15ab4U, 0xad756cd8U, 0x6dd55cb8U,
+       0xfb08f7f3U, 0x98d4264cU, 0xdb38ffe3U, 0x9354edc7U,
+       0x874ae8cdU, 0x4e699d27U, 0xa17f6fdeU, 0x02038e01U,
+       0x64561932U, 0xbae7a05dU, 0xe71af0fdU, 0x1e11890fU,
+       0x3c220f1eU, 0x1c12070eU, 0x86c5af43U, 0xcb20fbebU,
+       0x20300810U, 0x547e152aU, 0x342e0d1aU, 0x10180408U,
+       0x04060102U, 0x8d4564c8U, 0x5bf8dfa3U, 0xc52976ecU,
+       0xf90b79f2U, 0x53f4dda7U, 0xf48e3d7aU, 0x5874162cU,
+       0xfc823f7eU, 0xdcb2376eU, 0xa9736ddaU, 0xe0903870U,
+       0xdeb1b96fU, 0xd13773e6U, 0x834ce9cfU, 0xd4be356aU,
+       0x49e355aaU, 0xd93b71e2U, 0xf1077bf6U, 0x0a0f8c05U,
+       0xd53172e4U, 0x1a17880dU, 0xff0ef6f1U, 0xa8fc2a54U,
+       0xf8843e7cU, 0x65d95ebcU, 0x9cd2274eU, 0x0589468cU,
+       0x30280c18U, 0x894365caU, 0xbd6d68d0U, 0x995b61c2U,
+       0x0c0a0306U, 0x23bcc19fU, 0x41ef57aeU, 0x7fced6b1U,
+       0x43ecd9afU, 0x7dcd58b0U, 0x47ead8adU, 0x854966ccU,
+       0x7bc8d7b3U, 0xe89c3a74U, 0x078ac88dU, 0xf0883c78U,
+       0xcf26fae9U, 0x62539631U, 0xa6f5a753U, 0x5a77982dU,
+       0x9752ecc5U, 0xdab7b86dU, 0x3ba8c793U, 0x82c3ae41U,
+       0xb96b69d2U, 0x31a74b96U, 0x96ddab4bU, 0x9ed1a94fU,
+       0x814f67ceU, 0x283c0a14U, 0x018f478eU, 0xef16f2f9U,
+       0xee99b577U, 0x88cc2244U, 0xb364e5d7U, 0x9f5eeec1U,
+       0xc2a3be61U, 0xacfa2b56U, 0x3e21811fU, 0x486c1224U,
+       0x362d831bU, 0x6c5a1b36U, 0x38240e1cU, 0x8cca2346U,
+       0xf304f5f7U, 0x0983458aU, 0x84c62142U, 0x1f9ece81U,
+       0x39ab4992U, 0xb0e82c58U, 0xc32cf9efU, 0xbf6ee6d1U,
+       0xe293b671U, 0xa0f02850U, 0x5c72172eU, 0x322b8219U,
+       0x685c1a34U, 0x161d8b0bU, 0xdf3efee1U, 0x121b8a09U,
+       0x24360912U, 0x038cc98fU, 0x26358713U, 0x25b94e9cU,
+       0xa37ce1dfU, 0xb8e42e5cU, 0xb762e4d5U, 0xa77ae0ddU,
+       0x8b40ebcbU, 0x7a47903dU, 0xaaffa455U, 0x78441e3cU,
+       0x2e398517U, 0x9d5d60c0U, 0x00000000U, 0x94de254aU,
+       0xf702f4f5U, 0xe31cf1ffU, 0x6a5f9435U, 0x2c3a0b16U,
+       0xbb68e7d3U, 0xc92375eaU, 0x9b58efc3U, 0xd0b83468U,
+       0xc4a63162U, 0x77c2d4b5U, 0x67dad0bdU, 0x22338611U,
+       0xe5197efcU, 0x8ec9ad47U, 0xd334fde7U, 0xa4f62952U,
+       0xc0a03060U, 0xec9a3b76U, 0x46659f23U, 0xc72af8edU,
+       0x3faec691U, 0x4c6a1326U, 0x1814060cU, 0x141e050aU,
+       0x33a4c597U, 0x44661122U, 0xc12f77eeU, 0xed157cf8U,
+       0xf5017af4U, 0xfd0d78f0U, 0xd8b4366cU, 0x70481c38U,
+       0xe4963972U, 0x79cb59b2U, 0x60501830U, 0x45e956acU,
+       0xf68db37bU, 0xfa87b07dU, 0x90d82448U, 0x80c02040U,
+       0xf28bb279U, 0x724b9239U, 0xb6eda35bU, 0x27bac09dU,
+       0x0d854488U, 0x955162c4U, 0x40601020U, 0xea9fb475U,
+       0x2a3f8415U, 0x11974386U, 0x764d933bU, 0x2fb6c299U,
+       0x35a14a94U, 0xcea9bd67U, 0x06058f03U, 0xb4ee2d5aU,
+       0xcaafbc65U, 0x4a6f9c25U, 0xb5616ad4U, 0x1d9d4080U,
+       0x1b98cf83U, 0xb2eba259U, 0x3a27801dU, 0x21bf4f9eU,
+       0x7c421f3eU, 0x0f86ca89U, 0x92dbaa49U, 0x15914284U,
+};
+
+static const u32 T3[256] = {
+       0xbbd269baU, 0xe54da854U, 0xe2bc5e2fU, 0x25cde874U,
+       0xf751a653U, 0xd06bbbd3U, 0xd66fb9d2U, 0xb3299a4dU,
+       0xfd5da050U, 0xcf8a45acU, 0x090e078dU, 0xa5c663bfU,
+       0x3ddde070U, 0xf155a452U, 0x7b52299aU, 0xb52d984cU,
+       0x468fc9eaU, 0xc473b7d5U, 0x55663397U, 0xdc63bfd1U,
+       0xaacc6633U, 0xfb59a251U, 0xc771b65bU, 0xf3a251a6U,
+       0xfe5fa1deU, 0xad3d9048U, 0xd79a4da8U, 0x715e2f99U,
+       0xe04babdbU, 0xacc86432U, 0x95e673b7U, 0x32d7e5fcU,
+       0x70abdbe3U, 0x6342219eU, 0x417e3f91U, 0x7d562b9bU,
+       0x76afd9e2U, 0xbdd66bbbU, 0x9b198241U, 0x79a5dc6eU,
+       0xf9ae57a5U, 0x800b8bcbU, 0x67b1d66bU, 0x596e3795U,
+       0xe1be5fa1U, 0x10ebfbf3U, 0x81fe7fb1U, 0x0c080402U,
+       0x921785ccU, 0xa23795c4U, 0x4e743a1dU, 0x78502814U,
+       0xb02b9bc3U, 0x5791c663U, 0xe64fa9daU, 0xd369ba5dU,
+       0xdf61be5fU, 0xf257a5dcU, 0x13e9fa7dU, 0x941387cdU,
+       0x1fe1fe7fU, 0xc175b45aU, 0x75add86cU, 0xd56db85cU,
+       0x08fbf3f7U, 0xd4984c26U, 0x38dbe3ffU, 0x5493c7edU,
+       0x4a87cde8U, 0x694e279dU, 0x7fa1de6fU, 0x0302018eU,
+       0x56643219U, 0xe7ba5da0U, 0x1ae7fdf0U, 0x111e0f89U,
+       0x223c1e0fU, 0x121c0e07U, 0xc58643afU, 0x20cbebfbU,
+       0x30201008U, 0x7e542a15U, 0x2e341a0dU, 0x18100804U,
+       0x06040201U, 0x458dc864U, 0xf85ba3dfU, 0x29c5ec76U,
+       0x0bf9f279U, 0xf453a7ddU, 0x8ef47a3dU, 0x74582c16U,
+       0x82fc7e3fU, 0xb2dc6e37U, 0x73a9da6dU, 0x90e07038U,
+       0xb1de6fb9U, 0x37d1e673U, 0x4c83cfe9U, 0xbed46a35U,
+       0xe349aa55U, 0x3bd9e271U, 0x07f1f67bU, 0x0f0a058cU,
+       0x31d5e472U, 0x171a0d88U, 0x0efff1f6U, 0xfca8542aU,
+       0x84f87c3eU, 0xd965bc5eU, 0xd29c4e27U, 0x89058c46U,
+       0x2830180cU, 0x4389ca65U, 0x6dbdd068U, 0x5b99c261U,
+       0x0a0c0603U, 0xbc239fc1U, 0xef41ae57U, 0xce7fb1d6U,
+       0xec43afd9U, 0xcd7db058U, 0xea47add8U, 0x4985cc66U,
+       0xc87bb3d7U, 0x9ce8743aU, 0x8a078dc8U, 0x88f0783cU,
+       0x26cfe9faU, 0x53623196U, 0xf5a653a7U, 0x775a2d98U,
+       0x5297c5ecU, 0xb7da6db8U, 0xa83b93c7U, 0xc38241aeU,
+       0x6bb9d269U, 0xa731964bU, 0xdd964babU, 0xd19e4fa9U,
+       0x4f81ce67U, 0x3c28140aU, 0x8f018e47U, 0x16eff9f2U,
+       0x99ee77b5U, 0xcc884422U, 0x64b3d7e5U, 0x5e9fc1eeU,
+       0xa3c261beU, 0xfaac562bU, 0x213e1f81U, 0x6c482412U,
+       0x2d361b83U, 0x5a6c361bU, 0x24381c0eU, 0xca8c4623U,
+       0x04f3f7f5U, 0x83098a45U, 0xc6844221U, 0x9e1f81ceU,
+       0xab399249U, 0xe8b0582cU, 0x2cc3eff9U, 0x6ebfd1e6U,
+       0x93e271b6U, 0xf0a05028U, 0x725c2e17U, 0x2b321982U,
+       0x5c68341aU, 0x1d160b8bU, 0x3edfe1feU, 0x1b12098aU,
+       0x36241209U, 0x8c038fc9U, 0x35261387U, 0xb9259c4eU,
+       0x7ca3dfe1U, 0xe4b85c2eU, 0x62b7d5e4U, 0x7aa7dde0U,
+       0x408bcbebU, 0x477a3d90U, 0xffaa55a4U, 0x44783c1eU,
+       0x392e1785U, 0x5d9dc060U, 0x00000000U, 0xde944a25U,
+       0x02f7f5f4U, 0x1ce3fff1U, 0x5f6a3594U, 0x3a2c160bU,
+       0x68bbd3e7U, 0x23c9ea75U, 0x589bc3efU, 0xb8d06834U,
+       0xa6c46231U, 0xc277b5d4U, 0xda67bdd0U, 0x33221186U,
+       0x19e5fc7eU, 0xc98e47adU, 0x34d3e7fdU, 0xf6a45229U,
+       0xa0c06030U, 0x9aec763bU, 0x6546239fU, 0x2ac7edf8U,
+       0xae3f91c6U, 0x6a4c2613U, 0x14180c06U, 0x1e140a05U,
+       0xa43397c5U, 0x66442211U, 0x2fc1ee77U, 0x15edf87cU,
+       0x01f5f47aU, 0x0dfdf078U, 0xb4d86c36U, 0x4870381cU,
+       0x96e47239U, 0xcb79b259U, 0x50603018U, 0xe945ac56U,
+       0x8df67bb3U, 0x87fa7db0U, 0xd8904824U, 0xc0804020U,
+       0x8bf279b2U, 0x4b723992U, 0xedb65ba3U, 0xba279dc0U,
+       0x850d8844U, 0x5195c462U, 0x60402010U, 0x9fea75b4U,
+       0x3f2a1584U, 0x97118643U, 0x4d763b93U, 0xb62f99c2U,
+       0xa135944aU, 0xa9ce67bdU, 0x0506038fU, 0xeeb45a2dU,
+       0xafca65bcU, 0x6f4a259cU, 0x61b5d46aU, 0x9d1d8040U,
+       0x981b83cfU, 0xebb259a2U, 0x273a1d80U, 0xbf219e4fU,
+       0x427c3e1fU, 0x860f89caU, 0xdb9249aaU, 0x91158442U,
+};
+
+static const u32 T4[256] = {
+       0xbabababaU, 0x54545454U, 0x2f2f2f2fU, 0x74747474U,
+       0x53535353U, 0xd3d3d3d3U, 0xd2d2d2d2U, 0x4d4d4d4dU,
+       0x50505050U, 0xacacacacU, 0x8d8d8d8dU, 0xbfbfbfbfU,
+       0x70707070U, 0x52525252U, 0x9a9a9a9aU, 0x4c4c4c4cU,
+       0xeaeaeaeaU, 0xd5d5d5d5U, 0x97979797U, 0xd1d1d1d1U,
+       0x33333333U, 0x51515151U, 0x5b5b5b5bU, 0xa6a6a6a6U,
+       0xdedededeU, 0x48484848U, 0xa8a8a8a8U, 0x99999999U,
+       0xdbdbdbdbU, 0x32323232U, 0xb7b7b7b7U, 0xfcfcfcfcU,
+       0xe3e3e3e3U, 0x9e9e9e9eU, 0x91919191U, 0x9b9b9b9bU,
+       0xe2e2e2e2U, 0xbbbbbbbbU, 0x41414141U, 0x6e6e6e6eU,
+       0xa5a5a5a5U, 0xcbcbcbcbU, 0x6b6b6b6bU, 0x95959595U,
+       0xa1a1a1a1U, 0xf3f3f3f3U, 0xb1b1b1b1U, 0x02020202U,
+       0xccccccccU, 0xc4c4c4c4U, 0x1d1d1d1dU, 0x14141414U,
+       0xc3c3c3c3U, 0x63636363U, 0xdadadadaU, 0x5d5d5d5dU,
+       0x5f5f5f5fU, 0xdcdcdcdcU, 0x7d7d7d7dU, 0xcdcdcdcdU,
+       0x7f7f7f7fU, 0x5a5a5a5aU, 0x6c6c6c6cU, 0x5c5c5c5cU,
+       0xf7f7f7f7U, 0x26262626U, 0xffffffffU, 0xededededU,
+       0xe8e8e8e8U, 0x9d9d9d9dU, 0x6f6f6f6fU, 0x8e8e8e8eU,
+       0x19191919U, 0xa0a0a0a0U, 0xf0f0f0f0U, 0x89898989U,
+       0x0f0f0f0fU, 0x07070707U, 0xafafafafU, 0xfbfbfbfbU,
+       0x08080808U, 0x15151515U, 0x0d0d0d0dU, 0x04040404U,
+       0x01010101U, 0x64646464U, 0xdfdfdfdfU, 0x76767676U,
+       0x79797979U, 0xddddddddU, 0x3d3d3d3dU, 0x16161616U,
+       0x3f3f3f3fU, 0x37373737U, 0x6d6d6d6dU, 0x38383838U,
+       0xb9b9b9b9U, 0x73737373U, 0xe9e9e9e9U, 0x35353535U,
+       0x55555555U, 0x71717171U, 0x7b7b7b7bU, 0x8c8c8c8cU,
+       0x72727272U, 0x88888888U, 0xf6f6f6f6U, 0x2a2a2a2aU,
+       0x3e3e3e3eU, 0x5e5e5e5eU, 0x27272727U, 0x46464646U,
+       0x0c0c0c0cU, 0x65656565U, 0x68686868U, 0x61616161U,
+       0x03030303U, 0xc1c1c1c1U, 0x57575757U, 0xd6d6d6d6U,
+       0xd9d9d9d9U, 0x58585858U, 0xd8d8d8d8U, 0x66666666U,
+       0xd7d7d7d7U, 0x3a3a3a3aU, 0xc8c8c8c8U, 0x3c3c3c3cU,
+       0xfafafafaU, 0x96969696U, 0xa7a7a7a7U, 0x98989898U,
+       0xececececU, 0xb8b8b8b8U, 0xc7c7c7c7U, 0xaeaeaeaeU,
+       0x69696969U, 0x4b4b4b4bU, 0xababababU, 0xa9a9a9a9U,
+       0x67676767U, 0x0a0a0a0aU, 0x47474747U, 0xf2f2f2f2U,
+       0xb5b5b5b5U, 0x22222222U, 0xe5e5e5e5U, 0xeeeeeeeeU,
+       0xbebebebeU, 0x2b2b2b2bU, 0x81818181U, 0x12121212U,
+       0x83838383U, 0x1b1b1b1bU, 0x0e0e0e0eU, 0x23232323U,
+       0xf5f5f5f5U, 0x45454545U, 0x21212121U, 0xcecececeU,
+       0x49494949U, 0x2c2c2c2cU, 0xf9f9f9f9U, 0xe6e6e6e6U,
+       0xb6b6b6b6U, 0x28282828U, 0x17171717U, 0x82828282U,
+       0x1a1a1a1aU, 0x8b8b8b8bU, 0xfefefefeU, 0x8a8a8a8aU,
+       0x09090909U, 0xc9c9c9c9U, 0x87878787U, 0x4e4e4e4eU,
+       0xe1e1e1e1U, 0x2e2e2e2eU, 0xe4e4e4e4U, 0xe0e0e0e0U,
+       0xebebebebU, 0x90909090U, 0xa4a4a4a4U, 0x1e1e1e1eU,
+       0x85858585U, 0x60606060U, 0x00000000U, 0x25252525U,
+       0xf4f4f4f4U, 0xf1f1f1f1U, 0x94949494U, 0x0b0b0b0bU,
+       0xe7e7e7e7U, 0x75757575U, 0xefefefefU, 0x34343434U,
+       0x31313131U, 0xd4d4d4d4U, 0xd0d0d0d0U, 0x86868686U,
+       0x7e7e7e7eU, 0xadadadadU, 0xfdfdfdfdU, 0x29292929U,
+       0x30303030U, 0x3b3b3b3bU, 0x9f9f9f9fU, 0xf8f8f8f8U,
+       0xc6c6c6c6U, 0x13131313U, 0x06060606U, 0x05050505U,
+       0xc5c5c5c5U, 0x11111111U, 0x77777777U, 0x7c7c7c7cU,
+       0x7a7a7a7aU, 0x78787878U, 0x36363636U, 0x1c1c1c1cU,
+       0x39393939U, 0x59595959U, 0x18181818U, 0x56565656U,
+       0xb3b3b3b3U, 0xb0b0b0b0U, 0x24242424U, 0x20202020U,
+       0xb2b2b2b2U, 0x92929292U, 0xa3a3a3a3U, 0xc0c0c0c0U,
+       0x44444444U, 0x62626262U, 0x10101010U, 0xb4b4b4b4U,
+       0x84848484U, 0x43434343U, 0x93939393U, 0xc2c2c2c2U,
+       0x4a4a4a4aU, 0xbdbdbdbdU, 0x8f8f8f8fU, 0x2d2d2d2dU,
+       0xbcbcbcbcU, 0x9c9c9c9cU, 0x6a6a6a6aU, 0x40404040U,
+       0xcfcfcfcfU, 0xa2a2a2a2U, 0x80808080U, 0x4f4f4f4fU,
+       0x1f1f1f1fU, 0xcacacacaU, 0xaaaaaaaaU, 0x42424242U,
+};
+
+static const u32 T5[256] = {
+       0x00000000U, 0x01020608U, 0x02040c10U, 0x03060a18U,
+       0x04081820U, 0x050a1e28U, 0x060c1430U, 0x070e1238U,
+       0x08103040U, 0x09123648U, 0x0a143c50U, 0x0b163a58U,
+       0x0c182860U, 0x0d1a2e68U, 0x0e1c2470U, 0x0f1e2278U,
+       0x10206080U, 0x11226688U, 0x12246c90U, 0x13266a98U,
+       0x142878a0U, 0x152a7ea8U, 0x162c74b0U, 0x172e72b8U,
+       0x183050c0U, 0x193256c8U, 0x1a345cd0U, 0x1b365ad8U,
+       0x1c3848e0U, 0x1d3a4ee8U, 0x1e3c44f0U, 0x1f3e42f8U,
+       0x2040c01dU, 0x2142c615U, 0x2244cc0dU, 0x2346ca05U,
+       0x2448d83dU, 0x254ade35U, 0x264cd42dU, 0x274ed225U,
+       0x2850f05dU, 0x2952f655U, 0x2a54fc4dU, 0x2b56fa45U,
+       0x2c58e87dU, 0x2d5aee75U, 0x2e5ce46dU, 0x2f5ee265U,
+       0x3060a09dU, 0x3162a695U, 0x3264ac8dU, 0x3366aa85U,
+       0x3468b8bdU, 0x356abeb5U, 0x366cb4adU, 0x376eb2a5U,
+       0x387090ddU, 0x397296d5U, 0x3a749ccdU, 0x3b769ac5U,
+       0x3c7888fdU, 0x3d7a8ef5U, 0x3e7c84edU, 0x3f7e82e5U,
+       0x40809d3aU, 0x41829b32U, 0x4284912aU, 0x43869722U,
+       0x4488851aU, 0x458a8312U, 0x468c890aU, 0x478e8f02U,
+       0x4890ad7aU, 0x4992ab72U, 0x4a94a16aU, 0x4b96a762U,
+       0x4c98b55aU, 0x4d9ab352U, 0x4e9cb94aU, 0x4f9ebf42U,
+       0x50a0fdbaU, 0x51a2fbb2U, 0x52a4f1aaU, 0x53a6f7a2U,
+       0x54a8e59aU, 0x55aae392U, 0x56ace98aU, 0x57aeef82U,
+       0x58b0cdfaU, 0x59b2cbf2U, 0x5ab4c1eaU, 0x5bb6c7e2U,
+       0x5cb8d5daU, 0x5dbad3d2U, 0x5ebcd9caU, 0x5fbedfc2U,
+       0x60c05d27U, 0x61c25b2fU, 0x62c45137U, 0x63c6573fU,
+       0x64c84507U, 0x65ca430fU, 0x66cc4917U, 0x67ce4f1fU,
+       0x68d06d67U, 0x69d26b6fU, 0x6ad46177U, 0x6bd6677fU,
+       0x6cd87547U, 0x6dda734fU, 0x6edc7957U, 0x6fde7f5fU,
+       0x70e03da7U, 0x71e23bafU, 0x72e431b7U, 0x73e637bfU,
+       0x74e82587U, 0x75ea238fU, 0x76ec2997U, 0x77ee2f9fU,
+       0x78f00de7U, 0x79f20befU, 0x7af401f7U, 0x7bf607ffU,
+       0x7cf815c7U, 0x7dfa13cfU, 0x7efc19d7U, 0x7ffe1fdfU,
+       0x801d2774U, 0x811f217cU, 0x82192b64U, 0x831b2d6cU,
+       0x84153f54U, 0x8517395cU, 0x86113344U, 0x8713354cU,
+       0x880d1734U, 0x890f113cU, 0x8a091b24U, 0x8b0b1d2cU,
+       0x8c050f14U, 0x8d07091cU, 0x8e010304U, 0x8f03050cU,
+       0x903d47f4U, 0x913f41fcU, 0x92394be4U, 0x933b4decU,
+       0x94355fd4U, 0x953759dcU, 0x963153c4U, 0x973355ccU,
+       0x982d77b4U, 0x992f71bcU, 0x9a297ba4U, 0x9b2b7dacU,
+       0x9c256f94U, 0x9d27699cU, 0x9e216384U, 0x9f23658cU,
+       0xa05de769U, 0xa15fe161U, 0xa259eb79U, 0xa35bed71U,
+       0xa455ff49U, 0xa557f941U, 0xa651f359U, 0xa753f551U,
+       0xa84dd729U, 0xa94fd121U, 0xaa49db39U, 0xab4bdd31U,
+       0xac45cf09U, 0xad47c901U, 0xae41c319U, 0xaf43c511U,
+       0xb07d87e9U, 0xb17f81e1U, 0xb2798bf9U, 0xb37b8df1U,
+       0xb4759fc9U, 0xb57799c1U, 0xb67193d9U, 0xb77395d1U,
+       0xb86db7a9U, 0xb96fb1a1U, 0xba69bbb9U, 0xbb6bbdb1U,
+       0xbc65af89U, 0xbd67a981U, 0xbe61a399U, 0xbf63a591U,
+       0xc09dba4eU, 0xc19fbc46U, 0xc299b65eU, 0xc39bb056U,
+       0xc495a26eU, 0xc597a466U, 0xc691ae7eU, 0xc793a876U,
+       0xc88d8a0eU, 0xc98f8c06U, 0xca89861eU, 0xcb8b8016U,
+       0xcc85922eU, 0xcd879426U, 0xce819e3eU, 0xcf839836U,
+       0xd0bddaceU, 0xd1bfdcc6U, 0xd2b9d6deU, 0xd3bbd0d6U,
+       0xd4b5c2eeU, 0xd5b7c4e6U, 0xd6b1cefeU, 0xd7b3c8f6U,
+       0xd8adea8eU, 0xd9afec86U, 0xdaa9e69eU, 0xdbabe096U,
+       0xdca5f2aeU, 0xdda7f4a6U, 0xdea1febeU, 0xdfa3f8b6U,
+       0xe0dd7a53U, 0xe1df7c5bU, 0xe2d97643U, 0xe3db704bU,
+       0xe4d56273U, 0xe5d7647bU, 0xe6d16e63U, 0xe7d3686bU,
+       0xe8cd4a13U, 0xe9cf4c1bU, 0xeac94603U, 0xebcb400bU,
+       0xecc55233U, 0xedc7543bU, 0xeec15e23U, 0xefc3582bU,
+       0xf0fd1ad3U, 0xf1ff1cdbU, 0xf2f916c3U, 0xf3fb10cbU,
+       0xf4f502f3U, 0xf5f704fbU, 0xf6f10ee3U, 0xf7f308ebU,
+       0xf8ed2a93U, 0xf9ef2c9bU, 0xfae92683U, 0xfbeb208bU,
+       0xfce532b3U, 0xfde734bbU, 0xfee13ea3U, 0xffe338abU,
+};
+
+static const u32 rc[] = {
+       0xba542f74U, 0x53d3d24dU, 0x50ac8dbfU, 0x70529a4cU,
+       0xead597d1U, 0x33515ba6U, 0xde48a899U, 0xdb32b7fcU,
+       0xe39e919bU, 0xe2bb416eU, 0xa5cb6b95U, 0xa1f3b102U,
+       0xccc41d14U, 0xc363da5dU, 0x5fdc7dcdU, 0x7f5a6c5cU,
+       0xf726ffedU, 0xe89d6f8eU, 0x19a0f089U,
+};
+
+static int anubis_setkey(void *ctx_arg, const u8 *in_key,
+                        unsigned int key_len, u32 *flags)
+{
+
+       int N, R, i, pos, r;
+       u32 kappa[ANUBIS_MAX_N];
+       u32 inter[ANUBIS_MAX_N];
+
+       struct anubis_ctx *ctx = ctx_arg;
+
+       switch (key_len)
+       {
+               case 16: case 20: case 24: case 28:
+               case 32: case 36: case 40:
+                       break;
+               default:
+                       *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+                       return - EINVAL;
+       }
+
+       ctx->key_len = key_len * 8;
+       N = ctx->key_len >> 5;
+       ctx->R = R = 8 + N;
+
+       /* * map cipher key to initial key state (mu): */
+               for (i = 0, pos = 0; i < N; i++, pos += 4) {
+               kappa[i] =
+                       (in_key[pos    ] << 24) ^
+                       (in_key[pos + 1] << 16) ^
+                       (in_key[pos + 2] <<  8) ^
+                       (in_key[pos + 3]      );
+       }
+
+       /*
+        * generate R + 1 round keys:
+        */
+       for (r = 0; r <= R; r++) {
+               u32 K0, K1, K2, K3;
+               /*
+                * generate r-th round key K^r:
+                */
+               K0 = T4[(kappa[N - 1] >> 24)       ];
+               K1 = T4[(kappa[N - 1] >> 16) & 0xff];
+               K2 = T4[(kappa[N - 1] >>  8) & 0xff];
+               K3 = T4[(kappa[N - 1]      ) & 0xff];
+               for (i = N - 2; i >= 0; i--) {
+                       K0 = T4[(kappa[i] >> 24)       ] ^
+                               (T5[(K0 >> 24)       ] & 0xff000000U) ^
+                               (T5[(K0 >> 16) & 0xff] & 0x00ff0000U) ^
+                               (T5[(K0 >>  8) & 0xff] & 0x0000ff00U) ^
+                               (T5[(K0      ) & 0xff] & 0x000000ffU);
+                       K1 = T4[(kappa[i] >> 16) & 0xff] ^
+                               (T5[(K1 >> 24)       ] & 0xff000000U) ^
+                               (T5[(K1 >> 16) & 0xff] & 0x00ff0000U) ^
+                               (T5[(K1 >>  8) & 0xff] & 0x0000ff00U) ^
+                               (T5[(K1      ) & 0xff] & 0x000000ffU);
+                       K2 = T4[(kappa[i] >>  8) & 0xff] ^
+                               (T5[(K2 >> 24)       ] & 0xff000000U) ^
+                               (T5[(K2 >> 16) & 0xff] & 0x00ff0000U) ^
+                               (T5[(K2 >>  8) & 0xff] & 0x0000ff00U) ^
+                               (T5[(K2      ) & 0xff] & 0x000000ffU);
+                       K3 = T4[(kappa[i]      ) & 0xff] ^
+                               (T5[(K3 >> 24)       ] & 0xff000000U) ^
+                               (T5[(K3 >> 16) & 0xff] & 0x00ff0000U) ^
+                               (T5[(K3 >>  8) & 0xff] & 0x0000ff00U) ^
+                               (T5[(K3      ) & 0xff] & 0x000000ffU);
+               }
+
+               ctx->E[r][0] = K0;
+               ctx->E[r][1] = K1;
+               ctx->E[r][2] = K2;
+               ctx->E[r][3] = K3;
+
+               /*
+                * compute kappa^{r+1} from kappa^r:
+                */
+               if (r == R) {
+                       break;
+               }
+               for (i = 0; i < N; i++) {
+                       int j = i;
+                       inter[i]  = T0[(kappa[j--] >> 24)       ];
+                       if (j < 0) j = N - 1;
+                       inter[i] ^= T1[(kappa[j--] >> 16) & 0xff];
+                       if (j < 0) j = N - 1;
+                       inter[i] ^= T2[(kappa[j--] >>  8) & 0xff];
+                       if (j < 0) j = N - 1;
+                       inter[i] ^= T3[(kappa[j  ]      ) & 0xff];
+               }
+               kappa[0] = inter[0] ^ rc[r];
+               for (i = 1; i < N; i++) {
+                       kappa[i] = inter[i];
+               }
+       }
+
+       /*
+        * generate inverse key schedule: K'^0 = K^R, K'^R =
+        *                                K^0, K'^r = theta(K^{R-r}):
+        */
+       for (i = 0; i < 4; i++) {
+               ctx->D[0][i] = ctx->E[R][i];
+               ctx->D[R][i] = ctx->E[0][i];
+       }
+       for (r = 1; r < R; r++) {
+               for (i = 0; i < 4; i++) {
+                       u32 v = ctx->E[R - r][i];
+                       ctx->D[r][i] =
+                               T0[T4[(v >> 24)       ] & 0xff] ^
+                               T1[T4[(v >> 16) & 0xff] & 0xff] ^
+                               T2[T4[(v >>  8) & 0xff] & 0xff] ^
+                               T3[T4[(v      ) & 0xff] & 0xff];
+               }
+       }
+
+       return 0;
+}
+
+static void anubis_crypt(u32 roundKey[ANUBIS_MAX_ROUNDS + 1][4],
+               u8 *ciphertext, const u8 *plaintext, const int R)
+{
+       int i, pos, r;
+       u32 state[4];
+       u32 inter[4];
+
+       /*
+        * map plaintext block to cipher state (mu)
+        * and add initial round key (sigma[K^0]):
+        */
+       for (i = 0, pos = 0; i < 4; i++, pos += 4) {
+               state[i] =
+                       (plaintext[pos    ] << 24) ^
+                       (plaintext[pos + 1] << 16) ^
+                       (plaintext[pos + 2] <<  8) ^
+                       (plaintext[pos + 3]      ) ^
+                       roundKey[0][i];
+       }
+
+       /*
+        * R - 1 full rounds:
+        */
+
+       for (r = 1; r < R; r++) {
+               inter[0] =
+                       T0[(state[0] >> 24)       ] ^
+                       T1[(state[1] >> 24)       ] ^
+                       T2[(state[2] >> 24)       ] ^
+                       T3[(state[3] >> 24)       ] ^
+                       roundKey[r][0];
+               inter[1] =
+                       T0[(state[0] >> 16) & 0xff] ^
+                       T1[(state[1] >> 16) & 0xff] ^
+                       T2[(state[2] >> 16) & 0xff] ^
+                       T3[(state[3] >> 16) & 0xff] ^
+                       roundKey[r][1];
+               inter[2] =
+                       T0[(state[0] >>  8) & 0xff] ^
+                       T1[(state[1] >>  8) & 0xff] ^
+                       T2[(state[2] >>  8) & 0xff] ^
+                       T3[(state[3] >>  8) & 0xff] ^
+                       roundKey[r][2];
+               inter[3] =
+                       T0[(state[0]      ) & 0xff] ^
+                       T1[(state[1]      ) & 0xff] ^
+                       T2[(state[2]      ) & 0xff] ^
+                       T3[(state[3]      ) & 0xff] ^
+                       roundKey[r][3];
+               state[0] = inter[0];
+               state[1] = inter[1];
+               state[2] = inter[2];
+               state[3] = inter[3];
+       }
+
+       /*
+        * last round:
+        */
+
+       inter[0] =
+               (T0[(state[0] >> 24)       ] & 0xff000000U) ^
+               (T1[(state[1] >> 24)       ] & 0x00ff0000U) ^
+               (T2[(state[2] >> 24)       ] & 0x0000ff00U) ^
+               (T3[(state[3] >> 24)       ] & 0x000000ffU) ^
+               roundKey[R][0];
+       inter[1] =
+               (T0[(state[0] >> 16) & 0xff] & 0xff000000U) ^
+               (T1[(state[1] >> 16) & 0xff] & 0x00ff0000U) ^
+               (T2[(state[2] >> 16) & 0xff] & 0x0000ff00U) ^
+               (T3[(state[3] >> 16) & 0xff] & 0x000000ffU) ^
+               roundKey[R][1];
+       inter[2] =
+               (T0[(state[0] >>  8) & 0xff] & 0xff000000U) ^
+               (T1[(state[1] >>  8) & 0xff] & 0x00ff0000U) ^
+               (T2[(state[2] >>  8) & 0xff] & 0x0000ff00U) ^
+               (T3[(state[3] >>  8) & 0xff] & 0x000000ffU) ^
+               roundKey[R][2];
+       inter[3] =
+               (T0[(state[0]      ) & 0xff] & 0xff000000U) ^
+               (T1[(state[1]      ) & 0xff] & 0x00ff0000U) ^
+               (T2[(state[2]      ) & 0xff] & 0x0000ff00U) ^
+               (T3[(state[3]      ) & 0xff] & 0x000000ffU) ^
+               roundKey[R][3];
+
+       /*
+        * map cipher state to ciphertext block (mu^{-1}):
+        */
+
+       for (i = 0, pos = 0; i < 4; i++, pos += 4) {
+               u32 w = inter[i];
+               ciphertext[pos    ] = (u8)(w >> 24);
+               ciphertext[pos + 1] = (u8)(w >> 16);
+               ciphertext[pos + 2] = (u8)(w >>  8);
+               ciphertext[pos + 3] = (u8)(w      );
+       }
+}
+
+static void anubis_encrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{
+       struct anubis_ctx *ctx = ctx_arg;
+       anubis_crypt(ctx->E, dst, src, ctx->R);
+}
+
+static void anubis_decrypt(void *ctx_arg, u8 *dst, const u8 *src)
+{
+       struct anubis_ctx *ctx = ctx_arg;
+       anubis_crypt(ctx->D, dst, src, ctx->R);
+}
+
+static struct crypto_alg anubis_alg = {
+       .cra_name               =       "anubis",
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       ANUBIS_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof (struct anubis_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(anubis_alg.cra_list),
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       ANUBIS_MIN_KEY_SIZE,
+       .cia_max_keysize        =       ANUBIS_MAX_KEY_SIZE,
+       .cia_setkey             =       anubis_setkey,
+       .cia_encrypt            =       anubis_encrypt,
+       .cia_decrypt            =       anubis_decrypt } }
+};
+
+static int __init init(void)
+{
+       int ret = 0;
+       
+       ret = crypto_register_alg(&anubis_alg);
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&anubis_alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Anubis Cryptographic Algorithm");
diff --git a/crypto/wp512.c b/crypto/wp512.c
new file mode 100644 (file)
index 0000000..fd6e20e
--- /dev/null
@@ -0,0 +1,1208 @@
+/*
+ * Cryptographic API.
+ *
+ * Whirlpool hashing Algorithm
+ *
+ * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and
+ * Vincent Rijmen.  It has been selected as one of cryptographic
+ * primitives by the NESSIE project http://www.cryptonessie.org/
+ *
+ * The original authors have disclaimed all copyright interest in this
+ * code and thus put it in the public domain. The subsequent authors
+ * have put this under the GNU General Public License.
+ *
+ * By Aaron Grothe ajgrothe@yahoo.com, August 23, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+#define WP512_DIGEST_SIZE 64
+#define WP384_DIGEST_SIZE 48
+#define WP256_DIGEST_SIZE 32
+
+#define WP512_BLOCK_SIZE  64
+#define WP512_LENGTHBYTES 32
+
+#define WHIRLPOOL_ROUNDS 10
+
+struct wp512_ctx {
+       u8  bitLength[WP512_LENGTHBYTES];
+       u8  buffer[WP512_BLOCK_SIZE];
+       int bufferBits;
+       int bufferPos;
+       u64 hash[WP512_DIGEST_SIZE/8];
+};
+
+/*
+ * Though Whirlpool is endianness-neutral, the encryption tables are listed
+ * in BIG-ENDIAN format, which is adopted throughout this implementation
+ * (but little-endian notation would be equally suitable if consistently
+ * employed).
+ */
+
+static const u64 C0[256] = {
+       0x18186018c07830d8ULL, 0x23238c2305af4626ULL, 0xc6c63fc67ef991b8ULL,
+       0xe8e887e8136fcdfbULL, 0x878726874ca113cbULL, 0xb8b8dab8a9626d11ULL,
+       0x0101040108050209ULL, 0x4f4f214f426e9e0dULL, 0x3636d836adee6c9bULL,
+       0xa6a6a2a6590451ffULL, 0xd2d26fd2debdb90cULL, 0xf5f5f3f5fb06f70eULL,
+       0x7979f979ef80f296ULL, 0x6f6fa16f5fcede30ULL, 0x91917e91fcef3f6dULL,
+       0x52525552aa07a4f8ULL, 0x60609d6027fdc047ULL, 0xbcbccabc89766535ULL,
+       0x9b9b569baccd2b37ULL, 0x8e8e028e048c018aULL, 0xa3a3b6a371155bd2ULL,
+       0x0c0c300c603c186cULL, 0x7b7bf17bff8af684ULL, 0x3535d435b5e16a80ULL,
+       0x1d1d741de8693af5ULL, 0xe0e0a7e05347ddb3ULL, 0xd7d77bd7f6acb321ULL,
+       0xc2c22fc25eed999cULL, 0x2e2eb82e6d965c43ULL, 0x4b4b314b627a9629ULL,
+       0xfefedffea321e15dULL, 0x575741578216aed5ULL, 0x15155415a8412abdULL,
+       0x7777c1779fb6eee8ULL, 0x3737dc37a5eb6e92ULL, 0xe5e5b3e57b56d79eULL,
+       0x9f9f469f8cd92313ULL, 0xf0f0e7f0d317fd23ULL, 0x4a4a354a6a7f9420ULL,
+       0xdada4fda9e95a944ULL, 0x58587d58fa25b0a2ULL, 0xc9c903c906ca8fcfULL,
+       0x2929a429558d527cULL, 0x0a0a280a5022145aULL, 0xb1b1feb1e14f7f50ULL,
+       0xa0a0baa0691a5dc9ULL, 0x6b6bb16b7fdad614ULL, 0x85852e855cab17d9ULL,
+       0xbdbdcebd8173673cULL, 0x5d5d695dd234ba8fULL, 0x1010401080502090ULL,
+       0xf4f4f7f4f303f507ULL, 0xcbcb0bcb16c08bddULL, 0x3e3ef83eedc67cd3ULL,
+       0x0505140528110a2dULL, 0x676781671fe6ce78ULL, 0xe4e4b7e47353d597ULL,
+       0x27279c2725bb4e02ULL, 0x4141194132588273ULL, 0x8b8b168b2c9d0ba7ULL,
+       0xa7a7a6a7510153f6ULL, 0x7d7de97dcf94fab2ULL, 0x95956e95dcfb3749ULL,
+       0xd8d847d88e9fad56ULL, 0xfbfbcbfb8b30eb70ULL, 0xeeee9fee2371c1cdULL,
+       0x7c7ced7cc791f8bbULL, 0x6666856617e3cc71ULL, 0xdddd53dda68ea77bULL,
+       0x17175c17b84b2eafULL, 0x4747014702468e45ULL, 0x9e9e429e84dc211aULL,
+       0xcaca0fca1ec589d4ULL, 0x2d2db42d75995a58ULL, 0xbfbfc6bf9179632eULL,
+       0x07071c07381b0e3fULL, 0xadad8ead012347acULL, 0x5a5a755aea2fb4b0ULL,
+       0x838336836cb51befULL, 0x3333cc3385ff66b6ULL, 0x636391633ff2c65cULL,
+       0x02020802100a0412ULL, 0xaaaa92aa39384993ULL, 0x7171d971afa8e2deULL,
+       0xc8c807c80ecf8dc6ULL, 0x19196419c87d32d1ULL, 0x494939497270923bULL,
+       0xd9d943d9869aaf5fULL, 0xf2f2eff2c31df931ULL, 0xe3e3abe34b48dba8ULL,
+       0x5b5b715be22ab6b9ULL, 0x88881a8834920dbcULL, 0x9a9a529aa4c8293eULL,
+       0x262698262dbe4c0bULL, 0x3232c8328dfa64bfULL, 0xb0b0fab0e94a7d59ULL,
+       0xe9e983e91b6acff2ULL, 0x0f0f3c0f78331e77ULL, 0xd5d573d5e6a6b733ULL,
+       0x80803a8074ba1df4ULL, 0xbebec2be997c6127ULL, 0xcdcd13cd26de87ebULL,
+       0x3434d034bde46889ULL, 0x48483d487a759032ULL, 0xffffdbffab24e354ULL,
+       0x7a7af57af78ff48dULL, 0x90907a90f4ea3d64ULL, 0x5f5f615fc23ebe9dULL,
+       0x202080201da0403dULL, 0x6868bd6867d5d00fULL, 0x1a1a681ad07234caULL,
+       0xaeae82ae192c41b7ULL, 0xb4b4eab4c95e757dULL, 0x54544d549a19a8ceULL,
+       0x93937693ece53b7fULL, 0x222288220daa442fULL, 0x64648d6407e9c863ULL,
+       0xf1f1e3f1db12ff2aULL, 0x7373d173bfa2e6ccULL, 0x12124812905a2482ULL,
+       0x40401d403a5d807aULL, 0x0808200840281048ULL, 0xc3c32bc356e89b95ULL,
+       0xecec97ec337bc5dfULL, 0xdbdb4bdb9690ab4dULL, 0xa1a1bea1611f5fc0ULL,
+       0x8d8d0e8d1c830791ULL, 0x3d3df43df5c97ac8ULL, 0x97976697ccf1335bULL,
+       0x0000000000000000ULL, 0xcfcf1bcf36d483f9ULL, 0x2b2bac2b4587566eULL,
+       0x7676c57697b3ece1ULL, 0x8282328264b019e6ULL, 0xd6d67fd6fea9b128ULL,
+       0x1b1b6c1bd87736c3ULL, 0xb5b5eeb5c15b7774ULL, 0xafaf86af112943beULL,
+       0x6a6ab56a77dfd41dULL, 0x50505d50ba0da0eaULL, 0x45450945124c8a57ULL,
+       0xf3f3ebf3cb18fb38ULL, 0x3030c0309df060adULL, 0xefef9bef2b74c3c4ULL,
+       0x3f3ffc3fe5c37edaULL, 0x55554955921caac7ULL, 0xa2a2b2a2791059dbULL,
+       0xeaea8fea0365c9e9ULL, 0x656589650fecca6aULL, 0xbabad2bab9686903ULL,
+       0x2f2fbc2f65935e4aULL, 0xc0c027c04ee79d8eULL, 0xdede5fdebe81a160ULL,
+       0x1c1c701ce06c38fcULL, 0xfdfdd3fdbb2ee746ULL, 0x4d4d294d52649a1fULL,
+       0x92927292e4e03976ULL, 0x7575c9758fbceafaULL, 0x06061806301e0c36ULL,
+       0x8a8a128a249809aeULL, 0xb2b2f2b2f940794bULL, 0xe6e6bfe66359d185ULL,
+       0x0e0e380e70361c7eULL, 0x1f1f7c1ff8633ee7ULL, 0x6262956237f7c455ULL,
+       0xd4d477d4eea3b53aULL, 0xa8a89aa829324d81ULL, 0x96966296c4f43152ULL,
+       0xf9f9c3f99b3aef62ULL, 0xc5c533c566f697a3ULL, 0x2525942535b14a10ULL,
+       0x59597959f220b2abULL, 0x84842a8454ae15d0ULL, 0x7272d572b7a7e4c5ULL,
+       0x3939e439d5dd72ecULL, 0x4c4c2d4c5a619816ULL, 0x5e5e655eca3bbc94ULL,
+       0x7878fd78e785f09fULL, 0x3838e038ddd870e5ULL, 0x8c8c0a8c14860598ULL,
+       0xd1d163d1c6b2bf17ULL, 0xa5a5aea5410b57e4ULL, 0xe2e2afe2434dd9a1ULL,
+       0x616199612ff8c24eULL, 0xb3b3f6b3f1457b42ULL, 0x2121842115a54234ULL,
+       0x9c9c4a9c94d62508ULL, 0x1e1e781ef0663ceeULL, 0x4343114322528661ULL,
+       0xc7c73bc776fc93b1ULL, 0xfcfcd7fcb32be54fULL, 0x0404100420140824ULL,
+       0x51515951b208a2e3ULL, 0x99995e99bcc72f25ULL, 0x6d6da96d4fc4da22ULL,
+       0x0d0d340d68391a65ULL, 0xfafacffa8335e979ULL, 0xdfdf5bdfb684a369ULL,
+       0x7e7ee57ed79bfca9ULL, 0x242490243db44819ULL, 0x3b3bec3bc5d776feULL,
+       0xabab96ab313d4b9aULL, 0xcece1fce3ed181f0ULL, 0x1111441188552299ULL,
+       0x8f8f068f0c890383ULL, 0x4e4e254e4a6b9c04ULL, 0xb7b7e6b7d1517366ULL,
+       0xebeb8beb0b60cbe0ULL, 0x3c3cf03cfdcc78c1ULL, 0x81813e817cbf1ffdULL,
+       0x94946a94d4fe3540ULL, 0xf7f7fbf7eb0cf31cULL, 0xb9b9deb9a1676f18ULL,
+       0x13134c13985f268bULL, 0x2c2cb02c7d9c5851ULL, 0xd3d36bd3d6b8bb05ULL,
+       0xe7e7bbe76b5cd38cULL, 0x6e6ea56e57cbdc39ULL, 0xc4c437c46ef395aaULL,
+       0x03030c03180f061bULL, 0x565645568a13acdcULL, 0x44440d441a49885eULL,
+       0x7f7fe17fdf9efea0ULL, 0xa9a99ea921374f88ULL, 0x2a2aa82a4d825467ULL,
+       0xbbbbd6bbb16d6b0aULL, 0xc1c123c146e29f87ULL, 0x53535153a202a6f1ULL,
+       0xdcdc57dcae8ba572ULL, 0x0b0b2c0b58271653ULL, 0x9d9d4e9d9cd32701ULL,
+       0x6c6cad6c47c1d82bULL, 0x3131c43195f562a4ULL, 0x7474cd7487b9e8f3ULL,
+       0xf6f6fff6e309f115ULL, 0x464605460a438c4cULL, 0xacac8aac092645a5ULL,
+       0x89891e893c970fb5ULL, 0x14145014a04428b4ULL, 0xe1e1a3e15b42dfbaULL,
+       0x16165816b04e2ca6ULL, 0x3a3ae83acdd274f7ULL, 0x6969b9696fd0d206ULL,
+       0x09092409482d1241ULL, 0x7070dd70a7ade0d7ULL, 0xb6b6e2b6d954716fULL,
+       0xd0d067d0ceb7bd1eULL, 0xeded93ed3b7ec7d6ULL, 0xcccc17cc2edb85e2ULL,
+       0x424215422a578468ULL, 0x98985a98b4c22d2cULL, 0xa4a4aaa4490e55edULL,
+       0x2828a0285d885075ULL, 0x5c5c6d5cda31b886ULL, 0xf8f8c7f8933fed6bULL,
+       0x8686228644a411c2ULL,
+};
+
+static const u64 C1[256] = {
+       0xd818186018c07830ULL, 0x2623238c2305af46ULL, 0xb8c6c63fc67ef991ULL,
+       0xfbe8e887e8136fcdULL, 0xcb878726874ca113ULL, 0x11b8b8dab8a9626dULL,
+       0x0901010401080502ULL, 0x0d4f4f214f426e9eULL, 0x9b3636d836adee6cULL,
+       0xffa6a6a2a6590451ULL, 0x0cd2d26fd2debdb9ULL, 0x0ef5f5f3f5fb06f7ULL,
+       0x967979f979ef80f2ULL, 0x306f6fa16f5fcedeULL, 0x6d91917e91fcef3fULL,
+       0xf852525552aa07a4ULL, 0x4760609d6027fdc0ULL, 0x35bcbccabc897665ULL,
+       0x379b9b569baccd2bULL, 0x8a8e8e028e048c01ULL, 0xd2a3a3b6a371155bULL,
+       0x6c0c0c300c603c18ULL, 0x847b7bf17bff8af6ULL, 0x803535d435b5e16aULL,
+       0xf51d1d741de8693aULL, 0xb3e0e0a7e05347ddULL, 0x21d7d77bd7f6acb3ULL,
+       0x9cc2c22fc25eed99ULL, 0x432e2eb82e6d965cULL, 0x294b4b314b627a96ULL,
+       0x5dfefedffea321e1ULL, 0xd5575741578216aeULL, 0xbd15155415a8412aULL,
+       0xe87777c1779fb6eeULL, 0x923737dc37a5eb6eULL, 0x9ee5e5b3e57b56d7ULL,
+       0x139f9f469f8cd923ULL, 0x23f0f0e7f0d317fdULL, 0x204a4a354a6a7f94ULL,
+       0x44dada4fda9e95a9ULL, 0xa258587d58fa25b0ULL, 0xcfc9c903c906ca8fULL,
+       0x7c2929a429558d52ULL, 0x5a0a0a280a502214ULL, 0x50b1b1feb1e14f7fULL,
+       0xc9a0a0baa0691a5dULL, 0x146b6bb16b7fdad6ULL, 0xd985852e855cab17ULL,
+       0x3cbdbdcebd817367ULL, 0x8f5d5d695dd234baULL, 0x9010104010805020ULL,
+       0x07f4f4f7f4f303f5ULL, 0xddcbcb0bcb16c08bULL, 0xd33e3ef83eedc67cULL,
+       0x2d0505140528110aULL, 0x78676781671fe6ceULL, 0x97e4e4b7e47353d5ULL,
+       0x0227279c2725bb4eULL, 0x7341411941325882ULL, 0xa78b8b168b2c9d0bULL,
+       0xf6a7a7a6a7510153ULL, 0xb27d7de97dcf94faULL, 0x4995956e95dcfb37ULL,
+       0x56d8d847d88e9fadULL, 0x70fbfbcbfb8b30ebULL, 0xcdeeee9fee2371c1ULL,
+       0xbb7c7ced7cc791f8ULL, 0x716666856617e3ccULL, 0x7bdddd53dda68ea7ULL,
+       0xaf17175c17b84b2eULL, 0x454747014702468eULL, 0x1a9e9e429e84dc21ULL,
+       0xd4caca0fca1ec589ULL, 0x582d2db42d75995aULL, 0x2ebfbfc6bf917963ULL,
+       0x3f07071c07381b0eULL, 0xacadad8ead012347ULL, 0xb05a5a755aea2fb4ULL,
+       0xef838336836cb51bULL, 0xb63333cc3385ff66ULL, 0x5c636391633ff2c6ULL,
+       0x1202020802100a04ULL, 0x93aaaa92aa393849ULL, 0xde7171d971afa8e2ULL,
+       0xc6c8c807c80ecf8dULL, 0xd119196419c87d32ULL, 0x3b49493949727092ULL,
+       0x5fd9d943d9869aafULL, 0x31f2f2eff2c31df9ULL, 0xa8e3e3abe34b48dbULL,
+       0xb95b5b715be22ab6ULL, 0xbc88881a8834920dULL, 0x3e9a9a529aa4c829ULL,
+       0x0b262698262dbe4cULL, 0xbf3232c8328dfa64ULL, 0x59b0b0fab0e94a7dULL,
+       0xf2e9e983e91b6acfULL, 0x770f0f3c0f78331eULL, 0x33d5d573d5e6a6b7ULL,
+       0xf480803a8074ba1dULL, 0x27bebec2be997c61ULL, 0xebcdcd13cd26de87ULL,
+       0x893434d034bde468ULL, 0x3248483d487a7590ULL, 0x54ffffdbffab24e3ULL,
+       0x8d7a7af57af78ff4ULL, 0x6490907a90f4ea3dULL, 0x9d5f5f615fc23ebeULL,
+       0x3d202080201da040ULL, 0x0f6868bd6867d5d0ULL, 0xca1a1a681ad07234ULL,
+       0xb7aeae82ae192c41ULL, 0x7db4b4eab4c95e75ULL, 0xce54544d549a19a8ULL,
+       0x7f93937693ece53bULL, 0x2f222288220daa44ULL, 0x6364648d6407e9c8ULL,
+       0x2af1f1e3f1db12ffULL, 0xcc7373d173bfa2e6ULL, 0x8212124812905a24ULL,
+       0x7a40401d403a5d80ULL, 0x4808082008402810ULL, 0x95c3c32bc356e89bULL,
+       0xdfecec97ec337bc5ULL, 0x4ddbdb4bdb9690abULL, 0xc0a1a1bea1611f5fULL,
+       0x918d8d0e8d1c8307ULL, 0xc83d3df43df5c97aULL, 0x5b97976697ccf133ULL,
+       0x0000000000000000ULL, 0xf9cfcf1bcf36d483ULL, 0x6e2b2bac2b458756ULL,
+       0xe17676c57697b3ecULL, 0xe68282328264b019ULL, 0x28d6d67fd6fea9b1ULL,
+       0xc31b1b6c1bd87736ULL, 0x74b5b5eeb5c15b77ULL, 0xbeafaf86af112943ULL,
+       0x1d6a6ab56a77dfd4ULL, 0xea50505d50ba0da0ULL, 0x5745450945124c8aULL,
+       0x38f3f3ebf3cb18fbULL, 0xad3030c0309df060ULL, 0xc4efef9bef2b74c3ULL,
+       0xda3f3ffc3fe5c37eULL, 0xc755554955921caaULL, 0xdba2a2b2a2791059ULL,
+       0xe9eaea8fea0365c9ULL, 0x6a656589650feccaULL, 0x03babad2bab96869ULL,
+       0x4a2f2fbc2f65935eULL, 0x8ec0c027c04ee79dULL, 0x60dede5fdebe81a1ULL,
+       0xfc1c1c701ce06c38ULL, 0x46fdfdd3fdbb2ee7ULL, 0x1f4d4d294d52649aULL,
+       0x7692927292e4e039ULL, 0xfa7575c9758fbceaULL, 0x3606061806301e0cULL,
+       0xae8a8a128a249809ULL, 0x4bb2b2f2b2f94079ULL, 0x85e6e6bfe66359d1ULL,
+       0x7e0e0e380e70361cULL, 0xe71f1f7c1ff8633eULL, 0x556262956237f7c4ULL,
+       0x3ad4d477d4eea3b5ULL, 0x81a8a89aa829324dULL, 0x5296966296c4f431ULL,
+       0x62f9f9c3f99b3aefULL, 0xa3c5c533c566f697ULL, 0x102525942535b14aULL,
+       0xab59597959f220b2ULL, 0xd084842a8454ae15ULL, 0xc57272d572b7a7e4ULL,
+       0xec3939e439d5dd72ULL, 0x164c4c2d4c5a6198ULL, 0x945e5e655eca3bbcULL,
+       0x9f7878fd78e785f0ULL, 0xe53838e038ddd870ULL, 0x988c8c0a8c148605ULL,
+       0x17d1d163d1c6b2bfULL, 0xe4a5a5aea5410b57ULL, 0xa1e2e2afe2434dd9ULL,
+       0x4e616199612ff8c2ULL, 0x42b3b3f6b3f1457bULL, 0x342121842115a542ULL,
+       0x089c9c4a9c94d625ULL, 0xee1e1e781ef0663cULL, 0x6143431143225286ULL,
+       0xb1c7c73bc776fc93ULL, 0x4ffcfcd7fcb32be5ULL, 0x2404041004201408ULL,
+       0xe351515951b208a2ULL, 0x2599995e99bcc72fULL, 0x226d6da96d4fc4daULL,
+       0x650d0d340d68391aULL, 0x79fafacffa8335e9ULL, 0x69dfdf5bdfb684a3ULL,
+       0xa97e7ee57ed79bfcULL, 0x19242490243db448ULL, 0xfe3b3bec3bc5d776ULL,
+       0x9aabab96ab313d4bULL, 0xf0cece1fce3ed181ULL, 0x9911114411885522ULL,
+       0x838f8f068f0c8903ULL, 0x044e4e254e4a6b9cULL, 0x66b7b7e6b7d15173ULL,
+       0xe0ebeb8beb0b60cbULL, 0xc13c3cf03cfdcc78ULL, 0xfd81813e817cbf1fULL,
+       0x4094946a94d4fe35ULL, 0x1cf7f7fbf7eb0cf3ULL, 0x18b9b9deb9a1676fULL,
+       0x8b13134c13985f26ULL, 0x512c2cb02c7d9c58ULL, 0x05d3d36bd3d6b8bbULL,
+       0x8ce7e7bbe76b5cd3ULL, 0x396e6ea56e57cbdcULL, 0xaac4c437c46ef395ULL,
+       0x1b03030c03180f06ULL, 0xdc565645568a13acULL, 0x5e44440d441a4988ULL,
+       0xa07f7fe17fdf9efeULL, 0x88a9a99ea921374fULL, 0x672a2aa82a4d8254ULL,
+       0x0abbbbd6bbb16d6bULL, 0x87c1c123c146e29fULL, 0xf153535153a202a6ULL,
+       0x72dcdc57dcae8ba5ULL, 0x530b0b2c0b582716ULL, 0x019d9d4e9d9cd327ULL,
+       0x2b6c6cad6c47c1d8ULL, 0xa43131c43195f562ULL, 0xf37474cd7487b9e8ULL,
+       0x15f6f6fff6e309f1ULL, 0x4c464605460a438cULL, 0xa5acac8aac092645ULL,
+       0xb589891e893c970fULL, 0xb414145014a04428ULL, 0xbae1e1a3e15b42dfULL,
+       0xa616165816b04e2cULL, 0xf73a3ae83acdd274ULL, 0x066969b9696fd0d2ULL,
+       0x4109092409482d12ULL, 0xd77070dd70a7ade0ULL, 0x6fb6b6e2b6d95471ULL,
+       0x1ed0d067d0ceb7bdULL, 0xd6eded93ed3b7ec7ULL, 0xe2cccc17cc2edb85ULL,
+       0x68424215422a5784ULL, 0x2c98985a98b4c22dULL, 0xeda4a4aaa4490e55ULL,
+       0x752828a0285d8850ULL, 0x865c5c6d5cda31b8ULL, 0x6bf8f8c7f8933fedULL,
+       0xc28686228644a411ULL,
+};
+
+static const u64 C2[256] = {
+       0x30d818186018c078ULL, 0x462623238c2305afULL, 0x91b8c6c63fc67ef9ULL,
+       0xcdfbe8e887e8136fULL, 0x13cb878726874ca1ULL, 0x6d11b8b8dab8a962ULL,
+       0x0209010104010805ULL, 0x9e0d4f4f214f426eULL, 0x6c9b3636d836adeeULL,
+       0x51ffa6a6a2a65904ULL, 0xb90cd2d26fd2debdULL, 0xf70ef5f5f3f5fb06ULL,
+       0xf2967979f979ef80ULL, 0xde306f6fa16f5fceULL, 0x3f6d91917e91fcefULL,
+       0xa4f852525552aa07ULL, 0xc04760609d6027fdULL, 0x6535bcbccabc8976ULL,
+       0x2b379b9b569baccdULL, 0x018a8e8e028e048cULL, 0x5bd2a3a3b6a37115ULL,
+       0x186c0c0c300c603cULL, 0xf6847b7bf17bff8aULL, 0x6a803535d435b5e1ULL,
+       0x3af51d1d741de869ULL, 0xddb3e0e0a7e05347ULL, 0xb321d7d77bd7f6acULL,
+       0x999cc2c22fc25eedULL, 0x5c432e2eb82e6d96ULL, 0x96294b4b314b627aULL,
+       0xe15dfefedffea321ULL, 0xaed5575741578216ULL, 0x2abd15155415a841ULL,
+       0xeee87777c1779fb6ULL, 0x6e923737dc37a5ebULL, 0xd79ee5e5b3e57b56ULL,
+       0x23139f9f469f8cd9ULL, 0xfd23f0f0e7f0d317ULL, 0x94204a4a354a6a7fULL,
+       0xa944dada4fda9e95ULL, 0xb0a258587d58fa25ULL, 0x8fcfc9c903c906caULL,
+       0x527c2929a429558dULL, 0x145a0a0a280a5022ULL, 0x7f50b1b1feb1e14fULL,
+       0x5dc9a0a0baa0691aULL, 0xd6146b6bb16b7fdaULL, 0x17d985852e855cabULL,
+       0x673cbdbdcebd8173ULL, 0xba8f5d5d695dd234ULL, 0x2090101040108050ULL,
+       0xf507f4f4f7f4f303ULL, 0x8bddcbcb0bcb16c0ULL, 0x7cd33e3ef83eedc6ULL,
+       0x0a2d050514052811ULL, 0xce78676781671fe6ULL, 0xd597e4e4b7e47353ULL,
+       0x4e0227279c2725bbULL, 0x8273414119413258ULL, 0x0ba78b8b168b2c9dULL,
+       0x53f6a7a7a6a75101ULL, 0xfab27d7de97dcf94ULL, 0x374995956e95dcfbULL,
+       0xad56d8d847d88e9fULL, 0xeb70fbfbcbfb8b30ULL, 0xc1cdeeee9fee2371ULL,
+       0xf8bb7c7ced7cc791ULL, 0xcc716666856617e3ULL, 0xa77bdddd53dda68eULL,
+       0x2eaf17175c17b84bULL, 0x8e45474701470246ULL, 0x211a9e9e429e84dcULL,
+       0x89d4caca0fca1ec5ULL, 0x5a582d2db42d7599ULL, 0x632ebfbfc6bf9179ULL,
+       0x0e3f07071c07381bULL, 0x47acadad8ead0123ULL, 0xb4b05a5a755aea2fULL,
+       0x1bef838336836cb5ULL, 0x66b63333cc3385ffULL, 0xc65c636391633ff2ULL,
+       0x041202020802100aULL, 0x4993aaaa92aa3938ULL, 0xe2de7171d971afa8ULL,
+       0x8dc6c8c807c80ecfULL, 0x32d119196419c87dULL, 0x923b494939497270ULL,
+       0xaf5fd9d943d9869aULL, 0xf931f2f2eff2c31dULL, 0xdba8e3e3abe34b48ULL,
+       0xb6b95b5b715be22aULL, 0x0dbc88881a883492ULL, 0x293e9a9a529aa4c8ULL,
+       0x4c0b262698262dbeULL, 0x64bf3232c8328dfaULL, 0x7d59b0b0fab0e94aULL,
+       0xcff2e9e983e91b6aULL, 0x1e770f0f3c0f7833ULL, 0xb733d5d573d5e6a6ULL,
+       0x1df480803a8074baULL, 0x6127bebec2be997cULL, 0x87ebcdcd13cd26deULL,
+       0x68893434d034bde4ULL, 0x903248483d487a75ULL, 0xe354ffffdbffab24ULL,
+       0xf48d7a7af57af78fULL, 0x3d6490907a90f4eaULL, 0xbe9d5f5f615fc23eULL,
+       0x403d202080201da0ULL, 0xd00f6868bd6867d5ULL, 0x34ca1a1a681ad072ULL,
+       0x41b7aeae82ae192cULL, 0x757db4b4eab4c95eULL, 0xa8ce54544d549a19ULL,
+       0x3b7f93937693ece5ULL, 0x442f222288220daaULL, 0xc86364648d6407e9ULL,
+       0xff2af1f1e3f1db12ULL, 0xe6cc7373d173bfa2ULL, 0x248212124812905aULL,
+       0x807a40401d403a5dULL, 0x1048080820084028ULL, 0x9b95c3c32bc356e8ULL,
+       0xc5dfecec97ec337bULL, 0xab4ddbdb4bdb9690ULL, 0x5fc0a1a1bea1611fULL,
+       0x07918d8d0e8d1c83ULL, 0x7ac83d3df43df5c9ULL, 0x335b97976697ccf1ULL,
+       0x0000000000000000ULL, 0x83f9cfcf1bcf36d4ULL, 0x566e2b2bac2b4587ULL,
+       0xece17676c57697b3ULL, 0x19e68282328264b0ULL, 0xb128d6d67fd6fea9ULL,
+       0x36c31b1b6c1bd877ULL, 0x7774b5b5eeb5c15bULL, 0x43beafaf86af1129ULL,
+       0xd41d6a6ab56a77dfULL, 0xa0ea50505d50ba0dULL, 0x8a5745450945124cULL,
+       0xfb38f3f3ebf3cb18ULL, 0x60ad3030c0309df0ULL, 0xc3c4efef9bef2b74ULL,
+       0x7eda3f3ffc3fe5c3ULL, 0xaac755554955921cULL, 0x59dba2a2b2a27910ULL,
+       0xc9e9eaea8fea0365ULL, 0xca6a656589650fecULL, 0x6903babad2bab968ULL,
+       0x5e4a2f2fbc2f6593ULL, 0x9d8ec0c027c04ee7ULL, 0xa160dede5fdebe81ULL,
+       0x38fc1c1c701ce06cULL, 0xe746fdfdd3fdbb2eULL, 0x9a1f4d4d294d5264ULL,
+       0x397692927292e4e0ULL, 0xeafa7575c9758fbcULL, 0x0c3606061806301eULL,
+       0x09ae8a8a128a2498ULL, 0x794bb2b2f2b2f940ULL, 0xd185e6e6bfe66359ULL,
+       0x1c7e0e0e380e7036ULL, 0x3ee71f1f7c1ff863ULL, 0xc4556262956237f7ULL,
+       0xb53ad4d477d4eea3ULL, 0x4d81a8a89aa82932ULL, 0x315296966296c4f4ULL,
+       0xef62f9f9c3f99b3aULL, 0x97a3c5c533c566f6ULL, 0x4a102525942535b1ULL,
+       0xb2ab59597959f220ULL, 0x15d084842a8454aeULL, 0xe4c57272d572b7a7ULL,
+       0x72ec3939e439d5ddULL, 0x98164c4c2d4c5a61ULL, 0xbc945e5e655eca3bULL,
+       0xf09f7878fd78e785ULL, 0x70e53838e038ddd8ULL, 0x05988c8c0a8c1486ULL,
+       0xbf17d1d163d1c6b2ULL, 0x57e4a5a5aea5410bULL, 0xd9a1e2e2afe2434dULL,
+       0xc24e616199612ff8ULL, 0x7b42b3b3f6b3f145ULL, 0x42342121842115a5ULL,
+       0x25089c9c4a9c94d6ULL, 0x3cee1e1e781ef066ULL, 0x8661434311432252ULL,
+       0x93b1c7c73bc776fcULL, 0xe54ffcfcd7fcb32bULL, 0x0824040410042014ULL,
+       0xa2e351515951b208ULL, 0x2f2599995e99bcc7ULL, 0xda226d6da96d4fc4ULL,
+       0x1a650d0d340d6839ULL, 0xe979fafacffa8335ULL, 0xa369dfdf5bdfb684ULL,
+       0xfca97e7ee57ed79bULL, 0x4819242490243db4ULL, 0x76fe3b3bec3bc5d7ULL,
+       0x4b9aabab96ab313dULL, 0x81f0cece1fce3ed1ULL, 0x2299111144118855ULL,
+       0x03838f8f068f0c89ULL, 0x9c044e4e254e4a6bULL, 0x7366b7b7e6b7d151ULL,
+       0xcbe0ebeb8beb0b60ULL, 0x78c13c3cf03cfdccULL, 0x1ffd81813e817cbfULL,
+       0x354094946a94d4feULL, 0xf31cf7f7fbf7eb0cULL, 0x6f18b9b9deb9a167ULL,
+       0x268b13134c13985fULL, 0x58512c2cb02c7d9cULL, 0xbb05d3d36bd3d6b8ULL,
+       0xd38ce7e7bbe76b5cULL, 0xdc396e6ea56e57cbULL, 0x95aac4c437c46ef3ULL,
+       0x061b03030c03180fULL, 0xacdc565645568a13ULL, 0x885e44440d441a49ULL,
+       0xfea07f7fe17fdf9eULL, 0x4f88a9a99ea92137ULL, 0x54672a2aa82a4d82ULL,
+       0x6b0abbbbd6bbb16dULL, 0x9f87c1c123c146e2ULL, 0xa6f153535153a202ULL,
+       0xa572dcdc57dcae8bULL, 0x16530b0b2c0b5827ULL, 0x27019d9d4e9d9cd3ULL,
+       0xd82b6c6cad6c47c1ULL, 0x62a43131c43195f5ULL, 0xe8f37474cd7487b9ULL,
+       0xf115f6f6fff6e309ULL, 0x8c4c464605460a43ULL, 0x45a5acac8aac0926ULL,
+       0x0fb589891e893c97ULL, 0x28b414145014a044ULL, 0xdfbae1e1a3e15b42ULL,
+       0x2ca616165816b04eULL, 0x74f73a3ae83acdd2ULL, 0xd2066969b9696fd0ULL,
+       0x124109092409482dULL, 0xe0d77070dd70a7adULL, 0x716fb6b6e2b6d954ULL,
+       0xbd1ed0d067d0ceb7ULL, 0xc7d6eded93ed3b7eULL, 0x85e2cccc17cc2edbULL,
+       0x8468424215422a57ULL, 0x2d2c98985a98b4c2ULL, 0x55eda4a4aaa4490eULL,
+       0x50752828a0285d88ULL, 0xb8865c5c6d5cda31ULL, 0xed6bf8f8c7f8933fULL,
+       0x11c28686228644a4ULL,
+};
+
+static const u64 C3[256] = {
+       0x7830d818186018c0ULL, 0xaf462623238c2305ULL, 0xf991b8c6c63fc67eULL,
+       0x6fcdfbe8e887e813ULL, 0xa113cb878726874cULL, 0x626d11b8b8dab8a9ULL,
+       0x0502090101040108ULL, 0x6e9e0d4f4f214f42ULL, 0xee6c9b3636d836adULL,
+       0x0451ffa6a6a2a659ULL, 0xbdb90cd2d26fd2deULL, 0x06f70ef5f5f3f5fbULL,
+       0x80f2967979f979efULL, 0xcede306f6fa16f5fULL, 0xef3f6d91917e91fcULL,
+       0x07a4f852525552aaULL, 0xfdc04760609d6027ULL, 0x766535bcbccabc89ULL,
+       0xcd2b379b9b569bacULL, 0x8c018a8e8e028e04ULL, 0x155bd2a3a3b6a371ULL,
+       0x3c186c0c0c300c60ULL, 0x8af6847b7bf17bffULL, 0xe16a803535d435b5ULL,
+       0x693af51d1d741de8ULL, 0x47ddb3e0e0a7e053ULL, 0xacb321d7d77bd7f6ULL,
+       0xed999cc2c22fc25eULL, 0x965c432e2eb82e6dULL, 0x7a96294b4b314b62ULL,
+       0x21e15dfefedffea3ULL, 0x16aed55757415782ULL, 0x412abd15155415a8ULL,
+       0xb6eee87777c1779fULL, 0xeb6e923737dc37a5ULL, 0x56d79ee5e5b3e57bULL,
+       0xd923139f9f469f8cULL, 0x17fd23f0f0e7f0d3ULL, 0x7f94204a4a354a6aULL,
+       0x95a944dada4fda9eULL, 0x25b0a258587d58faULL, 0xca8fcfc9c903c906ULL,
+       0x8d527c2929a42955ULL, 0x22145a0a0a280a50ULL, 0x4f7f50b1b1feb1e1ULL,
+       0x1a5dc9a0a0baa069ULL, 0xdad6146b6bb16b7fULL, 0xab17d985852e855cULL,
+       0x73673cbdbdcebd81ULL, 0x34ba8f5d5d695dd2ULL, 0x5020901010401080ULL,
+       0x03f507f4f4f7f4f3ULL, 0xc08bddcbcb0bcb16ULL, 0xc67cd33e3ef83eedULL,
+       0x110a2d0505140528ULL, 0xe6ce78676781671fULL, 0x53d597e4e4b7e473ULL,
+       0xbb4e0227279c2725ULL, 0x5882734141194132ULL, 0x9d0ba78b8b168b2cULL,
+       0x0153f6a7a7a6a751ULL, 0x94fab27d7de97dcfULL, 0xfb374995956e95dcULL,
+       0x9fad56d8d847d88eULL, 0x30eb70fbfbcbfb8bULL, 0x71c1cdeeee9fee23ULL,
+       0x91f8bb7c7ced7cc7ULL, 0xe3cc716666856617ULL, 0x8ea77bdddd53dda6ULL,
+       0x4b2eaf17175c17b8ULL, 0x468e454747014702ULL, 0xdc211a9e9e429e84ULL,
+       0xc589d4caca0fca1eULL, 0x995a582d2db42d75ULL, 0x79632ebfbfc6bf91ULL,
+       0x1b0e3f07071c0738ULL, 0x2347acadad8ead01ULL, 0x2fb4b05a5a755aeaULL,
+       0xb51bef838336836cULL, 0xff66b63333cc3385ULL, 0xf2c65c636391633fULL,
+       0x0a04120202080210ULL, 0x384993aaaa92aa39ULL, 0xa8e2de7171d971afULL,
+       0xcf8dc6c8c807c80eULL, 0x7d32d119196419c8ULL, 0x70923b4949394972ULL,
+       0x9aaf5fd9d943d986ULL, 0x1df931f2f2eff2c3ULL, 0x48dba8e3e3abe34bULL,
+       0x2ab6b95b5b715be2ULL, 0x920dbc88881a8834ULL, 0xc8293e9a9a529aa4ULL,
+       0xbe4c0b262698262dULL, 0xfa64bf3232c8328dULL, 0x4a7d59b0b0fab0e9ULL,
+       0x6acff2e9e983e91bULL, 0x331e770f0f3c0f78ULL, 0xa6b733d5d573d5e6ULL,
+       0xba1df480803a8074ULL, 0x7c6127bebec2be99ULL, 0xde87ebcdcd13cd26ULL,
+       0xe468893434d034bdULL, 0x75903248483d487aULL, 0x24e354ffffdbffabULL,
+       0x8ff48d7a7af57af7ULL, 0xea3d6490907a90f4ULL, 0x3ebe9d5f5f615fc2ULL,
+       0xa0403d202080201dULL, 0xd5d00f6868bd6867ULL, 0x7234ca1a1a681ad0ULL,
+       0x2c41b7aeae82ae19ULL, 0x5e757db4b4eab4c9ULL, 0x19a8ce54544d549aULL,
+       0xe53b7f93937693ecULL, 0xaa442f222288220dULL, 0xe9c86364648d6407ULL,
+       0x12ff2af1f1e3f1dbULL, 0xa2e6cc7373d173bfULL, 0x5a24821212481290ULL,
+       0x5d807a40401d403aULL, 0x2810480808200840ULL, 0xe89b95c3c32bc356ULL,
+       0x7bc5dfecec97ec33ULL, 0x90ab4ddbdb4bdb96ULL, 0x1f5fc0a1a1bea161ULL,
+       0x8307918d8d0e8d1cULL, 0xc97ac83d3df43df5ULL, 0xf1335b97976697ccULL,
+       0x0000000000000000ULL, 0xd483f9cfcf1bcf36ULL, 0x87566e2b2bac2b45ULL,
+       0xb3ece17676c57697ULL, 0xb019e68282328264ULL, 0xa9b128d6d67fd6feULL,
+       0x7736c31b1b6c1bd8ULL, 0x5b7774b5b5eeb5c1ULL, 0x2943beafaf86af11ULL,
+       0xdfd41d6a6ab56a77ULL, 0x0da0ea50505d50baULL, 0x4c8a574545094512ULL,
+       0x18fb38f3f3ebf3cbULL, 0xf060ad3030c0309dULL, 0x74c3c4efef9bef2bULL,
+       0xc37eda3f3ffc3fe5ULL, 0x1caac75555495592ULL, 0x1059dba2a2b2a279ULL,
+       0x65c9e9eaea8fea03ULL, 0xecca6a656589650fULL, 0x686903babad2bab9ULL,
+       0x935e4a2f2fbc2f65ULL, 0xe79d8ec0c027c04eULL, 0x81a160dede5fdebeULL,
+       0x6c38fc1c1c701ce0ULL, 0x2ee746fdfdd3fdbbULL, 0x649a1f4d4d294d52ULL,
+       0xe0397692927292e4ULL, 0xbceafa7575c9758fULL, 0x1e0c360606180630ULL,
+       0x9809ae8a8a128a24ULL, 0x40794bb2b2f2b2f9ULL, 0x59d185e6e6bfe663ULL,
+       0x361c7e0e0e380e70ULL, 0x633ee71f1f7c1ff8ULL, 0xf7c4556262956237ULL,
+       0xa3b53ad4d477d4eeULL, 0x324d81a8a89aa829ULL, 0xf4315296966296c4ULL,
+       0x3aef62f9f9c3f99bULL, 0xf697a3c5c533c566ULL, 0xb14a102525942535ULL,
+       0x20b2ab59597959f2ULL, 0xae15d084842a8454ULL, 0xa7e4c57272d572b7ULL,
+       0xdd72ec3939e439d5ULL, 0x6198164c4c2d4c5aULL, 0x3bbc945e5e655ecaULL,
+       0x85f09f7878fd78e7ULL, 0xd870e53838e038ddULL, 0x8605988c8c0a8c14ULL,
+       0xb2bf17d1d163d1c6ULL, 0x0b57e4a5a5aea541ULL, 0x4dd9a1e2e2afe243ULL,
+       0xf8c24e616199612fULL, 0x457b42b3b3f6b3f1ULL, 0xa542342121842115ULL,
+       0xd625089c9c4a9c94ULL, 0x663cee1e1e781ef0ULL, 0x5286614343114322ULL,
+       0xfc93b1c7c73bc776ULL, 0x2be54ffcfcd7fcb3ULL, 0x1408240404100420ULL,
+       0x08a2e351515951b2ULL, 0xc72f2599995e99bcULL, 0xc4da226d6da96d4fULL,
+       0x391a650d0d340d68ULL, 0x35e979fafacffa83ULL, 0x84a369dfdf5bdfb6ULL,
+       0x9bfca97e7ee57ed7ULL, 0xb44819242490243dULL, 0xd776fe3b3bec3bc5ULL,
+       0x3d4b9aabab96ab31ULL, 0xd181f0cece1fce3eULL, 0x5522991111441188ULL,
+       0x8903838f8f068f0cULL, 0x6b9c044e4e254e4aULL, 0x517366b7b7e6b7d1ULL,
+       0x60cbe0ebeb8beb0bULL, 0xcc78c13c3cf03cfdULL, 0xbf1ffd81813e817cULL,
+       0xfe354094946a94d4ULL, 0x0cf31cf7f7fbf7ebULL, 0x676f18b9b9deb9a1ULL,
+       0x5f268b13134c1398ULL, 0x9c58512c2cb02c7dULL, 0xb8bb05d3d36bd3d6ULL,
+       0x5cd38ce7e7bbe76bULL, 0xcbdc396e6ea56e57ULL, 0xf395aac4c437c46eULL,
+       0x0f061b03030c0318ULL, 0x13acdc565645568aULL, 0x49885e44440d441aULL,
+       0x9efea07f7fe17fdfULL, 0x374f88a9a99ea921ULL, 0x8254672a2aa82a4dULL,
+       0x6d6b0abbbbd6bbb1ULL, 0xe29f87c1c123c146ULL, 0x02a6f153535153a2ULL,
+       0x8ba572dcdc57dcaeULL, 0x2716530b0b2c0b58ULL, 0xd327019d9d4e9d9cULL,
+       0xc1d82b6c6cad6c47ULL, 0xf562a43131c43195ULL, 0xb9e8f37474cd7487ULL,
+       0x09f115f6f6fff6e3ULL, 0x438c4c464605460aULL, 0x2645a5acac8aac09ULL,
+       0x970fb589891e893cULL, 0x4428b414145014a0ULL, 0x42dfbae1e1a3e15bULL,
+       0x4e2ca616165816b0ULL, 0xd274f73a3ae83acdULL, 0xd0d2066969b9696fULL,
+       0x2d12410909240948ULL, 0xade0d77070dd70a7ULL, 0x54716fb6b6e2b6d9ULL,
+       0xb7bd1ed0d067d0ceULL, 0x7ec7d6eded93ed3bULL, 0xdb85e2cccc17cc2eULL,
+       0x578468424215422aULL, 0xc22d2c98985a98b4ULL, 0x0e55eda4a4aaa449ULL,
+       0x8850752828a0285dULL, 0x31b8865c5c6d5cdaULL, 0x3fed6bf8f8c7f893ULL,
+       0xa411c28686228644ULL,
+};
+
+static const u64 C4[256] = {
+       0xc07830d818186018ULL, 0x05af462623238c23ULL, 0x7ef991b8c6c63fc6ULL,
+       0x136fcdfbe8e887e8ULL, 0x4ca113cb87872687ULL, 0xa9626d11b8b8dab8ULL,
+       0x0805020901010401ULL, 0x426e9e0d4f4f214fULL, 0xadee6c9b3636d836ULL,
+       0x590451ffa6a6a2a6ULL, 0xdebdb90cd2d26fd2ULL, 0xfb06f70ef5f5f3f5ULL,
+       0xef80f2967979f979ULL, 0x5fcede306f6fa16fULL, 0xfcef3f6d91917e91ULL,
+       0xaa07a4f852525552ULL, 0x27fdc04760609d60ULL, 0x89766535bcbccabcULL,
+       0xaccd2b379b9b569bULL, 0x048c018a8e8e028eULL, 0x71155bd2a3a3b6a3ULL,
+       0x603c186c0c0c300cULL, 0xff8af6847b7bf17bULL, 0xb5e16a803535d435ULL,
+       0xe8693af51d1d741dULL, 0x5347ddb3e0e0a7e0ULL, 0xf6acb321d7d77bd7ULL,
+       0x5eed999cc2c22fc2ULL, 0x6d965c432e2eb82eULL, 0x627a96294b4b314bULL,
+       0xa321e15dfefedffeULL, 0x8216aed557574157ULL, 0xa8412abd15155415ULL,
+       0x9fb6eee87777c177ULL, 0xa5eb6e923737dc37ULL, 0x7b56d79ee5e5b3e5ULL,
+       0x8cd923139f9f469fULL, 0xd317fd23f0f0e7f0ULL, 0x6a7f94204a4a354aULL,
+       0x9e95a944dada4fdaULL, 0xfa25b0a258587d58ULL, 0x06ca8fcfc9c903c9ULL,
+       0x558d527c2929a429ULL, 0x5022145a0a0a280aULL, 0xe14f7f50b1b1feb1ULL,
+       0x691a5dc9a0a0baa0ULL, 0x7fdad6146b6bb16bULL, 0x5cab17d985852e85ULL,
+       0x8173673cbdbdcebdULL, 0xd234ba8f5d5d695dULL, 0x8050209010104010ULL,
+       0xf303f507f4f4f7f4ULL, 0x16c08bddcbcb0bcbULL, 0xedc67cd33e3ef83eULL,
+       0x28110a2d05051405ULL, 0x1fe6ce7867678167ULL, 0x7353d597e4e4b7e4ULL,
+       0x25bb4e0227279c27ULL, 0x3258827341411941ULL, 0x2c9d0ba78b8b168bULL,
+       0x510153f6a7a7a6a7ULL, 0xcf94fab27d7de97dULL, 0xdcfb374995956e95ULL,
+       0x8e9fad56d8d847d8ULL, 0x8b30eb70fbfbcbfbULL, 0x2371c1cdeeee9feeULL,
+       0xc791f8bb7c7ced7cULL, 0x17e3cc7166668566ULL, 0xa68ea77bdddd53ddULL,
+       0xb84b2eaf17175c17ULL, 0x02468e4547470147ULL, 0x84dc211a9e9e429eULL,
+       0x1ec589d4caca0fcaULL, 0x75995a582d2db42dULL, 0x9179632ebfbfc6bfULL,
+       0x381b0e3f07071c07ULL, 0x012347acadad8eadULL, 0xea2fb4b05a5a755aULL,
+       0x6cb51bef83833683ULL, 0x85ff66b63333cc33ULL, 0x3ff2c65c63639163ULL,
+       0x100a041202020802ULL, 0x39384993aaaa92aaULL, 0xafa8e2de7171d971ULL,
+       0x0ecf8dc6c8c807c8ULL, 0xc87d32d119196419ULL, 0x7270923b49493949ULL,
+       0x869aaf5fd9d943d9ULL, 0xc31df931f2f2eff2ULL, 0x4b48dba8e3e3abe3ULL,
+       0xe22ab6b95b5b715bULL, 0x34920dbc88881a88ULL, 0xa4c8293e9a9a529aULL,
+       0x2dbe4c0b26269826ULL, 0x8dfa64bf3232c832ULL, 0xe94a7d59b0b0fab0ULL,
+       0x1b6acff2e9e983e9ULL, 0x78331e770f0f3c0fULL, 0xe6a6b733d5d573d5ULL,
+       0x74ba1df480803a80ULL, 0x997c6127bebec2beULL, 0x26de87ebcdcd13cdULL,
+       0xbde468893434d034ULL, 0x7a75903248483d48ULL, 0xab24e354ffffdbffULL,
+       0xf78ff48d7a7af57aULL, 0xf4ea3d6490907a90ULL, 0xc23ebe9d5f5f615fULL,
+       0x1da0403d20208020ULL, 0x67d5d00f6868bd68ULL, 0xd07234ca1a1a681aULL,
+       0x192c41b7aeae82aeULL, 0xc95e757db4b4eab4ULL, 0x9a19a8ce54544d54ULL,
+       0xece53b7f93937693ULL, 0x0daa442f22228822ULL, 0x07e9c86364648d64ULL,
+       0xdb12ff2af1f1e3f1ULL, 0xbfa2e6cc7373d173ULL, 0x905a248212124812ULL,
+       0x3a5d807a40401d40ULL, 0x4028104808082008ULL, 0x56e89b95c3c32bc3ULL,
+       0x337bc5dfecec97ecULL, 0x9690ab4ddbdb4bdbULL, 0x611f5fc0a1a1bea1ULL,
+       0x1c8307918d8d0e8dULL, 0xf5c97ac83d3df43dULL, 0xccf1335b97976697ULL,
+       0x0000000000000000ULL, 0x36d483f9cfcf1bcfULL, 0x4587566e2b2bac2bULL,
+       0x97b3ece17676c576ULL, 0x64b019e682823282ULL, 0xfea9b128d6d67fd6ULL,
+       0xd87736c31b1b6c1bULL, 0xc15b7774b5b5eeb5ULL, 0x112943beafaf86afULL,
+       0x77dfd41d6a6ab56aULL, 0xba0da0ea50505d50ULL, 0x124c8a5745450945ULL,
+       0xcb18fb38f3f3ebf3ULL, 0x9df060ad3030c030ULL, 0x2b74c3c4efef9befULL,
+       0xe5c37eda3f3ffc3fULL, 0x921caac755554955ULL, 0x791059dba2a2b2a2ULL,
+       0x0365c9e9eaea8feaULL, 0x0fecca6a65658965ULL, 0xb9686903babad2baULL,
+       0x65935e4a2f2fbc2fULL, 0x4ee79d8ec0c027c0ULL, 0xbe81a160dede5fdeULL,
+       0xe06c38fc1c1c701cULL, 0xbb2ee746fdfdd3fdULL, 0x52649a1f4d4d294dULL,
+       0xe4e0397692927292ULL, 0x8fbceafa7575c975ULL, 0x301e0c3606061806ULL,
+       0x249809ae8a8a128aULL, 0xf940794bb2b2f2b2ULL, 0x6359d185e6e6bfe6ULL,
+       0x70361c7e0e0e380eULL, 0xf8633ee71f1f7c1fULL, 0x37f7c45562629562ULL,
+       0xeea3b53ad4d477d4ULL, 0x29324d81a8a89aa8ULL, 0xc4f4315296966296ULL,
+       0x9b3aef62f9f9c3f9ULL, 0x66f697a3c5c533c5ULL, 0x35b14a1025259425ULL,
+       0xf220b2ab59597959ULL, 0x54ae15d084842a84ULL, 0xb7a7e4c57272d572ULL,
+       0xd5dd72ec3939e439ULL, 0x5a6198164c4c2d4cULL, 0xca3bbc945e5e655eULL,
+       0xe785f09f7878fd78ULL, 0xddd870e53838e038ULL, 0x148605988c8c0a8cULL,
+       0xc6b2bf17d1d163d1ULL, 0x410b57e4a5a5aea5ULL, 0x434dd9a1e2e2afe2ULL,
+       0x2ff8c24e61619961ULL, 0xf1457b42b3b3f6b3ULL, 0x15a5423421218421ULL,
+       0x94d625089c9c4a9cULL, 0xf0663cee1e1e781eULL, 0x2252866143431143ULL,
+       0x76fc93b1c7c73bc7ULL, 0xb32be54ffcfcd7fcULL, 0x2014082404041004ULL,
+       0xb208a2e351515951ULL, 0xbcc72f2599995e99ULL, 0x4fc4da226d6da96dULL,
+       0x68391a650d0d340dULL, 0x8335e979fafacffaULL, 0xb684a369dfdf5bdfULL,
+       0xd79bfca97e7ee57eULL, 0x3db4481924249024ULL, 0xc5d776fe3b3bec3bULL,
+       0x313d4b9aabab96abULL, 0x3ed181f0cece1fceULL, 0x8855229911114411ULL,
+       0x0c8903838f8f068fULL, 0x4a6b9c044e4e254eULL, 0xd1517366b7b7e6b7ULL,
+       0x0b60cbe0ebeb8bebULL, 0xfdcc78c13c3cf03cULL, 0x7cbf1ffd81813e81ULL,
+       0xd4fe354094946a94ULL, 0xeb0cf31cf7f7fbf7ULL, 0xa1676f18b9b9deb9ULL,
+       0x985f268b13134c13ULL, 0x7d9c58512c2cb02cULL, 0xd6b8bb05d3d36bd3ULL,
+       0x6b5cd38ce7e7bbe7ULL, 0x57cbdc396e6ea56eULL, 0x6ef395aac4c437c4ULL,
+       0x180f061b03030c03ULL, 0x8a13acdc56564556ULL, 0x1a49885e44440d44ULL,
+       0xdf9efea07f7fe17fULL, 0x21374f88a9a99ea9ULL, 0x4d8254672a2aa82aULL,
+       0xb16d6b0abbbbd6bbULL, 0x46e29f87c1c123c1ULL, 0xa202a6f153535153ULL,
+       0xae8ba572dcdc57dcULL, 0x582716530b0b2c0bULL, 0x9cd327019d9d4e9dULL,
+       0x47c1d82b6c6cad6cULL, 0x95f562a43131c431ULL, 0x87b9e8f37474cd74ULL,
+       0xe309f115f6f6fff6ULL, 0x0a438c4c46460546ULL, 0x092645a5acac8aacULL,
+       0x3c970fb589891e89ULL, 0xa04428b414145014ULL, 0x5b42dfbae1e1a3e1ULL,
+       0xb04e2ca616165816ULL, 0xcdd274f73a3ae83aULL, 0x6fd0d2066969b969ULL,
+       0x482d124109092409ULL, 0xa7ade0d77070dd70ULL, 0xd954716fb6b6e2b6ULL,
+       0xceb7bd1ed0d067d0ULL, 0x3b7ec7d6eded93edULL, 0x2edb85e2cccc17ccULL,
+       0x2a57846842421542ULL, 0xb4c22d2c98985a98ULL, 0x490e55eda4a4aaa4ULL,
+       0x5d8850752828a028ULL, 0xda31b8865c5c6d5cULL, 0x933fed6bf8f8c7f8ULL,
+       0x44a411c286862286ULL,
+};
+
+static const u64 C5[256] = {
+       0x18c07830d8181860ULL, 0x2305af462623238cULL, 0xc67ef991b8c6c63fULL,
+       0xe8136fcdfbe8e887ULL, 0x874ca113cb878726ULL, 0xb8a9626d11b8b8daULL,
+       0x0108050209010104ULL, 0x4f426e9e0d4f4f21ULL, 0x36adee6c9b3636d8ULL,
+       0xa6590451ffa6a6a2ULL, 0xd2debdb90cd2d26fULL, 0xf5fb06f70ef5f5f3ULL,
+       0x79ef80f2967979f9ULL, 0x6f5fcede306f6fa1ULL, 0x91fcef3f6d91917eULL,
+       0x52aa07a4f8525255ULL, 0x6027fdc04760609dULL, 0xbc89766535bcbccaULL,
+       0x9baccd2b379b9b56ULL, 0x8e048c018a8e8e02ULL, 0xa371155bd2a3a3b6ULL,
+       0x0c603c186c0c0c30ULL, 0x7bff8af6847b7bf1ULL, 0x35b5e16a803535d4ULL,
+       0x1de8693af51d1d74ULL, 0xe05347ddb3e0e0a7ULL, 0xd7f6acb321d7d77bULL,
+       0xc25eed999cc2c22fULL, 0x2e6d965c432e2eb8ULL, 0x4b627a96294b4b31ULL,
+       0xfea321e15dfefedfULL, 0x578216aed5575741ULL, 0x15a8412abd151554ULL,
+       0x779fb6eee87777c1ULL, 0x37a5eb6e923737dcULL, 0xe57b56d79ee5e5b3ULL,
+       0x9f8cd923139f9f46ULL, 0xf0d317fd23f0f0e7ULL, 0x4a6a7f94204a4a35ULL,
+       0xda9e95a944dada4fULL, 0x58fa25b0a258587dULL, 0xc906ca8fcfc9c903ULL,
+       0x29558d527c2929a4ULL, 0x0a5022145a0a0a28ULL, 0xb1e14f7f50b1b1feULL,
+       0xa0691a5dc9a0a0baULL, 0x6b7fdad6146b6bb1ULL, 0x855cab17d985852eULL,
+       0xbd8173673cbdbdceULL, 0x5dd234ba8f5d5d69ULL, 0x1080502090101040ULL,
+       0xf4f303f507f4f4f7ULL, 0xcb16c08bddcbcb0bULL, 0x3eedc67cd33e3ef8ULL,
+       0x0528110a2d050514ULL, 0x671fe6ce78676781ULL, 0xe47353d597e4e4b7ULL,
+       0x2725bb4e0227279cULL, 0x4132588273414119ULL, 0x8b2c9d0ba78b8b16ULL,
+       0xa7510153f6a7a7a6ULL, 0x7dcf94fab27d7de9ULL, 0x95dcfb374995956eULL,
+       0xd88e9fad56d8d847ULL, 0xfb8b30eb70fbfbcbULL, 0xee2371c1cdeeee9fULL,
+       0x7cc791f8bb7c7cedULL, 0x6617e3cc71666685ULL, 0xdda68ea77bdddd53ULL,
+       0x17b84b2eaf17175cULL, 0x4702468e45474701ULL, 0x9e84dc211a9e9e42ULL,
+       0xca1ec589d4caca0fULL, 0x2d75995a582d2db4ULL, 0xbf9179632ebfbfc6ULL,
+       0x07381b0e3f07071cULL, 0xad012347acadad8eULL, 0x5aea2fb4b05a5a75ULL,
+       0x836cb51bef838336ULL, 0x3385ff66b63333ccULL, 0x633ff2c65c636391ULL,
+       0x02100a0412020208ULL, 0xaa39384993aaaa92ULL, 0x71afa8e2de7171d9ULL,
+       0xc80ecf8dc6c8c807ULL, 0x19c87d32d1191964ULL, 0x497270923b494939ULL,
+       0xd9869aaf5fd9d943ULL, 0xf2c31df931f2f2efULL, 0xe34b48dba8e3e3abULL,
+       0x5be22ab6b95b5b71ULL, 0x8834920dbc88881aULL, 0x9aa4c8293e9a9a52ULL,
+       0x262dbe4c0b262698ULL, 0x328dfa64bf3232c8ULL, 0xb0e94a7d59b0b0faULL,
+       0xe91b6acff2e9e983ULL, 0x0f78331e770f0f3cULL, 0xd5e6a6b733d5d573ULL,
+       0x8074ba1df480803aULL, 0xbe997c6127bebec2ULL, 0xcd26de87ebcdcd13ULL,
+       0x34bde468893434d0ULL, 0x487a75903248483dULL, 0xffab24e354ffffdbULL,
+       0x7af78ff48d7a7af5ULL, 0x90f4ea3d6490907aULL, 0x5fc23ebe9d5f5f61ULL,
+       0x201da0403d202080ULL, 0x6867d5d00f6868bdULL, 0x1ad07234ca1a1a68ULL,
+       0xae192c41b7aeae82ULL, 0xb4c95e757db4b4eaULL, 0x549a19a8ce54544dULL,
+       0x93ece53b7f939376ULL, 0x220daa442f222288ULL, 0x6407e9c86364648dULL,
+       0xf1db12ff2af1f1e3ULL, 0x73bfa2e6cc7373d1ULL, 0x12905a2482121248ULL,
+       0x403a5d807a40401dULL, 0x0840281048080820ULL, 0xc356e89b95c3c32bULL,
+       0xec337bc5dfecec97ULL, 0xdb9690ab4ddbdb4bULL, 0xa1611f5fc0a1a1beULL,
+       0x8d1c8307918d8d0eULL, 0x3df5c97ac83d3df4ULL, 0x97ccf1335b979766ULL,
+       0x0000000000000000ULL, 0xcf36d483f9cfcf1bULL, 0x2b4587566e2b2bacULL,
+       0x7697b3ece17676c5ULL, 0x8264b019e6828232ULL, 0xd6fea9b128d6d67fULL,
+       0x1bd87736c31b1b6cULL, 0xb5c15b7774b5b5eeULL, 0xaf112943beafaf86ULL,
+       0x6a77dfd41d6a6ab5ULL, 0x50ba0da0ea50505dULL, 0x45124c8a57454509ULL,
+       0xf3cb18fb38f3f3ebULL, 0x309df060ad3030c0ULL, 0xef2b74c3c4efef9bULL,
+       0x3fe5c37eda3f3ffcULL, 0x55921caac7555549ULL, 0xa2791059dba2a2b2ULL,
+       0xea0365c9e9eaea8fULL, 0x650fecca6a656589ULL, 0xbab9686903babad2ULL,
+       0x2f65935e4a2f2fbcULL, 0xc04ee79d8ec0c027ULL, 0xdebe81a160dede5fULL,
+       0x1ce06c38fc1c1c70ULL, 0xfdbb2ee746fdfdd3ULL, 0x4d52649a1f4d4d29ULL,
+       0x92e4e03976929272ULL, 0x758fbceafa7575c9ULL, 0x06301e0c36060618ULL,
+       0x8a249809ae8a8a12ULL, 0xb2f940794bb2b2f2ULL, 0xe66359d185e6e6bfULL,
+       0x0e70361c7e0e0e38ULL, 0x1ff8633ee71f1f7cULL, 0x6237f7c455626295ULL,
+       0xd4eea3b53ad4d477ULL, 0xa829324d81a8a89aULL, 0x96c4f43152969662ULL,
+       0xf99b3aef62f9f9c3ULL, 0xc566f697a3c5c533ULL, 0x2535b14a10252594ULL,
+       0x59f220b2ab595979ULL, 0x8454ae15d084842aULL, 0x72b7a7e4c57272d5ULL,
+       0x39d5dd72ec3939e4ULL, 0x4c5a6198164c4c2dULL, 0x5eca3bbc945e5e65ULL,
+       0x78e785f09f7878fdULL, 0x38ddd870e53838e0ULL, 0x8c148605988c8c0aULL,
+       0xd1c6b2bf17d1d163ULL, 0xa5410b57e4a5a5aeULL, 0xe2434dd9a1e2e2afULL,
+       0x612ff8c24e616199ULL, 0xb3f1457b42b3b3f6ULL, 0x2115a54234212184ULL,
+       0x9c94d625089c9c4aULL, 0x1ef0663cee1e1e78ULL, 0x4322528661434311ULL,
+       0xc776fc93b1c7c73bULL, 0xfcb32be54ffcfcd7ULL, 0x0420140824040410ULL,
+       0x51b208a2e3515159ULL, 0x99bcc72f2599995eULL, 0x6d4fc4da226d6da9ULL,
+       0x0d68391a650d0d34ULL, 0xfa8335e979fafacfULL, 0xdfb684a369dfdf5bULL,
+       0x7ed79bfca97e7ee5ULL, 0x243db44819242490ULL, 0x3bc5d776fe3b3becULL,
+       0xab313d4b9aabab96ULL, 0xce3ed181f0cece1fULL, 0x1188552299111144ULL,
+       0x8f0c8903838f8f06ULL, 0x4e4a6b9c044e4e25ULL, 0xb7d1517366b7b7e6ULL,
+       0xeb0b60cbe0ebeb8bULL, 0x3cfdcc78c13c3cf0ULL, 0x817cbf1ffd81813eULL,
+       0x94d4fe354094946aULL, 0xf7eb0cf31cf7f7fbULL, 0xb9a1676f18b9b9deULL,
+       0x13985f268b13134cULL, 0x2c7d9c58512c2cb0ULL, 0xd3d6b8bb05d3d36bULL,
+       0xe76b5cd38ce7e7bbULL, 0x6e57cbdc396e6ea5ULL, 0xc46ef395aac4c437ULL,
+       0x03180f061b03030cULL, 0x568a13acdc565645ULL, 0x441a49885e44440dULL,
+       0x7fdf9efea07f7fe1ULL, 0xa921374f88a9a99eULL, 0x2a4d8254672a2aa8ULL,
+       0xbbb16d6b0abbbbd6ULL, 0xc146e29f87c1c123ULL, 0x53a202a6f1535351ULL,
+       0xdcae8ba572dcdc57ULL, 0x0b582716530b0b2cULL, 0x9d9cd327019d9d4eULL,
+       0x6c47c1d82b6c6cadULL, 0x3195f562a43131c4ULL, 0x7487b9e8f37474cdULL,
+       0xf6e309f115f6f6ffULL, 0x460a438c4c464605ULL, 0xac092645a5acac8aULL,
+       0x893c970fb589891eULL, 0x14a04428b4141450ULL, 0xe15b42dfbae1e1a3ULL,
+       0x16b04e2ca6161658ULL, 0x3acdd274f73a3ae8ULL, 0x696fd0d2066969b9ULL,
+       0x09482d1241090924ULL, 0x70a7ade0d77070ddULL, 0xb6d954716fb6b6e2ULL,
+       0xd0ceb7bd1ed0d067ULL, 0xed3b7ec7d6eded93ULL, 0xcc2edb85e2cccc17ULL,
+       0x422a578468424215ULL, 0x98b4c22d2c98985aULL, 0xa4490e55eda4a4aaULL,
+       0x285d8850752828a0ULL, 0x5cda31b8865c5c6dULL, 0xf8933fed6bf8f8c7ULL,
+       0x8644a411c2868622ULL,
+};
+
+static const u64 C6[256] = {
+       0x6018c07830d81818ULL, 0x8c2305af46262323ULL, 0x3fc67ef991b8c6c6ULL,
+       0x87e8136fcdfbe8e8ULL, 0x26874ca113cb8787ULL, 0xdab8a9626d11b8b8ULL,
+       0x0401080502090101ULL, 0x214f426e9e0d4f4fULL, 0xd836adee6c9b3636ULL,
+       0xa2a6590451ffa6a6ULL, 0x6fd2debdb90cd2d2ULL, 0xf3f5fb06f70ef5f5ULL,
+       0xf979ef80f2967979ULL, 0xa16f5fcede306f6fULL, 0x7e91fcef3f6d9191ULL,
+       0x5552aa07a4f85252ULL, 0x9d6027fdc0476060ULL, 0xcabc89766535bcbcULL,
+       0x569baccd2b379b9bULL, 0x028e048c018a8e8eULL, 0xb6a371155bd2a3a3ULL,
+       0x300c603c186c0c0cULL, 0xf17bff8af6847b7bULL, 0xd435b5e16a803535ULL,
+       0x741de8693af51d1dULL, 0xa7e05347ddb3e0e0ULL, 0x7bd7f6acb321d7d7ULL,
+       0x2fc25eed999cc2c2ULL, 0xb82e6d965c432e2eULL, 0x314b627a96294b4bULL,
+       0xdffea321e15dfefeULL, 0x41578216aed55757ULL, 0x5415a8412abd1515ULL,
+       0xc1779fb6eee87777ULL, 0xdc37a5eb6e923737ULL, 0xb3e57b56d79ee5e5ULL,
+       0x469f8cd923139f9fULL, 0xe7f0d317fd23f0f0ULL, 0x354a6a7f94204a4aULL,
+       0x4fda9e95a944dadaULL, 0x7d58fa25b0a25858ULL, 0x03c906ca8fcfc9c9ULL,
+       0xa429558d527c2929ULL, 0x280a5022145a0a0aULL, 0xfeb1e14f7f50b1b1ULL,
+       0xbaa0691a5dc9a0a0ULL, 0xb16b7fdad6146b6bULL, 0x2e855cab17d98585ULL,
+       0xcebd8173673cbdbdULL, 0x695dd234ba8f5d5dULL, 0x4010805020901010ULL,
+       0xf7f4f303f507f4f4ULL, 0x0bcb16c08bddcbcbULL, 0xf83eedc67cd33e3eULL,
+       0x140528110a2d0505ULL, 0x81671fe6ce786767ULL, 0xb7e47353d597e4e4ULL,
+       0x9c2725bb4e022727ULL, 0x1941325882734141ULL, 0x168b2c9d0ba78b8bULL,
+       0xa6a7510153f6a7a7ULL, 0xe97dcf94fab27d7dULL, 0x6e95dcfb37499595ULL,
+       0x47d88e9fad56d8d8ULL, 0xcbfb8b30eb70fbfbULL, 0x9fee2371c1cdeeeeULL,
+       0xed7cc791f8bb7c7cULL, 0x856617e3cc716666ULL, 0x53dda68ea77bddddULL,
+       0x5c17b84b2eaf1717ULL, 0x014702468e454747ULL, 0x429e84dc211a9e9eULL,
+       0x0fca1ec589d4cacaULL, 0xb42d75995a582d2dULL, 0xc6bf9179632ebfbfULL,
+       0x1c07381b0e3f0707ULL, 0x8ead012347acadadULL, 0x755aea2fb4b05a5aULL,
+       0x36836cb51bef8383ULL, 0xcc3385ff66b63333ULL, 0x91633ff2c65c6363ULL,
+       0x0802100a04120202ULL, 0x92aa39384993aaaaULL, 0xd971afa8e2de7171ULL,
+       0x07c80ecf8dc6c8c8ULL, 0x6419c87d32d11919ULL, 0x39497270923b4949ULL,
+       0x43d9869aaf5fd9d9ULL, 0xeff2c31df931f2f2ULL, 0xabe34b48dba8e3e3ULL,
+       0x715be22ab6b95b5bULL, 0x1a8834920dbc8888ULL, 0x529aa4c8293e9a9aULL,
+       0x98262dbe4c0b2626ULL, 0xc8328dfa64bf3232ULL, 0xfab0e94a7d59b0b0ULL,
+       0x83e91b6acff2e9e9ULL, 0x3c0f78331e770f0fULL, 0x73d5e6a6b733d5d5ULL,
+       0x3a8074ba1df48080ULL, 0xc2be997c6127bebeULL, 0x13cd26de87ebcdcdULL,
+       0xd034bde468893434ULL, 0x3d487a7590324848ULL, 0xdbffab24e354ffffULL,
+       0xf57af78ff48d7a7aULL, 0x7a90f4ea3d649090ULL, 0x615fc23ebe9d5f5fULL,
+       0x80201da0403d2020ULL, 0xbd6867d5d00f6868ULL, 0x681ad07234ca1a1aULL,
+       0x82ae192c41b7aeaeULL, 0xeab4c95e757db4b4ULL, 0x4d549a19a8ce5454ULL,
+       0x7693ece53b7f9393ULL, 0x88220daa442f2222ULL, 0x8d6407e9c8636464ULL,
+       0xe3f1db12ff2af1f1ULL, 0xd173bfa2e6cc7373ULL, 0x4812905a24821212ULL,
+       0x1d403a5d807a4040ULL, 0x2008402810480808ULL, 0x2bc356e89b95c3c3ULL,
+       0x97ec337bc5dfececULL, 0x4bdb9690ab4ddbdbULL, 0xbea1611f5fc0a1a1ULL,
+       0x0e8d1c8307918d8dULL, 0xf43df5c97ac83d3dULL, 0x6697ccf1335b9797ULL,
+       0x0000000000000000ULL, 0x1bcf36d483f9cfcfULL, 0xac2b4587566e2b2bULL,
+       0xc57697b3ece17676ULL, 0x328264b019e68282ULL, 0x7fd6fea9b128d6d6ULL,
+       0x6c1bd87736c31b1bULL, 0xeeb5c15b7774b5b5ULL, 0x86af112943beafafULL,
+       0xb56a77dfd41d6a6aULL, 0x5d50ba0da0ea5050ULL, 0x0945124c8a574545ULL,
+       0xebf3cb18fb38f3f3ULL, 0xc0309df060ad3030ULL, 0x9bef2b74c3c4efefULL,
+       0xfc3fe5c37eda3f3fULL, 0x4955921caac75555ULL, 0xb2a2791059dba2a2ULL,
+       0x8fea0365c9e9eaeaULL, 0x89650fecca6a6565ULL, 0xd2bab9686903babaULL,
+       0xbc2f65935e4a2f2fULL, 0x27c04ee79d8ec0c0ULL, 0x5fdebe81a160dedeULL,
+       0x701ce06c38fc1c1cULL, 0xd3fdbb2ee746fdfdULL, 0x294d52649a1f4d4dULL,
+       0x7292e4e039769292ULL, 0xc9758fbceafa7575ULL, 0x1806301e0c360606ULL,
+       0x128a249809ae8a8aULL, 0xf2b2f940794bb2b2ULL, 0xbfe66359d185e6e6ULL,
+       0x380e70361c7e0e0eULL, 0x7c1ff8633ee71f1fULL, 0x956237f7c4556262ULL,
+       0x77d4eea3b53ad4d4ULL, 0x9aa829324d81a8a8ULL, 0x6296c4f431529696ULL,
+       0xc3f99b3aef62f9f9ULL, 0x33c566f697a3c5c5ULL, 0x942535b14a102525ULL,
+       0x7959f220b2ab5959ULL, 0x2a8454ae15d08484ULL, 0xd572b7a7e4c57272ULL,
+       0xe439d5dd72ec3939ULL, 0x2d4c5a6198164c4cULL, 0x655eca3bbc945e5eULL,
+       0xfd78e785f09f7878ULL, 0xe038ddd870e53838ULL, 0x0a8c148605988c8cULL,
+       0x63d1c6b2bf17d1d1ULL, 0xaea5410b57e4a5a5ULL, 0xafe2434dd9a1e2e2ULL,
+       0x99612ff8c24e6161ULL, 0xf6b3f1457b42b3b3ULL, 0x842115a542342121ULL,
+       0x4a9c94d625089c9cULL, 0x781ef0663cee1e1eULL, 0x1143225286614343ULL,
+       0x3bc776fc93b1c7c7ULL, 0xd7fcb32be54ffcfcULL, 0x1004201408240404ULL,
+       0x5951b208a2e35151ULL, 0x5e99bcc72f259999ULL, 0xa96d4fc4da226d6dULL,
+       0x340d68391a650d0dULL, 0xcffa8335e979fafaULL, 0x5bdfb684a369dfdfULL,
+       0xe57ed79bfca97e7eULL, 0x90243db448192424ULL, 0xec3bc5d776fe3b3bULL,
+       0x96ab313d4b9aababULL, 0x1fce3ed181f0ceceULL, 0x4411885522991111ULL,
+       0x068f0c8903838f8fULL, 0x254e4a6b9c044e4eULL, 0xe6b7d1517366b7b7ULL,
+       0x8beb0b60cbe0ebebULL, 0xf03cfdcc78c13c3cULL, 0x3e817cbf1ffd8181ULL,
+       0x6a94d4fe35409494ULL, 0xfbf7eb0cf31cf7f7ULL, 0xdeb9a1676f18b9b9ULL,
+       0x4c13985f268b1313ULL, 0xb02c7d9c58512c2cULL, 0x6bd3d6b8bb05d3d3ULL,
+       0xbbe76b5cd38ce7e7ULL, 0xa56e57cbdc396e6eULL, 0x37c46ef395aac4c4ULL,
+       0x0c03180f061b0303ULL, 0x45568a13acdc5656ULL, 0x0d441a49885e4444ULL,
+       0xe17fdf9efea07f7fULL, 0x9ea921374f88a9a9ULL, 0xa82a4d8254672a2aULL,
+       0xd6bbb16d6b0abbbbULL, 0x23c146e29f87c1c1ULL, 0x5153a202a6f15353ULL,
+       0x57dcae8ba572dcdcULL, 0x2c0b582716530b0bULL, 0x4e9d9cd327019d9dULL,
+       0xad6c47c1d82b6c6cULL, 0xc43195f562a43131ULL, 0xcd7487b9e8f37474ULL,
+       0xfff6e309f115f6f6ULL, 0x05460a438c4c4646ULL, 0x8aac092645a5acacULL,
+       0x1e893c970fb58989ULL, 0x5014a04428b41414ULL, 0xa3e15b42dfbae1e1ULL,
+       0x5816b04e2ca61616ULL, 0xe83acdd274f73a3aULL, 0xb9696fd0d2066969ULL,
+       0x2409482d12410909ULL, 0xdd70a7ade0d77070ULL, 0xe2b6d954716fb6b6ULL,
+       0x67d0ceb7bd1ed0d0ULL, 0x93ed3b7ec7d6ededULL, 0x17cc2edb85e2ccccULL,
+       0x15422a5784684242ULL, 0x5a98b4c22d2c9898ULL, 0xaaa4490e55eda4a4ULL,
+       0xa0285d8850752828ULL, 0x6d5cda31b8865c5cULL, 0xc7f8933fed6bf8f8ULL,
+       0x228644a411c28686ULL,
+};
+
+static const u64 C7[256] = {
+       0x186018c07830d818ULL, 0x238c2305af462623ULL, 0xc63fc67ef991b8c6ULL,
+       0xe887e8136fcdfbe8ULL, 0x8726874ca113cb87ULL, 0xb8dab8a9626d11b8ULL,
+       0x0104010805020901ULL, 0x4f214f426e9e0d4fULL, 0x36d836adee6c9b36ULL,
+       0xa6a2a6590451ffa6ULL, 0xd26fd2debdb90cd2ULL, 0xf5f3f5fb06f70ef5ULL,
+       0x79f979ef80f29679ULL, 0x6fa16f5fcede306fULL, 0x917e91fcef3f6d91ULL,
+       0x525552aa07a4f852ULL, 0x609d6027fdc04760ULL, 0xbccabc89766535bcULL,
+       0x9b569baccd2b379bULL, 0x8e028e048c018a8eULL, 0xa3b6a371155bd2a3ULL,
+       0x0c300c603c186c0cULL, 0x7bf17bff8af6847bULL, 0x35d435b5e16a8035ULL,
+       0x1d741de8693af51dULL, 0xe0a7e05347ddb3e0ULL, 0xd77bd7f6acb321d7ULL,
+       0xc22fc25eed999cc2ULL, 0x2eb82e6d965c432eULL, 0x4b314b627a96294bULL,
+       0xfedffea321e15dfeULL, 0x5741578216aed557ULL, 0x155415a8412abd15ULL,
+       0x77c1779fb6eee877ULL, 0x37dc37a5eb6e9237ULL, 0xe5b3e57b56d79ee5ULL,
+       0x9f469f8cd923139fULL, 0xf0e7f0d317fd23f0ULL, 0x4a354a6a7f94204aULL,
+       0xda4fda9e95a944daULL, 0x587d58fa25b0a258ULL, 0xc903c906ca8fcfc9ULL,
+       0x29a429558d527c29ULL, 0x0a280a5022145a0aULL, 0xb1feb1e14f7f50b1ULL,
+       0xa0baa0691a5dc9a0ULL, 0x6bb16b7fdad6146bULL, 0x852e855cab17d985ULL,
+       0xbdcebd8173673cbdULL, 0x5d695dd234ba8f5dULL, 0x1040108050209010ULL,
+       0xf4f7f4f303f507f4ULL, 0xcb0bcb16c08bddcbULL, 0x3ef83eedc67cd33eULL,
+       0x05140528110a2d05ULL, 0x6781671fe6ce7867ULL, 0xe4b7e47353d597e4ULL,
+       0x279c2725bb4e0227ULL, 0x4119413258827341ULL, 0x8b168b2c9d0ba78bULL,
+       0xa7a6a7510153f6a7ULL, 0x7de97dcf94fab27dULL, 0x956e95dcfb374995ULL,
+       0xd847d88e9fad56d8ULL, 0xfbcbfb8b30eb70fbULL, 0xee9fee2371c1cdeeULL,
+       0x7ced7cc791f8bb7cULL, 0x66856617e3cc7166ULL, 0xdd53dda68ea77bddULL,
+       0x175c17b84b2eaf17ULL, 0x47014702468e4547ULL, 0x9e429e84dc211a9eULL,
+       0xca0fca1ec589d4caULL, 0x2db42d75995a582dULL, 0xbfc6bf9179632ebfULL,
+       0x071c07381b0e3f07ULL, 0xad8ead012347acadULL, 0x5a755aea2fb4b05aULL,
+       0x8336836cb51bef83ULL, 0x33cc3385ff66b633ULL, 0x6391633ff2c65c63ULL,
+       0x020802100a041202ULL, 0xaa92aa39384993aaULL, 0x71d971afa8e2de71ULL,
+       0xc807c80ecf8dc6c8ULL, 0x196419c87d32d119ULL, 0x4939497270923b49ULL,
+       0xd943d9869aaf5fd9ULL, 0xf2eff2c31df931f2ULL, 0xe3abe34b48dba8e3ULL,
+       0x5b715be22ab6b95bULL, 0x881a8834920dbc88ULL, 0x9a529aa4c8293e9aULL,
+       0x2698262dbe4c0b26ULL, 0x32c8328dfa64bf32ULL, 0xb0fab0e94a7d59b0ULL,
+       0xe983e91b6acff2e9ULL, 0x0f3c0f78331e770fULL, 0xd573d5e6a6b733d5ULL,
+       0x803a8074ba1df480ULL, 0xbec2be997c6127beULL, 0xcd13cd26de87ebcdULL,
+       0x34d034bde4688934ULL, 0x483d487a75903248ULL, 0xffdbffab24e354ffULL,
+       0x7af57af78ff48d7aULL, 0x907a90f4ea3d6490ULL, 0x5f615fc23ebe9d5fULL,
+       0x2080201da0403d20ULL, 0x68bd6867d5d00f68ULL, 0x1a681ad07234ca1aULL,
+       0xae82ae192c41b7aeULL, 0xb4eab4c95e757db4ULL, 0x544d549a19a8ce54ULL,
+       0x937693ece53b7f93ULL, 0x2288220daa442f22ULL, 0x648d6407e9c86364ULL,
+       0xf1e3f1db12ff2af1ULL, 0x73d173bfa2e6cc73ULL, 0x124812905a248212ULL,
+       0x401d403a5d807a40ULL, 0x0820084028104808ULL, 0xc32bc356e89b95c3ULL,
+       0xec97ec337bc5dfecULL, 0xdb4bdb9690ab4ddbULL, 0xa1bea1611f5fc0a1ULL,
+       0x8d0e8d1c8307918dULL, 0x3df43df5c97ac83dULL, 0x976697ccf1335b97ULL,
+       0x0000000000000000ULL, 0xcf1bcf36d483f9cfULL, 0x2bac2b4587566e2bULL,
+       0x76c57697b3ece176ULL, 0x82328264b019e682ULL, 0xd67fd6fea9b128d6ULL,
+       0x1b6c1bd87736c31bULL, 0xb5eeb5c15b7774b5ULL, 0xaf86af112943beafULL,
+       0x6ab56a77dfd41d6aULL, 0x505d50ba0da0ea50ULL, 0x450945124c8a5745ULL,
+       0xf3ebf3cb18fb38f3ULL, 0x30c0309df060ad30ULL, 0xef9bef2b74c3c4efULL,
+       0x3ffc3fe5c37eda3fULL, 0x554955921caac755ULL, 0xa2b2a2791059dba2ULL,
+       0xea8fea0365c9e9eaULL, 0x6589650fecca6a65ULL, 0xbad2bab9686903baULL,
+       0x2fbc2f65935e4a2fULL, 0xc027c04ee79d8ec0ULL, 0xde5fdebe81a160deULL,
+       0x1c701ce06c38fc1cULL, 0xfdd3fdbb2ee746fdULL, 0x4d294d52649a1f4dULL,
+       0x927292e4e0397692ULL, 0x75c9758fbceafa75ULL, 0x061806301e0c3606ULL,
+       0x8a128a249809ae8aULL, 0xb2f2b2f940794bb2ULL, 0xe6bfe66359d185e6ULL,
+       0x0e380e70361c7e0eULL, 0x1f7c1ff8633ee71fULL, 0x62956237f7c45562ULL,
+       0xd477d4eea3b53ad4ULL, 0xa89aa829324d81a8ULL, 0x966296c4f4315296ULL,
+       0xf9c3f99b3aef62f9ULL, 0xc533c566f697a3c5ULL, 0x25942535b14a1025ULL,
+       0x597959f220b2ab59ULL, 0x842a8454ae15d084ULL, 0x72d572b7a7e4c572ULL,
+       0x39e439d5dd72ec39ULL, 0x4c2d4c5a6198164cULL, 0x5e655eca3bbc945eULL,
+       0x78fd78e785f09f78ULL, 0x38e038ddd870e538ULL, 0x8c0a8c148605988cULL,
+       0xd163d1c6b2bf17d1ULL, 0xa5aea5410b57e4a5ULL, 0xe2afe2434dd9a1e2ULL,
+       0x6199612ff8c24e61ULL, 0xb3f6b3f1457b42b3ULL, 0x21842115a5423421ULL,
+       0x9c4a9c94d625089cULL, 0x1e781ef0663cee1eULL, 0x4311432252866143ULL,
+       0xc73bc776fc93b1c7ULL, 0xfcd7fcb32be54ffcULL, 0x0410042014082404ULL,
+       0x515951b208a2e351ULL, 0x995e99bcc72f2599ULL, 0x6da96d4fc4da226dULL,
+       0x0d340d68391a650dULL, 0xfacffa8335e979faULL, 0xdf5bdfb684a369dfULL,
+       0x7ee57ed79bfca97eULL, 0x2490243db4481924ULL, 0x3bec3bc5d776fe3bULL,
+       0xab96ab313d4b9aabULL, 0xce1fce3ed181f0ceULL, 0x1144118855229911ULL,
+       0x8f068f0c8903838fULL, 0x4e254e4a6b9c044eULL, 0xb7e6b7d1517366b7ULL,
+       0xeb8beb0b60cbe0ebULL, 0x3cf03cfdcc78c13cULL, 0x813e817cbf1ffd81ULL,
+       0x946a94d4fe354094ULL, 0xf7fbf7eb0cf31cf7ULL, 0xb9deb9a1676f18b9ULL,
+       0x134c13985f268b13ULL, 0x2cb02c7d9c58512cULL, 0xd36bd3d6b8bb05d3ULL,
+       0xe7bbe76b5cd38ce7ULL, 0x6ea56e57cbdc396eULL, 0xc437c46ef395aac4ULL,
+       0x030c03180f061b03ULL, 0x5645568a13acdc56ULL, 0x440d441a49885e44ULL,
+       0x7fe17fdf9efea07fULL, 0xa99ea921374f88a9ULL, 0x2aa82a4d8254672aULL,
+       0xbbd6bbb16d6b0abbULL, 0xc123c146e29f87c1ULL, 0x535153a202a6f153ULL,
+       0xdc57dcae8ba572dcULL, 0x0b2c0b582716530bULL, 0x9d4e9d9cd327019dULL,
+       0x6cad6c47c1d82b6cULL, 0x31c43195f562a431ULL, 0x74cd7487b9e8f374ULL,
+       0xf6fff6e309f115f6ULL, 0x4605460a438c4c46ULL, 0xac8aac092645a5acULL,
+       0x891e893c970fb589ULL, 0x145014a04428b414ULL, 0xe1a3e15b42dfbae1ULL,
+       0x165816b04e2ca616ULL, 0x3ae83acdd274f73aULL, 0x69b9696fd0d20669ULL,
+       0x092409482d124109ULL, 0x70dd70a7ade0d770ULL, 0xb6e2b6d954716fb6ULL,
+       0xd067d0ceb7bd1ed0ULL, 0xed93ed3b7ec7d6edULL, 0xcc17cc2edb85e2ccULL,
+       0x4215422a57846842ULL, 0x985a98b4c22d2c98ULL, 0xa4aaa4490e55eda4ULL,
+       0x28a0285d88507528ULL, 0x5c6d5cda31b8865cULL, 0xf8c7f8933fed6bf8ULL,
+       0x86228644a411c286ULL,
+};
+
+static const u64 rc[WHIRLPOOL_ROUNDS + 1] = {
+       0x0000000000000000ULL, 0x1823c6e887b8014fULL, 0x36a6d2f5796f9152ULL,
+       0x60bc9b8ea30c7b35ULL, 0x1de0d7c22e4bfe57ULL, 0x157737e59ff04adaULL,
+       0x58c9290ab1a06b85ULL, 0xbd5d10f4cb3e0567ULL, 0xe427418ba77d95d8ULL,
+       0xfbee7c66dd17479eULL, 0xca2dbf07ad5a8333ULL,
+};
+
+/**
+ * The core Whirlpool transform.
+ */
+
+static void wp512_process_buffer(struct wp512_ctx *wctx) {
+       int i, r;
+       u64 K[8];        /* the round key */
+       u64 block[8];    /* mu(buffer) */
+       u64 state[8];    /* the cipher state */
+       u64 L[8];
+       u8 *buffer = wctx->buffer;
+
+       for (i = 0; i < 8; i++, buffer += 8) {
+               block[i] =
+               (((u64)buffer[0]        ) << 56) ^
+               (((u64)buffer[1] & 0xffL) << 48) ^
+               (((u64)buffer[2] & 0xffL) << 40) ^
+               (((u64)buffer[3] & 0xffL) << 32) ^
+               (((u64)buffer[4] & 0xffL) << 24) ^
+               (((u64)buffer[5] & 0xffL) << 16) ^
+               (((u64)buffer[6] & 0xffL) <<  8) ^
+               (((u64)buffer[7] & 0xffL)      );
+       }
+
+       state[0] = block[0] ^ (K[0] = wctx->hash[0]);
+       state[1] = block[1] ^ (K[1] = wctx->hash[1]);
+       state[2] = block[2] ^ (K[2] = wctx->hash[2]);
+       state[3] = block[3] ^ (K[3] = wctx->hash[3]);
+       state[4] = block[4] ^ (K[4] = wctx->hash[4]);
+       state[5] = block[5] ^ (K[5] = wctx->hash[5]);
+       state[6] = block[6] ^ (K[6] = wctx->hash[6]);
+       state[7] = block[7] ^ (K[7] = wctx->hash[7]);
+
+       for (r = 1; r <= WHIRLPOOL_ROUNDS; r++) {
+
+               L[0] = C0[(int)(K[0] >> 56)       ] ^
+                          C1[(int)(K[7] >> 48) & 0xff] ^
+                          C2[(int)(K[6] >> 40) & 0xff] ^
+                          C3[(int)(K[5] >> 32) & 0xff] ^
+                          C4[(int)(K[4] >> 24) & 0xff] ^
+                          C5[(int)(K[3] >> 16) & 0xff] ^
+                          C6[(int)(K[2] >>  8) & 0xff] ^
+                          C7[(int)(K[1]      ) & 0xff] ^
+                          rc[r];
+
+               L[1] = C0[(int)(K[1] >> 56)       ] ^
+                          C1[(int)(K[0] >> 48) & 0xff] ^
+                          C2[(int)(K[7] >> 40) & 0xff] ^
+                          C3[(int)(K[6] >> 32) & 0xff] ^
+                          C4[(int)(K[5] >> 24) & 0xff] ^
+                          C5[(int)(K[4] >> 16) & 0xff] ^
+                          C6[(int)(K[3] >>  8) & 0xff] ^
+                          C7[(int)(K[2]      ) & 0xff];
+
+               L[2] = C0[(int)(K[2] >> 56)       ] ^
+                          C1[(int)(K[1] >> 48) & 0xff] ^
+                          C2[(int)(K[0] >> 40) & 0xff] ^
+                          C3[(int)(K[7] >> 32) & 0xff] ^
+                          C4[(int)(K[6] >> 24) & 0xff] ^
+                          C5[(int)(K[5] >> 16) & 0xff] ^
+                          C6[(int)(K[4] >>  8) & 0xff] ^
+                          C7[(int)(K[3]      ) & 0xff];
+
+               L[3] = C0[(int)(K[3] >> 56)       ] ^
+                          C1[(int)(K[2] >> 48) & 0xff] ^
+                          C2[(int)(K[1] >> 40) & 0xff] ^
+                          C3[(int)(K[0] >> 32) & 0xff] ^
+                          C4[(int)(K[7] >> 24) & 0xff] ^
+                          C5[(int)(K[6] >> 16) & 0xff] ^
+                          C6[(int)(K[5] >>  8) & 0xff] ^
+                          C7[(int)(K[4]      ) & 0xff];
+
+               L[4] = C0[(int)(K[4] >> 56)       ] ^
+                          C1[(int)(K[3] >> 48) & 0xff] ^
+                          C2[(int)(K[2] >> 40) & 0xff] ^
+                          C3[(int)(K[1] >> 32) & 0xff] ^
+                          C4[(int)(K[0] >> 24) & 0xff] ^
+                          C5[(int)(K[7] >> 16) & 0xff] ^
+                          C6[(int)(K[6] >>  8) & 0xff] ^
+                          C7[(int)(K[5]      ) & 0xff];
+
+               L[5] = C0[(int)(K[5] >> 56)       ] ^
+                          C1[(int)(K[4] >> 48) & 0xff] ^
+                          C2[(int)(K[3] >> 40) & 0xff] ^
+                          C3[(int)(K[2] >> 32) & 0xff] ^
+                          C4[(int)(K[1] >> 24) & 0xff] ^
+                          C5[(int)(K[0] >> 16) & 0xff] ^
+                          C6[(int)(K[7] >>  8) & 0xff] ^
+                          C7[(int)(K[6]      ) & 0xff];
+
+               L[6] = C0[(int)(K[6] >> 56)       ] ^
+                          C1[(int)(K[5] >> 48) & 0xff] ^
+                          C2[(int)(K[4] >> 40) & 0xff] ^
+                          C3[(int)(K[3] >> 32) & 0xff] ^
+                          C4[(int)(K[2] >> 24) & 0xff] ^
+                          C5[(int)(K[1] >> 16) & 0xff] ^
+                          C6[(int)(K[0] >>  8) & 0xff] ^
+                          C7[(int)(K[7]      ) & 0xff];
+
+               L[7] = C0[(int)(K[7] >> 56)       ] ^
+                          C1[(int)(K[6] >> 48) & 0xff] ^
+                          C2[(int)(K[5] >> 40) & 0xff] ^
+                          C3[(int)(K[4] >> 32) & 0xff] ^
+                          C4[(int)(K[3] >> 24) & 0xff] ^
+                          C5[(int)(K[2] >> 16) & 0xff] ^
+                          C6[(int)(K[1] >>  8) & 0xff] ^
+                          C7[(int)(K[0]      ) & 0xff];
+
+               K[0] = L[0];
+               K[1] = L[1];
+               K[2] = L[2];
+               K[3] = L[3];
+               K[4] = L[4];
+               K[5] = L[5];
+               K[6] = L[6];
+               K[7] = L[7];
+
+               L[0] = C0[(int)(state[0] >> 56)       ] ^
+                          C1[(int)(state[7] >> 48) & 0xff] ^
+                          C2[(int)(state[6] >> 40) & 0xff] ^
+                          C3[(int)(state[5] >> 32) & 0xff] ^
+                          C4[(int)(state[4] >> 24) & 0xff] ^
+                          C5[(int)(state[3] >> 16) & 0xff] ^
+                          C6[(int)(state[2] >>  8) & 0xff] ^
+                          C7[(int)(state[1]      ) & 0xff] ^
+                          K[0];
+
+               L[1] = C0[(int)(state[1] >> 56)       ] ^
+                          C1[(int)(state[0] >> 48) & 0xff] ^
+                          C2[(int)(state[7] >> 40) & 0xff] ^
+                          C3[(int)(state[6] >> 32) & 0xff] ^
+                          C4[(int)(state[5] >> 24) & 0xff] ^
+                          C5[(int)(state[4] >> 16) & 0xff] ^
+                          C6[(int)(state[3] >>  8) & 0xff] ^
+                          C7[(int)(state[2]      ) & 0xff] ^
+                          K[1];
+
+               L[2] = C0[(int)(state[2] >> 56)       ] ^
+                          C1[(int)(state[1] >> 48) & 0xff] ^
+                          C2[(int)(state[0] >> 40) & 0xff] ^
+                          C3[(int)(state[7] >> 32) & 0xff] ^
+                          C4[(int)(state[6] >> 24) & 0xff] ^
+                          C5[(int)(state[5] >> 16) & 0xff] ^
+                          C6[(int)(state[4] >>  8) & 0xff] ^
+                          C7[(int)(state[3]      ) & 0xff] ^
+                          K[2];
+
+               L[3] = C0[(int)(state[3] >> 56)       ] ^
+                          C1[(int)(state[2] >> 48) & 0xff] ^
+                          C2[(int)(state[1] >> 40) & 0xff] ^
+                          C3[(int)(state[0] >> 32) & 0xff] ^
+                          C4[(int)(state[7] >> 24) & 0xff] ^
+                          C5[(int)(state[6] >> 16) & 0xff] ^
+                          C6[(int)(state[5] >>  8) & 0xff] ^
+                          C7[(int)(state[4]      ) & 0xff] ^
+                          K[3];
+
+               L[4] = C0[(int)(state[4] >> 56)       ] ^
+                          C1[(int)(state[3] >> 48) & 0xff] ^
+                          C2[(int)(state[2] >> 40) & 0xff] ^
+                          C3[(int)(state[1] >> 32) & 0xff] ^
+                          C4[(int)(state[0] >> 24) & 0xff] ^
+                          C5[(int)(state[7] >> 16) & 0xff] ^
+                          C6[(int)(state[6] >>  8) & 0xff] ^
+                          C7[(int)(state[5]      ) & 0xff] ^
+                          K[4];
+
+               L[5] = C0[(int)(state[5] >> 56)       ] ^
+                          C1[(int)(state[4] >> 48) & 0xff] ^
+                          C2[(int)(state[3] >> 40) & 0xff] ^
+                          C3[(int)(state[2] >> 32) & 0xff] ^
+                          C4[(int)(state[1] >> 24) & 0xff] ^
+                          C5[(int)(state[0] >> 16) & 0xff] ^
+                          C6[(int)(state[7] >>  8) & 0xff] ^
+                          C7[(int)(state[6]      ) & 0xff] ^
+                          K[5];
+
+               L[6] = C0[(int)(state[6] >> 56)       ] ^
+                          C1[(int)(state[5] >> 48) & 0xff] ^
+                          C2[(int)(state[4] >> 40) & 0xff] ^
+                          C3[(int)(state[3] >> 32) & 0xff] ^
+                          C4[(int)(state[2] >> 24) & 0xff] ^
+                          C5[(int)(state[1] >> 16) & 0xff] ^
+                          C6[(int)(state[0] >>  8) & 0xff] ^
+                          C7[(int)(state[7]      ) & 0xff] ^
+                          K[6];
+
+               L[7] = C0[(int)(state[7] >> 56)       ] ^
+                          C1[(int)(state[6] >> 48) & 0xff] ^
+                          C2[(int)(state[5] >> 40) & 0xff] ^
+                          C3[(int)(state[4] >> 32) & 0xff] ^
+                          C4[(int)(state[3] >> 24) & 0xff] ^
+                          C5[(int)(state[2] >> 16) & 0xff] ^
+                          C6[(int)(state[1] >>  8) & 0xff] ^
+                          C7[(int)(state[0]      ) & 0xff] ^
+                          K[7];
+
+               state[0] = L[0];
+               state[1] = L[1];
+               state[2] = L[2];
+               state[3] = L[3];
+               state[4] = L[4];
+               state[5] = L[5];
+               state[6] = L[6];
+               state[7] = L[7];
+       }
+       /*
+       * apply the Miyaguchi-Preneel compression function:
+       */
+       wctx->hash[0] ^= state[0] ^ block[0];
+       wctx->hash[1] ^= state[1] ^ block[1];
+       wctx->hash[2] ^= state[2] ^ block[2];
+       wctx->hash[3] ^= state[3] ^ block[3];
+       wctx->hash[4] ^= state[4] ^ block[4];
+       wctx->hash[5] ^= state[5] ^ block[5];
+       wctx->hash[6] ^= state[6] ^ block[6];
+       wctx->hash[7] ^= state[7] ^ block[7];
+
+}
+
+static void wp512_init (void *ctx) {
+       int i;
+       struct wp512_ctx *wctx = ctx;
+
+       memset(wctx->bitLength, 0, 32);
+       wctx->bufferBits = wctx->bufferPos = 0;
+       wctx->buffer[0] = 0;
+       for (i = 0; i < 8; i++) {
+               wctx->hash[i] = 0L;
+       }
+}
+
+static void wp512_update(void *ctx, const u8 *source, unsigned int len)
+{
+
+       struct wp512_ctx *wctx = ctx;
+       int sourcePos    = 0;
+       unsigned int bits_len = len * 8; // convert to number of bits
+       int sourceGap    = (8 - ((int)bits_len & 7)) & 7;
+       int bufferRem    = wctx->bufferBits & 7;
+       int i;
+       u32 b, carry;
+       u8 *buffer       = wctx->buffer;
+       u8 *bitLength    = wctx->bitLength;
+       int bufferBits   = wctx->bufferBits;
+       int bufferPos    = wctx->bufferPos;
+
+       u64 value = bits_len;
+       for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) {
+               carry += bitLength[i] + ((u32)value & 0xff);
+               bitLength[i] = (u8)carry;
+               carry >>= 8;
+               value >>= 8;
+       }
+       while (bits_len > 8) {
+               b = ((source[sourcePos] << sourceGap) & 0xff) |
+               ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
+               buffer[bufferPos++] |= (u8)(b >> bufferRem);
+               bufferBits += 8 - bufferRem;
+               if (bufferBits == WP512_BLOCK_SIZE * 8) {
+                       wp512_process_buffer(wctx);
+                       bufferBits = bufferPos = 0;
+               }
+               buffer[bufferPos] = b << (8 - bufferRem);
+               bufferBits += bufferRem;
+               bits_len -= 8;
+               sourcePos++;
+       }
+       if (bits_len > 0) {
+               b = (source[sourcePos] << sourceGap) & 0xff;
+               buffer[bufferPos] |= b >> bufferRem;
+       } else {
+               b = 0;
+       }
+       if (bufferRem + bits_len < 8) {
+               bufferBits += bits_len;
+       } else {
+               bufferPos++;
+               bufferBits += 8 - bufferRem;
+               bits_len -= 8 - bufferRem;
+               if (bufferBits == WP512_BLOCK_SIZE * 8) {
+                       wp512_process_buffer(wctx);
+                       bufferBits = bufferPos = 0;
+               }
+               buffer[bufferPos] = b << (8 - bufferRem);
+               bufferBits += (int)bits_len;
+       }
+
+       wctx->bufferBits   = bufferBits;
+       wctx->bufferPos    = bufferPos;
+
+}
+
+static void wp512_final(void *ctx, u8 *out)
+{
+       struct wp512_ctx *wctx = ctx;
+       int i;
+       u8 *buffer      = wctx->buffer;
+       u8 *bitLength   = wctx->bitLength;
+       int bufferBits  = wctx->bufferBits;
+       int bufferPos   = wctx->bufferPos;
+       u8 *digest      = out;
+
+       buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
+       bufferPos++;
+       if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
+               if (bufferPos < WP512_BLOCK_SIZE) {
+               memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos);
+               }
+               wp512_process_buffer(wctx);
+               bufferPos = 0;
+       }
+       if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
+               memset(&buffer[bufferPos], 0,
+                         (WP512_BLOCK_SIZE - WP512_LENGTHBYTES) - bufferPos);
+       }
+       bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES;
+       memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES],
+                  bitLength, WP512_LENGTHBYTES);
+       wp512_process_buffer(wctx);
+       for (i = 0; i < WP512_DIGEST_SIZE/8; i++) {
+               digest[0] = (u8)(wctx->hash[i] >> 56);
+               digest[1] = (u8)(wctx->hash[i] >> 48);
+               digest[2] = (u8)(wctx->hash[i] >> 40);
+               digest[3] = (u8)(wctx->hash[i] >> 32);
+               digest[4] = (u8)(wctx->hash[i] >> 24);
+               digest[5] = (u8)(wctx->hash[i] >> 16);
+               digest[6] = (u8)(wctx->hash[i] >>  8);
+               digest[7] = (u8)(wctx->hash[i]      );
+               digest += 8;
+       }
+       wctx->bufferBits   = bufferBits;
+       wctx->bufferPos    = bufferPos;
+}
+
+static void wp384_final(void *ctx, u8 *out)
+{
+       struct wp512_ctx *wctx = ctx;
+       u8 D[64];
+
+       wp512_final (wctx, D);
+       memcpy (out, D, WP384_DIGEST_SIZE);
+       memset (D, 0, WP512_DIGEST_SIZE);
+}
+
+static void wp256_final(void *ctx, u8 *out)
+{
+       struct wp512_ctx *wctx = ctx;
+       u8 D[64];
+
+       wp512_final (wctx, D);
+       memcpy (out, D, WP256_DIGEST_SIZE);
+       memset (D, 0, WP512_DIGEST_SIZE);
+}
+
+static struct crypto_alg wp512 = {
+       .cra_name       =       "wp512",
+       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize  =       WP512_BLOCK_SIZE,
+       .cra_ctxsize    =       sizeof(struct wp512_ctx),
+       .cra_module     =       THIS_MODULE,
+       .cra_list       =       LIST_HEAD_INIT(wp512.cra_list), 
+       .cra_u          =       { .digest = {
+       .dia_digestsize =       WP512_DIGEST_SIZE,
+       .dia_init       =       wp512_init,
+       .dia_update     =       wp512_update,
+       .dia_final      =       wp512_final } }
+};
+
+static struct crypto_alg wp384 = {
+       .cra_name       =       "wp384",
+       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize  =       WP512_BLOCK_SIZE,
+       .cra_ctxsize    =       sizeof(struct wp512_ctx),
+       .cra_module     =       THIS_MODULE,
+       .cra_list       =       LIST_HEAD_INIT(wp384.cra_list), 
+       .cra_u          =       { .digest = {
+       .dia_digestsize =       WP384_DIGEST_SIZE,
+       .dia_init       =       wp512_init,
+       .dia_update     =       wp512_update,
+       .dia_final      =       wp384_final } }
+};
+
+static struct crypto_alg wp256 = {
+       .cra_name       =       "wp256",
+       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize  =       WP512_BLOCK_SIZE,
+       .cra_ctxsize    =       sizeof(struct wp512_ctx),
+       .cra_module     =       THIS_MODULE,
+       .cra_list       =       LIST_HEAD_INIT(wp256.cra_list), 
+       .cra_u          =       { .digest = {
+       .dia_digestsize =       WP256_DIGEST_SIZE,
+       .dia_init       =       wp512_init,
+       .dia_update     =       wp512_update,
+       .dia_final      =       wp256_final } }
+};
+
+static int __init init(void)
+{
+       int ret = 0;
+
+       ret = crypto_register_alg(&wp512);
+
+       if (ret < 0)
+               goto out;
+
+       ret = crypto_register_alg(&wp384);
+       if (ret < 0)
+       {
+               crypto_unregister_alg(&wp512);
+               goto out;
+       }
+
+       ret = crypto_register_alg(&wp256);
+       if (ret < 0)
+       {
+               crypto_unregister_alg(&wp512);
+               crypto_unregister_alg(&wp384);
+       }
+out:
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&wp512);
+       crypto_unregister_alg(&wp384);
+       crypto_unregister_alg(&wp256);
+}
+
+MODULE_ALIAS("wp384");
+MODULE_ALIAS("wp256");
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm");
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
new file mode 100644 (file)
index 0000000..b435b3e
--- /dev/null
@@ -0,0 +1,1242 @@
+/*
+ *  ibm_acpi.c - IBM ThinkPad ACPI Extras
+ *
+ *
+ *  Copyright (C) 2004 Borislav Deianov
+ *
+ *  This 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
+ *
+ *  Changelog:
+ *
+ *  2004-08-09 0.1     initial release, support for X series
+ *  2004-08-14 0.2     support for T series, X20
+ *                     bluetooth enable/disable
+ *                     hotkey events disabled by default
+ *                     removed fan control, currently useless
+ *  2004-08-17 0.3     support for R40
+ *                     lcd off, brightness control
+ *                     thinklight on/off
+ *  2004-09-16 0.4     support for module parameters
+ *                     hotkey mask can be prefixed by 0x
+ *                     video output switching
+ *                     video expansion control
+ *                     ultrabay eject support
+ *                     removed lcd brightness/on/off control, didn't work
+ *  2004-10-18 0.5     thinklight support on A21e, G40, R32, T20, T21, X20
+ *                     proc file format changed
+ *                     video_switch command
+ *                     experimental cmos control
+ *                     experimental led control
+ *                     experimental acpi sounds
+ *  2004-10-19 0.6     use acpi_bus_register_driver() to claim HKEY device
+ *  2004-10-23 0.7     fix module loading on A21e, A22p, T20, T21, X20
+ *                     fix LED control on A21e
+ *  2004-11-08 0.8     fix init error case, don't return from a macro
+ *                             thanks to Chris Wright <chrisw@osdl.org>
+ */
+
+#define IBM_VERSION "0.8"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+#define IBM_NAME "ibm"
+#define IBM_DESC "IBM ThinkPad ACPI Extras"
+#define IBM_FILE "ibm_acpi"
+#define IBM_URL "http://ibm-acpi.sf.net/"
+
+#define IBM_DIR IBM_NAME
+
+#define IBM_LOG IBM_FILE ": "
+#define IBM_ERR           KERN_ERR    IBM_LOG
+#define IBM_NOTICE KERN_NOTICE IBM_LOG
+#define IBM_INFO   KERN_INFO   IBM_LOG
+#define IBM_DEBUG  KERN_DEBUG  IBM_LOG
+
+#define IBM_MAX_ACPI_ARGS 3
+
+#define __unused __attribute__ ((unused))
+
+static int experimental;
+module_param(experimental, int, 0);
+
+static acpi_handle root_handle = NULL;
+
+#define IBM_HANDLE(object, parent, paths...)                   \
+       static acpi_handle  object##_handle;                    \
+       static acpi_handle *object##_parent = &parent##_handle; \
+       static char        *object##_paths[] = { paths }
+
+IBM_HANDLE(ec, root,
+          "\\_SB.PCI0.ISA.EC",    /* A21e, A22p, T20, T21, X20 */
+          "\\_SB.PCI0.LPC.EC",    /* all others */
+);
+
+IBM_HANDLE(vid, root, 
+          "\\_SB.PCI0.VID",       /* A21e, G40, X30, X40 */
+          "\\_SB.PCI0.AGP.VID",   /* all others */
+);
+
+IBM_HANDLE(cmos, root,
+          "\\UCMS",               /* R50, R50p, R51, T4x, X31, X40 */
+          "\\CMOS",               /* A3x, G40, R32, T23, T30, X22, X24, X30 */
+          "\\CMS",                /* R40, R40e */
+);                                 /* A21e, A22p, T20, T21, X20 */
+
+IBM_HANDLE(dock, root,
+          "\\_SB.GDCK",           /* X30, X31, X40 */
+          "\\_SB.PCI0.DOCK",      /* A22p, T20, T21, X20 */
+          "\\_SB.PCI0.PCI1.DOCK", /* all others */
+);                                 /* A21e, G40, R32, R40, R40e */
+
+IBM_HANDLE(bay, root,
+          "\\_SB.PCI0.IDE0.SCND.MSTR");      /* all except A21e */
+IBM_HANDLE(bayej, root,
+          "\\_SB.PCI0.IDE0.SCND.MSTR._EJ0"); /* all except A2x, A3x */
+
+IBM_HANDLE(lght, root, "\\LGHT");  /* A21e, A22p, T20, T21, X20 */
+IBM_HANDLE(hkey, ec,   "HKEY");    /* all */
+IBM_HANDLE(led,  ec,   "LED");     /* all except A21e, A22p, T20, T21, X20 */
+IBM_HANDLE(sysl, ec,   "SYSL");    /* A21e, A22p, T20, T21, X20 */
+IBM_HANDLE(bled, ec,   "BLED");    /* A22p, T20, T21, X20 */
+IBM_HANDLE(beep, ec,   "BEEP");    /* all models */
+
+struct ibm_struct {
+       char *name;
+
+       char *hid;
+       struct acpi_driver *driver;
+       
+       int  (*init)   (struct ibm_struct *);
+       int  (*read)   (struct ibm_struct *, char *);
+       int  (*write)  (struct ibm_struct *, char *);
+       void (*exit)   (struct ibm_struct *);
+
+       void (*notify) (struct ibm_struct *, u32);      
+       acpi_handle *handle;
+       int type;
+       struct acpi_device *device;
+
+       int driver_registered;
+       int proc_created;
+       int init_called;
+       int notify_installed;
+
+       int supported;
+       union {
+               struct {
+                       int status;
+                       int mask;
+               } hotkey;
+               struct {
+                       int autoswitch;
+               } video;
+       } state;
+
+       int experimental;
+};
+
+struct proc_dir_entry *proc_dir = NULL;
+
+#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
+
+static int acpi_evalf(acpi_handle handle,
+                     void *res, char *method, char *fmt, ...)
+{
+       char *fmt0 = fmt;
+        struct acpi_object_list        params;
+        union acpi_object      in_objs[IBM_MAX_ACPI_ARGS];
+        struct acpi_buffer     result;
+        union acpi_object      out_obj;
+        acpi_status            status;
+       va_list                 ap;
+       char                    res_type;
+       int                     success;
+       int                     quiet;
+
+       if (!*fmt) {
+               printk(IBM_ERR "acpi_evalf() called with empty format\n");
+               return 0;
+       }
+
+       if (*fmt == 'q') {
+               quiet = 1;
+               fmt++;
+       } else
+               quiet = 0;
+
+       res_type = *(fmt++);
+
+       params.count = 0;
+       params.pointer = &in_objs[0];
+
+       va_start(ap, fmt);
+       while (*fmt) {
+               char c = *(fmt++);
+               switch (c) {
+               case 'd':       /* int */
+                       in_objs[params.count].integer.value = va_arg(ap, int);
+                       in_objs[params.count++].type = ACPI_TYPE_INTEGER;
+                       break;
+               /* add more types as needed */
+               default:
+                       printk(IBM_ERR "acpi_evalf() called "
+                              "with invalid format character '%c'\n", c);
+                       return 0;
+               }
+       }
+       va_end(ap);
+
+       result.length = sizeof(out_obj);
+       result.pointer = &out_obj;
+
+       status = acpi_evaluate_object(handle, method, &params, &result);
+
+       switch (res_type) {
+       case 'd':       /* int */
+               if (res)
+                       *(int *)res = out_obj.integer.value;
+               success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+               break;
+       case 'v':       /* void */
+               success = status == AE_OK;
+               break;
+       /* add more types as needed */
+       default:
+               printk(IBM_ERR "acpi_evalf() called "
+                      "with invalid format character '%c'\n", res_type);
+               return 0;
+       }
+
+       if (!success && !quiet)
+               printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+                      method, fmt0, status);
+
+       return success;
+}
+
+static void __unused acpi_print_int(acpi_handle handle, char *method)
+{
+       int i;
+
+       if (acpi_evalf(handle, &i, method, "d"))
+               printk(IBM_INFO "%s = 0x%x\n", method, i);
+       else
+               printk(IBM_ERR "error calling %s\n", method);
+}
+
+static char *next_cmd(char **cmds)
+{
+       char *start = *cmds;
+       char *end;
+
+       while ((end = strchr(start, ',')) && end == start)
+               start = end + 1;
+
+       if (!end)
+               return NULL;
+
+       *end = 0;
+       *cmds = end + 1;
+       return start;
+}
+
+static int driver_init(struct ibm_struct *ibm)
+{
+       printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
+       printk(IBM_INFO "%s\n", IBM_URL);
+
+       return 0;
+}
+
+static int driver_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+
+       len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
+       len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+
+       return len;
+}
+
+static int hotkey_get(struct ibm_struct *ibm, int *status, int *mask)
+{
+       if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+               return -EIO;
+       if (ibm->supported) {
+               if (!acpi_evalf(hkey_handle, mask, "DHKN", "qd"))
+                       return -EIO;
+       } else {
+               *mask = ibm->state.hotkey.mask;
+       }
+       return 0;
+}
+
+static int hotkey_set(struct ibm_struct *ibm, int status, int mask)
+{
+       int i;
+
+       if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+               return -EIO;
+
+       if (!ibm->supported)
+               return 0;
+
+       for (i=0; i<32; i++) {
+               int bit = ((1 << i) & mask) != 0;
+               if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i+1, bit))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int hotkey_init(struct ibm_struct *ibm)
+{
+       int ret;
+
+       ibm->supported = 1;
+       ret = hotkey_get(ibm,
+                        &ibm->state.hotkey.status,
+                        &ibm->state.hotkey.mask);
+       if (ret < 0) {
+               /* mask not supported on A21e, A22p, T20, T21, X20, X22, X24 */
+               ibm->supported = 0;
+               ret = hotkey_get(ibm,
+                                &ibm->state.hotkey.status,
+                                &ibm->state.hotkey.mask);
+       }
+
+       return ret;
+}      
+
+static int hotkey_read(struct ibm_struct *ibm, char *p)
+{
+       int status, mask;
+       int len = 0;
+
+       if (hotkey_get(ibm, &status, &mask) < 0)
+               return -EIO;
+
+       len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+       if (ibm->supported) {
+               len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+               len += sprintf(p + len,
+                              "commands:\tenable, disable, reset, <mask>\n");
+       } else {
+               len += sprintf(p + len, "mask:\t\tnot supported\n");
+               len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+       }
+
+       return len;
+}
+
+static int hotkey_write(struct ibm_struct *ibm, char *buf)
+{
+       int status, mask;
+       char *cmd;
+       int do_cmd = 0;
+
+       if (hotkey_get(ibm, &status, &mask) < 0)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "enable") == 0) {
+                       status = 1;
+               } else if (strlencmp(cmd, "disable") == 0) {
+                       status = 0;
+               } else if (strlencmp(cmd, "reset") == 0) {
+                       status = ibm->state.hotkey.status;
+                       mask   = ibm->state.hotkey.mask;
+               } else if (sscanf(cmd, "0x%x", &mask) == 1) {
+                       /* mask set */
+               } else if (sscanf(cmd, "%x", &mask) == 1) {
+                       /* mask set */
+               } else
+                       return -EINVAL;
+               do_cmd = 1;
+       }
+
+       if (do_cmd && hotkey_set(ibm, status, mask) < 0)
+               return -EIO;
+
+       return 0;
+}      
+
+static void hotkey_exit(struct ibm_struct *ibm)
+{
+       hotkey_set(ibm, ibm->state.hotkey.status, ibm->state.hotkey.mask);
+}
+
+static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+{
+       int hkey;
+
+       if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
+               acpi_bus_generate_event(ibm->device, event, hkey);
+       else {
+               printk(IBM_ERR "unknown hotkey event %d\n", event);
+               acpi_bus_generate_event(ibm->device, event, 0);
+       }       
+}
+
+static int bluetooth_init(struct ibm_struct *ibm)
+{
+       /* bluetooth not supported on A21e, G40, T20, T21, X20 */
+       ibm->supported = acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
+
+       return 0;
+}
+
+static int bluetooth_status(struct ibm_struct *ibm)
+{
+       int status;
+
+       if (!ibm->supported || !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+               status = 0;
+
+       return status;
+}
+
+static int bluetooth_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+       int status = bluetooth_status(ibm);
+
+       if (!ibm->supported)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else if (!(status & 1))
+               len += sprintf(p + len, "status:\t\tnot installed\n");
+       else {
+               len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
+               len += sprintf(p + len, "commands:\tenable, disable\n");
+       }
+
+       return len;
+}
+
+static int bluetooth_write(struct ibm_struct *ibm, char *buf)
+{
+       int status = bluetooth_status(ibm);
+       char *cmd;
+       int do_cmd = 0;
+
+       if (!ibm->supported)
+               return -EINVAL;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "enable") == 0) {
+                       status |= 2;
+               } else if (strlencmp(cmd, "disable") == 0) {
+                       status &= ~2;
+               } else
+                       return -EINVAL;
+               do_cmd = 1;
+       }
+
+       if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+           return -EIO;
+
+       return 0;
+}
+
+static int video_init(struct ibm_struct *ibm)
+{
+       if (!acpi_evalf(vid_handle,
+                       &ibm->state.video.autoswitch, "^VDEE", "d"))
+               return -ENODEV;
+
+       return 0;
+}
+
+static int video_status(struct ibm_struct *ibm)
+{
+       int status = 0;
+       int i;
+
+       acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
+       if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
+               status |= 0x02 * i;
+
+       acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
+       if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
+               status |= 0x01 * i;
+       if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
+               status |= 0x08 * i;
+
+       if (acpi_evalf(vid_handle, &i, "^VDEE", "d"))
+               status |= 0x10 * (i & 1);
+
+       return status;
+}
+
+static int video_read(struct ibm_struct *ibm, char *p)
+{
+       int status = video_status(ibm);
+       int len = 0;
+
+       len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+       len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+       len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+       len += sprintf(p + len, "auto:\t\t%s\n", enabled(status, 4));
+       len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable, "
+                      "crt_enable, crt_disable\n");
+       len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable, "
+                      "auto_enable, auto_disable\n");
+       len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+
+       return len;
+}
+
+static int video_write(struct ibm_struct *ibm, char *buf)
+{
+       char *cmd;
+       int enable, disable, status;
+
+       enable = disable = 0;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "lcd_enable") == 0) {
+                       enable |= 0x01;
+               } else if (strlencmp(cmd, "lcd_disable") == 0) {
+                       disable |= 0x01;
+               } else if (strlencmp(cmd, "crt_enable") == 0) {
+                       enable |= 0x02;
+               } else if (strlencmp(cmd, "crt_disable") == 0) {
+                       disable |= 0x02;
+               } else if (strlencmp(cmd, "dvi_enable") == 0) {
+                       enable |= 0x08;
+               } else if (strlencmp(cmd, "dvi_disable") == 0) {
+                       disable |= 0x08;
+               } else if (strlencmp(cmd, "auto_enable") == 0) {
+                       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
+                               return -EIO;
+               } else if (strlencmp(cmd, "auto_disable") == 0) {
+                       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
+                               return -EIO;
+               } else if (strlencmp(cmd, "video_switch") == 0) {
+                       int autoswitch;
+                       if (!acpi_evalf(vid_handle, &autoswitch, "^VDEE", "d"))
+                               return -EIO;
+                       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
+                               return -EIO;
+                       if (!acpi_evalf(vid_handle, NULL, "VSWT", "v"))
+                               return -EIO;
+                       if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd",
+                                       autoswitch))
+                               return -EIO;
+               } else if (strlencmp(cmd, "expand_toggle") == 0) {
+                       if (!acpi_evalf(NULL, NULL, "\\VEXP", "v"))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       if (enable || disable) {
+               status = (video_status(ibm) & 0x0f & ~disable) | enable;
+               if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80))
+                       return -EIO;
+               if (!acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static void video_exit(struct ibm_struct *ibm)
+{
+       acpi_evalf(vid_handle, NULL, "_DOS", "vd",
+                  ibm->state.video.autoswitch);
+}
+
+static int light_init(struct ibm_struct *ibm)
+{
+       /* kblt not supported on G40, R32, X20 */
+       ibm->supported = acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+
+       return 0;
+}
+
+static int light_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+       int status = 0;
+
+       if (ibm->supported) {
+               if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+                       return -EIO;
+               len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+       } else
+               len += sprintf(p + len, "status:\t\tunknown\n");
+
+       len += sprintf(p + len, "commands:\ton, off\n");
+
+       return len;
+}
+
+static int light_write(struct ibm_struct *ibm, char *buf)
+{
+       int cmos_cmd, lght_cmd;
+       char *cmd;
+       int success;
+       
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "on") == 0) {
+                       cmos_cmd = 0x0c;
+                       lght_cmd = 1;
+               } else if (strlencmp(cmd, "off") == 0) {
+                       cmos_cmd = 0x0d;
+                       lght_cmd = 0;
+               } else
+                       return -EINVAL;
+               
+               success = cmos_handle ?
+                       acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
+                       acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
+               if (!success)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int _sta(acpi_handle handle)
+{
+       int status;
+
+       if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
+               status = 0;
+
+       return status;
+}
+
+#define dock_docked() (_sta(dock_handle) & 1)
+
+static int dock_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+       int docked = dock_docked();
+
+       if (!dock_handle)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else if (!docked)
+               len += sprintf(p + len, "status:\t\tundocked\n");
+       else {
+               len += sprintf(p + len, "status:\t\tdocked\n");
+               len += sprintf(p + len, "commands:\tdock, undock\n");
+       }
+
+       return len;
+}
+
+static int dock_write(struct ibm_struct *ibm, char *buf)
+{
+       char *cmd;
+
+       if (!dock_docked())
+               return -EINVAL;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "undock") == 0) {
+                       if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0))
+                               return -EIO;
+                       if (!acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
+                               return -EIO;
+               } else if (strlencmp(cmd, "dock") == 0) {
+                       if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}      
+
+static void dock_notify(struct ibm_struct *ibm, u32 event)
+{
+       int docked = dock_docked();
+
+       if (event == 3 && docked)
+               acpi_bus_generate_event(ibm->device, event, 1); /* button */
+       else if (event == 3 && !docked)
+               acpi_bus_generate_event(ibm->device, event, 2); /* undock */
+       else if (event == 0 && docked)
+               acpi_bus_generate_event(ibm->device, event, 3); /* dock */
+       else {
+               printk(IBM_ERR "unknown dock event %d, status %d\n",
+                      event, _sta(dock_handle));
+               acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
+       }
+}
+
+#define bay_occupied() (_sta(bay_handle) & 1)
+
+static int bay_init(struct ibm_struct *ibm)
+{
+       /* bay not supported on A21e, A22p, A31, A31p, G40, R32, R40e */
+       ibm->supported = bay_handle && bayej_handle &&
+               acpi_evalf(bay_handle, NULL, "_STA", "qv");
+
+       return 0;
+}
+
+static int bay_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+       int occupied = bay_occupied();
+       
+       if (!ibm->supported)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else if (!occupied)
+               len += sprintf(p + len, "status:\t\tunoccupied\n");
+       else {
+               len += sprintf(p + len, "status:\t\toccupied\n");
+               len += sprintf(p + len, "commands:\teject\n");
+       }
+
+       return len;
+}
+
+static int bay_write(struct ibm_struct *ibm, char *buf)
+{
+       char *cmd;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "eject") == 0) {
+                       if (!ibm->supported ||
+                           !acpi_evalf(bay_handle, NULL, "_EJ0", "vd", 1))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}      
+
+static void bay_notify(struct ibm_struct *ibm, u32 event)
+{
+       acpi_bus_generate_event(ibm->device, event, 0);
+}
+
+static int cmos_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+
+       /* cmos not supported on A21e, A22p, T20, T21, X20 */
+       if (!cmos_handle)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else {
+               len += sprintf(p + len, "status:\t\tsupported\n");
+               len += sprintf(p + len, "commands:\t<int>\n");
+       }
+
+       return len;
+}
+
+static int cmos_write(struct ibm_struct *ibm, char *buf)
+{
+       char *cmd;
+       int cmos_cmd;
+
+       if (!cmos_handle)
+               return -EINVAL;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "%u", &cmos_cmd) == 1) {
+                       /* cmos_cmd set */
+               } else
+                       return -EINVAL;
+
+               if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
+                       return -EIO;
+       }
+
+       return 0;
+}      
+               
+static int led_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+
+       len += sprintf(p + len, "commands:\t"
+                      "<int> on, <int> off, <int> blink\n");
+
+       return len;
+}
+
+static int led_write(struct ibm_struct *ibm, char *buf)
+{
+       char *cmd;
+       unsigned int led;
+       int led_cmd, sysl_cmd, bled_a, bled_b;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "%u", &led) != 1)
+                       return -EINVAL;
+
+               if (strstr(cmd, "blink")) {
+                       led_cmd = 0xc0;
+                       sysl_cmd = 2;
+                       bled_a = 2;
+                       bled_b = 1;
+               } else if (strstr(cmd, "on")) {
+                       led_cmd = 0x80;
+                       sysl_cmd = 1;
+                       bled_a = 2;
+                       bled_b = 0;
+               } else if (strstr(cmd, "off")) {
+                       led_cmd = sysl_cmd = bled_a = bled_b = 0;
+               } else
+                       return -EINVAL;
+               
+               if (led_handle) {
+                       if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+                                       led, led_cmd))
+                               return -EIO;
+               } else if (led < 2) {
+                       if (acpi_evalf(sysl_handle, NULL, NULL, "vdd",
+                                      led, sysl_cmd))
+                               return -EIO;
+               } else if (led == 2 && bled_handle) {
+                       if (acpi_evalf(bled_handle, NULL, NULL, "vdd",
+                                      bled_a, bled_b))
+                               return -EIO;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}      
+               
+static int beep_read(struct ibm_struct *ibm, char *p)
+{
+       int len = 0;
+
+       len += sprintf(p + len, "commands:\t<int>\n");
+
+       return len;
+}
+
+static int beep_write(struct ibm_struct *ibm, char *buf)
+{
+       char *cmd;
+       int beep_cmd;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (sscanf(cmd, "%u", &beep_cmd) == 1) {
+                       /* beep_cmd set */
+               } else
+                       return -EINVAL;
+
+               if (!acpi_evalf(beep_handle, NULL, NULL, "vd", beep_cmd))
+                       return -EIO;
+       }
+
+       return 0;
+}      
+               
+struct ibm_struct ibms[] = {
+       {
+               .name   = "driver",
+               .init   = driver_init,
+               .read   = driver_read,
+       },
+       {
+               .name   = "hotkey",
+               .hid    = "IBM0068",
+               .init   = hotkey_init,
+               .read   = hotkey_read,
+               .write  = hotkey_write,
+               .exit   = hotkey_exit,
+               .notify = hotkey_notify,
+               .handle = &hkey_handle,
+               .type   = ACPI_DEVICE_NOTIFY,
+       },
+       {
+               .name   = "bluetooth",
+               .init   = bluetooth_init,
+               .read   = bluetooth_read,
+               .write  = bluetooth_write,
+       },
+       {
+               .name   = "video",
+               .init   = video_init,
+               .read   = video_read,
+               .write  = video_write,
+               .exit   = video_exit,
+       },
+       {
+               .name   = "light",
+               .init   = light_init,
+               .read   = light_read,
+               .write  = light_write,
+       },
+       {
+               .name   = "dock",
+               .read   = dock_read,
+               .write  = dock_write,
+               .notify = dock_notify,
+               .handle = &dock_handle,
+               .type   = ACPI_SYSTEM_NOTIFY,
+       },
+       {
+               .name   = "bay",
+               .init   = bay_init,
+               .read   = bay_read,
+               .write  = bay_write,
+               .notify = bay_notify,
+               .handle = &bay_handle,
+               .type   = ACPI_SYSTEM_NOTIFY,
+       },
+       {
+               .name   = "cmos",
+               .read   = cmos_read,
+               .write  = cmos_write,
+               .experimental = 1,
+       },
+       {
+               .name   = "led",
+               .read   = led_read,
+               .write  = led_write,
+               .experimental = 1,
+       },
+       {
+               .name   = "beep",
+               .read   = beep_read,
+               .write  = beep_write,
+               .experimental = 1,
+       },
+};
+#define NUM_IBMS (sizeof(ibms)/sizeof(ibms[0]))
+
+static int dispatch_read(char *page, char **start, off_t off, int count,
+                        int *eof, void *data)
+{
+       struct ibm_struct *ibm = (struct ibm_struct *)data;
+       int len;
+       
+       if (!ibm || !ibm->read)
+               return -EINVAL;
+
+       len = ibm->read(ibm, page);
+       if (len < 0)
+               return len;
+
+       if (len <= off + count)
+               *eof = 1;
+       *start = page + off;
+       len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+
+       return len;
+}
+
+static int dispatch_write(struct file *file, const char __user *userbuf,
+                         unsigned long count, void *data)
+{
+       struct ibm_struct *ibm = (struct ibm_struct *)data;
+       char *kernbuf;
+       int ret;
+
+       if (!ibm || !ibm->write)
+               return -EINVAL;
+
+       kernbuf = kmalloc(count + 2, GFP_KERNEL);
+       if (!kernbuf)
+               return -ENOMEM;
+
+        if (copy_from_user(kernbuf, userbuf, count)) {
+               kfree(kernbuf);
+                return -EFAULT;
+       }
+
+       kernbuf[count] = 0;
+       strcat(kernbuf, ",");
+       ret = ibm->write(ibm, kernbuf);
+       if (ret == 0)
+               ret = count;
+
+       kfree(kernbuf);
+
+        return ret;
+}
+
+static void dispatch_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct ibm_struct *ibm = (struct ibm_struct *)data;
+
+       if (!ibm || !ibm->notify)
+               return;
+
+       ibm->notify(ibm, event);
+}
+
+static int setup_notify(struct ibm_struct *ibm)
+{
+       acpi_status status;
+       int ret;
+
+       if (!*ibm->handle)
+               return 0;
+
+       ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
+       if (ret < 0) {
+               printk(IBM_ERR "%s device not present\n", ibm->name);
+               return 0;
+       }
+
+       acpi_driver_data(ibm->device) = ibm;
+       sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
+
+       status = acpi_install_notify_handler(*ibm->handle, ibm->type,
+                                            dispatch_notify, ibm);
+       if (ACPI_FAILURE(status)) {
+               printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
+                      ibm->name, status);
+               return -ENODEV;
+       }
+
+       ibm->notify_installed = 1;
+
+       return 0;
+}
+
+static int device_add(struct acpi_device *device)
+{
+       return 0;
+}
+
+static int register_driver(struct ibm_struct *ibm)
+{
+       int ret;
+
+       ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+       if (!ibm->driver) {
+               printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
+               return -1;
+       }
+
+       memset(ibm->driver, 0, sizeof(struct acpi_driver));
+       sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
+       ibm->driver->ids = ibm->hid;
+       ibm->driver->ops.add = &device_add;
+
+       ret = acpi_bus_register_driver(ibm->driver);
+       if (ret < 0) {
+               printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+                      ibm->hid, ret);
+               kfree(ibm->driver);
+       }
+
+       return ret;
+}
+
+static int ibm_init(struct ibm_struct *ibm)
+{
+       int ret;
+       struct proc_dir_entry *entry;
+
+       if (ibm->experimental && !experimental)
+               return 0;
+
+       if (ibm->hid) {
+               ret = register_driver(ibm);
+               if (ret < 0)
+                       return ret;
+               ibm->driver_registered = 1;
+       }
+
+       if (ibm->init) {
+               ret = ibm->init(ibm);
+               if (ret != 0)
+                       return ret;
+               ibm->init_called = 1;
+       }
+
+       entry = create_proc_entry(ibm->name, S_IFREG | S_IRUGO | S_IWUSR,
+                                 proc_dir);
+       if (!entry) {
+               printk(IBM_ERR "unable to create proc entry %s\n", ibm->name);
+               return -ENODEV;
+       }
+       entry->owner = THIS_MODULE;
+       ibm->proc_created = 1;
+       
+       entry->data = ibm;
+       if (ibm->read)
+               entry->read_proc = &dispatch_read;
+       if (ibm->write)
+               entry->write_proc = &dispatch_write;
+
+       if (ibm->notify) {
+               ret = setup_notify(ibm);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void ibm_exit(struct ibm_struct *ibm)
+{
+       if (ibm->notify_installed)
+               acpi_remove_notify_handler(*ibm->handle, ibm->type,
+                                          dispatch_notify);
+
+       if (ibm->proc_created)
+               remove_proc_entry(ibm->name, proc_dir);
+
+       if (ibm->init_called && ibm->exit)
+               ibm->exit(ibm);
+
+       if (ibm->driver_registered) {
+               acpi_bus_unregister_driver(ibm->driver);
+               kfree(ibm->driver);
+       }
+}
+
+static int ibm_handle_init(char *name,
+                          acpi_handle *handle, acpi_handle parent,
+                          char **paths, int num_paths, int required)
+{
+       int i;
+       acpi_status status;
+
+       for (i=0; i<num_paths; i++) {
+               status = acpi_get_handle(parent, paths[i], handle);
+               if (ACPI_SUCCESS(status))
+                       return 0;
+       }
+       
+       *handle = NULL;
+
+       if (required) {
+               printk(IBM_ERR "%s object not found\n", name);
+               return -1;
+       }
+
+       return 0;
+}
+
+#define IBM_HANDLE_INIT(object, required)                              \
+       ibm_handle_init(#object, &object##_handle, *object##_parent,    \
+               object##_paths, sizeof(object##_paths)/sizeof(char*), required)
+
+
+static int set_ibm_param(const char *val, struct kernel_param *kp)
+{
+       unsigned int i;
+       char arg_with_comma[32];
+
+       if (strlen(val) > 30)
+               return -ENOSPC;
+
+       strcpy(arg_with_comma, val);
+       strcat(arg_with_comma, ",");
+
+       for (i=0; i<NUM_IBMS; i++)
+               if (strcmp(ibms[i].name, kp->name) == 0)
+                       return ibms[i].write(&ibms[i], arg_with_comma);
+       BUG();
+       return -EINVAL;
+}
+
+#define IBM_PARAM(feature) \
+       module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+
+static void __exit acpi_ibm_exit(void)
+{
+       int i;
+
+       for (i=NUM_IBMS-1; i>=0; i--)
+               ibm_exit(&ibms[i]);
+
+       remove_proc_entry(IBM_DIR, acpi_root_dir);
+}
+
+static int __init acpi_ibm_init(void)
+{
+       int ret, i;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       /* these handles are required */
+       if (IBM_HANDLE_INIT(ec,   1) < 0 ||
+           IBM_HANDLE_INIT(hkey, 1) < 0 ||
+           IBM_HANDLE_INIT(vid,  1) < 0 ||
+           IBM_HANDLE_INIT(beep, 1) < 0)
+               return -ENODEV;
+
+       /* these handles have alternatives */
+       IBM_HANDLE_INIT(lght, 0);
+       if (IBM_HANDLE_INIT(cmos, !lght_handle) < 0)
+               return -ENODEV;
+       IBM_HANDLE_INIT(sysl, 0);
+       if (IBM_HANDLE_INIT(led, !sysl_handle) < 0)
+               return -ENODEV;
+
+       /* these handles are not required */
+       IBM_HANDLE_INIT(dock,  0);
+       IBM_HANDLE_INIT(bay,   0);
+       IBM_HANDLE_INIT(bayej, 0);
+       IBM_HANDLE_INIT(bled,  0);
+
+       proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
+       if (!proc_dir) {
+               printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
+               return -ENODEV;
+       }
+       proc_dir->owner = THIS_MODULE;
+       
+       for (i=0; i<NUM_IBMS; i++) {
+               ret = ibm_init(&ibms[i]);
+               if (ret < 0) {
+                       acpi_ibm_exit();
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+module_init(acpi_ibm_init);
+module_exit(acpi_ibm_exit);
+
+MODULE_AUTHOR("Borislav Deianov");
+MODULE_DESCRIPTION(IBM_DESC);
+MODULE_LICENSE("GPL");
+
+IBM_PARAM(hotkey);
+IBM_PARAM(bluetooth);
+IBM_PARAM(video);
+IBM_PARAM(light);
+IBM_PARAM(dock);
+IBM_PARAM(bay);
+IBM_PARAM(cmos);
+IBM_PARAM(led);
+IBM_PARAM(beep);
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
new file mode 100644 (file)
index 0000000..ee9c5d1
--- /dev/null
@@ -0,0 +1,177 @@
+/* 
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *  This 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define _COMPONENT             ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME               ("acpi_motherboard")
+
+/* Dell use PNP0C01 instead of PNP0C02 */
+#define ACPI_MB_HID1                   "PNP0C01"
+#define ACPI_MB_HID2                   "PNP0C02"
+
+/**
+ * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
+ * Doesn't care about the failure of 'request_region', since other may reserve 
+ * the io ports as well
+ */
+#define IS_RESERVED_ADDR(base, len) \
+       (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
+       && ((base) + (len) > PCIBIOS_MIN_IO))
+
+/*
+ * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
+ * the io ports if they really know they can use it, while
+ * still preventing hotplug PCI devices from using it. 
+ */
+
+static acpi_status
+acpi_reserve_io_ranges (struct acpi_resource *res, void *data)
+{
+       struct resource *requested_res = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges");
+
+       if (res->id == ACPI_RSTYPE_IO) {
+               struct acpi_resource_io *io_res = &res->data.io;
+
+               if (io_res->min_base_address != io_res->max_base_address)
+                       return AE_OK;
+               if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n",
+                               io_res->min_base_address, 
+                               io_res->min_base_address + io_res->range_length));
+                       requested_res = request_region(io_res->min_base_address, 
+                               io_res->range_length, "motherboard");
+               }
+       } else if (res->id == ACPI_RSTYPE_FIXED_IO) {
+               struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io;
+
+               if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n",
+                               fixed_io_res->base_address, 
+                               fixed_io_res->base_address + fixed_io_res->range_length));
+                       requested_res = request_region(fixed_io_res->base_address, 
+                               fixed_io_res->range_length, "motherboard");
+               }
+       } else {
+               /* Memory mapped IO? */
+       }
+
+       if (requested_res)
+               requested_res->flags &= ~IORESOURCE_BUSY;
+       return AE_OK;
+}
+
+static int acpi_motherboard_add (struct acpi_device *device)
+{
+       if (!device)
+               return -EINVAL;
+       acpi_walk_resources(device->handle, METHOD_NAME__CRS, 
+               acpi_reserve_io_ranges, NULL);
+
+       return 0;
+}
+
+static struct acpi_driver acpi_motherboard_driver1 = {
+       .name =         "motherboard",
+       .class =        "",
+       .ids =          ACPI_MB_HID1,
+       .ops =  {
+               .add =          acpi_motherboard_add,
+       },
+};
+
+static struct acpi_driver acpi_motherboard_driver2 = {
+       .name =         "motherboard",
+       .class =        "",
+       .ids =          ACPI_MB_HID2,
+       .ops =  {
+               .add =          acpi_motherboard_add,
+       },
+};
+
+static void __init
+acpi_reserve_resources (void)
+{
+       if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
+               request_region(acpi_gbl_FADT->xpm1a_evt_blk.address, 
+                       acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK");
+
+       if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
+               request_region(acpi_gbl_FADT->xpm1b_evt_blk.address,
+                       acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK");
+
+       if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
+               request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address, 
+                       acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK");
+
+       if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
+               request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address, 
+                       acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK");
+
+       if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4)
+               request_region(acpi_gbl_FADT->xpm_tmr_blk.address,
+                       4, "PM_TMR");
+
+       if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len)
+               request_region(acpi_gbl_FADT->xpm2_cnt_blk.address,
+                       acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK");
+
+       /* Length of GPE blocks must be a non-negative multiple of 2 */
+
+       if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len &&
+                       !(acpi_gbl_FADT->gpe0_blk_len & 0x1))
+               request_region(acpi_gbl_FADT->xgpe0_blk.address,
+                       acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK");
+
+       if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len &&
+                       !(acpi_gbl_FADT->gpe1_blk_len & 0x1))
+               request_region(acpi_gbl_FADT->xgpe1_blk.address,
+                       acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK");
+}
+
+static int __init acpi_motherboard_init(void)
+{
+       acpi_bus_register_driver(&acpi_motherboard_driver1);
+       acpi_bus_register_driver(&acpi_motherboard_driver2);
+       /* 
+        * Guarantee motherboard IO reservation first
+        * This module must run after scan.c
+        */
+       if (!acpi_disabled)
+               acpi_reserve_resources ();
+       return 0;
+}
+
+/**
+ * Reserve motherboard resources after PCI claim BARs,
+ * but before PCI assign resources for uninitialized PCI devices
+ */
+fs_initcall(acpi_motherboard_init);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
new file mode 100644 (file)
index 0000000..9c004b9
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * wakeup.c - support wakeup devices
+ */
+
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <acpi/acevents.h>
+#include "sleep.h"
+
+#define _COMPONENT             ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME               ("wakeup_devices")
+
+/**
+ * acpi_enable_wakeup_device_prep - prepare wakeup devices
+ *     @sleep_state:   ACPI state
+ * Enable all wakup devices power if the devices' wakeup level
+ * is higher than requested sleep level
+ */
+extern struct list_head        acpi_wakeup_device_list;
+extern spinlock_t acpi_device_lock;
+
+void
+acpi_enable_wakeup_device_prep(
+       u8              sleep_state)
+{
+       struct list_head * node, * next;
+
+       ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep");
+
+       spin_lock(&acpi_device_lock);
+       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+               struct acpi_device * dev = container_of(node, 
+                       struct acpi_device, wakeup_list);
+               
+               if (!dev->wakeup.flags.valid || 
+                       !dev->wakeup.state.enabled ||
+                       (sleep_state > (u32) dev->wakeup.sleep_state))
+                       continue;
+
+               spin_unlock(&acpi_device_lock);
+               acpi_enable_wakeup_device_power(dev);
+               spin_lock(&acpi_device_lock);
+       }
+       spin_unlock(&acpi_device_lock);
+}
+
+/**
+ * acpi_enable_wakeup_device - enable wakeup devices
+ *     @sleep_state:   ACPI state
+ * Enable all wakup devices's GPE
+ */
+void
+acpi_enable_wakeup_device(
+       u8              sleep_state)
+{
+       struct list_head * node, * next;
+
+       /* 
+        * Caution: this routine must be invoked when interrupt is disabled 
+        * Refer ACPI2.0: P212
+        */
+       ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
+       spin_lock(&acpi_device_lock);
+       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+               struct acpi_device * dev = container_of(node, 
+                       struct acpi_device, wakeup_list);
+
+               /* If users want to disable run-wake GPE,
+                * we only disable it for wake and leave it for runtime
+                */
+               if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+                       spin_unlock(&acpi_device_lock);
+                       acpi_set_gpe_type(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME);
+                       /* Re-enable it, since set_gpe_type will disable it */
+                       acpi_enable_gpe(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_ISR);
+                       spin_lock(&acpi_device_lock);
+                       continue;
+               }
+
+               if (!dev->wakeup.flags.valid ||
+                       !dev->wakeup.state.enabled ||
+                       (sleep_state > (u32) dev->wakeup.sleep_state))
+                       continue;
+
+               spin_unlock(&acpi_device_lock);
+               /* run-wake GPE has been enabled */
+               if (!dev->wakeup.flags.run_wake)
+                       acpi_enable_gpe(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_ISR);
+               dev->wakeup.state.active = 1;
+               spin_lock(&acpi_device_lock);
+       }
+       spin_unlock(&acpi_device_lock);
+}
+
+/**
+ * acpi_disable_wakeup_device - disable devices' wakeup capability
+ *     @sleep_state:   ACPI state
+ * Disable all wakup devices's GPE and wakeup capability
+ */
+void
+acpi_disable_wakeup_device (
+       u8              sleep_state)
+{
+       struct list_head * node, * next;
+
+       ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device");
+
+       spin_lock(&acpi_device_lock);
+       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+               struct acpi_device * dev = container_of(node, 
+                       struct acpi_device, wakeup_list);
+
+               if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+                       spin_unlock(&acpi_device_lock);
+                       acpi_set_gpe_type(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+                       /* Re-enable it, since set_gpe_type will disable it */
+                       acpi_enable_gpe(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_NOT_ISR);
+                       spin_lock(&acpi_device_lock);
+                       continue;
+               }
+
+               if (!dev->wakeup.flags.valid || 
+                       !dev->wakeup.state.active ||
+                       (sleep_state > (u32) dev->wakeup.sleep_state))
+                       continue;
+
+               spin_unlock(&acpi_device_lock);
+               acpi_disable_wakeup_device_power(dev);
+               /* Never disable run-wake GPE */
+               if (!dev->wakeup.flags.run_wake) {
+                       acpi_disable_gpe(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_NOT_ISR);
+                       acpi_clear_gpe(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_NOT_ISR);
+               }
+               dev->wakeup.state.active = 0;
+               spin_lock(&acpi_device_lock);
+       }
+       spin_unlock(&acpi_device_lock);
+}
+
+static int __init acpi_wakeup_device_init(void)
+{
+       struct list_head * node, * next;
+
+       if (acpi_disabled)
+               return 0;
+       printk("ACPI wakeup devices: \n");
+
+       spin_lock(&acpi_device_lock);
+       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+               struct acpi_device * dev = container_of(node, 
+                       struct acpi_device, wakeup_list);
+               
+               /* In case user doesn't load button driver */
+               if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+                       spin_unlock(&acpi_device_lock);
+                       acpi_set_gpe_type(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+                       acpi_enable_gpe(dev->wakeup.gpe_device, 
+                               dev->wakeup.gpe_number, ACPI_NOT_ISR);
+                       dev->wakeup.state.enabled = 1;
+                       spin_lock(&acpi_device_lock);
+               }
+               printk("%4s ", dev->pnp.bus_id);
+       }
+       spin_unlock(&acpi_device_lock);
+       printk("\n");
+
+       return 0;
+}
+
+late_initcall(acpi_wakeup_device_init);
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
new file mode 100644 (file)
index 0000000..5618a23
--- /dev/null
@@ -0,0 +1,1988 @@
+/*
+ *  video.c - ACPI Video Driver ($Revision:$)
+ *
+ *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
+ *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_VIDEO_COMPONENT           0x08000000
+#define ACPI_VIDEO_CLASS               "video"
+#define ACPI_VIDEO_DRIVER_NAME         "ACPI Video Driver"
+#define ACPI_VIDEO_BUS_NAME            "Video Bus"
+#define ACPI_VIDEO_DEVICE_NAME         "Video Device"
+#define ACPI_VIDEO_NOTIFY_SWITCH       0x80
+#define ACPI_VIDEO_NOTIFY_PROBE                0x81
+#define ACPI_VIDEO_NOTIFY_CYCLE                0x82
+#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT  0x83
+#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT  0x84
+
+#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS     0x82
+#define        ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS        0x83
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS       0x84
+#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS      0x85
+#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF          0x86
+
+
+#define ACPI_VIDEO_HEAD_INVALID                (~0u - 1)
+#define ACPI_VIDEO_HEAD_END            (~0u)
+
+
+#define _COMPONENT             ACPI_VIDEO_COMPONENT
+ACPI_MODULE_NAME               ("acpi_video")
+
+MODULE_AUTHOR("Bruno Ducrot");
+MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int acpi_video_bus_add (struct acpi_device *device);
+static int acpi_video_bus_remove (struct acpi_device *device, int type);
+static int acpi_video_bus_match (struct acpi_device *device, struct acpi_driver *driver);
+
+static struct acpi_driver acpi_video_bus = {
+       .name = ACPI_VIDEO_DRIVER_NAME,
+       .class = ACPI_VIDEO_CLASS,
+       .ops = {
+               .add = acpi_video_bus_add,
+               .remove = acpi_video_bus_remove,
+               .match = acpi_video_bus_match,
+       },
+};
+
+struct acpi_video_bus_flags {
+       u8      multihead:1;    /* can switch video heads */
+       u8      rom:1;          /* can retrieve a video rom */
+       u8      post:1;         /* can configure the head to */
+       u8      reserved:5;
+};
+
+struct acpi_video_bus_cap {
+       u8      _DOS:1; /*Enable/Disable output switching*/
+       u8      _DOD:1; /*Enumerate all devices attached to display adapter*/
+       u8      _ROM:1; /*Get ROM Data*/
+       u8      _GPD:1; /*Get POST Device*/
+       u8      _SPD:1; /*Set POST Device*/
+       u8      _VPO:1; /*Video POST Options*/
+       u8      reserved:2;
+};
+
+struct acpi_video_device_attrib{
+       u32     display_index:4; /* A zero-based instance of the Display*/
+       u32     display_port_attachment:4; /*This field differenates displays type*/
+       u32     display_type:4; /*Describe the specific type in use*/
+       u32     vendor_specific:4; /*Chipset Vendor Specifi*/ 
+       u32     bios_can_detect:1; /*BIOS can detect the device*/
+       u32     depend_on_vga:1; /*Non-VGA output device whose power is related to 
+                                  the VGA device.*/
+       u32     pipe_id:3; /*For VGA multiple-head devices.*/
+       u32     reserved:10; /*Must be 0*/
+       u32     device_id_scheme:1; /*Device ID Scheme*/
+};
+
+struct acpi_video_enumerated_device {
+       union {
+               u32 int_val;
+               struct acpi_video_device_attrib attrib;
+       } value;
+       struct acpi_video_device *bind_info;
+};
+
+struct acpi_video_bus {
+       acpi_handle     handle;
+       u8      dos_setting;
+       struct acpi_video_enumerated_device *attached_array;
+       u8                      attached_count;
+       struct acpi_video_bus_cap       cap;
+       struct acpi_video_bus_flags flags;
+       struct semaphore        sem;
+       struct list_head        video_device_list;
+       struct proc_dir_entry   *dir;
+};
+
+struct acpi_video_device_flags {
+       u8      crt:1;
+       u8      lcd:1;
+       u8      tvout:1;
+       u8      bios:1;
+       u8      unknown:1;
+       u8      reserved:3;
+};
+
+struct acpi_video_device_cap {
+       u8      _ADR:1; /*Return the unique ID */
+       u8      _BCL:1; /*Query list of brightness control levels supported*/
+       u8      _BCM:1; /*Set the brightness level*/
+       u8      _DDC:1; /*Return the EDID for this device*/
+       u8      _DCS:1; /*Return status of output device*/
+       u8      _DGS:1; /*Query graphics state*/
+       u8      _DSS:1; /*Device state set*/
+       u8      _reserved:1;
+};
+
+struct acpi_video_device_brightness {
+       int     curr;
+       int     count;
+       int     *levels;
+};
+
+struct acpi_video_device {
+       acpi_handle             handle;
+       unsigned long           device_id;
+       struct acpi_video_device_flags  flags;
+       struct acpi_video_device_cap    cap;
+       struct list_head        entry;
+       struct acpi_video_bus   *video;
+       struct acpi_device      *dev;
+       struct acpi_video_device_brightness *brightness;
+};
+
+
+/* bus */
+static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_info_fops = {
+       .open           = acpi_video_bus_info_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_ROM_fops = {
+       .open           = acpi_video_bus_ROM_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_POST_info_fops = {
+       .open           = acpi_video_bus_POST_info_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_POST_fops = {
+       .open           = acpi_video_bus_POST_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+
+static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_DOS_fops = {
+       .open           = acpi_video_bus_DOS_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/* device */
+static int acpi_video_device_info_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_info_fops = {
+       .open           = acpi_video_device_info_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int acpi_video_device_state_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_state_fops = {
+       .open           = acpi_video_device_state_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_brightness_fops = {
+       .open           = acpi_video_device_brightness_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_EDID_fops = {
+       .open           = acpi_video_device_EDID_open_fs,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void acpi_video_device_notify ( acpi_handle handle, u32 event, void *data);
+static void acpi_video_device_rebind( struct acpi_video_bus *video);
+static void acpi_video_device_bind( struct acpi_video_bus *video, struct acpi_video_device *device);
+static int acpi_video_device_enumerate(struct acpi_video_bus *video);
+static int acpi_video_switch_output( struct acpi_video_bus *video, int event);
+static int acpi_video_get_next_level( struct acpi_video_device *device, u32 level_current,u32 event);
+static void acpi_video_switch_brightness ( struct acpi_video_device *device, int event);
+
+
+/* --------------------------------------------------------------------------
+                               Video Management
+   -------------------------------------------------------------------------- */
+
+/* device */
+
+static int
+acpi_video_device_query (
+       struct acpi_video_device        *device,
+       unsigned long                   *state)
+{
+       int                     status;
+       ACPI_FUNCTION_TRACE("acpi_video_device_query");
+       status = acpi_evaluate_integer(device->handle, "_DGS", NULL, state);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_device_get_state (
+       struct acpi_video_device        *device,
+       unsigned long           *state)
+{
+       int                     status;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_get_state");
+
+       status = acpi_evaluate_integer(device->handle, "_DCS", NULL, state);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_device_set_state (
+       struct acpi_video_device        *device,
+       int                     state)
+{
+       int                     status;
+       union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
+       struct acpi_object_list args = {1, &arg0};
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_set_state");
+
+       arg0.integer.value = state;
+       status = acpi_evaluate_integer(device->handle, "_DSS", &args, NULL);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_device_lcd_query_levels (
+       struct acpi_video_device        *device,
+       union acpi_object               **levels)
+{
+       int                     status;
+       struct acpi_buffer      buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object       *obj;
+
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_lcd_query_levels");
+
+       *levels = NULL;
+
+       status = acpi_evaluate_object(device->handle, "_BCL", NULL, &buffer);
+       if (!ACPI_SUCCESS(status))
+               return_VALUE(status);
+       obj = (union acpi_object *) buffer.pointer;
+       if (!obj && (obj->type != ACPI_TYPE_PACKAGE)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
+               status = -EFAULT;
+               goto err;
+       }
+
+       *levels = obj;
+
+       return_VALUE(0);
+
+err:
+       if (buffer.pointer)
+               kfree(buffer.pointer);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_device_lcd_set_level (
+       struct acpi_video_device        *device,
+       int                             level)
+{
+       int                     status;
+       union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
+       struct acpi_object_list args = {1, &arg0};
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_lcd_set_level");
+
+       arg0.integer.value = level;
+       status = acpi_evaluate_object(device->handle, "_BCM", &args, NULL);
+
+       printk(KERN_DEBUG "set_level status: %x\n", status);
+       return_VALUE(status);
+}
+
+static int
+acpi_video_device_lcd_get_level_current (
+       struct acpi_video_device        *device,
+       unsigned long   *level)
+{
+       int                     status;
+       ACPI_FUNCTION_TRACE("acpi_video_device_lcd_get_level_current");
+
+       status = acpi_evaluate_integer(device->handle, "_BQC", NULL, level);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_device_EDID (
+       struct acpi_video_device        *device,
+       union acpi_object               **edid,
+       ssize_t                         length)
+{
+       int                     status;
+       struct acpi_buffer      buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object       *obj;
+       union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
+       struct acpi_object_list args = {1, &arg0};
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_get_EDID");
+
+       *edid = NULL;
+
+       if (!device)
+               return_VALUE(-ENODEV);
+       if (length == 128)
+               arg0.integer.value = 1;
+       else if (length == 256)
+               arg0.integer.value = 2;
+       else
+               return_VALUE(-EINVAL);
+
+       status = acpi_evaluate_object(device->handle, "_DDC", &args, &buffer);
+       if (ACPI_FAILURE(status))
+               return_VALUE(-ENODEV);
+
+       obj = (union acpi_object *) buffer.pointer;
+
+       if (obj && obj->type == ACPI_TYPE_BUFFER)
+               *edid = obj;
+       else {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DDC data\n"));
+               status = -EFAULT;
+               kfree(obj);
+       }
+
+       return_VALUE(status);
+}
+
+
+/* bus */
+
+static int
+acpi_video_bus_set_POST (
+       struct acpi_video_bus   *video,
+       unsigned long           option)
+{
+       int                     status;
+       unsigned long           tmp;
+       union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
+       struct acpi_object_list args = {1, &arg0};
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_set_POST");
+
+       arg0.integer.value = option;
+
+       status = acpi_evaluate_integer(video->handle, "_SPD", &args, &tmp);
+       if (ACPI_SUCCESS(status))
+               status = tmp ? (-EINVAL):(AE_OK);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_bus_get_POST (
+       struct acpi_video_bus   *video,
+       unsigned long           *id)
+{
+       int status;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_get_POST");
+
+       status = acpi_evaluate_integer(video->handle, "_GPD", NULL, id);
+
+       return_VALUE(status);
+}
+
+static int
+acpi_video_bus_POST_options (
+       struct acpi_video_bus   *video,
+       unsigned long           *options)
+{
+       int                     status;
+       ACPI_FUNCTION_TRACE("acpi_video_bus_POST_options");
+
+       status = acpi_evaluate_integer(video->handle, "_VPO", NULL, options);
+       *options &= 3;
+
+       return_VALUE(status);
+}
+
+/*
+ *  Arg:
+ *     video           : video bus device pointer
+ *     bios_flag       : 
+ *             0.      The system BIOS should NOT automatically switch(toggle)
+ *                     the active display output.
+ *             1.      The system BIOS should automatically switch (toggle) the
+ *                     active display output. No swich event.
+ *             2.      The _DGS value should be locked.
+ *             3.      The system BIOS should not automatically switch (toggle) the
+ *                     active display output, but instead generate the display switch
+ *                     event notify code.
+ *     lcd_flag        :
+ *             0.      The system BIOS should automatically control the brightness level
+ *                     of the LCD, when the power changes from AC to DC
+ *             1.      The system BIOS should NOT automatically control the brightness 
+ *                     level of the LCD, when the power changes from AC to DC.
+ * Return Value:
+ *             -1      wrong arg.
+ */
+
+static int
+acpi_video_bus_DOS(
+       struct acpi_video_bus   *video,
+       int                     bios_flag,
+       int                     lcd_flag)
+{
+       acpi_integer            status = 0;
+       union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
+       struct acpi_object_list args = {1, &arg0};
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_DOS");
+
+       if (bios_flag < 0 || bios_flag >3 || lcd_flag < 0 || lcd_flag > 1){
+               status = -1;
+               goto Failed;
+       }
+       arg0.integer.value = (lcd_flag << 2) | bios_flag;
+       video->dos_setting = arg0.integer.value;
+       acpi_evaluate_object(video->handle, "_DOS", &args, NULL);
+
+Failed:
+       return_VALUE(status);
+}
+
+/*
+ *  Arg:       
+ *     device  : video output device (LCD, CRT, ..)
+ *
+ *  Return Value:
+ *     None
+ *
+ *  Find out all required AML method defined under the output
+ *  device.
+ */
+
+static void
+acpi_video_device_find_cap (struct acpi_video_device *device)
+{
+       acpi_integer            status;
+       acpi_handle h_dummy1;
+       int i;
+       union acpi_object *obj = NULL;
+       struct acpi_video_device_brightness *br = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_find_cap");
+
+       memset( &device->cap, 0, 4);
+
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_ADR", &h_dummy1))) {
+               device->cap._ADR = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCL", &h_dummy1))) {
+               device->cap._BCL= 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCM", &h_dummy1))) {
+               device->cap._BCM= 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DDC", &h_dummy1))) {
+               device->cap._DDC= 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DCS", &h_dummy1))) {
+               device->cap._DCS = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DGS", &h_dummy1))) {
+               device->cap._DGS = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DSS", &h_dummy1))) {
+               device->cap._DSS = 1;
+       }
+
+       status = acpi_video_device_lcd_query_levels(device, &obj);
+
+       if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
+               int count = 0;
+               union acpi_object *o;
+               
+               br = kmalloc(sizeof &br, GFP_KERNEL);
+               if (!br) {
+                       printk(KERN_ERR "can't allocate memory\n");
+               } else {
+                       memset(br, 0, sizeof &br);
+                       br->levels = kmalloc(obj->package.count * sizeof &br->levels, GFP_KERNEL);
+                       if (!br->levels)
+                               goto out;
+
+                       for (i = 0; i < obj->package.count; i++) {
+                               o = (union acpi_object *) &obj->package.elements[i];
+                               if (o->type != ACPI_TYPE_INTEGER) {
+                                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
+                                       continue;
+                               }
+                               br->levels[count] = (u32) o->integer.value;
+                               count++;
+                       }
+out:
+                       if (count < 2) {
+                               if (br->levels)
+                                       kfree(br->levels);
+                               kfree(br);
+                       } else {
+                               br->count = count;
+                               device->brightness = br;
+                               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count));
+                       }
+               }
+       }
+
+       if (obj)
+               kfree(obj);
+
+       return_VOID;
+}
+
+/*
+ *  Arg:       
+ *     device  : video output device (VGA)
+ *
+ *  Return Value:
+ *     None
+ *
+ *  Find out all required AML method defined under the video bus device.
+ */
+
+static void 
+acpi_video_bus_find_cap (struct acpi_video_bus *video)
+{
+       acpi_handle     h_dummy1;
+
+       memset(&video->cap ,0, 4);
+       if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOS", &h_dummy1))) {
+               video->cap._DOS = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOD", &h_dummy1))) {
+               video->cap._DOD = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_ROM", &h_dummy1))) {
+               video->cap._ROM = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_GPD", &h_dummy1))) {
+               video->cap._GPD = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_SPD", &h_dummy1))) {
+               video->cap._SPD = 1;
+       }
+       if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_VPO", &h_dummy1))) {
+               video->cap._VPO = 1;
+       }
+}
+
+/*
+ * Check whether the video bus device has required AML method to
+ * support the desired features
+ */
+
+static int
+acpi_video_bus_check (
+       struct acpi_video_bus   *video)
+{
+       acpi_status             status = -ENOENT;
+
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_check");
+
+       if (!video)
+               return_VALUE(-EINVAL);
+
+       /* Since there is no HID, CID and so on for VGA driver, we have
+        * to check well known required nodes.
+        */
+
+       /* Does this device able to support video switching ? */
+       if(video->cap._DOS){
+               video->flags.multihead = 1;
+               status = 0;
+       }
+
+       /* Does this device able to retrieve a retrieve a video ROM ? */
+       if(video->cap._ROM){
+               video->flags.rom = 1;
+               status = 0;
+       }
+
+       /* Does this device able to configure which video device to POST ? */
+       if(video->cap._GPD && video->cap._SPD && video->cap._VPO){
+               video->flags.post = 1;
+               status = 0;
+       }
+
+       return_VALUE(status);
+}
+
+/* --------------------------------------------------------------------------
+                              FS Interface (/proc)
+   -------------------------------------------------------------------------- */
+
+struct proc_dir_entry          *acpi_video_dir;
+
+/* video devices */
+
+static int
+acpi_video_device_info_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_device        *dev = (struct acpi_video_device *) seq->private;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_info_seq_show");
+
+       if (!dev)
+               goto end;
+
+       seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
+       seq_printf(seq, "type:         ");
+       if (dev->flags.crt)
+               seq_printf(seq, "CRT\n");
+       else if (dev->flags.lcd)
+               seq_printf(seq, "LCD\n");
+       else if (dev->flags.tvout)
+               seq_printf(seq, "TVOUT\n");
+       else
+               seq_printf(seq, "UNKNOWN\n");
+
+       seq_printf(seq,"known by bios: %s\n",
+                  dev->flags.bios ? "yes":"no");
+
+end:
+       return_VALUE(0);
+}
+
+static int
+acpi_video_device_info_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_device_info_seq_show,
+                          PDE(inode)->data);
+}
+
+static int  
+acpi_video_device_state_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       int                     status;
+       struct acpi_video_device        *dev = (struct acpi_video_device *) seq->private;
+       unsigned long   state;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_state_seq_show");
+
+       if (!dev)
+               goto end;
+
+       status = acpi_video_device_get_state(dev, &state);
+       seq_printf(seq, "state:     ");
+       if (ACPI_SUCCESS(status))
+               seq_printf(seq, "0x%02lx\n", state);
+       else
+               seq_printf(seq, "<not supported>\n");
+
+       status = acpi_video_device_query(dev, &state);
+       seq_printf(seq, "query:     ");
+       if (ACPI_SUCCESS(status))
+               seq_printf(seq, "0x%02lx\n", state);
+       else
+               seq_printf(seq, "<not supported>\n");
+
+end:
+       return_VALUE(0);
+}
+
+static int
+acpi_video_device_state_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_device_state_seq_show,
+                          PDE(inode)->data);
+}
+
+static ssize_t
+acpi_video_device_write_state (
+       struct file             *file,
+       const char              __user *buffer,
+       size_t                  count,
+       loff_t                  *data)
+{
+       int                     status;
+       struct seq_file         *m = (struct seq_file *) file->private_data;
+       struct acpi_video_device        *dev = (struct acpi_video_device *) m->private;
+       char                    str[12] = {0};
+       u32                     state = 0;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_write_state");
+
+       if (!dev || count + 1 > sizeof str)
+               return_VALUE(-EINVAL);
+
+       if (copy_from_user(str, buffer, count))
+               return_VALUE(-EFAULT);
+
+       str[count] = 0;
+       state = simple_strtoul(str, NULL, 0);
+       state &= ((1ul<<31) | (1ul<<30) | (1ul<<0));
+
+       status = acpi_video_device_set_state(dev, state);
+
+       if (status)
+               return_VALUE(-EFAULT);
+
+       return_VALUE(count);
+}
+
+static int
+acpi_video_device_brightness_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_device        *dev = (struct acpi_video_device *) seq->private;
+       int                     i;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_brightness_seq_show");
+
+       if (!dev || !dev->brightness) {
+               seq_printf(seq, "<not supported>\n");
+               return_VALUE(0);
+       }
+
+       seq_printf(seq, "levels: ");
+       for (i = 0; i < dev->brightness->count; i++)
+               seq_printf(seq, " %d", dev->brightness->levels[i]);
+       seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
+
+       return_VALUE(0);
+}
+
+static int
+acpi_video_device_brightness_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_device_brightness_seq_show,
+                          PDE(inode)->data);
+}
+
+static ssize_t
+acpi_video_device_write_brightness (
+       struct file             *file,
+       const char              __user *buffer,
+       size_t                  count,
+       loff_t                  *data)
+{
+       struct seq_file         *m = (struct seq_file *) file->private_data;
+       struct acpi_video_device        *dev = (struct acpi_video_device *) m->private;
+       char                    str[4] = {0};
+       unsigned int            level = 0;
+       int                     i;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness");
+
+       if (!dev || count + 1 > sizeof str)
+               return_VALUE(-EINVAL);
+
+       if (copy_from_user(str, buffer, count))
+               return_VALUE(-EFAULT);
+
+       str[count] = 0;
+       level = simple_strtoul(str, NULL, 0);
+       
+       if (level > 100)
+               return_VALUE(-EFAULT);
+
+       /* validate though the list of available levels */
+       for (i = 0; i < dev->brightness->count; i++)
+               if (level == dev->brightness->levels[i]) {
+                       if (ACPI_SUCCESS(acpi_video_device_lcd_set_level(dev, level)))
+                               dev->brightness->curr = level;
+                       break;
+               }
+
+       return_VALUE(count);
+}
+
+static int
+acpi_video_device_EDID_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_device        *dev = (struct acpi_video_device *) seq->private;
+       int                     status;
+       int                     i;
+       union acpi_object       *edid = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_EDID_seq_show");
+
+       if (!dev)
+               goto out;
+
+       status = acpi_video_device_EDID (dev, &edid, 128);
+       if (ACPI_FAILURE(status)) {
+               status = acpi_video_device_EDID (dev, &edid, 256);
+       }
+
+       if (ACPI_FAILURE(status)) {
+               goto out;
+       }
+
+       if (edid && edid->type == ACPI_TYPE_BUFFER) {
+               for (i = 0; i < edid->buffer.length; i++)
+                       seq_putc(seq, edid->buffer.pointer[i]);
+       }
+
+out:
+       if (!edid)
+               seq_printf(seq, "<not supported>\n");
+       else
+               kfree(edid);
+
+       return_VALUE(0);
+}
+
+static int
+acpi_video_device_EDID_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_device_EDID_seq_show,
+                          PDE(inode)->data);
+}
+
+
+static int
+acpi_video_device_add_fs (
+       struct acpi_device      *device)
+{
+       struct proc_dir_entry   *entry = NULL;
+       struct acpi_video_device *vid_dev;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_add_fs");
+
+       if (!device)
+               return_VALUE(-ENODEV);
+
+       vid_dev = (struct acpi_video_device *) acpi_driver_data(device);
+       if (!vid_dev)
+               return_VALUE(-ENODEV);
+
+       if (!acpi_device_dir(device)) {
+               acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+                               vid_dev->video->dir);
+               if (!acpi_device_dir(device))
+                       return_VALUE(-ENODEV);
+               acpi_device_dir(device)->owner = THIS_MODULE;
+       }
+
+       /* 'info' [R] */
+       entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Unable to create 'info' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_device_info_fops;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'state' [R/W] */
+       entry = create_proc_entry("state", S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Unable to create 'state' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_device_state_fops;
+               entry->proc_fops->write = acpi_video_device_write_state;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'brightness' [R/W] */
+       entry = create_proc_entry("brightness", S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Unable to create 'brightness' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_device_brightness_fops;
+               entry->proc_fops->write = acpi_video_device_write_brightness;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'EDID' [R] */
+       entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Unable to create 'brightness' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_device_EDID_fops;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       return_VALUE(0);
+}
+
+static int
+acpi_video_device_remove_fs (
+       struct acpi_device      *device)
+{
+       struct acpi_video_device *vid_dev;
+       ACPI_FUNCTION_TRACE("acpi_video_device_remove_fs");
+
+       vid_dev = (struct acpi_video_device *) acpi_driver_data(device);
+       if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
+               return_VALUE(-ENODEV);
+
+       if (acpi_device_dir(device)) {
+               remove_proc_entry("info", acpi_device_dir(device));
+               remove_proc_entry("state", acpi_device_dir(device));
+               remove_proc_entry("brightness", acpi_device_dir(device));
+               remove_proc_entry("EDID", acpi_device_dir(device));
+               remove_proc_entry(acpi_device_bid(device),
+                                vid_dev->video->dir);
+               acpi_device_dir(device) = NULL;
+       }
+
+       return_VALUE(0);
+}
+
+
+/* video bus */
+static int
+acpi_video_bus_info_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) seq->private;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_info_seq_show");
+
+       if (!video)
+               goto end;
+
+       seq_printf(seq, "Switching heads:              %s\n",
+                       video->flags.multihead ? "yes":"no");
+       seq_printf(seq, "Video ROM:                    %s\n",
+                       video->flags.rom ? "yes":"no");
+       seq_printf(seq, "Device to be POSTed on boot:  %s\n",
+                       video->flags.post ? "yes":"no");
+
+end:
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_info_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_bus_info_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_ROM_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) seq->private;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_ROM_seq_show");
+
+       if (!video)
+               goto end;
+
+       printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__);
+       seq_printf(seq, "<TODO>\n");
+
+end:
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_ROM_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_POST_info_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) seq->private;
+       unsigned long           options;
+       int                     status;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_POST_info_seq_show");
+
+       if (!video)
+               goto end;
+
+       status = acpi_video_bus_POST_options(video, &options);
+       if (ACPI_SUCCESS(status)) {
+               if (!(options & 1)) {
+                       printk(KERN_WARNING PREFIX "The motherboard VGA device is not listed as a possible POST device.\n");
+                       printk(KERN_WARNING PREFIX "This indicate a BIOS bug.  Please contact the manufacturer.\n");
+               }
+               printk("%lx\n", options);
+               seq_printf(seq, "can POST: <intgrated video>");
+               if (options & 2)
+                       seq_printf(seq, " <PCI video>");
+               if (options & 4)
+                       seq_printf(seq, " <AGP video>");
+               seq_putc(seq, '\n');
+       } else
+               seq_printf(seq, "<not supported>\n");
+end:
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_POST_info_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_bus_POST_info_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_POST_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) seq->private;
+       int                     status;
+       unsigned long           id;
+       char                    device_decode[][30] = {
+                                       "motherboard VGA device",
+                                       "PCI VGA device",
+                                       "AGP VGA device",
+                                       "UNKNOWN",
+       };
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_POST_seq_show");
+
+       if (!video)
+               goto end;
+
+       status = acpi_video_bus_get_POST (video, &id);
+       if (!ACPI_SUCCESS(status)) {
+               seq_printf(seq, "<not supported>\n");
+               goto end;
+       }
+       seq_printf(seq, "device posted is <%s>\n",  device_decode[id & 3]);
+
+end:
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_DOS_seq_show (
+       struct seq_file         *seq,
+       void                    *offset)
+{
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) seq->private;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_DOS_seq_show");
+
+       seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting );
+
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_POST_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_bus_POST_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_DOS_open_fs (
+       struct inode            *inode,
+       struct file             *file)
+{
+       return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
+}
+
+static ssize_t
+acpi_video_bus_write_POST (
+       struct file             *file,
+       const char              __user *buffer,
+       size_t                  count,
+       loff_t                  *data)
+{
+       int                     status;
+       struct seq_file         *m = (struct seq_file *) file->private_data;
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) m->private;
+       char                    str[12] = {0};
+       unsigned long           opt, options;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_write_POST");
+
+
+       if (!video || count + 1 > sizeof str)
+               return_VALUE(-EINVAL);
+
+       status = acpi_video_bus_POST_options(video, &options);
+       if (!ACPI_SUCCESS(status))
+               return_VALUE(-EINVAL);
+
+       if (copy_from_user(str, buffer, count))
+               return_VALUE(-EFAULT);
+
+       str[count] = 0;
+       opt = strtoul(str, NULL, 0);
+       if (opt > 3)
+               return_VALUE(-EFAULT);
+
+       /* just in case an OEM 'forget' the motherboard... */
+       options |= 1;
+
+       if (options & (1ul << opt)) {
+               status = acpi_video_bus_set_POST (video, opt);
+               if (!ACPI_SUCCESS(status))
+                       return_VALUE(-EFAULT);
+
+       }
+
+
+       return_VALUE(count);
+}
+
+static ssize_t
+acpi_video_bus_write_DOS (
+       struct file             *file,
+       const char              __user *buffer,
+       size_t                  count,
+       loff_t                  *data)
+{
+       int                     status;
+       struct seq_file         *m = (struct seq_file *) file->private_data;
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) m->private;
+       char                    str[12] = {0};
+       unsigned long           opt;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_write_DOS");
+
+
+       if (!video || count + 1 > sizeof str)
+               return_VALUE(-EINVAL);
+
+       if (copy_from_user(str, buffer, count))
+               return_VALUE(-EFAULT);
+
+       str[count] = 0;
+       opt = strtoul(str, NULL, 0);
+       if (opt > 7)
+               return_VALUE(-EFAULT);
+
+       status = acpi_video_bus_DOS (video, opt & 0x3, (opt & 0x4)>>2);
+
+       if (!ACPI_SUCCESS(status))
+               return_VALUE(-EFAULT);
+
+       return_VALUE(count);
+}
+
+static int
+acpi_video_bus_add_fs (
+       struct acpi_device      *device)
+{
+       struct proc_dir_entry   *entry = NULL;
+       struct acpi_video_bus   *video;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_add_fs");
+
+       video = (struct acpi_video_bus *) acpi_driver_data(device);
+
+       if (!acpi_device_dir(device)) {
+               acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+                               acpi_video_dir);
+               if (!acpi_device_dir(device))
+                       return_VALUE(-ENODEV);
+               video->dir = acpi_device_dir(device);
+               acpi_device_dir(device)->owner = THIS_MODULE;
+       }
+
+       /* 'info' [R] */
+       entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'info' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_bus_info_fops;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'ROM' [R] */
+       entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'ROM' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_bus_ROM_fops;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'POST_info' [R] */
+       entry = create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST_info' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_bus_POST_info_fops;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'POST' [R/W] */
+       entry = create_proc_entry("POST", S_IFREG|S_IRUGO|S_IRUSR, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_bus_POST_fops;
+               entry->proc_fops->write = acpi_video_bus_write_POST;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       /* 'DOS' [R/W] */
+       entry = create_proc_entry("DOS", S_IFREG|S_IRUGO|S_IRUSR, acpi_device_dir(device));
+       if (!entry)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'DOS' fs entry\n"));
+       else {
+               entry->proc_fops = &acpi_video_bus_DOS_fops;
+               entry->proc_fops->write = acpi_video_bus_write_DOS;
+               entry->data = acpi_driver_data(device);
+               entry->owner = THIS_MODULE;
+       }
+
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_remove_fs (
+       struct acpi_device      *device)
+{
+       struct acpi_video_bus   *video;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_remove_fs");
+
+       video = (struct acpi_video_bus *) acpi_driver_data(device);
+
+       if (acpi_device_dir(device)) {
+               remove_proc_entry("info", acpi_device_dir(device));
+               remove_proc_entry("ROM", acpi_device_dir(device));
+               remove_proc_entry("POST_info", acpi_device_dir(device));
+               remove_proc_entry("POST", acpi_device_dir(device));
+               remove_proc_entry("DOS", acpi_device_dir(device));
+               remove_proc_entry(acpi_device_bid(device),
+                               acpi_video_dir); 
+               acpi_device_dir(device) = NULL;
+       }
+
+       return_VALUE(0);
+}
+
+/* --------------------------------------------------------------------------
+                                 Driver Interface
+   -------------------------------------------------------------------------- */
+
+/* device interface */
+
+static int
+acpi_video_bus_get_one_device (
+       struct acpi_device      *device,
+       struct acpi_video_bus   *video)
+{
+       unsigned long           device_id;
+       int                     status, result;
+       struct acpi_video_device        *data;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
+
+       if (!device || !video)
+               return_VALUE(-EINVAL);
+
+       status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+       if (ACPI_SUCCESS(status)) {
+
+               data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+               if (!data)
+                       return_VALUE(-ENOMEM);
+
+               memset(data, 0, sizeof(struct acpi_video_device));
+
+               data->handle = device->handle;
+               strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
+               strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+               acpi_driver_data(device) = data;
+
+               data->device_id = device_id;
+               data->video = video;
+               data->dev = device;
+
+               switch (device_id & 0xffff) {
+               case 0x0100:
+                       data->flags.crt = 1;
+                       break;
+               case 0x0400:
+                       data->flags.lcd = 1;
+                       break;
+               case 0x0200:
+                       data->flags.tvout = 1;
+                       break;
+               default:
+                       data->flags.unknown = 1;
+                       break;
+               }
+               
+               acpi_video_device_bind(video, data);
+               acpi_video_device_find_cap(data);
+
+               status = acpi_install_notify_handler(data->handle,
+                       ACPI_DEVICE_NOTIFY, acpi_video_device_notify, data);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                               "Error installing notify handler\n"));
+                       result = -ENODEV;
+                       goto end;
+               }
+
+               down(&video->sem);
+               list_add_tail(&data->entry, &video->video_device_list);
+               up(&video->sem);
+
+               acpi_video_device_add_fs(device);
+
+               return_VALUE(0);
+       }
+
+end:
+       return_VALUE(-ENOENT);
+}
+
+/*
+ *  Arg:
+ *     video   : video bus device 
+ *
+ *  Return:
+ *     none
+ *  
+ *  Enumerate the video device list of the video bus, 
+ *  bind the ids with the corresponding video devices
+ *  under the video bus.
+ */  
+
+static void
+acpi_video_device_rebind( struct acpi_video_bus *video)
+{
+       struct list_head * node, * next;
+       list_for_each_safe(node, next, &video->video_device_list) {
+               struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
+               acpi_video_device_bind( video, dev);
+       }
+}
+
+/*
+ *  Arg:
+ *     video   : video bus device 
+ *     device  : video output device under the video 
+ *             bus
+ *
+ *  Return:
+ *     none
+ *  
+ *  Bind the ids with the corresponding video devices
+ *  under the video bus.
+ */  
+
+static void
+acpi_video_device_bind( struct acpi_video_bus *video,
+                       struct acpi_video_device *device)
+{
+       int     i;
+       ACPI_FUNCTION_TRACE("acpi_video_device_bind");
+
+#define IDS_VAL(i) video->attached_array[i].value.int_val
+#define IDS_BIND(i) video->attached_array[i].bind_info
+       
+       for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID && 
+               i < video->attached_count; i++) {
+               if (device->device_id == (IDS_VAL(i)& 0xffff)) {
+                       IDS_BIND(i) = device;
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
+               }
+       }
+#undef IDS_VAL
+#undef IDS_BIND
+}
+
+/*
+ *  Arg:
+ *     video   : video bus device 
+ *
+ *  Return:
+ *     < 0     : error
+ *  
+ *  Call _DOD to enumerate all devices attached to display adapter
+ *
+ */  
+
+static int acpi_video_device_enumerate(struct acpi_video_bus *video)
+{
+       int                     status;
+       int                     count;
+       int                     i;
+       struct acpi_video_enumerated_device *active_device_list;
+       struct acpi_buffer      buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object       *dod = NULL;
+       union acpi_object       *obj;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
+
+       status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
+       if (!ACPI_SUCCESS(status)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
+               return_VALUE(status);
+       }
+
+       dod = (union acpi_object *) buffer.pointer;
+       if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
+               status = -EFAULT;
+               goto out;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
+               dod->package.count));
+
+       active_device_list= kmalloc(
+               dod->package.count*sizeof(struct acpi_video_enumerated_device),
+               GFP_KERNEL);
+
+       if (!active_device_list) {
+               status = -ENOMEM;
+               goto out;
+       }
+
+       count = 0;
+       for (i = 0; i < dod->package.count; i++) {
+               obj = (union acpi_object *) &dod->package.elements[i];
+
+               if (obj->type != ACPI_TYPE_INTEGER) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
+                       active_device_list[i].value.int_val = ACPI_VIDEO_HEAD_INVALID;
+               }
+               active_device_list[i].value.int_val = obj->integer.value;
+               active_device_list[i].bind_info = NULL;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, (int) obj->integer.value));
+               count++;
+       }
+       active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
+
+       if(video->attached_array)
+               kfree(video->attached_array);
+       
+       video->attached_array = active_device_list;
+       video->attached_count = count;
+out:
+       acpi_os_free(buffer.pointer);
+       return_VALUE(status);
+}
+
+/*
+ *  Arg:
+ *     video   : video bus device 
+ *     event   : Nontify Event
+ *
+ *  Return:
+ *     < 0     : error
+ *  
+ *     1. Find out the current active output device.
+ *     2. Identify the next output device to switch
+ *     3. call _DSS to do actual switch.
+ */  
+
+static int 
+acpi_video_switch_output(
+       struct acpi_video_bus *video, 
+       int     event)
+{
+       struct list_head * node, * next;
+       struct acpi_video_device *dev=NULL;
+               struct acpi_video_device *dev_next=NULL;
+       struct acpi_video_device *dev_prev=NULL;
+       unsigned long state;
+       int status = 0;
+
+       ACPI_FUNCTION_TRACE("acpi_video_switch_output");
+
+       list_for_each_safe(node, next, &video->video_device_list) {
+               struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
+               status = acpi_video_device_get_state(dev, &state);
+               if (state & 0x2){
+                       dev_next = container_of(node->next, struct acpi_video_device, entry);
+                       dev_prev = container_of(node->prev, struct acpi_video_device, entry);
+                       goto out;
+               }
+       }
+       dev_next = container_of(node->next, struct acpi_video_device, entry);
+       dev_prev = container_of(node->prev, struct acpi_video_device, entry);
+out:   
+       switch (event) {
+       case ACPI_VIDEO_NOTIFY_CYCLE:
+       case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
+               acpi_video_device_set_state(dev, 0);
+               acpi_video_device_set_state(dev_next, 0x80000001);
+               break;
+       case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
+               acpi_video_device_set_state(dev, 0);
+               acpi_video_device_set_state(dev_prev, 0x80000001);
+       default:
+               break;
+       }
+
+       return_VALUE(status);
+}
+
+static int 
+acpi_video_get_next_level(
+       struct acpi_video_device *device,
+       u32     level_current,
+       u32     event)
+{
+       /*Fix me*/
+       return level_current;
+}
+
+
+static void
+acpi_video_switch_brightness (
+       struct acpi_video_device *device, 
+       int     event)
+{
+       unsigned long level_current, level_next;
+       acpi_video_device_lcd_get_level_current(device, &level_current);
+       level_next = acpi_video_get_next_level(device, level_current, event);
+       acpi_video_device_lcd_set_level(device, level_next);
+}
+
+static int
+acpi_video_bus_get_devices (
+       struct acpi_video_bus   *video,
+       struct acpi_device      *device)
+{
+       int                     status = 0;
+       struct list_head        *node, *next;
+
+       ACPI_FUNCTION_TRACE("acpi_video_get_devices");
+
+       acpi_video_device_enumerate(video);
+
+       list_for_each_safe(node, next, &device->children) {
+               struct acpi_device *dev = list_entry(node, struct acpi_device, node);
+
+               if (!dev)
+                       continue;
+
+               status = acpi_video_bus_get_one_device(dev, video);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cant attach device\n"));
+                       continue;
+               }
+
+       }
+       return_VALUE(status);
+}
+
+static int
+acpi_video_bus_put_one_device(
+       struct acpi_video_device        *device)
+{
+       struct acpi_video_bus *video;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
+
+       if (!device || !device->video)
+               return_VALUE(-ENOENT);
+
+       video = device->video;
+
+       down(&video->sem);
+       list_del(&device->entry);
+       up(&video->sem);
+       acpi_video_device_remove_fs(device->dev);
+
+       return_VALUE(0);
+}
+
+static int
+acpi_video_bus_put_devices (
+       struct acpi_video_bus   *video)
+{
+       int                     status;
+       struct list_head        *node, *next;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
+
+       list_for_each_safe(node, next, &video->video_device_list) {
+               struct acpi_video_device *data = list_entry(node, struct acpi_video_device, entry);
+               if (!data)
+                       continue;
+
+               status = acpi_video_bus_put_one_device(data);
+               if(ACPI_FAILURE(status))
+                       printk(KERN_WARNING PREFIX "hhuuhhuu bug in acpi video driver.\n");
+
+               if (data->brightness)
+                       kfree(data->brightness);
+
+               kfree(data);
+       }
+
+       return_VALUE(0);
+}
+
+/* acpi_video interface */
+
+static int
+acpi_video_bus_start_devices(
+       struct acpi_video_bus   *video)
+{
+       return acpi_video_bus_DOS(video, 1, 0);
+}
+
+static int
+acpi_video_bus_stop_devices(
+       struct acpi_video_bus   *video)
+{
+       return acpi_video_bus_DOS(video, 0, 1);
+}
+
+static void
+acpi_video_bus_notify (
+       acpi_handle             handle,
+       u32                     event,
+       void                    *data)
+{
+       struct acpi_video_bus   *video = (struct acpi_video_bus *) data;
+       struct acpi_device      *device = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
+       printk("video bus notify\n");
+
+       if (!video)
+               return_VOID;
+
+       if (acpi_bus_get_device(handle, &device))
+               return_VOID;
+
+       switch (event) {
+       case ACPI_VIDEO_NOTIFY_SWITCH:  /* User request that a switch occur,
+                                        * most likely via hotkey. */
+               acpi_bus_generate_event(device, event, 0);
+               break;
+
+       case ACPI_VIDEO_NOTIFY_PROBE:   /* User plug or remove a video
+                                        * connector. */
+               acpi_video_device_enumerate(video);
+               acpi_video_device_rebind(video);
+               acpi_video_switch_output(video, event);
+               acpi_bus_generate_event(device, event, 0);
+               break;
+
+       case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed.*/
+       case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
+       case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
+               acpi_video_switch_output(video, event);
+               acpi_bus_generate_event(device, event, 0);
+               break;
+
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                       "Unsupported event [0x%x]\n", event));
+               break;
+       }
+
+       return_VOID;
+}
+
+static void
+acpi_video_device_notify (
+       acpi_handle             handle,
+       u32                     event,
+       void                    *data)
+{
+       struct acpi_video_device        *video_device = (struct acpi_video_device *) data;
+       struct acpi_device      *device = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_video_device_notify");
+
+       printk("video device notify\n");
+       if (!video_device)
+               return_VOID;
+
+       if (acpi_bus_get_device(handle, &device))
+               return_VOID;
+
+       switch (event) {
+       case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */
+       case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */
+               acpi_bus_generate_event(device, event, 0);
+               break;
+       case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
+       case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
+       case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
+       case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
+       case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
+               acpi_video_switch_brightness (video_device, event);
+               acpi_bus_generate_event(device, event, 0);
+               break;
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                       "Unsupported event [0x%x]\n", event));
+               break;
+       }
+       return_VOID;
+}
+
+static int
+acpi_video_bus_add (
+       struct acpi_device      *device)
+{
+       int                     result = 0;
+       acpi_status             status = 0;
+       struct acpi_video_bus   *video = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_add");
+       
+       if (!device)
+               return_VALUE(-EINVAL);
+
+       video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
+       if (!video)
+               return_VALUE(-ENOMEM);
+       memset(video, 0, sizeof(struct acpi_video_bus));
+
+       video->handle = device->handle;
+       strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
+       strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+       acpi_driver_data(device) = video;
+
+       acpi_video_bus_find_cap(video);
+       result = acpi_video_bus_check(video);
+       if (result)
+               goto end;
+
+       result = acpi_video_bus_add_fs(device);
+       if (result)
+               goto end;
+
+       init_MUTEX(&video->sem);
+       INIT_LIST_HEAD(&video->video_device_list);
+
+       acpi_video_bus_get_devices(video, device);
+       acpi_video_bus_start_devices(video);
+
+       status = acpi_install_notify_handler(video->handle,
+               ACPI_DEVICE_NOTIFY, acpi_video_bus_notify, video);
+       if (ACPI_FAILURE(status)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Error installing notify handler\n"));
+               result = -ENODEV;
+               goto end;
+       }
+
+       printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
+               ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
+               video->flags.multihead ? "yes":"no",
+               video->flags.rom ? "yes":"no",
+               video->flags.post ? "yes":"no");
+
+end:
+       if (result) {
+               acpi_video_bus_remove_fs(device);
+               kfree(video);
+       }
+
+       return_VALUE(result);
+}
+
+static int
+acpi_video_bus_remove (
+       struct acpi_device      *device,
+       int                     type)
+{
+       acpi_status             status = 0;
+       struct acpi_video_bus   *video = NULL;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
+
+       if (!device || !acpi_driver_data(device))
+               return_VALUE(-EINVAL);
+
+       video = (struct acpi_video_bus *) acpi_driver_data(device);
+
+       acpi_video_bus_stop_devices(video);
+
+       status = acpi_remove_notify_handler(video->handle,
+               ACPI_DEVICE_NOTIFY, acpi_video_bus_notify);
+       if (ACPI_FAILURE(status))
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Error removing notify handler\n"));
+
+       acpi_video_bus_put_devices(video);
+       acpi_video_bus_remove_fs(device);
+
+       if (video->attached_array)
+               kfree(video->attached_array);
+       kfree(video);
+
+       return_VALUE(0);
+}
+
+
+static int
+acpi_video_bus_match (
+       struct acpi_device      *device,
+       struct acpi_driver      *driver)
+{
+       acpi_handle             h_dummy1;
+       acpi_handle             h_dummy2;
+       acpi_handle             h_dummy3;
+
+       ACPI_FUNCTION_TRACE("acpi_video_bus_match");
+
+       if (!device || !driver)
+               return_VALUE(-EINVAL);
+
+       /* Since there is no HID, CID for ACPI Video drivers, we have
+        * to check well known required nodes for each feature we support.
+        */
+
+       /* Does this device able to support video switching ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+               return_VALUE(0);
+
+       /* Does this device able to retrieve a video ROM ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+               return_VALUE(0);
+
+       /* Does this device able to configure which video head to be POSTed ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+               return_VALUE(0);
+
+
+       return_VALUE(-ENODEV);
+}
+
+
+static int __init
+acpi_video_init (void)
+{
+       int                     result = 0;
+
+       ACPI_FUNCTION_TRACE("acpi_video_init");
+
+       /*
+       acpi_dbg_level = 0xFFFFFFFF;
+       acpi_dbg_layer = 0x08000000;
+       */
+
+       acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
+       if (!acpi_video_dir)
+               return_VALUE(-ENODEV);
+       acpi_video_dir->owner = THIS_MODULE;
+
+       result = acpi_bus_register_driver(&acpi_video_bus);
+       if (result < 0) {
+               remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+               return_VALUE(-ENODEV);
+       }
+
+       return_VALUE(0);
+}
+
+static void __exit
+acpi_video_exit (void)
+{
+       ACPI_FUNCTION_TRACE("acpi_video_exit");
+
+       acpi_bus_unregister_driver(&acpi_video_bus);
+
+       remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+
+       return_VOID;
+}
+
+module_init(acpi_video_init);
+module_exit(acpi_video_exit);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
new file mode 100644 (file)
index 0000000..03a9388
--- /dev/null
@@ -0,0 +1,2679 @@
+/*
+ * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
+ * DVD-RW devices (aka an exercise in block layer masturbation)
+ *
+ *
+ * TODO: (circa order of when I will fix it)
+ * - Only able to write on CD-RW media right now.
+ * - check host application code on media and set it in write page
+ * - interface for UDF <-> packet to negotiate a new location when a write
+ *   fails.
+ * - handle OPC, especially for -RW media
+ *
+ * Theory of operation:
+ *
+ * We use a custom make_request_fn function that forwards reads directly to
+ * the underlying CD device. Write requests are either attached directly to
+ * a live packet_data object, or simply stored sequentially in a list for
+ * later processing by the kcdrwd kernel thread. This driver doesn't use
+ * any elevator functionally as defined by the elevator_s struct, but the
+ * underlying CD device uses a standard elevator.
+ *
+ * This strategy makes it possible to do very late merging of IO requests.
+ * A new bio sent to pkt_make_request can be merged with a live packet_data
+ * object even if the object is in the data gathering state.
+ *
+ *************************************************************************/
+
+#define VERSION_CODE   "v0.2.0a 2004-07-14 Jens Axboe (axboe@suse.de) and petero2@telia.com"
+
+#include <linux/pktcdvd.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/file.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/miscdevice.h>
+#include <linux/suspend.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <asm/uaccess.h>
+
+#if PACKET_DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#if PACKET_DEBUG > 1
+#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
+#else
+#define VPRINTK(fmt, args...)
+#endif
+
+#define MAX_SPEED 0xffff
+
+#define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1))
+
+static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
+static struct proc_dir_entry *pkt_proc;
+static int pkt_major;
+static struct semaphore ctl_mutex;     /* Serialize open/close/setup/teardown */
+static mempool_t *psd_pool;
+
+
+static void pkt_bio_finished(struct pktcdvd_device *pd)
+{
+       BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
+       if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
+               VPRINTK("pktcdvd: queue empty\n");
+               atomic_set(&pd->iosched.attention, 1);
+               wake_up(&pd->wqueue);
+       }
+}
+
+static void pkt_bio_destructor(struct bio *bio)
+{
+       kfree(bio->bi_io_vec);
+       kfree(bio);
+}
+
+static struct bio *pkt_bio_alloc(int nr_iovecs)
+{
+       struct bio_vec *bvl = NULL;
+       struct bio *bio;
+
+       bio = kmalloc(sizeof(struct bio), GFP_KERNEL);
+       if (!bio)
+               goto no_bio;
+       bio_init(bio);
+
+       bvl = kmalloc(nr_iovecs * sizeof(struct bio_vec), GFP_KERNEL);
+       if (!bvl)
+               goto no_bvl;
+       memset(bvl, 0, nr_iovecs * sizeof(struct bio_vec));
+
+       bio->bi_max_vecs = nr_iovecs;
+       bio->bi_io_vec = bvl;
+       bio->bi_destructor = pkt_bio_destructor;
+
+       return bio;
+
+ no_bvl:
+       kfree(bio);
+ no_bio:
+       return NULL;
+}
+
+/*
+ * Allocate a packet_data struct
+ */
+static struct packet_data *pkt_alloc_packet_data(void)
+{
+       int i;
+       struct packet_data *pkt;
+
+       pkt = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+       if (!pkt)
+               goto no_pkt;
+       memset(pkt, 0, sizeof(struct packet_data));
+
+       pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE);
+       if (!pkt->w_bio)
+               goto no_bio;
+
+       for (i = 0; i < PAGES_PER_PACKET; i++) {
+               pkt->pages[i] = alloc_page(GFP_KERNEL);
+               if (!pkt->pages[i])
+                       goto no_page;
+       }
+       for (i = 0; i < PAGES_PER_PACKET; i++)
+               clear_page(page_address(pkt->pages[i]));
+
+       spin_lock_init(&pkt->lock);
+
+       for (i = 0; i < PACKET_MAX_SIZE; i++) {
+               struct bio *bio = pkt_bio_alloc(1);
+               if (!bio)
+                       goto no_rd_bio;
+               pkt->r_bios[i] = bio;
+       }
+
+       return pkt;
+
+no_rd_bio:
+       for (i = 0; i < PACKET_MAX_SIZE; i++) {
+               struct bio *bio = pkt->r_bios[i];
+               if (bio)
+                       bio_put(bio);
+       }
+
+no_page:
+       for (i = 0; i < PAGES_PER_PACKET; i++)
+               if (pkt->pages[i])
+                       __free_page(pkt->pages[i]);
+       bio_put(pkt->w_bio);
+no_bio:
+       kfree(pkt);
+no_pkt:
+       return NULL;
+}
+
+/*
+ * Free a packet_data struct
+ */
+static void pkt_free_packet_data(struct packet_data *pkt)
+{
+       int i;
+
+       for (i = 0; i < PACKET_MAX_SIZE; i++) {
+               struct bio *bio = pkt->r_bios[i];
+               if (bio)
+                       bio_put(bio);
+       }
+       for (i = 0; i < PAGES_PER_PACKET; i++)
+               __free_page(pkt->pages[i]);
+       bio_put(pkt->w_bio);
+       kfree(pkt);
+}
+
+static void pkt_shrink_pktlist(struct pktcdvd_device *pd)
+{
+       struct packet_data *pkt, *next;
+
+       BUG_ON(!list_empty(&pd->cdrw.pkt_active_list));
+
+       list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) {
+               pkt_free_packet_data(pkt);
+       }
+}
+
+static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets)
+{
+       struct packet_data *pkt;
+
+       INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
+       INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
+       spin_lock_init(&pd->cdrw.active_list_lock);
+       while (nr_packets > 0) {
+               pkt = pkt_alloc_packet_data();
+               if (!pkt) {
+                       pkt_shrink_pktlist(pd);
+                       return 0;
+               }
+               pkt->id = nr_packets;
+               pkt->pd = pd;
+               list_add(&pkt->list, &pd->cdrw.pkt_free_list);
+               nr_packets--;
+       }
+       return 1;
+}
+
+static void *pkt_rb_alloc(int gfp_mask, void *data)
+{
+       return kmalloc(sizeof(struct pkt_rb_node), gfp_mask);
+}
+
+static void pkt_rb_free(void *ptr, void *data)
+{
+       kfree(ptr);
+}
+
+static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node)
+{
+       struct rb_node *n = rb_next(&node->rb_node);
+       if (!n)
+               return NULL;
+       return rb_entry(n, struct pkt_rb_node, rb_node);
+}
+
+static inline void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
+{
+       rb_erase(&node->rb_node, &pd->bio_queue);
+       mempool_free(node, pd->rb_pool);
+       pd->bio_queue_size--;
+       BUG_ON(pd->bio_queue_size < 0);
+}
+
+/*
+ * Find the first node in the pd->bio_queue rb tree with a starting sector >= s.
+ */
+static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s)
+{
+       struct rb_node *n = pd->bio_queue.rb_node;
+       struct rb_node *next;
+       struct pkt_rb_node *tmp;
+
+       if (!n) {
+               BUG_ON(pd->bio_queue_size > 0);
+               return NULL;
+       }
+
+       for (;;) {
+               tmp = rb_entry(n, struct pkt_rb_node, rb_node);
+               if (s <= tmp->bio->bi_sector)
+                       next = n->rb_left;
+               else
+                       next = n->rb_right;
+               if (!next)
+                       break;
+               n = next;
+       }
+
+       if (s > tmp->bio->bi_sector) {
+               tmp = pkt_rbtree_next(tmp);
+               if (!tmp)
+                       return NULL;
+       }
+       BUG_ON(s > tmp->bio->bi_sector);
+       return tmp;
+}
+
+/*
+ * Insert a node into the pd->bio_queue rb tree.
+ */
+static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *node)
+{
+       struct rb_node **p = &pd->bio_queue.rb_node;
+       struct rb_node *parent = NULL;
+       sector_t s = node->bio->bi_sector;
+       struct pkt_rb_node *tmp;
+
+       while (*p) {
+               parent = *p;
+               tmp = rb_entry(parent, struct pkt_rb_node, rb_node);
+               if (s < tmp->bio->bi_sector)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&node->rb_node, parent, p);
+       rb_insert_color(&node->rb_node, &pd->bio_queue);
+       pd->bio_queue_size++;
+}
+
+/*
+ * Add a bio to a single linked list defined by its head and tail pointers.
+ */
+static inline void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
+{
+       bio->bi_next = NULL;
+       if (*list_tail) {
+               BUG_ON((*list_head) == NULL);
+               (*list_tail)->bi_next = bio;
+               (*list_tail) = bio;
+       } else {
+               BUG_ON((*list_head) != NULL);
+               (*list_head) = bio;
+               (*list_tail) = bio;
+       }
+}
+
+/*
+ * Remove and return the first bio from a single linked list defined by its
+ * head and tail pointers.
+ */
+static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio **list_tail)
+{
+       struct bio *bio;
+
+       if (*list_head == NULL)
+               return NULL;
+
+       bio = *list_head;
+       *list_head = bio->bi_next;
+       if (*list_head == NULL)
+               *list_tail = NULL;
+
+       bio->bi_next = NULL;
+       return bio;
+}
+
+/*
+ * Send a packet_command to the underlying block device and
+ * wait for completion.
+ */
+static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
+{
+       char sense[SCSI_SENSE_BUFFERSIZE];
+       request_queue_t *q;
+       struct request *rq;
+       DECLARE_COMPLETION(wait);
+       int err = 0;
+
+       q = bdev_get_queue(pd->bdev);
+
+       rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ,
+                            __GFP_WAIT);
+       rq->errors = 0;
+       rq->rq_disk = pd->bdev->bd_disk;
+       rq->bio = NULL;
+       rq->buffer = NULL;
+       rq->timeout = 60*HZ;
+       rq->data = cgc->buffer;
+       rq->data_len = cgc->buflen;
+       rq->sense = sense;
+       memset(sense, 0, sizeof(sense));
+       rq->sense_len = 0;
+       rq->flags |= REQ_BLOCK_PC | REQ_HARDBARRIER;
+       if (cgc->quiet)
+               rq->flags |= REQ_QUIET;
+       memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
+       if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
+               memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
+
+       rq->ref_count++;
+       rq->flags |= REQ_NOMERGE;
+       rq->waiting = &wait;
+       elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+       generic_unplug_device(q);
+       wait_for_completion(&wait);
+
+       if (rq->errors)
+               err = -EIO;
+
+       blk_put_request(rq);
+       return err;
+}
+
+/*
+ * A generic sense dump / resolve mechanism should be implemented across
+ * all ATAPI + SCSI devices.
+ */
+static void pkt_dump_sense(struct packet_command *cgc)
+{
+       static char *info[9] = { "No sense", "Recovered error", "Not ready",
+                                "Medium error", "Hardware error", "Illegal request",
+                                "Unit attention", "Data protect", "Blank check" };
+       int i;
+       struct request_sense *sense = cgc->sense;
+
+       printk("pktcdvd:");
+       for (i = 0; i < CDROM_PACKET_SIZE; i++)
+               printk(" %02x", cgc->cmd[i]);
+       printk(" - ");
+
+       if (sense == NULL) {
+               printk("no sense\n");
+               return;
+       }
+
+       printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq);
+
+       if (sense->sense_key > 8) {
+               printk(" (INVALID)\n");
+               return;
+       }
+
+       printk(" (%s)\n", info[sense->sense_key]);
+}
+
+/*
+ * flush the drive cache to media
+ */
+static int pkt_flush_cache(struct pktcdvd_device *pd)
+{
+       struct packet_command cgc;
+
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+       cgc.cmd[0] = GPCMD_FLUSH_CACHE;
+       cgc.quiet = 1;
+
+       /*
+        * the IMMED bit -- we default to not setting it, although that
+        * would allow a much faster close, this is safer
+        */
+#if 0
+       cgc.cmd[1] = 1 << 1;
+#endif
+       return pkt_generic_packet(pd, &cgc);
+}
+
+/*
+ * speed is given as the normal factor, e.g. 4 for 4x
+ */
+static int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed, unsigned read_speed)
+{
+       struct packet_command cgc;
+       struct request_sense sense;
+       int ret;
+
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+       cgc.sense = &sense;
+       cgc.cmd[0] = GPCMD_SET_SPEED;
+       cgc.cmd[2] = (read_speed >> 8) & 0xff;
+       cgc.cmd[3] = read_speed & 0xff;
+       cgc.cmd[4] = (write_speed >> 8) & 0xff;
+       cgc.cmd[5] = write_speed & 0xff;
+
+       if ((ret = pkt_generic_packet(pd, &cgc)))
+               pkt_dump_sense(&cgc);
+
+       return ret;
+}
+
+/*
+ * Queue a bio for processing by the low-level CD device. Must be called
+ * from process context.
+ */
+static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio, int high_prio_read)
+{
+       spin_lock(&pd->iosched.lock);
+       if (bio_data_dir(bio) == READ) {
+               pkt_add_list_last(bio, &pd->iosched.read_queue,
+                                 &pd->iosched.read_queue_tail);
+               if (high_prio_read)
+                       pd->iosched.high_prio_read = 1;
+       } else {
+               pkt_add_list_last(bio, &pd->iosched.write_queue,
+                                 &pd->iosched.write_queue_tail);
+       }
+       spin_unlock(&pd->iosched.lock);
+
+       atomic_set(&pd->iosched.attention, 1);
+       wake_up(&pd->wqueue);
+}
+
+/*
+ * Process the queued read/write requests. This function handles special
+ * requirements for CDRW drives:
+ * - A cache flush command must be inserted before a read request if the
+ *   previous request was a write.
+ * - Switching between reading and writing is slow, so don't it more often
+ *   than necessary.
+ * - Set the read speed according to current usage pattern. When only reading
+ *   from the device, it's best to use the highest possible read speed, but
+ *   when switching often between reading and writing, it's better to have the
+ *   same read and write speeds.
+ * - Reads originating from user space should have higher priority than reads
+ *   originating from pkt_gather_data, because some process is usually waiting
+ *   on reads of the first kind.
+ */
+static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
+{
+       request_queue_t *q;
+
+       if (atomic_read(&pd->iosched.attention) == 0)
+               return;
+       atomic_set(&pd->iosched.attention, 0);
+
+       q = bdev_get_queue(pd->bdev);
+
+       for (;;) {
+               struct bio *bio;
+               int reads_queued, writes_queued, high_prio_read;
+
+               spin_lock(&pd->iosched.lock);
+               reads_queued = (pd->iosched.read_queue != NULL);
+               writes_queued = (pd->iosched.write_queue != NULL);
+               if (!reads_queued)
+                       pd->iosched.high_prio_read = 0;
+               high_prio_read = pd->iosched.high_prio_read;
+               spin_unlock(&pd->iosched.lock);
+
+               if (!reads_queued && !writes_queued)
+                       break;
+
+               if (pd->iosched.writing) {
+                       if (high_prio_read || (!writes_queued && reads_queued)) {
+                               if (atomic_read(&pd->cdrw.pending_bios) > 0) {
+                                       VPRINTK("pktcdvd: write, waiting\n");
+                                       break;
+                               }
+                               pkt_flush_cache(pd);
+                               pd->iosched.writing = 0;
+                       }
+               } else {
+                       if (!reads_queued && writes_queued) {
+                               if (atomic_read(&pd->cdrw.pending_bios) > 0) {
+                                       VPRINTK("pktcdvd: read, waiting\n");
+                                       break;
+                               }
+                               pd->iosched.writing = 1;
+                       }
+               }
+
+               spin_lock(&pd->iosched.lock);
+               if (pd->iosched.writing) {
+                       bio = pkt_get_list_first(&pd->iosched.write_queue,
+                                                &pd->iosched.write_queue_tail);
+               } else {
+                       bio = pkt_get_list_first(&pd->iosched.read_queue,
+                                                &pd->iosched.read_queue_tail);
+               }
+               spin_unlock(&pd->iosched.lock);
+
+               if (!bio)
+                       continue;
+
+               if (bio_data_dir(bio) == READ)
+                       pd->iosched.successive_reads += bio->bi_size >> 10;
+               else
+                       pd->iosched.successive_reads = 0;
+               if (pd->iosched.successive_reads >= HI_SPEED_SWITCH) {
+                       if (pd->read_speed == pd->write_speed) {
+                               pd->read_speed = MAX_SPEED;
+                               pkt_set_speed(pd, pd->write_speed, pd->read_speed);
+                       }
+               } else {
+                       if (pd->read_speed != pd->write_speed) {
+                               pd->read_speed = pd->write_speed;
+                               pkt_set_speed(pd, pd->write_speed, pd->read_speed);
+                       }
+               }
+
+               atomic_inc(&pd->cdrw.pending_bios);
+               generic_make_request(bio);
+       }
+}
+
+/*
+ * Special care is needed if the underlying block device has a small
+ * max_phys_segments value.
+ */
+static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q)
+{
+       if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) {
+               /*
+                * The cdrom device can handle one segment/frame
+                */
+               clear_bit(PACKET_MERGE_SEGS, &pd->flags);
+               return 0;
+       } else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) {
+               /*
+                * We can handle this case at the expense of some extra memory
+                * copies during write operations
+                */
+               set_bit(PACKET_MERGE_SEGS, &pd->flags);
+               return 0;
+       } else {
+               printk("pktcdvd: cdrom max_phys_segments too small\n");
+               return -EIO;
+       }
+}
+
+/*
+ * Copy CD_FRAMESIZE bytes from src_bio into a destination page
+ */
+static void pkt_copy_bio_data(struct bio *src_bio, int seg, int offs,
+                             struct page *dst_page, int dst_offs)
+{
+       unsigned int copy_size = CD_FRAMESIZE;
+
+       while (copy_size > 0) {
+               struct bio_vec *src_bvl = bio_iovec_idx(src_bio, seg);
+               void *vfrom = kmap_atomic(src_bvl->bv_page, KM_USER0) +
+                       src_bvl->bv_offset + offs;
+               void *vto = page_address(dst_page) + dst_offs;
+               int len = min_t(int, copy_size, src_bvl->bv_len - offs);
+
+               BUG_ON(len < 0);
+               memcpy(vto, vfrom, len);
+               kunmap_atomic(vfrom, KM_USER0);
+
+               seg++;
+               offs = 0;
+               dst_offs += len;
+               copy_size -= len;
+       }
+}
+
+/*
+ * Copy all data for this packet to pkt->pages[], so that
+ * a) The number of required segments for the write bio is minimized, which
+ *    is necessary for some scsi controllers.
+ * b) The data can be used as cache to avoid read requests if we receive a
+ *    new write request for the same zone.
+ */
+static void pkt_make_local_copy(struct packet_data *pkt, struct page **pages, int *offsets)
+{
+       int f, p, offs;
+
+       /* Copy all data to pkt->pages[] */
+       p = 0;
+       offs = 0;
+       for (f = 0; f < pkt->frames; f++) {
+               if (pages[f] != pkt->pages[p]) {
+                       void *vfrom = kmap_atomic(pages[f], KM_USER0) + offsets[f];
+                       void *vto = page_address(pkt->pages[p]) + offs;
+                       memcpy(vto, vfrom, CD_FRAMESIZE);
+                       kunmap_atomic(vfrom, KM_USER0);
+                       pages[f] = pkt->pages[p];
+                       offsets[f] = offs;
+               } else {
+                       BUG_ON(offsets[f] != offs);
+               }
+               offs += CD_FRAMESIZE;
+               if (offs >= PAGE_SIZE) {
+                       BUG_ON(offs > PAGE_SIZE);
+                       offs = 0;
+                       p++;
+               }
+       }
+}
+
+static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
+{
+       struct packet_data *pkt = bio->bi_private;
+       struct pktcdvd_device *pd = pkt->pd;
+       BUG_ON(!pd);
+
+       if (bio->bi_size)
+               return 1;
+
+       VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio,
+               (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err);
+
+       if (err)
+               atomic_inc(&pkt->io_errors);
+       if (atomic_dec_and_test(&pkt->io_wait)) {
+               atomic_inc(&pkt->run_sm);
+               wake_up(&pd->wqueue);
+       }
+       pkt_bio_finished(pd);
+
+       return 0;
+}
+
+static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err)
+{
+       struct packet_data *pkt = bio->bi_private;
+       struct pktcdvd_device *pd = pkt->pd;
+       BUG_ON(!pd);
+
+       if (bio->bi_size)
+               return 1;
+
+       VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err);
+
+       pd->stats.pkt_ended++;
+
+       pkt_bio_finished(pd);
+       atomic_dec(&pkt->io_wait);
+       atomic_inc(&pkt->run_sm);
+       wake_up(&pd->wqueue);
+       return 0;
+}
+
+/*
+ * Schedule reads for the holes in a packet
+ */
+static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
+{
+       int frames_read = 0;
+       struct bio *bio;
+       int f;
+       char written[PACKET_MAX_SIZE];
+
+       BUG_ON(!pkt->orig_bios);
+
+       atomic_set(&pkt->io_wait, 0);
+       atomic_set(&pkt->io_errors, 0);
+
+       if (pkt->cache_valid) {
+               VPRINTK("pkt_gather_data: zone %llx cached\n",
+                       (unsigned long long)pkt->sector);
+               goto out_account;
+       }
+
+       /*
+        * Figure out which frames we need to read before we can write.
+        */
+       memset(written, 0, sizeof(written));
+       spin_lock(&pkt->lock);
+       for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
+               int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
+               int num_frames = bio->bi_size / CD_FRAMESIZE;
+               BUG_ON(first_frame < 0);
+               BUG_ON(first_frame + num_frames > pkt->frames);
+               for (f = first_frame; f < first_frame + num_frames; f++)
+                       written[f] = 1;
+       }
+       spin_unlock(&pkt->lock);
+
+       /*
+        * Schedule reads for missing parts of the packet.
+        */
+       for (f = 0; f < pkt->frames; f++) {
+               int p, offset;
+               if (written[f])
+                       continue;
+               bio = pkt->r_bios[f];
+               bio_init(bio);
+               bio->bi_max_vecs = 1;
+               bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
+               bio->bi_bdev = pd->bdev;
+               bio->bi_end_io = pkt_end_io_read;
+               bio->bi_private = pkt;
+
+               p = (f * CD_FRAMESIZE) / PAGE_SIZE;
+               offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
+               VPRINTK("pkt_gather_data: Adding frame %d, page:%p offs:%d\n",
+                       f, pkt->pages[p], offset);
+               if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset))
+                       BUG();
+
+               atomic_inc(&pkt->io_wait);
+               bio->bi_rw = READ;
+               pkt_queue_bio(pd, bio, 0);
+               frames_read++;
+       }
+
+out_account:
+       VPRINTK("pkt_gather_data: need %d frames for zone %llx\n",
+               frames_read, (unsigned long long)pkt->sector);
+       pd->stats.pkt_started++;
+       pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
+       pd->stats.secs_w += pd->settings.size;
+}
+
+/*
+ * Find a packet matching zone, or the least recently used packet if
+ * there is no match.
+ */
+static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zone)
+{
+       struct packet_data *pkt;
+
+       list_for_each_entry(pkt, &pd->cdrw.pkt_free_list, list) {
+               if (pkt->sector == zone || pkt->list.next == &pd->cdrw.pkt_free_list) {
+                       list_del_init(&pkt->list);
+                       if (pkt->sector != zone)
+                               pkt->cache_valid = 0;
+                       break;
+               }
+       }
+       return pkt;
+}
+
+static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt)
+{
+       if (pkt->cache_valid) {
+               list_add(&pkt->list, &pd->cdrw.pkt_free_list);
+       } else {
+               list_add_tail(&pkt->list, &pd->cdrw.pkt_free_list);
+       }
+}
+
+/*
+ * recover a failed write, query for relocation if possible
+ *
+ * returns 1 if recovery is possible, or 0 if not
+ *
+ */
+static int pkt_start_recovery(struct packet_data *pkt)
+{
+       /*
+        * FIXME. We need help from the file system to implement
+        * recovery handling.
+        */
+       return 0;
+#if 0
+       struct request *rq = pkt->rq;
+       struct pktcdvd_device *pd = rq->rq_disk->private_data;
+       struct block_device *pkt_bdev;
+       struct super_block *sb = NULL;
+       unsigned long old_block, new_block;
+       sector_t new_sector;
+
+       pkt_bdev = bdget(kdev_t_to_nr(pd->pkt_dev));
+       if (pkt_bdev) {
+               sb = get_super(pkt_bdev);
+               bdput(pkt_bdev);
+       }
+
+       if (!sb)
+               return 0;
+
+       if (!sb->s_op || !sb->s_op->relocate_blocks)
+               goto out;
+
+       old_block = pkt->sector / (CD_FRAMESIZE >> 9);
+       if (sb->s_op->relocate_blocks(sb, old_block, &new_block))
+               goto out;
+
+       new_sector = new_block * (CD_FRAMESIZE >> 9);
+       pkt->sector = new_sector;
+
+       pkt->bio->bi_sector = new_sector;
+       pkt->bio->bi_next = NULL;
+       pkt->bio->bi_flags = 1 << BIO_UPTODATE;
+       pkt->bio->bi_idx = 0;
+
+       BUG_ON(pkt->bio->bi_rw != (1 << BIO_RW));
+       BUG_ON(pkt->bio->bi_vcnt != pkt->frames);
+       BUG_ON(pkt->bio->bi_size != pkt->frames * CD_FRAMESIZE);
+       BUG_ON(pkt->bio->bi_end_io != pkt_end_io_packet_write);
+       BUG_ON(pkt->bio->bi_private != pkt);
+
+       drop_super(sb);
+       return 1;
+
+out:
+       drop_super(sb);
+       return 0;
+#endif
+}
+
+static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state state)
+{
+#if PACKET_DEBUG > 1
+       static const char *state_name[] = {
+               "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED"
+       };
+       enum packet_data_state old_state = pkt->state;
+       VPRINTK("pkt %2d : s=%6llx %s -> %s\n", pkt->id, (unsigned long long)pkt->sector,
+               state_name[old_state], state_name[state]);
+#endif
+       pkt->state = state;
+}
+
+/*
+ * Scan the work queue to see if we can start a new packet.
+ * returns non-zero if any work was done.
+ */
+static int pkt_handle_queue(struct pktcdvd_device *pd)
+{
+       struct packet_data *pkt, *p;
+       struct bio *bio = NULL;
+       sector_t zone = 0; /* Suppress gcc warning */
+       struct pkt_rb_node *node, *first_node;
+       struct rb_node *n;
+
+       VPRINTK("handle_queue\n");
+
+       atomic_set(&pd->scan_queue, 0);
+
+       if (list_empty(&pd->cdrw.pkt_free_list)) {
+               VPRINTK("handle_queue: no pkt\n");
+               return 0;
+       }
+
+       /*
+        * Try to find a zone we are not already working on.
+        */
+       spin_lock(&pd->lock);
+       first_node = pkt_rbtree_find(pd, pd->current_sector);
+       if (!first_node) {
+               n = rb_first(&pd->bio_queue);
+               if (n)
+                       first_node = rb_entry(n, struct pkt_rb_node, rb_node);
+       }
+       node = first_node;
+       while (node) {
+               bio = node->bio;
+               zone = ZONE(bio->bi_sector, pd);
+               list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
+                       if (p->sector == zone)
+                               goto try_next_bio;
+               }
+               break;
+try_next_bio:
+               node = pkt_rbtree_next(node);
+               if (!node) {
+                       n = rb_first(&pd->bio_queue);
+                       if (n)
+                               node = rb_entry(n, struct pkt_rb_node, rb_node);
+               }
+               if (node == first_node)
+                       node = NULL;
+       }
+       spin_unlock(&pd->lock);
+       if (!bio) {
+               VPRINTK("handle_queue: no bio\n");
+               return 0;
+       }
+
+       pkt = pkt_get_packet_data(pd, zone);
+       BUG_ON(!pkt);
+
+       pd->current_sector = zone + pd->settings.size;
+       pkt->sector = zone;
+       pkt->frames = pd->settings.size >> 2;
+       BUG_ON(pkt->frames > PACKET_MAX_SIZE);
+       pkt->write_size = 0;
+
+       /*
+        * Scan work queue for bios in the same zone and link them
+        * to this packet.
+        */
+       spin_lock(&pd->lock);
+       VPRINTK("pkt_handle_queue: looking for zone %llx\n", (unsigned long long)zone);
+       while ((node = pkt_rbtree_find(pd, zone)) != NULL) {
+               bio = node->bio;
+               VPRINTK("pkt_handle_queue: found zone=%llx\n",
+                       (unsigned long long)ZONE(bio->bi_sector, pd));
+               if (ZONE(bio->bi_sector, pd) != zone)
+                       break;
+               pkt_rbtree_erase(pd, node);
+               spin_lock(&pkt->lock);
+               pkt_add_list_last(bio, &pkt->orig_bios, &pkt->orig_bios_tail);
+               pkt->write_size += bio->bi_size / CD_FRAMESIZE;
+               spin_unlock(&pkt->lock);
+       }
+       spin_unlock(&pd->lock);
+
+       pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
+       pkt_set_state(pkt, PACKET_WAITING_STATE);
+       atomic_set(&pkt->run_sm, 1);
+
+       spin_lock(&pd->cdrw.active_list_lock);
+       list_add(&pkt->list, &pd->cdrw.pkt_active_list);
+       spin_unlock(&pd->cdrw.active_list_lock);
+
+       return 1;
+}
+
+/*
+ * Assemble a bio to write one packet and queue the bio for processing
+ * by the underlying block device.
+ */
+static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
+{
+       struct bio *bio;
+       struct page *pages[PACKET_MAX_SIZE];
+       int offsets[PACKET_MAX_SIZE];
+       int f;
+       int frames_write;
+
+       for (f = 0; f < pkt->frames; f++) {
+               pages[f] = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE];
+               offsets[f] = (f * CD_FRAMESIZE) % PAGE_SIZE;
+       }
+
+       /*
+        * Fill-in pages[] and offsets[] with data from orig_bios.
+        */
+       frames_write = 0;
+       spin_lock(&pkt->lock);
+       for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
+               int segment = bio->bi_idx;
+               int src_offs = 0;
+               int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
+               int num_frames = bio->bi_size / CD_FRAMESIZE;
+               BUG_ON(first_frame < 0);
+               BUG_ON(first_frame + num_frames > pkt->frames);
+               for (f = first_frame; f < first_frame + num_frames; f++) {
+                       struct bio_vec *src_bvl = bio_iovec_idx(bio, segment);
+
+                       while (src_offs >= src_bvl->bv_len) {
+                               src_offs -= src_bvl->bv_len;
+                               segment++;
+                               BUG_ON(segment >= bio->bi_vcnt);
+                               src_bvl = bio_iovec_idx(bio, segment);
+                       }
+
+                       if (src_bvl->bv_len - src_offs >= CD_FRAMESIZE) {
+                               pages[f] = src_bvl->bv_page;
+                               offsets[f] = src_bvl->bv_offset + src_offs;
+                       } else {
+                               pkt_copy_bio_data(bio, segment, src_offs,
+                                                 pages[f], offsets[f]);
+                       }
+                       src_offs += CD_FRAMESIZE;
+                       frames_write++;
+               }
+       }
+       pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE);
+       spin_unlock(&pkt->lock);
+
+       VPRINTK("pkt_start_write: Writing %d frames for zone %llx\n",
+               frames_write, (unsigned long long)pkt->sector);
+       BUG_ON(frames_write != pkt->write_size);
+
+       if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) {
+               pkt_make_local_copy(pkt, pages, offsets);
+               pkt->cache_valid = 1;
+       } else {
+               pkt->cache_valid = 0;
+       }
+
+       /* Start the write request */
+       bio_init(pkt->w_bio);
+       pkt->w_bio->bi_max_vecs = PACKET_MAX_SIZE;
+       pkt->w_bio->bi_sector = pkt->sector;
+       pkt->w_bio->bi_bdev = pd->bdev;
+       pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
+       pkt->w_bio->bi_private = pkt;
+       for (f = 0; f < pkt->frames; f++) {
+               if ((f + 1 < pkt->frames) && (pages[f + 1] == pages[f]) &&
+                   (offsets[f + 1] = offsets[f] + CD_FRAMESIZE)) {
+                       if (!bio_add_page(pkt->w_bio, pages[f], CD_FRAMESIZE * 2, offsets[f]))
+                               BUG();
+                       f++;
+               } else {
+                       if (!bio_add_page(pkt->w_bio, pages[f], CD_FRAMESIZE, offsets[f]))
+                               BUG();
+               }
+       }
+       VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt);
+
+       atomic_set(&pkt->io_wait, 1);
+       pkt->w_bio->bi_rw = WRITE;
+       pkt_queue_bio(pd, pkt->w_bio, 0);
+}
+
+static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
+{
+       struct bio *bio, *next;
+
+       if (!uptodate)
+               pkt->cache_valid = 0;
+
+       /* Finish all bios corresponding to this packet */
+       bio = pkt->orig_bios;
+       while (bio) {
+               next = bio->bi_next;
+               bio->bi_next = NULL;
+               bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
+               bio = next;
+       }
+       pkt->orig_bios = pkt->orig_bios_tail = NULL;
+}
+
+static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt)
+{
+       int uptodate;
+
+       VPRINTK("run_state_machine: pkt %d\n", pkt->id);
+
+       for (;;) {
+               switch (pkt->state) {
+               case PACKET_WAITING_STATE:
+                       if ((pkt->write_size < pkt->frames) && (pkt->sleep_time > 0))
+                               return;
+
+                       pkt->sleep_time = 0;
+                       pkt_gather_data(pd, pkt);
+                       pkt_set_state(pkt, PACKET_READ_WAIT_STATE);
+                       break;
+
+               case PACKET_READ_WAIT_STATE:
+                       if (atomic_read(&pkt->io_wait) > 0)
+                               return;
+
+                       if (atomic_read(&pkt->io_errors) > 0) {
+                               pkt_set_state(pkt, PACKET_RECOVERY_STATE);
+                       } else {
+                               pkt_start_write(pd, pkt);
+                       }
+                       break;
+
+               case PACKET_WRITE_WAIT_STATE:
+                       if (atomic_read(&pkt->io_wait) > 0)
+                               return;
+
+                       if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) {
+                               pkt_set_state(pkt, PACKET_FINISHED_STATE);
+                       } else {
+                               pkt_set_state(pkt, PACKET_RECOVERY_STATE);
+                       }
+                       break;
+
+               case PACKET_RECOVERY_STATE:
+                       if (pkt_start_recovery(pkt)) {
+                               pkt_start_write(pd, pkt);
+                       } else {
+                               VPRINTK("No recovery possible\n");
+                               pkt_set_state(pkt, PACKET_FINISHED_STATE);
+                       }
+                       break;
+
+               case PACKET_FINISHED_STATE:
+                       uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags);
+                       pkt_finish_packet(pkt, uptodate);
+                       return;
+
+               default:
+                       BUG();
+                       break;
+               }
+       }
+}
+
+static void pkt_handle_packets(struct pktcdvd_device *pd)
+{
+       struct packet_data *pkt, *next;
+
+       VPRINTK("pkt_handle_packets\n");
+
+       /*
+        * Run state machine for active packets
+        */
+       list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
+               if (atomic_read(&pkt->run_sm) > 0) {
+                       atomic_set(&pkt->run_sm, 0);
+                       pkt_run_state_machine(pd, pkt);
+               }
+       }
+
+       /*
+        * Move no longer active packets to the free list
+        */
+       spin_lock(&pd->cdrw.active_list_lock);
+       list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_active_list, list) {
+               if (pkt->state == PACKET_FINISHED_STATE) {
+                       list_del(&pkt->list);
+                       pkt_put_packet_data(pd, pkt);
+                       pkt_set_state(pkt, PACKET_IDLE_STATE);
+                       atomic_set(&pd->scan_queue, 1);
+               }
+       }
+       spin_unlock(&pd->cdrw.active_list_lock);
+}
+
+static void pkt_count_states(struct pktcdvd_device *pd, int *states)
+{
+       struct packet_data *pkt;
+       int i;
+
+       for (i = 0; i <= PACKET_NUM_STATES; i++)
+               states[i] = 0;
+
+       spin_lock(&pd->cdrw.active_list_lock);
+       list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
+               states[pkt->state]++;
+       }
+       spin_unlock(&pd->cdrw.active_list_lock);
+}
+
+/*
+ * kcdrwd is woken up when writes have been queued for one of our
+ * registered devices
+ */
+static int kcdrwd(void *foobar)
+{
+       struct pktcdvd_device *pd = foobar;
+       struct packet_data *pkt;
+       long min_sleep_time, residue;
+
+       set_user_nice(current, -20);
+
+       for (;;) {
+               DECLARE_WAITQUEUE(wait, current);
+
+               /*
+                * Wait until there is something to do
+                */
+               add_wait_queue(&pd->wqueue, &wait);
+               for (;;) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       /* Check if we need to run pkt_handle_queue */
+                       if (atomic_read(&pd->scan_queue) > 0)
+                               goto work_to_do;
+
+                       /* Check if we need to run the state machine for some packet */
+                       list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
+                               if (atomic_read(&pkt->run_sm) > 0)
+                                       goto work_to_do;
+                       }
+
+                       /* Check if we need to process the iosched queues */
+                       if (atomic_read(&pd->iosched.attention) != 0)
+                               goto work_to_do;
+
+                       /* Otherwise, go to sleep */
+                       if (PACKET_DEBUG > 1) {
+                               int states[PACKET_NUM_STATES];
+                               pkt_count_states(pd, states);
+                               VPRINTK("kcdrwd: i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
+                                       states[0], states[1], states[2], states[3],
+                                       states[4], states[5]);
+                       }
+
+                       min_sleep_time = MAX_SCHEDULE_TIMEOUT;
+                       list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
+                               if (pkt->sleep_time && pkt->sleep_time < min_sleep_time)
+                                       min_sleep_time = pkt->sleep_time;
+                       }
+
+                       generic_unplug_device(bdev_get_queue(pd->bdev));
+
+                       VPRINTK("kcdrwd: sleeping\n");
+                       residue = schedule_timeout(min_sleep_time);
+                       VPRINTK("kcdrwd: wake up\n");
+
+                       /* make swsusp happy with our thread */
+                       if (current->flags & PF_FREEZE)
+                               refrigerator(PF_FREEZE);
+
+                       list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
+                               if (!pkt->sleep_time)
+                                       continue;
+                               pkt->sleep_time -= min_sleep_time - residue;
+                               if (pkt->sleep_time <= 0) {
+                                       pkt->sleep_time = 0;
+                                       atomic_inc(&pkt->run_sm);
+                               }
+                       }
+
+                       if (signal_pending(current)) {
+                               flush_signals(current);
+                       }
+                       if (kthread_should_stop())
+                               break;
+               }
+work_to_do:
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&pd->wqueue, &wait);
+
+               if (kthread_should_stop())
+                       break;
+
+               /*
+                * if pkt_handle_queue returns true, we can queue
+                * another request.
+                */
+               while (pkt_handle_queue(pd))
+                       ;
+
+               /*
+                * Handle packet state machine
+                */
+               pkt_handle_packets(pd);
+
+               /*
+                * Handle iosched queues
+                */
+               pkt_iosched_process_queue(pd);
+       }
+
+       return 0;
+}
+
+static void pkt_print_settings(struct pktcdvd_device *pd)
+{
+       printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
+       printk("%u blocks, ", pd->settings.size >> 2);
+       printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2');
+}
+
+static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc,
+                         int page_code, int page_control)
+{
+       memset(cgc->cmd, 0, sizeof(cgc->cmd));
+
+       cgc->cmd[0] = GPCMD_MODE_SENSE_10;
+       cgc->cmd[2] = page_code | (page_control << 6);
+       cgc->cmd[7] = cgc->buflen >> 8;
+       cgc->cmd[8] = cgc->buflen & 0xff;
+       cgc->data_direction = CGC_DATA_READ;
+       return pkt_generic_packet(pd, cgc);
+}
+
+static int pkt_mode_select(struct pktcdvd_device *pd, struct packet_command *cgc)
+{
+       memset(cgc->cmd, 0, sizeof(cgc->cmd));
+       memset(cgc->buffer, 0, 2);
+       cgc->cmd[0] = GPCMD_MODE_SELECT_10;
+       cgc->cmd[1] = 0x10;             /* PF */
+       cgc->cmd[7] = cgc->buflen >> 8;
+       cgc->cmd[8] = cgc->buflen & 0xff;
+       cgc->data_direction = CGC_DATA_WRITE;
+       return pkt_generic_packet(pd, cgc);
+}
+
+static int pkt_get_disc_info(struct pktcdvd_device *pd, disc_information *di)
+{
+       struct packet_command cgc;
+       int ret;
+
+       /* set up command and get the disc info */
+       init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_READ_DISC_INFO;
+       cgc.cmd[8] = cgc.buflen = 2;
+       cgc.quiet = 1;
+
+       if ((ret = pkt_generic_packet(pd, &cgc)))
+               return ret;
+
+       /* not all drives have the same disc_info length, so requeue
+        * packet with the length the drive tells us it can supply
+        */
+       cgc.buflen = be16_to_cpu(di->disc_information_length) +
+                    sizeof(di->disc_information_length);
+
+       if (cgc.buflen > sizeof(disc_information))
+               cgc.buflen = sizeof(disc_information);
+
+       cgc.cmd[8] = cgc.buflen;
+       return pkt_generic_packet(pd, &cgc);
+}
+
+static int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, track_information *ti)
+{
+       struct packet_command cgc;
+       int ret;
+
+       init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
+       cgc.cmd[1] = type & 3;
+       cgc.cmd[4] = (track & 0xff00) >> 8;
+       cgc.cmd[5] = track & 0xff;
+       cgc.cmd[8] = 8;
+       cgc.quiet = 1;
+
+       if ((ret = pkt_generic_packet(pd, &cgc)))
+               return ret;
+
+       cgc.buflen = be16_to_cpu(ti->track_information_length) +
+                    sizeof(ti->track_information_length);
+
+       if (cgc.buflen > sizeof(track_information))
+               cgc.buflen = sizeof(track_information);
+
+       cgc.cmd[8] = cgc.buflen;
+       return pkt_generic_packet(pd, &cgc);
+}
+
+static int pkt_get_last_written(struct pktcdvd_device *pd, long *last_written)
+{
+       disc_information di;
+       track_information ti;
+       __u32 last_track;
+       int ret = -1;
+
+       if ((ret = pkt_get_disc_info(pd, &di)))
+               return ret;
+
+       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
+       if ((ret = pkt_get_track_info(pd, last_track, 1, &ti)))
+               return ret;
+
+       /* if this track is blank, try the previous. */
+       if (ti.blank) {
+               last_track--;
+               if ((ret = pkt_get_track_info(pd, last_track, 1, &ti)))
+                       return ret;
+       }
+
+       /* if last recorded field is valid, return it. */
+       if (ti.lra_v) {
+               *last_written = be32_to_cpu(ti.last_rec_address);
+       } else {
+               /* make it up instead */
+               *last_written = be32_to_cpu(ti.track_start) +
+                               be32_to_cpu(ti.track_size);
+               if (ti.free_blocks)
+                       *last_written -= (be32_to_cpu(ti.free_blocks) + 7);
+       }
+       return 0;
+}
+
+/*
+ * write mode select package based on pd->settings
+ */
+static int pkt_set_write_settings(struct pktcdvd_device *pd)
+{
+       struct packet_command cgc;
+       struct request_sense sense;
+       write_param_page *wp;
+       char buffer[128];
+       int ret, size;
+
+       /* doesn't apply to DVD+RW */
+       if (pd->mmc3_profile == 0x1a)
+               return 0;
+
+       memset(buffer, 0, sizeof(buffer));
+       init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ);
+       cgc.sense = &sense;
+       if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) {
+               pkt_dump_sense(&cgc);
+               return ret;
+       }
+
+       size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff));
+       pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff);
+       if (size > sizeof(buffer))
+               size = sizeof(buffer);
+
+       /*
+        * now get it all
+        */
+       init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ);
+       cgc.sense = &sense;
+       if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) {
+               pkt_dump_sense(&cgc);
+               return ret;
+       }
+
+       /*
+        * write page is offset header + block descriptor length
+        */
+       wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset];
+
+       wp->fp = pd->settings.fp;
+       wp->track_mode = pd->settings.track_mode;
+       wp->write_type = pd->settings.write_type;
+       wp->data_block_type = pd->settings.block_mode;
+
+       wp->multi_session = 0;
+
+#ifdef PACKET_USE_LS
+       wp->link_size = 7;
+       wp->ls_v = 1;
+#endif
+
+       if (wp->data_block_type == PACKET_BLOCK_MODE1) {
+               wp->session_format = 0;
+               wp->subhdr2 = 0x20;
+       } else if (wp->data_block_type == PACKET_BLOCK_MODE2) {
+               wp->session_format = 0x20;
+               wp->subhdr2 = 8;
+#if 0
+               wp->mcn[0] = 0x80;
+               memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1);
+#endif
+       } else {
+               /*
+                * paranoia
+                */
+               printk("pktcdvd: write mode wrong %d\n", wp->data_block_type);
+               return 1;
+       }
+       wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
+
+       cgc.buflen = cgc.cmd[8] = size;
+       if ((ret = pkt_mode_select(pd, &cgc))) {
+               pkt_dump_sense(&cgc);
+               return ret;
+       }
+
+       pkt_print_settings(pd);
+       return 0;
+}
+
+/*
+ * 0 -- we can write to this track, 1 -- we can't
+ */
+static int pkt_good_track(track_information *ti)
+{
+       /*
+        * only good for CD-RW at the moment, not DVD-RW
+        */
+
+       /*
+        * FIXME: only for FP
+        */
+       if (ti->fp == 0)
+               return 0;
+
+       /*
+        * "good" settings as per Mt Fuji.
+        */
+       if (ti->rt == 0 && ti->blank == 0 && ti->packet == 1)
+               return 0;
+
+       if (ti->rt == 0 && ti->blank == 1 && ti->packet == 1)
+               return 0;
+
+       if (ti->rt == 1 && ti->blank == 0 && ti->packet == 1)
+               return 0;
+
+       printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+       return 1;
+}
+
+/*
+ * 0 -- we can write to this disc, 1 -- we can't
+ */
+static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
+{
+       switch (pd->mmc3_profile) {
+               case 0x0a: /* CD-RW */
+               case 0xffff: /* MMC3 not supported */
+                       break;
+               case 0x1a: /* DVD+RW */
+               case 0x13: /* DVD-RW */
+                       return 0;
+               default:
+                       printk("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
+                       return 1;
+       }
+
+       /*
+        * for disc type 0xff we should probably reserve a new track.
+        * but i'm not sure, should we leave this to user apps? probably.
+        */
+       if (di->disc_type == 0xff) {
+               printk("pktcdvd: Unknown disc. No track?\n");
+               return 1;
+       }
+
+       if (di->disc_type != 0x20 && di->disc_type != 0) {
+               printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
+               return 1;
+       }
+
+       if (di->erasable == 0) {
+               printk("pktcdvd: Disc not erasable\n");
+               return 1;
+       }
+
+       if (di->border_status == PACKET_SESSION_RESERVED) {
+               printk("pktcdvd: Can't write to last track (reserved)\n");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int pkt_probe_settings(struct pktcdvd_device *pd)
+{
+       struct packet_command cgc;
+       unsigned char buf[12];
+       disc_information di;
+       track_information ti;
+       int ret, track;
+
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
+       cgc.cmd[8] = 8;
+       ret = pkt_generic_packet(pd, &cgc);
+       pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7];
+
+       memset(&di, 0, sizeof(disc_information));
+       memset(&ti, 0, sizeof(track_information));
+
+       if ((ret = pkt_get_disc_info(pd, &di))) {
+               printk("failed get_disc\n");
+               return ret;
+       }
+
+       if (pkt_good_disc(pd, &di))
+               return -ENXIO;
+
+       switch (pd->mmc3_profile) {
+               case 0x1a: /* DVD+RW */
+                       printk("pktcdvd: inserted media is DVD+RW\n");
+                       break;
+               case 0x13: /* DVD-RW */
+                       printk("pktcdvd: inserted media is DVD-RW\n");
+                       break;
+               default:
+                       printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");
+                       break;
+       }
+       pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
+
+       track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
+       if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
+               printk("pktcdvd: failed get_track\n");
+               return ret;
+       }
+
+       if (pkt_good_track(&ti)) {
+               printk("pktcdvd: can't write to this track\n");
+               return -ENXIO;
+       }
+
+       /*
+        * we keep packet size in 512 byte units, makes it easier to
+        * deal with request calculations.
+        */
+       pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
+       if (pd->settings.size == 0) {
+               printk("pktcdvd: detected zero packet size!\n");
+               pd->settings.size = 128;
+       }
+       pd->settings.fp = ti.fp;
+       pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
+
+       if (ti.nwa_v) {
+               pd->nwa = be32_to_cpu(ti.next_writable);
+               set_bit(PACKET_NWA_VALID, &pd->flags);
+       }
+
+       /*
+        * in theory we could use lra on -RW media as well and just zero
+        * blocks that haven't been written yet, but in practice that
+        * is just a no-go. we'll use that for -R, naturally.
+        */
+       if (ti.lra_v) {
+               pd->lra = be32_to_cpu(ti.last_rec_address);
+               set_bit(PACKET_LRA_VALID, &pd->flags);
+       } else {
+               pd->lra = 0xffffffff;
+               set_bit(PACKET_LRA_VALID, &pd->flags);
+       }
+
+       /*
+        * fine for now
+        */
+       pd->settings.link_loss = 7;
+       pd->settings.write_type = 0;    /* packet */
+       pd->settings.track_mode = ti.track_mode;
+
+       /*
+        * mode1 or mode2 disc
+        */
+       switch (ti.data_mode) {
+               case PACKET_MODE1:
+                       pd->settings.block_mode = PACKET_BLOCK_MODE1;
+                       break;
+               case PACKET_MODE2:
+                       pd->settings.block_mode = PACKET_BLOCK_MODE2;
+                       break;
+               default:
+                       printk("pktcdvd: unknown data mode\n");
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * enable/disable write caching on drive
+ */
+static int pkt_write_caching(struct pktcdvd_device *pd, int set)
+{
+       struct packet_command cgc;
+       struct request_sense sense;
+       unsigned char buf[64];
+       int ret;
+
+       memset(buf, 0, sizeof(buf));
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
+       cgc.sense = &sense;
+       cgc.buflen = pd->mode_offset + 12;
+
+       /*
+        * caching mode page might not be there, so quiet this command
+        */
+       cgc.quiet = 1;
+
+       if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0)))
+               return ret;
+
+       buf[pd->mode_offset + 10] |= (!!set << 2);
+
+       cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
+       ret = pkt_mode_select(pd, &cgc);
+       if (ret) {
+               printk("pktcdvd: write caching control failed\n");
+               pkt_dump_sense(&cgc);
+       } else if (!ret && set)
+               printk("pktcdvd: enabled write caching on %s\n", pd->name);
+       return ret;
+}
+
+static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag)
+{
+       struct packet_command cgc;
+
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+       cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+       cgc.cmd[4] = lockflag ? 1 : 0;
+       return pkt_generic_packet(pd, &cgc);
+}
+
+/*
+ * Returns drive maximum write speed
+ */
+static int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned *write_speed)
+{
+       struct packet_command cgc;
+       struct request_sense sense;
+       unsigned char buf[256+18];
+       unsigned char *cap_buf;
+       int ret, offset;
+
+       memset(buf, 0, sizeof(buf));
+       cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset];
+       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN);
+       cgc.sense = &sense;
+
+       ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+       if (ret) {
+               cgc.buflen = pd->mode_offset + cap_buf[1] + 2 +
+                            sizeof(struct mode_page_header);
+               ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+               if (ret) {
+                       pkt_dump_sense(&cgc);
+                       return ret;
+               }
+       }
+
+       offset = 20;                        /* Obsoleted field, used by older drives */
+       if (cap_buf[1] >= 28)
+               offset = 28;                /* Current write speed selected */
+       if (cap_buf[1] >= 30) {
+               /* If the drive reports at least one "Logical Unit Write
+                * Speed Performance Descriptor Block", use the information
+                * in the first block. (contains the highest speed)
+                */
+               int num_spdb = (cap_buf[30] << 8) + cap_buf[31];
+               if (num_spdb > 0)
+                       offset = 34;
+       }
+
+       *write_speed = (cap_buf[offset] << 8) | cap_buf[offset + 1];
+       return 0;
+}
+
+/* These tables from cdrecord - I don't have orange book */
+/* standard speed CD-RW (1-4x) */
+static char clv_to_speed[16] = {
+       /* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
+          0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+/* high speed CD-RW (-10x) */
+static char hs_clv_to_speed[16] = {
+       /* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
+          0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+/* ultra high speed CD-RW */
+static char us_clv_to_speed[16] = {
+       /* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
+          0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0
+};
+
+/*
+ * reads the maximum media speed from ATIP
+ */
+static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
+{
+       struct packet_command cgc;
+       struct request_sense sense;
+       unsigned char buf[64];
+       unsigned int size, st, sp;
+       int ret;
+
+       init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ);
+       cgc.sense = &sense;
+       cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+       cgc.cmd[1] = 2;
+       cgc.cmd[2] = 4; /* READ ATIP */
+       cgc.cmd[8] = 2;
+       ret = pkt_generic_packet(pd, &cgc);
+       if (ret) {
+               pkt_dump_sense(&cgc);
+               return ret;
+       }
+       size = ((unsigned int) buf[0]<<8) + buf[1] + 2;
+       if (size > sizeof(buf))
+               size = sizeof(buf);
+
+       init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
+       cgc.sense = &sense;
+       cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+       cgc.cmd[1] = 2;
+       cgc.cmd[2] = 4;
+       cgc.cmd[8] = size;
+       ret = pkt_generic_packet(pd, &cgc);
+       if (ret) {
+               pkt_dump_sense(&cgc);
+               return ret;
+       }
+
+       if (!buf[6] & 0x40) {
+               printk("pktcdvd: Disc type is not CD-RW\n");
+               return 1;
+       }
+       if (!buf[6] & 0x4) {
+               printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");
+               return 1;
+       }
+
+       st = (buf[6] >> 3) & 0x7; /* disc sub-type */
+
+       sp = buf[16] & 0xf; /* max speed from ATIP A1 field */
+
+       /* Info from cdrecord */
+       switch (st) {
+               case 0: /* standard speed */
+                       *speed = clv_to_speed[sp];
+                       break;
+               case 1: /* high speed */
+                       *speed = hs_clv_to_speed[sp];
+                       break;
+               case 2: /* ultra high speed */
+                       *speed = us_clv_to_speed[sp];
+                       break;
+               default:
+                       printk("pktcdvd: Unknown disc sub-type %d\n",st);
+                       return 1;
+       }
+       if (*speed) {
+               printk("pktcdvd: Max. media speed: %d\n",*speed);
+               return 0;
+       } else {
+               printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);
+               return 1;
+       }
+}
+
+static int pkt_perform_opc(struct pktcdvd_device *pd)
+{
+       struct packet_command cgc;
+       struct request_sense sense;
+       int ret;
+
+       VPRINTK("pktcdvd: Performing OPC\n");
+
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+       cgc.sense = &sense;
+       cgc.timeout = 60*HZ;
+       cgc.cmd[0] = GPCMD_SEND_OPC;
+       cgc.cmd[1] = 1;
+       if ((ret = pkt_generic_packet(pd, &cgc)))
+               pkt_dump_sense(&cgc);
+       return ret;
+}
+
+static int pkt_open_write(struct pktcdvd_device *pd)
+{
+       int ret;
+       unsigned int write_speed, media_write_speed, read_speed;
+
+       if ((ret = pkt_probe_settings(pd))) {
+               DPRINTK("pktcdvd: %s failed probe\n", pd->name);
+               return -EIO;
+       }
+
+       if ((ret = pkt_set_write_settings(pd))) {
+               DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);
+               return -EIO;
+       }
+
+       pkt_write_caching(pd, USE_WCACHING);
+
+       if ((ret = pkt_get_max_speed(pd, &write_speed)))
+               write_speed = 16 * 177;
+       switch (pd->mmc3_profile) {
+               case 0x13: /* DVD-RW */
+               case 0x1a: /* DVD+RW */
+                       DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
+                       break;
+               default:
+                       if ((ret = pkt_media_speed(pd, &media_write_speed)))
+                               media_write_speed = 16;
+                       write_speed = min(write_speed, media_write_speed * 177);
+                       DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);
+                       break;
+       }
+       read_speed = write_speed;
+
+       if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
+               DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
+               return -EIO;
+       }
+       pd->write_speed = write_speed;
+       pd->read_speed = read_speed;
+
+       if ((ret = pkt_perform_opc(pd))) {
+               DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);
+       }
+
+       return 0;
+}
+
+/*
+ * called at open time.
+ */
+static int pkt_open_dev(struct pktcdvd_device *pd, int write)
+{
+       int ret;
+       long lba;
+       request_queue_t *q;
+
+       /*
+        * We need to re-open the cdrom device without O_NONBLOCK to be able
+        * to read/write from/to it. It is already opened in O_NONBLOCK mode
+        * so bdget() can't fail.
+        */
+       bdget(pd->bdev->bd_dev);
+       if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY)))
+               goto out;
+
+       if ((ret = pkt_get_last_written(pd, &lba))) {
+               printk("pktcdvd: pkt_get_last_written failed\n");
+               goto out_putdev;
+       }
+
+       set_capacity(pd->disk, lba << 2);
+       set_capacity(pd->bdev->bd_disk, lba << 2);
+       bd_set_size(pd->bdev, (loff_t)lba << 11);
+
+       q = bdev_get_queue(pd->bdev);
+       if (write) {
+               if ((ret = pkt_open_write(pd)))
+                       goto out_putdev;
+               /*
+                * Some CDRW drives can not handle writes larger than one packet,
+                * even if the size is a multiple of the packet size.
+                */
+               spin_lock_irq(q->queue_lock);
+               blk_queue_max_sectors(q, pd->settings.size);
+               spin_unlock_irq(q->queue_lock);
+               set_bit(PACKET_WRITABLE, &pd->flags);
+       } else {
+               pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
+               clear_bit(PACKET_WRITABLE, &pd->flags);
+       }
+
+       if ((ret = pkt_set_segment_merging(pd, q)))
+               goto out_putdev;
+
+       if (write)
+               printk("pktcdvd: %lukB available on disc\n", lba << 1);
+
+       return 0;
+
+out_putdev:
+       blkdev_put(pd->bdev);
+out:
+       return ret;
+}
+
+/*
+ * called when the device is closed. makes sure that the device flushes
+ * the internal cache before we close.
+ */
+static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
+{
+       if (flush && pkt_flush_cache(pd))
+               DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
+
+       pkt_lock_door(pd, 0);
+
+       pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
+       blkdev_put(pd->bdev);
+}
+
+static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor)
+{
+       if (dev_minor >= MAX_WRITERS)
+               return NULL;
+       return pkt_devs[dev_minor];
+}
+
+static int pkt_open(struct inode *inode, struct file *file)
+{
+       struct pktcdvd_device *pd = NULL;
+       int ret;
+
+       VPRINTK("pktcdvd: entering open\n");
+
+       down(&ctl_mutex);
+       pd = pkt_find_dev_from_minor(iminor(inode));
+       if (!pd) {
+               ret = -ENODEV;
+               goto out;
+       }
+       BUG_ON(pd->refcnt < 0);
+
+       pd->refcnt++;
+       if (pd->refcnt == 1) {
+               if (pkt_open_dev(pd, file->f_mode & FMODE_WRITE)) {
+                       ret = -EIO;
+                       goto out_dec;
+               }
+               /*
+                * needed here as well, since ext2 (among others) may change
+                * the blocksize at mount time
+                */
+               set_blocksize(inode->i_bdev, CD_FRAMESIZE);
+       }
+
+       up(&ctl_mutex);
+       return 0;
+
+out_dec:
+       pd->refcnt--;
+out:
+       VPRINTK("pktcdvd: failed open (%d)\n", ret);
+       up(&ctl_mutex);
+       return ret;
+}
+
+static int pkt_close(struct inode *inode, struct file *file)
+{
+       struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
+       int ret = 0;
+
+       down(&ctl_mutex);
+       pd->refcnt--;
+       BUG_ON(pd->refcnt < 0);
+       if (pd->refcnt == 0) {
+               int flush = test_bit(PACKET_WRITABLE, &pd->flags);
+               pkt_release_dev(pd, flush);
+       }
+       up(&ctl_mutex);
+       return ret;
+}
+
+
+static void *psd_pool_alloc(int gfp_mask, void *data)
+{
+       return kmalloc(sizeof(struct packet_stacked_data), gfp_mask);
+}
+
+static void psd_pool_free(void *ptr, void *data)
+{
+       kfree(ptr);
+}
+
+static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err)
+{
+       struct packet_stacked_data *psd = bio->bi_private;
+       struct pktcdvd_device *pd = psd->pd;
+
+       if (bio->bi_size)
+               return 1;
+
+       bio_put(bio);
+       bio_endio(psd->bio, psd->bio->bi_size, err);
+       mempool_free(psd, psd_pool);
+       pkt_bio_finished(pd);
+       return 0;
+}
+
+static int pkt_make_request(request_queue_t *q, struct bio *bio)
+{
+       struct pktcdvd_device *pd;
+       char b[BDEVNAME_SIZE];
+       sector_t zone;
+       struct packet_data *pkt;
+       int was_empty, blocked_bio;
+       struct pkt_rb_node *node;
+
+       pd = q->queuedata;
+       if (!pd) {
+               printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+               goto end_io;
+       }
+
+       /*
+        * Clone READ bios so we can have our own bi_end_io callback.
+        */
+       if (bio_data_dir(bio) == READ) {
+               struct bio *cloned_bio = bio_clone(bio, GFP_NOIO);
+               struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO);
+
+               psd->pd = pd;
+               psd->bio = bio;
+               cloned_bio->bi_bdev = pd->bdev;
+               cloned_bio->bi_private = psd;
+               cloned_bio->bi_end_io = pkt_end_io_read_cloned;
+               pd->stats.secs_r += bio->bi_size >> 9;
+               pkt_queue_bio(pd, cloned_bio, 1);
+               return 0;
+       }
+
+       if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
+               printk("pktcdvd: WRITE for ro device %s (%llu)\n",
+                       pd->name, (unsigned long long)bio->bi_sector);
+               goto end_io;
+       }
+
+       if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
+               printk("pktcdvd: wrong bio size\n");
+               goto end_io;
+       }
+
+       blk_queue_bounce(q, &bio);
+
+       zone = ZONE(bio->bi_sector, pd);
+       VPRINTK("pkt_make_request: start = %6llx stop = %6llx\n",
+               (unsigned long long)bio->bi_sector,
+               (unsigned long long)(bio->bi_sector + bio_sectors(bio)));
+
+       /* Check if we have to split the bio */
+       {
+               struct bio_pair *bp;
+               sector_t last_zone;
+               int first_sectors;
+
+               last_zone = ZONE(bio->bi_sector + bio_sectors(bio) - 1, pd);
+               if (last_zone != zone) {
+                       BUG_ON(last_zone != zone + pd->settings.size);
+                       first_sectors = last_zone - bio->bi_sector;
+                       bp = bio_split(bio, bio_split_pool, first_sectors);
+                       BUG_ON(!bp);
+                       pkt_make_request(q, &bp->bio1);
+                       pkt_make_request(q, &bp->bio2);
+                       bio_pair_release(bp);
+                       return 0;
+               }
+       }
+
+       /*
+        * If we find a matching packet in state WAITING or READ_WAIT, we can
+        * just append this bio to that packet.
+        */
+       spin_lock(&pd->cdrw.active_list_lock);
+       blocked_bio = 0;
+       list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
+               if (pkt->sector == zone) {
+                       spin_lock(&pkt->lock);
+                       if ((pkt->state == PACKET_WAITING_STATE) ||
+                           (pkt->state == PACKET_READ_WAIT_STATE)) {
+                               pkt_add_list_last(bio, &pkt->orig_bios,
+                                                 &pkt->orig_bios_tail);
+                               pkt->write_size += bio->bi_size / CD_FRAMESIZE;
+                               if ((pkt->write_size >= pkt->frames) &&
+                                   (pkt->state == PACKET_WAITING_STATE)) {
+                                       atomic_inc(&pkt->run_sm);
+                                       wake_up(&pd->wqueue);
+                               }
+                               spin_unlock(&pkt->lock);
+                               spin_unlock(&pd->cdrw.active_list_lock);
+                               return 0;
+                       } else {
+                               blocked_bio = 1;
+                       }
+                       spin_unlock(&pkt->lock);
+               }
+       }
+       spin_unlock(&pd->cdrw.active_list_lock);
+
+       /*
+        * No matching packet found. Store the bio in the work queue.
+        */
+       node = mempool_alloc(pd->rb_pool, GFP_NOIO);
+       BUG_ON(!node);
+       node->bio = bio;
+       spin_lock(&pd->lock);
+       BUG_ON(pd->bio_queue_size < 0);
+       was_empty = (pd->bio_queue_size == 0);
+       pkt_rbtree_insert(pd, node);
+       spin_unlock(&pd->lock);
+
+       /*
+        * Wake up the worker thread.
+        */
+       atomic_set(&pd->scan_queue, 1);
+       if (was_empty) {
+               /* This wake_up is required for correct operation */
+               wake_up(&pd->wqueue);
+       } else if (!list_empty(&pd->cdrw.pkt_free_list) && !blocked_bio) {
+               /*
+                * This wake up is not required for correct operation,
+                * but improves performance in some cases.
+                */
+               wake_up(&pd->wqueue);
+       }
+       return 0;
+end_io:
+       bio_io_error(bio, bio->bi_size);
+       return 0;
+}
+
+
+
+static int pkt_merge_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *bvec)
+{
+       struct pktcdvd_device *pd = q->queuedata;
+       sector_t zone = ZONE(bio->bi_sector, pd);
+       int used = ((bio->bi_sector - zone) << 9) + bio->bi_size;
+       int remaining = (pd->settings.size << 9) - used;
+       int remaining2;
+
+       /*
+        * A bio <= PAGE_SIZE must be allowed. If it crosses a packet
+        * boundary, pkt_make_request() will split the bio.
+        */
+       remaining2 = PAGE_SIZE - bio->bi_size;
+       remaining = max(remaining, remaining2);
+
+       BUG_ON(remaining < 0);
+       return remaining;
+}
+
+static void pkt_init_queue(struct pktcdvd_device *pd)
+{
+       request_queue_t *q = pd->disk->queue;
+
+       blk_queue_make_request(q, pkt_make_request);
+       blk_queue_hardsect_size(q, CD_FRAMESIZE);
+       blk_queue_max_sectors(q, PACKET_MAX_SECTORS);
+       blk_queue_merge_bvec(q, pkt_merge_bvec);
+       q->queuedata = pd;
+}
+
+static int pkt_seq_show(struct seq_file *m, void *p)
+{
+       struct pktcdvd_device *pd = m->private;
+       char *msg;
+       char bdev_buf[BDEVNAME_SIZE];
+       int states[PACKET_NUM_STATES];
+
+       seq_printf(m, "Writer %s mapped to %s:\n", pd->name,
+                  bdevname(pd->bdev, bdev_buf));
+
+       seq_printf(m, "\nSettings:\n");
+       seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2);
+
+       if (pd->settings.write_type == 0)
+               msg = "Packet";
+       else
+               msg = "Unknown";
+       seq_printf(m, "\twrite type:\t\t%s\n", msg);
+
+       seq_printf(m, "\tpacket type:\t\t%s\n", pd->settings.fp ? "Fixed" : "Variable");
+       seq_printf(m, "\tlink loss:\t\t%d\n", pd->settings.link_loss);
+
+       seq_printf(m, "\ttrack mode:\t\t%d\n", pd->settings.track_mode);
+
+       if (pd->settings.block_mode == PACKET_BLOCK_MODE1)
+               msg = "Mode 1";
+       else if (pd->settings.block_mode == PACKET_BLOCK_MODE2)
+               msg = "Mode 2";
+       else
+               msg = "Unknown";
+       seq_printf(m, "\tblock mode:\t\t%s\n", msg);
+
+       seq_printf(m, "\nStatistics:\n");
+       seq_printf(m, "\tpackets started:\t%lu\n", pd->stats.pkt_started);
+       seq_printf(m, "\tpackets ended:\t\t%lu\n", pd->stats.pkt_ended);
+       seq_printf(m, "\twritten:\t\t%lukB\n", pd->stats.secs_w >> 1);
+       seq_printf(m, "\tread gather:\t\t%lukB\n", pd->stats.secs_rg >> 1);
+       seq_printf(m, "\tread:\t\t\t%lukB\n", pd->stats.secs_r >> 1);
+
+       seq_printf(m, "\nMisc:\n");
+       seq_printf(m, "\treference count:\t%d\n", pd->refcnt);
+       seq_printf(m, "\tflags:\t\t\t0x%lx\n", pd->flags);
+       seq_printf(m, "\tread speed:\t\t%ukB/s\n", pd->read_speed);
+       seq_printf(m, "\twrite speed:\t\t%ukB/s\n", pd->write_speed);
+       seq_printf(m, "\tstart offset:\t\t%lu\n", pd->offset);
+       seq_printf(m, "\tmode page offset:\t%u\n", pd->mode_offset);
+
+       seq_printf(m, "\nQueue state:\n");
+       seq_printf(m, "\tbios queued:\t\t%d\n", pd->bio_queue_size);
+       seq_printf(m, "\tbios pending:\t\t%d\n", atomic_read(&pd->cdrw.pending_bios));
+       seq_printf(m, "\tcurrent sector:\t\t0x%llx\n", (unsigned long long)pd->current_sector);
+
+       pkt_count_states(pd, states);
+       seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
+                  states[0], states[1], states[2], states[3], states[4], states[5]);
+
+       return 0;
+}
+
+static int pkt_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, pkt_seq_show, PDE(inode)->data);
+}
+
+static struct file_operations pkt_proc_fops = {
+       .open   = pkt_seq_open,
+       .read   = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release
+};
+
+static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
+{
+       int i;
+       int ret = 0;
+       char b[BDEVNAME_SIZE];
+       struct proc_dir_entry *proc;
+       struct block_device *bdev;
+
+       if (pd->pkt_dev == dev) {
+               printk("pktcdvd: Recursive setup not allowed\n");
+               return -EBUSY;
+       }
+       for (i = 0; i < MAX_WRITERS; i++) {
+               struct pktcdvd_device *pd2 = pkt_devs[i];
+               if (!pd2)
+                       continue;
+               if (pd2->bdev->bd_dev == dev) {
+                       printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b));
+                       return -EBUSY;
+               }
+               if (pd2->pkt_dev == dev) {
+                       printk("pktcdvd: Can't chain pktcdvd devices\n");
+                       return -EBUSY;
+               }
+       }
+
+       bdev = bdget(dev);
+       if (!bdev)
+               return -ENOMEM;
+       ret = blkdev_get(bdev, FMODE_READ, O_RDONLY | O_NONBLOCK);
+       if (ret)
+               return ret;
+
+       /* This is safe, since we have a reference from open(). */
+       __module_get(THIS_MODULE);
+
+       if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
+               printk("pktcdvd: not enough memory for buffers\n");
+               ret = -ENOMEM;
+               goto out_mem;
+       }
+
+       pd->bdev = bdev;
+       set_blocksize(bdev, CD_FRAMESIZE);
+
+       pkt_init_queue(pd);
+
+       atomic_set(&pd->cdrw.pending_bios, 0);
+       pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
+       if (IS_ERR(pd->cdrw.thread)) {
+               printk("pktcdvd: can't start kernel thread\n");
+               ret = -ENOMEM;
+               goto out_thread;
+       }
+
+       proc = create_proc_entry(pd->name, 0, pkt_proc);
+       if (proc) {
+               proc->data = pd;
+               proc->proc_fops = &pkt_proc_fops;
+       }
+       DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+       return 0;
+
+out_thread:
+       pkt_shrink_pktlist(pd);
+out_mem:
+       blkdev_put(bdev);
+       /* This is safe: open() is still holding a reference. */
+       module_put(THIS_MODULE);
+       return ret;
+}
+
+static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
+
+       VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode));
+       BUG_ON(!pd);
+
+       switch (cmd) {
+       /*
+        * forward selected CDROM ioctls to CD-ROM, for UDF
+        */
+       case CDROMMULTISESSION:
+       case CDROMREADTOCENTRY:
+       case CDROM_LAST_WRITTEN:
+       case CDROM_SEND_PACKET:
+       case SCSI_IOCTL_SEND_COMMAND:
+               return ioctl_by_bdev(pd->bdev, cmd, arg);
+
+       case CDROMEJECT:
+               /*
+                * The door gets locked when the device is opened, so we
+                * have to unlock it or else the eject command fails.
+                */
+               pkt_lock_door(pd, 0);
+               return ioctl_by_bdev(pd->bdev, cmd, arg);
+
+       default:
+               printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
+               return -ENOTTY;
+       }
+
+       return 0;
+}
+
+static int pkt_media_changed(struct gendisk *disk)
+{
+       struct pktcdvd_device *pd = disk->private_data;
+       struct gendisk *attached_disk;
+
+       if (!pd)
+               return 0;
+       if (!pd->bdev)
+               return 0;
+       attached_disk = pd->bdev->bd_disk;
+       if (!attached_disk)
+               return 0;
+       return attached_disk->fops->media_changed(attached_disk);
+}
+
+static struct block_device_operations pktcdvd_ops = {
+       .owner =                THIS_MODULE,
+       .open =                 pkt_open,
+       .release =              pkt_close,
+       .ioctl =                pkt_ioctl,
+       .media_changed =        pkt_media_changed,
+};
+
+/*
+ * Set up mapping from pktcdvd device to CD-ROM device.
+ */
+static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
+{
+       int idx;
+       int ret = -ENOMEM;
+       struct pktcdvd_device *pd;
+       struct gendisk *disk;
+       dev_t dev = new_decode_dev(ctrl_cmd->dev);
+
+       for (idx = 0; idx < MAX_WRITERS; idx++)
+               if (!pkt_devs[idx])
+                       break;
+       if (idx == MAX_WRITERS) {
+               printk("pktcdvd: max %d writers supported\n", MAX_WRITERS);
+               return -EBUSY;
+       }
+
+       pd = kmalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
+       if (!pd)
+               return ret;
+       memset(pd, 0, sizeof(struct pktcdvd_device));
+
+       pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL);
+       if (!pd->rb_pool)
+               goto out_mem;
+
+       disk = alloc_disk(1);
+       if (!disk)
+               goto out_mem;
+       pd->disk = disk;
+
+       spin_lock_init(&pd->lock);
+       spin_lock_init(&pd->iosched.lock);
+       sprintf(pd->name, "pktcdvd%d", idx);
+       init_waitqueue_head(&pd->wqueue);
+       pd->bio_queue = RB_ROOT;
+
+       disk->major = pkt_major;
+       disk->first_minor = idx;
+       disk->fops = &pktcdvd_ops;
+       disk->flags = GENHD_FL_REMOVABLE;
+       sprintf(disk->disk_name, "pktcdvd%d", idx);
+       disk->private_data = pd;
+       disk->queue = blk_alloc_queue(GFP_KERNEL);
+       if (!disk->queue)
+               goto out_mem2;
+
+       pd->pkt_dev = MKDEV(disk->major, disk->first_minor);
+       ret = pkt_new_dev(pd, dev);
+       if (ret)
+               goto out_new_dev;
+
+       add_disk(disk);
+       pkt_devs[idx] = pd;
+       ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
+       return 0;
+
+out_new_dev:
+       blk_put_queue(disk->queue);
+out_mem2:
+       put_disk(disk);
+out_mem:
+       if (pd->rb_pool)
+               mempool_destroy(pd->rb_pool);
+       kfree(pd);
+       return ret;
+}
+
+/*
+ * Tear down mapping from pktcdvd device to CD-ROM device.
+ */
+static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
+{
+       struct pktcdvd_device *pd;
+       int idx;
+       dev_t pkt_dev = new_decode_dev(ctrl_cmd->pkt_dev);
+
+       for (idx = 0; idx < MAX_WRITERS; idx++) {
+               pd = pkt_devs[idx];
+               if (pd && (pd->pkt_dev == pkt_dev))
+                       break;
+       }
+       if (idx == MAX_WRITERS) {
+               DPRINTK("pktcdvd: dev not setup\n");
+               return -ENXIO;
+       }
+
+       if (pd->refcnt > 0)
+               return -EBUSY;
+
+       if (!IS_ERR(pd->cdrw.thread))
+               kthread_stop(pd->cdrw.thread);
+
+       blkdev_put(pd->bdev);
+
+       pkt_shrink_pktlist(pd);
+
+       remove_proc_entry(pd->name, pkt_proc);
+       DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
+
+       del_gendisk(pd->disk);
+       blk_put_queue(pd->disk->queue);
+       put_disk(pd->disk);
+
+       pkt_devs[idx] = NULL;
+       mempool_destroy(pd->rb_pool);
+       kfree(pd);
+
+       /* This is safe: open() is still holding a reference. */
+       module_put(THIS_MODULE);
+       return 0;
+}
+
+static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
+{
+       struct pktcdvd_device *pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
+       if (pd) {
+               ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev);
+               ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
+       } else {
+               ctrl_cmd->dev = 0;
+               ctrl_cmd->pkt_dev = 0;
+       }
+       ctrl_cmd->num_devices = MAX_WRITERS;
+}
+
+static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       struct pkt_ctrl_command ctrl_cmd;
+       int ret = 0;
+
+       if (cmd != PACKET_CTRL_CMD)
+               return -ENOTTY;
+
+       if (copy_from_user(&ctrl_cmd, argp, sizeof(struct pkt_ctrl_command)))
+               return -EFAULT;
+
+       switch (ctrl_cmd.command) {
+       case PKT_CTRL_CMD_SETUP:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               down(&ctl_mutex);
+               ret = pkt_setup_dev(&ctrl_cmd);
+               up(&ctl_mutex);
+               break;
+       case PKT_CTRL_CMD_TEARDOWN:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               down(&ctl_mutex);
+               ret = pkt_remove_dev(&ctrl_cmd);
+               up(&ctl_mutex);
+               break;
+       case PKT_CTRL_CMD_STATUS:
+               down(&ctl_mutex);
+               pkt_get_status(&ctrl_cmd);
+               up(&ctl_mutex);
+               break;
+       default:
+               return -ENOTTY;
+       }
+
+       if (copy_to_user(argp, &ctrl_cmd, sizeof(struct pkt_ctrl_command)))
+               return -EFAULT;
+       return ret;
+}
+
+
+static struct file_operations pkt_ctl_fops = {
+       .ioctl   = pkt_ctl_ioctl,
+       .owner   = THIS_MODULE,
+};
+
+static struct miscdevice pkt_misc = {
+       .minor          = MISC_DYNAMIC_MINOR,
+       .name           = "pktcdvd",
+       .devfs_name     = "pktcdvd/control",
+       .fops           = &pkt_ctl_fops
+};
+
+int pkt_init(void)
+{
+       int ret;
+
+       psd_pool = mempool_create(PSD_POOL_SIZE, psd_pool_alloc, psd_pool_free, NULL);
+       if (!psd_pool)
+               return -ENOMEM;
+
+       ret = register_blkdev(pkt_major, "pktcdvd");
+       if (ret < 0) {
+               printk("pktcdvd: Unable to register block device\n");
+               goto out2;
+       }
+       if (!pkt_major)
+               pkt_major = ret;
+
+       ret = misc_register(&pkt_misc);
+       if (ret) {
+               printk("pktcdvd: Unable to register misc device\n");
+               goto out;
+       }
+
+       init_MUTEX(&ctl_mutex);
+
+       pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
+
+       DPRINTK("pktcdvd: %s\n", VERSION_CODE);
+       return 0;
+
+out:
+       unregister_blkdev(pkt_major, "pktcdvd");
+out2:
+       mempool_destroy(psd_pool);
+       return ret;
+}
+
+void pkt_exit(void)
+{
+       remove_proc_entry("pktcdvd", proc_root_driver);
+       misc_deregister(&pkt_misc);
+       unregister_blkdev(pkt_major, "pktcdvd");
+       mempool_destroy(psd_pool);
+}
+
+MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives");
+MODULE_AUTHOR("Jens Axboe <axboe@suse.de>");
+MODULE_LICENSE("GPL");
+
+module_init(pkt_init);
+module_exit(pkt_exit);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
new file mode 100644 (file)
index 0000000..f605535
--- /dev/null
@@ -0,0 +1,2097 @@
+/*
+ * The low performance USB storage driver (ub).
+ *
+ * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com)
+ *
+ * This work is a part of Linux kernel, is derived from it,
+ * and is not licensed separately. See file COPYING for details.
+ *
+ * TODO (sorted by decreasing priority)
+ *  -- ZIP does "ub: resid 18 len 0 act 0" and whole transport quits (toggles?)
+ *  -- set readonly flag for CDs, set removable flag for CF readers
+ *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
+ *  -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...)
+ *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
+ *  -- do something about spin-down devices, they are extremely dangerous
+ *     (ZIP is one. Needs spin-up command as well.)
+ *  -- verify the 13 conditions and do bulk resets
+ *  -- normal pool of commands instead of cmdv[]?
+ *  -- kill last_pipe and simply do two-state clearing on both pipes
+ *  -- verify protocol (bulk) from USB descriptors (maybe...)
+ *  -- highmem and sg
+ *  -- move top_sense and work_bcs into separate allocations (if they survive)
+ *     for cache purists and esoteric architectures.
+ *  -- prune comments, they are too volumnous
+ *  -- Exterminate P3 printks
+ *  -- Resove XXX's
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/blkdev.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/timer.h>
+#include <scsi/scsi.h>
+
+#define DRV_NAME "ub"
+#define DEVFS_NAME DRV_NAME
+
+#define UB_MAJOR 125   /* Stolen from Experimental range for a week - XXX */
+
+/*
+ * Definitions which have to be scattered once we understand the layout better.
+ */
+
+/* Transport (despite PR in the name) */
+#define US_PR_BULK     0x50            /* bulk only */
+
+/* Protocol */
+#define US_SC_SCSI     0x06            /* Transparent */
+
+/*
+ */
+#define UB_MINORS_PER_MAJOR    8
+
+#define UB_MAX_CDB_SIZE      16                /* Corresponds to Bulk */
+
+#define UB_SENSE_SIZE  18
+
+/*
+ */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+       u32     Signature;              /* contains 'USBC' */
+       u32     Tag;                    /* unique per command id */
+       u32     DataTransferLength;     /* size of data */
+       u8      Flags;                  /* direction in bit 0 */
+       u8      Lun;                    /* LUN normally 0 */
+       u8      Length;                 /* of of the CDB */
+       u8      CDB[UB_MAX_CDB_SIZE];   /* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN    31
+#define US_BULK_CB_SIGN                0x43425355      /*spells out USBC */
+#define US_BULK_FLAG_IN                1
+#define US_BULK_FLAG_OUT       0
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+       u32     Signature;              /* should = 'USBS' */
+       u32     Tag;                    /* same as original command */
+       u32     Residue;                /* amount not transferred */
+       u8      Status;                 /* see below */
+};
+
+#define US_BULK_CS_WRAP_LEN    13
+#define US_BULK_CS_SIGN                0x53425355      /* spells out 'USBS' */
+/* This is for Olympus Camedia digital cameras */
+#define US_BULK_CS_OLYMPUS_SIGN        0x55425355      /* spells out 'USBU' */
+#define US_BULK_STAT_OK                0
+#define US_BULK_STAT_FAIL      1
+#define US_BULK_STAT_PHASE     2
+
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST  0xff
+#define US_BULK_GET_MAX_LUN    0xfe
+
+/*
+ */
+struct ub_dev;
+
+#define UB_MAX_REQ_SG  1
+#define UB_MAX_SECTORS 64
+
+/*
+ * A second ought to be enough for a 32K transfer (UB_MAX_SECTORS)
+ * even if a webcam hogs the bus (famous last words).
+ * Some CDs need a second to spin up though.
+ * ZIP drive rejects commands when it's not spinning,
+ * so it does not need long timeouts either.
+ */
+#define UB_URB_TIMEOUT (HZ*2)
+#define UB_CTRL_TIMEOUT        (HZ/2) /* 500ms ought to be enough to clear a stall */
+
+/*
+ * An instance of a SCSI command in transit.
+ */
+#define UB_DIR_NONE    0
+#define UB_DIR_READ    1
+#define UB_DIR_ILLEGAL2        2
+#define UB_DIR_WRITE   3
+
+#define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
+                        (((c)==UB_DIR_READ)? 'r': 'n'))
+
+enum ub_scsi_cmd_state {
+       UB_CMDST_INIT,                  /* Initial state */
+       UB_CMDST_CMD,                   /* Command submitted */
+       UB_CMDST_DATA,                  /* Data phase */
+       UB_CMDST_CLR2STS,               /* Clearing before requesting status */
+       UB_CMDST_STAT,                  /* Status phase */
+       UB_CMDST_CLEAR,                 /* Clearing a stall (halt, actually) */
+       UB_CMDST_SENSE,                 /* Sending Request Sense */
+       UB_CMDST_DONE                   /* Final state */
+};
+
+static char *ub_scsi_cmd_stname[] = {
+       ".  ",
+       "Cmd",
+       "dat",
+       "c2s",
+       "sts",
+       "clr",
+       "Sen",
+       "fin"
+};
+
+struct ub_scsi_cmd {
+       unsigned char cdb[UB_MAX_CDB_SIZE];
+       unsigned char cdb_len;
+
+       unsigned char dir;              /* 0 - none, 1 - read, 3 - write. */
+       unsigned char trace_index;
+       enum ub_scsi_cmd_state state;
+       unsigned int tag;
+       struct ub_scsi_cmd *next;
+
+       int error;                      /* Return code - valid upon done */
+       int act_len;                    /* Return size */
+
+       int stat_count;                 /* Retries getting status. */
+
+       /*
+        * We do not support transfers from highmem pages
+        * because the underlying USB framework does not do what we need.
+        */
+       char *data;                     /* Requested buffer */
+       unsigned int len;               /* Requested length */
+       // struct scatterlist sgv[UB_MAX_REQ_SG];
+
+       void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
+       void *back;
+};
+
+/*
+ */
+struct ub_capacity {
+       unsigned long nsec;             /* Linux size - 512 byte sectors */
+       unsigned int bsize;             /* Linux hardsect_size */
+       unsigned int bshift;            /* Shift between 512 and hard sects */
+};
+
+/*
+ * The SCSI command tracing structure.
+ */
+
+#define SCMD_ST_HIST_SZ   8
+#define SCMD_TRACE_SZ    15    /* No more than 256 (trace_index) */
+
+struct ub_scsi_cmd_trace {
+       int hcur;
+       unsigned int tag;
+       unsigned int req_size, act_size;
+       unsigned char op;
+       unsigned char dir;
+       unsigned char key, asc, ascq;
+       char st_hst[SCMD_ST_HIST_SZ];   
+};
+
+struct ub_scsi_trace {
+       int cur;
+       struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
+};
+
+/*
+ * This is a direct take-off from linux/include/completion.h
+ * The difference is that I do not wait on this thing, just poll.
+ * When I want to wait (ub_probe), I just use the stock completion.
+ *
+ * Note that INIT_COMPLETION takes no lock. It is correct. But why
+ * in the bloody hell that thing takes struct instead of pointer to struct
+ * is quite beyond me. I just copied it from the stock completion.
+ */
+struct ub_completion {
+       unsigned int done;
+       spinlock_t lock;
+};
+
+static inline void ub_init_completion(struct ub_completion *x)
+{
+       x->done = 0;
+       spin_lock_init(&x->lock);
+}
+
+#define UB_INIT_COMPLETION(x)  ((x).done = 0)
+
+static void ub_complete(struct ub_completion *x)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&x->lock, flags);
+       x->done++;
+       spin_unlock_irqrestore(&x->lock, flags);
+}
+
+static int ub_is_completed(struct ub_completion *x)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&x->lock, flags);
+       ret = x->done;
+       spin_unlock_irqrestore(&x->lock, flags);
+       return ret;
+}
+
+/*
+ */
+struct ub_scsi_cmd_queue {
+       int qlen, qmax;
+       struct ub_scsi_cmd *head, *tail;
+};
+
+/*
+ * The UB device instance.
+ */
+struct ub_dev {
+       spinlock_t lock;
+       int id;                         /* Number among ub's */
+       atomic_t poison;                /* The USB device is disconnected */
+       int openc;                      /* protected by ub_lock! */
+                                       /* kref is too implicit for our taste */
+       unsigned int tagcnt;
+       int changed;                    /* Media was changed */
+       int removable;
+       int readonly;
+       char name[8];
+       struct usb_device *dev;
+       struct usb_interface *intf;
+
+       struct ub_capacity capacity; 
+       struct gendisk *disk;
+
+       unsigned int send_bulk_pipe;    /* cached pipe values */
+       unsigned int recv_bulk_pipe;
+       unsigned int send_ctrl_pipe;
+       unsigned int recv_ctrl_pipe;
+
+       struct tasklet_struct tasklet;
+
+       /* XXX Use Ingo's mempool (once we have more than one) */
+       int cmda[1];
+       struct ub_scsi_cmd cmdv[1];
+
+       struct ub_scsi_cmd_queue cmd_queue;
+       struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */
+       unsigned char top_sense[UB_SENSE_SIZE];
+
+       struct ub_completion work_done;
+       struct urb work_urb;
+       struct timer_list work_timer;
+       int last_pipe;                  /* What might need clearing */
+       struct bulk_cb_wrap work_bcb;
+       struct bulk_cs_wrap work_bcs;
+       struct usb_ctrlrequest work_cr;
+
+       struct ub_scsi_trace tr;
+};
+
+/*
+ */
+static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static void ub_end_rq(struct request *rq, int uptodate);
+static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
+static void ub_scsi_action(unsigned long _dev);
+static void ub_scsi_dispatch(struct ub_dev *sc);
+static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
+static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
+    int stalled_pipe);
+static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
+static int ub_sync_tur(struct ub_dev *sc);
+static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret);
+
+/*
+ */
+static struct usb_device_id ub_usb_ids[] = {
+       // { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) },  /* SDDR-31 */
+       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, ub_usb_ids);
+
+/*
+ * Find me a way to identify "next free minor" for add_disk(),
+ * and the array disappears the next day. However, the number of
+ * hosts has something to do with the naming and /proc/partitions.
+ * This has to be thought out in detail before changing.
+ * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure.
+ */
+#define UB_MAX_HOSTS  26
+static char ub_hostv[UB_MAX_HOSTS];
+static spinlock_t ub_lock = SPIN_LOCK_UNLOCKED;        /* Locks globals and ->openc */
+
+/*
+ * The SCSI command tracing procedures.
+ */
+
+static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       int n;
+       struct ub_scsi_cmd_trace *t;
+
+       if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
+       t = &sc->tr.vec[n];
+
+       memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
+       t->tag = cmd->tag;
+       t->op = cmd->cdb[0];
+       t->dir = cmd->dir;
+       t->req_size = cmd->len;
+       t->st_hst[0] = cmd->state;
+
+       sc->tr.cur = n;
+       cmd->trace_index = n;
+}
+
+static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       int n;
+       struct ub_scsi_cmd_trace *t;
+
+       t = &sc->tr.vec[cmd->trace_index];
+       if (t->tag == cmd->tag) {
+               if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
+               t->st_hst[n] = cmd->state;
+               t->hcur = n;
+       }
+}
+
+static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct ub_scsi_cmd_trace *t;
+
+       t = &sc->tr.vec[cmd->trace_index];
+       if (t->tag == cmd->tag)
+               t->act_size = cmd->act_len;
+}
+
+static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
+    unsigned char *sense)
+{
+       struct ub_scsi_cmd_trace *t;
+
+       t = &sc->tr.vec[cmd->trace_index];
+       if (t->tag == cmd->tag) {
+               t->key = sense[2] & 0x0F;
+               t->asc = sense[12];
+               t->ascq = sense[13];
+       }
+}
+
+static ssize_t ub_diag_show(struct device *dev, char *page)
+{
+       struct usb_interface *intf;
+       struct ub_dev *sc;
+       int cnt;
+       unsigned long flags;
+       int nc, nh;
+       int i, j;
+       struct ub_scsi_cmd_trace *t;
+
+       intf = to_usb_interface(dev);
+       sc = usb_get_intfdata(intf);
+       if (sc == NULL)
+               return 0;
+
+       cnt = 0;
+       spin_lock_irqsave(&sc->lock, flags);
+
+       cnt += sprintf(page + cnt,
+           "qlen %d qmax %d changed %d removable %d readonly %d\n",
+           sc->cmd_queue.qlen, sc->cmd_queue.qmax,
+           sc->changed, sc->removable, sc->readonly);
+
+       if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
+       for (j = 0; j < SCMD_TRACE_SZ; j++) {
+               t = &sc->tr.vec[nc];
+
+               cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
+               if (t->op == REQUEST_SENSE) {
+                       cnt += sprintf(page + cnt, " [sense %x %02x %02x]",
+                                       t->key, t->asc, t->ascq);
+               } else {
+                       cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir));
+                       cnt += sprintf(page + cnt, " [%5d %5d]",
+                                       t->req_size, t->act_size);
+               }
+               if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
+               for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
+                       cnt += sprintf(page + cnt, " %s",
+                                       ub_scsi_cmd_stname[(int)t->st_hst[nh]]);
+                       if (++nh == SCMD_ST_HIST_SZ) nh = 0;
+               }
+               cnt += sprintf(page + cnt, "\n");
+
+               if (++nc == SCMD_TRACE_SZ) nc = 0;
+       }
+
+       spin_unlock_irqrestore(&sc->lock, flags);
+       return cnt;
+}
+
+static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */
+
+/*
+ * The id allocator.
+ *
+ * This also stores the host for indexing by minor, which is somewhat dirty.
+ */
+static int ub_id_get(void)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&ub_lock, flags);
+       for (i = 0; i < UB_MAX_HOSTS; i++) {
+               if (ub_hostv[i] == 0) {
+                       ub_hostv[i] = 1;
+                       spin_unlock_irqrestore(&ub_lock, flags);
+                       return i;
+               }
+       }
+       spin_unlock_irqrestore(&ub_lock, flags);
+       return -1;
+}
+
+static void ub_id_put(int id)
+{
+
+       if (id < 0 || id >= UB_MAX_HOSTS) {
+               printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id);
+               return;
+       }
+       if (ub_hostv[id] == 0) {
+               printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
+               return;
+       }
+       ub_hostv[id] = 0;
+}
+
+/*
+ * Final cleanup and deallocation.
+ * This must be called with ub_lock taken.
+ */
+static void ub_cleanup(struct ub_dev *sc)
+{
+       ub_id_put(sc->id);
+       kfree(sc);
+}
+
+/*
+ * The "command allocator".
+ */
+static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc)
+{
+       struct ub_scsi_cmd *ret;
+
+       if (sc->cmda[0])
+               return NULL;
+       ret = &sc->cmdv[0];
+       sc->cmda[0] = 1;
+       return ret;
+}
+
+static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       if (cmd != &sc->cmdv[0]) {
+               printk(KERN_WARNING "%s: releasing a foreign cmd %p\n",
+                   sc->name, cmd);
+               return;
+       }
+       if (!sc->cmda[0]) {
+               printk(KERN_WARNING "%s: releasing a free cmd\n", sc->name);
+               return;
+       }
+       sc->cmda[0] = 0;
+}
+
+/*
+ * The command queue.
+ */
+static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
+
+       if (t->qlen++ == 0) {
+               t->head = cmd;
+               t->tail = cmd;
+       } else {
+               t->tail->next = cmd;
+               t->tail = cmd;
+       }
+
+       if (t->qlen > t->qmax)
+               t->qmax = t->qlen;
+}
+
+static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
+
+       if (t->qlen++ == 0) {
+               t->head = cmd;
+               t->tail = cmd;
+       } else {
+               cmd->next = t->head;
+               t->head = cmd;
+       }
+
+       if (t->qlen > t->qmax)
+               t->qmax = t->qlen;
+}
+
+static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
+{
+       struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
+       struct ub_scsi_cmd *cmd;
+
+       if (t->qlen == 0)
+               return NULL;
+       if (--t->qlen == 0)
+               t->tail = NULL;
+       cmd = t->head;
+       t->head = cmd->next;
+       cmd->next = NULL;
+       return cmd;
+}
+
+#define ub_cmdq_peek(sc)  ((sc)->cmd_queue.head)
+
+/*
+ * The request function is our main entry point
+ */
+
+static inline int ub_bd_rq_fn_1(request_queue_t *q)
+{
+#if 0
+       int writing = 0, pci_dir, i, n_elem;
+       u32 tmp;
+       unsigned int msg_size;
+#endif
+       struct ub_dev *sc = q->queuedata;
+       struct request *rq;
+#if 0 /* We use rq->buffer for now */
+       struct scatterlist *sg;
+       int n_elem;
+#endif
+       struct ub_scsi_cmd *cmd;
+       int ub_dir;
+       unsigned int block, nblks;
+       int rc;
+
+       if ((rq = elv_next_request(q)) == NULL)
+               return 1;
+
+       if (atomic_read(&sc->poison) || sc->changed) {
+               blkdev_dequeue_request(rq);
+               ub_end_rq(rq, 0);
+               return 0;
+       }
+
+       if ((cmd = ub_get_cmd(sc)) == NULL) {
+               blk_stop_queue(q);
+               return 1;
+       }
+
+       blkdev_dequeue_request(rq);
+
+       if (rq_data_dir(rq) == WRITE)
+               ub_dir = UB_DIR_WRITE;
+       else
+               ub_dir = UB_DIR_READ;
+
+       /*
+        * get scatterlist from block layer
+        */
+#if 0 /* We use rq->buffer for now */
+       sg = &cmd->sgv[0];
+       n_elem = blk_rq_map_sg(q, rq, sg);
+       if (n_elem <= 0) {
+               ub_put_cmd(sc, cmd);
+               ub_end_rq(rq, 0);
+               blk_start_queue(q);
+               return 0;               /* request with no s/g entries? */
+       }
+
+       if (n_elem != 1) {              /* Paranoia */
+               printk(KERN_WARNING "%s: request with %d segments\n",
+                   sc->name, n_elem);
+               ub_put_cmd(sc, cmd);
+               ub_end_rq(rq, 0);
+               blk_start_queue(q);
+               return 0;
+       }
+#endif
+       /*
+        * XXX Unfortunately, this check does not work. It is quite possible
+        * to get bogus non-null rq->buffer if you allow sg by mistake.
+        */
+       if (rq->buffer == NULL) {
+               /*
+                * This must not happen if we set the queue right.
+                * The block level must create bounce buffers for us.
+                */
+               static int do_print = 1;
+               if (do_print) {
+                       printk(KERN_WARNING "%s: unmapped request\n", sc->name);
+                       do_print = 0;
+               }
+               ub_put_cmd(sc, cmd);
+               ub_end_rq(rq, 0);
+               blk_start_queue(q);
+               return 0;
+       }
+
+       /*
+        * build the command
+        */
+       block = rq->sector;
+       nblks = rq->nr_sectors;
+
+       memset(cmd, 0, sizeof(struct ub_scsi_cmd));
+       cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
+       /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
+       cmd->cdb[2] = block >> 24;
+       cmd->cdb[3] = block >> 16;
+       cmd->cdb[4] = block >> 8;
+       cmd->cdb[5] = block;
+       cmd->cdb[7] = nblks >> 8;
+       cmd->cdb[8] = nblks;
+       cmd->cdb_len = 10;
+       cmd->dir = ub_dir;
+       cmd->state = UB_CMDST_INIT;
+       cmd->data = rq->buffer;
+       cmd->len = nblks * 512;
+       cmd->done = ub_rw_cmd_done;
+       cmd->back = rq;
+
+       cmd->tag = sc->tagcnt++;
+       if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
+               ub_put_cmd(sc, cmd);
+               ub_end_rq(rq, 0);
+               blk_start_queue(q);
+               return 0;
+       }
+
+       return 0;
+}
+
+static void ub_bd_rq_fn(request_queue_t *q)
+{
+       do { } while (ub_bd_rq_fn_1(q) == 0);
+}
+
+static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct request *rq = cmd->back;
+       struct gendisk *disk = sc->disk;
+       request_queue_t *q = disk->queue;
+       int uptodate;
+
+       if (cmd->error == 0)
+               uptodate = 1;
+       else
+               uptodate = 0;
+
+       ub_put_cmd(sc, cmd);
+       ub_end_rq(rq, uptodate);
+       blk_start_queue(q);
+}
+
+static void ub_end_rq(struct request *rq, int uptodate)
+{
+       int rc;
+
+       rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
+       // assert(rc == 0);
+       end_that_request_last(rq);
+}
+
+/*
+ * Submit a regular SCSI operation (not an auto-sense).
+ *
+ * The Iron Law of Good Submit Routine is:
+ * Zero return - callback is done, Nonzero return - callback is not done.
+ * No exceptions.
+ *
+ * Host is assumed locked.
+ *
+ * XXX We only support Bulk for the moment.
+ */
+static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+
+       if (cmd->state != UB_CMDST_INIT ||
+           (cmd->dir != UB_DIR_NONE && cmd->len == 0)) {
+               return -EINVAL;
+       }
+
+       ub_cmdq_add(sc, cmd);
+       /*
+        * We can call ub_scsi_dispatch(sc) right away here, but it's a little
+        * safer to jump to a tasklet, in case upper layers do something silly.
+        */
+       tasklet_schedule(&sc->tasklet);
+       return 0;
+}
+
+/*
+ * Submit the first URB for the queued command.
+ * This function does not deal with queueing in any way.
+ */
+static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct bulk_cb_wrap *bcb;
+       int rc;
+
+       bcb = &sc->work_bcb;
+
+       /* set up the command wrapper */
+       bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+       bcb->Tag = cmd->tag;            /* Endianness is not important */
+       bcb->DataTransferLength = cpu_to_le32(cmd->len);
+       bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0;
+       bcb->Lun = 0;                   /* No multi-LUN yet */
+       bcb->Length = cmd->cdb_len;
+
+       /* copy the command payload */
+       memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE);
+
+       UB_INIT_COMPLETION(sc->work_done);
+
+       sc->last_pipe = sc->send_bulk_pipe;
+       usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
+           bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
+       sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+
+       /* Fill what we shouldn't be filling, because usb-storage did so. */
+       sc->work_urb.actual_length = 0;
+       sc->work_urb.error_count = 0;
+       sc->work_urb.status = 0;
+
+       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+       add_timer(&sc->work_timer);
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+               /* XXX Clear stalls */
+               printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */
+               del_timer(&sc->work_timer);
+               ub_complete(&sc->work_done);
+               return rc;
+       }
+
+       cmd->state = UB_CMDST_CMD;
+       ub_cmdtr_state(sc, cmd);
+       return 0;
+}
+
+/*
+ * Timeout handler.
+ */
+static void ub_urb_timeout(unsigned long arg)
+{
+       struct ub_dev *sc = (struct ub_dev *) arg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->lock, flags);
+       usb_unlink_urb(&sc->work_urb);
+       spin_unlock_irqrestore(&sc->lock, flags);
+}
+
+/*
+ * Completion routine for the work URB.
+ *
+ * This can be called directly from usb_submit_urb (while we have
+ * the sc->lock taken) and from an interrupt (while we do NOT have
+ * the sc->lock taken). Therefore, bounce this off to a tasklet.
+ */
+static void ub_urb_complete(struct urb *urb, struct pt_regs *pt)
+{
+       struct ub_dev *sc = urb->context;
+
+       ub_complete(&sc->work_done);
+       tasklet_schedule(&sc->tasklet);
+}
+
+static void ub_scsi_action(unsigned long _dev)
+{
+       struct ub_dev *sc = (struct ub_dev *) _dev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->lock, flags);
+       ub_scsi_dispatch(sc);
+       spin_unlock_irqrestore(&sc->lock, flags);
+}
+
+static void ub_scsi_dispatch(struct ub_dev *sc)
+{
+       struct ub_scsi_cmd *cmd;
+       int rc;
+
+       while ((cmd = ub_cmdq_peek(sc)) != NULL) {
+               if (cmd->state == UB_CMDST_DONE) {
+                       ub_cmdq_pop(sc);
+                       (*cmd->done)(sc, cmd);
+               } else if (cmd->state == UB_CMDST_INIT) {
+                       ub_cmdtr_new(sc, cmd);
+                       if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
+                               break;
+                       cmd->error = rc;
+                       cmd->state = UB_CMDST_DONE;
+                       ub_cmdtr_state(sc, cmd);
+               } else {
+                       if (!ub_is_completed(&sc->work_done))
+                               break;
+                       ub_scsi_urb_compl(sc, cmd);
+               }
+       }
+}
+
+static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct urb *urb = &sc->work_urb;
+       struct bulk_cs_wrap *bcs;
+       int pipe;
+       int rc;
+
+/* P3 */ /** printk("ub: urb status %d pipe 0x%08x len %d act %d\n",
+ urb->status, urb->pipe, urb->transfer_buffer_length, urb->actual_length); **/
+
+       if (atomic_read(&sc->poison)) {
+               /* A little too simplistic, I feel... */
+               goto Bad_End;
+       }
+
+       if (cmd->state == UB_CMDST_CLEAR) {
+               if (urb->status == -EPIPE) {
+                       /*
+                        * STALL while clearning STALL.
+                        * A STALL is illegal on a control pipe!
+                        * XXX Might try to reset the device here and retry.
+                        */
+                       printk(KERN_NOTICE "%s: "
+                           "stall on control pipe for device %u\n",
+                           sc->name, sc->dev->devnum);
+                       goto Bad_End;
+               }
+
+               /*
+                * We ignore the result for the halt clear.
+                */
+
+               /* reset the endpoint toggle */
+               usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
+                       usb_pipeout(sc->last_pipe), 0);
+
+               ub_state_sense(sc, cmd);
+
+       } else if (cmd->state == UB_CMDST_CLR2STS) {
+               if (urb->status == -EPIPE) {
+                       /*
+                        * STALL while clearning STALL.
+                        * A STALL is illegal on a control pipe!
+                        * XXX Might try to reset the device here and retry.
+                        */
+                       printk(KERN_NOTICE "%s: "
+                           "stall on control pipe for device %u\n",
+                           sc->name, sc->dev->devnum);
+                       goto Bad_End;
+               }
+
+               /*
+                * We ignore the result for the halt clear.
+                */
+
+               /* reset the endpoint toggle */
+               usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),
+                       usb_pipeout(sc->last_pipe), 0);
+
+               ub_state_stat(sc, cmd);
+
+       } else if (cmd->state == UB_CMDST_CMD) {
+               if (urb->status == -EPIPE) {
+                       rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
+                       if (rc != 0) {
+                               printk(KERN_NOTICE "%s: "
+                                   "unable to submit clear for device %u (%d)\n",
+                                   sc->name, sc->dev->devnum, rc);
+                               /*
+                                * This is typically ENOMEM or some other such shit.
+                                * Retrying is pointless. Just do Bad End on it...
+                                */
+                               goto Bad_End;
+                       }
+                       cmd->state = UB_CMDST_CLEAR;
+                       ub_cmdtr_state(sc, cmd);
+                       return;
+               }
+               if (urb->status != 0)
+                       goto Bad_End;
+               if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
+                       /* XXX Must do reset here to unconfuse the device */
+                       goto Bad_End;
+               }
+
+               if (cmd->dir == UB_DIR_NONE) {
+                       ub_state_stat(sc, cmd);
+                       return;
+               }
+
+               UB_INIT_COMPLETION(sc->work_done);
+
+               if (cmd->dir == UB_DIR_READ)
+                       pipe = sc->recv_bulk_pipe;
+               else
+                       pipe = sc->send_bulk_pipe;
+               sc->last_pipe = pipe;
+               usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
+                   cmd->data, cmd->len, ub_urb_complete, sc);
+               sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+               sc->work_urb.actual_length = 0;
+               sc->work_urb.error_count = 0;
+               sc->work_urb.status = 0;
+
+               sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+               add_timer(&sc->work_timer);
+
+               if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+                       /* XXX Clear stalls */
+                       printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
+                       del_timer(&sc->work_timer);
+                       ub_complete(&sc->work_done);
+                       ub_state_done(sc, cmd, rc);
+                       return;
+               }
+
+               cmd->state = UB_CMDST_DATA;
+               ub_cmdtr_state(sc, cmd);
+
+       } else if (cmd->state == UB_CMDST_DATA) {
+               if (urb->status == -EPIPE) {
+                       rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
+                       if (rc != 0) {
+                               printk(KERN_NOTICE "%s: "
+                                   "unable to submit clear for device %u (%d)\n",
+                                   sc->name, sc->dev->devnum, rc);
+                               /*
+                                * This is typically ENOMEM or some other such shit.
+                                * Retrying is pointless. Just do Bad End on it...
+                                */
+                               goto Bad_End;
+                       }
+                       cmd->state = UB_CMDST_CLR2STS;
+                       ub_cmdtr_state(sc, cmd);
+                       return;
+               }
+               if (urb->status == -EOVERFLOW) {
+                       /*
+                        * A babble? Failure, but we must transfer CSW now.
+                        */
+                       cmd->error = -EOVERFLOW;        /* A cheap trick... */
+               } else {
+                       if (urb->status != 0)
+                               goto Bad_End;
+               }
+
+               cmd->act_len = urb->actual_length;
+               ub_cmdtr_act_len(sc, cmd);
+
+               ub_state_stat(sc, cmd);
+
+       } else if (cmd->state == UB_CMDST_STAT) {
+               if (urb->status == -EPIPE) {
+                       rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
+                       if (rc != 0) {
+                               printk(KERN_NOTICE "%s: "
+                                   "unable to submit clear for device %u (%d)\n",
+                                   sc->name, sc->dev->devnum, rc);
+                               /*
+                                * This is typically ENOMEM or some other such shit.
+                                * Retrying is pointless. Just do Bad End on it...
+                                */
+                               goto Bad_End;
+                       }
+                       cmd->state = UB_CMDST_CLEAR;
+                       ub_cmdtr_state(sc, cmd);
+                       return;
+               }
+               if (urb->status != 0)
+                       goto Bad_End;
+
+               if (urb->actual_length == 0) {
+                       /*
+                        * Some broken devices add unnecessary zero-length
+                        * packets to the end of their data transfers.
+                        * Such packets show up as 0-length CSWs. If we
+                        * encounter such a thing, try to read the CSW again.
+                        */
+                       if (++cmd->stat_count >= 4) {
+                               printk(KERN_NOTICE "%s: "
+                                   "unable to get CSW on device %u\n",
+                                   sc->name, sc->dev->devnum);
+                               goto Bad_End;
+                       }
+
+                       /*
+                        * ub_state_stat only not dropping the count...
+                        */
+                       UB_INIT_COMPLETION(sc->work_done);
+
+                       sc->last_pipe = sc->recv_bulk_pipe;
+                       usb_fill_bulk_urb(&sc->work_urb, sc->dev,
+                           sc->recv_bulk_pipe, &sc->work_bcs,
+                           US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
+                       sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+                       sc->work_urb.actual_length = 0;
+                       sc->work_urb.error_count = 0;
+                       sc->work_urb.status = 0;
+
+                       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+                       add_timer(&sc->work_timer);
+
+                       rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC);
+                       if (rc != 0) {
+                               /* XXX Clear stalls */
+                               printk("%s: CSW #%d submit failed (%d)\n",
+                                  sc->name, cmd->tag, rc); /* P3 */
+                               del_timer(&sc->work_timer);
+                               ub_complete(&sc->work_done);
+                               ub_state_done(sc, cmd, rc);
+                               return;
+                       }
+                       return;
+               }
+
+               /*
+                * Check the returned Bulk protocol status.
+                */
+
+               bcs = &sc->work_bcs;
+               rc = le32_to_cpu(bcs->Residue);
+               if (rc != cmd->len - cmd->act_len) {
+                       /*
+                        * It is all right to transfer less, the caller has
+                        * to check. But it's not all right if the device
+                        * counts disagree with our counts.
+                        */
+                       /* P3 */ printk("%s: resid %d len %d act %d\n",
+                           sc->name, rc, cmd->len, cmd->act_len);
+                       goto Bad_End;
+               }
+
+               if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) &&
+                   bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) {
+                       /* XXX Rate-limit, even for P3 tagged */
+                       /* P3 */ printk("ub: signature 0x%x\n", bcs->Signature);
+                       /* Windows ignores signatures, so do we. */
+               }
+
+               if (bcs->Tag != cmd->tag) {
+                       /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n",
+                           sc->name, cmd->tag, bcs->Tag);
+                       goto Bad_End;
+               }
+
+               switch (bcs->Status) {
+               case US_BULK_STAT_OK:
+                       break;
+               case US_BULK_STAT_FAIL:
+                       ub_state_sense(sc, cmd);
+                       return;
+               case US_BULK_STAT_PHASE:
+                       /* XXX We must reset the transport here */
+                       /* P3 */ printk("%s: status PHASE\n", sc->name);
+                       goto Bad_End;
+               default:
+                       printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
+                           sc->name, bcs->Status);
+                       goto Bad_End;
+               }
+
+               /* Not zeroing error to preserve a babble indicator */
+               cmd->state = UB_CMDST_DONE;
+               ub_cmdtr_state(sc, cmd);
+               ub_cmdq_pop(sc);
+               (*cmd->done)(sc, cmd);
+
+       } else if (cmd->state == UB_CMDST_SENSE) {
+               /* 
+                * We do not look at sense, because even if there was no sense,
+                * we get into UB_CMDST_SENSE from a STALL or CSW FAIL only.
+                * We request sense because we want to clear CHECK CONDITION
+                * on devices with delusions of SCSI, and not because we
+                * are curious in any way about the sense itself.
+                */
+               /* if ((cmd->top_sense[2] & 0x0F) == NO_SENSE) { foo } */
+
+               ub_state_done(sc, cmd, -EIO);
+       } else {
+               printk(KERN_WARNING "%s: "
+                   "wrong command state %d on device %u\n",
+                   sc->name, cmd->state, sc->dev->devnum);
+               goto Bad_End;
+       }
+       return;
+
+Bad_End: /* Little Excel is dead */
+       ub_state_done(sc, cmd, -EIO);
+}
+
+/*
+ * Factorization helper for the command state machine:
+ * Finish the command.
+ */
+static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
+{
+
+       cmd->error = rc;
+       cmd->state = UB_CMDST_DONE;
+       ub_cmdtr_state(sc, cmd);
+       ub_cmdq_pop(sc);
+       (*cmd->done)(sc, cmd);
+}
+
+/*
+ * Factorization helper for the command state machine:
+ * Submit a CSW read and go to STAT state.
+ */
+static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       int rc;
+
+       UB_INIT_COMPLETION(sc->work_done);
+
+       sc->last_pipe = sc->recv_bulk_pipe;
+       usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
+           &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
+       sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+       sc->work_urb.actual_length = 0;
+       sc->work_urb.error_count = 0;
+       sc->work_urb.status = 0;
+
+       sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;
+       add_timer(&sc->work_timer);
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+               /* XXX Clear stalls */
+               printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
+               del_timer(&sc->work_timer);
+               ub_complete(&sc->work_done);
+               ub_state_done(sc, cmd, rc);
+               return;
+       }
+
+       cmd->stat_count = 0;
+       cmd->state = UB_CMDST_STAT;
+       ub_cmdtr_state(sc, cmd);
+}
+
+/*
+ * Factorization helper for the command state machine:
+ * Submit a REQUEST SENSE and go to SENSE state.
+ */
+static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct ub_scsi_cmd *scmd;
+       int rc;
+
+       if (cmd->cdb[0] == REQUEST_SENSE) {
+               rc = -EPIPE;
+               goto error;
+       }
+
+       memset(&sc->top_sense, 0, UB_SENSE_SIZE);
+       scmd = &sc->top_rqs_cmd;
+       scmd->cdb[0] = REQUEST_SENSE;
+       scmd->cdb_len = 6;
+       scmd->dir = UB_DIR_READ;
+       scmd->state = UB_CMDST_INIT;
+       scmd->data = sc->top_sense;
+       scmd->len = UB_SENSE_SIZE;
+       scmd->done = ub_top_sense_done;
+       scmd->back = cmd;
+
+       scmd->tag = sc->tagcnt++;
+
+       cmd->state = UB_CMDST_SENSE;
+       ub_cmdtr_state(sc, cmd);
+
+       ub_cmdq_insert(sc, scmd);
+       return;
+
+error:
+       ub_state_done(sc, cmd, rc);
+}
+
+/*
+ * A helper for the command's state machine:
+ * Submit a stall clear.
+ */
+static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
+    int stalled_pipe)
+{
+       int endp;
+       struct usb_ctrlrequest *cr;
+       int rc;
+
+       endp = usb_pipeendpoint(stalled_pipe);
+       if (usb_pipein (stalled_pipe))
+               endp |= USB_DIR_IN;
+
+       cr = &sc->work_cr;
+       cr->bRequestType = USB_RECIP_ENDPOINT;
+       cr->bRequest = USB_REQ_CLEAR_FEATURE;
+       cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);
+       cr->wIndex = cpu_to_le16(endp);
+       cr->wLength = cpu_to_le16(0);
+
+       UB_INIT_COMPLETION(sc->work_done);
+
+       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+           (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
+       sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+       sc->work_urb.actual_length = 0;
+       sc->work_urb.error_count = 0;
+       sc->work_urb.status = 0;
+
+       sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&sc->work_timer);
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+               del_timer(&sc->work_timer);
+               ub_complete(&sc->work_done);
+               return rc;
+       }
+       return 0;
+}
+
+/*
+ */
+static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
+{
+       unsigned char *sense = scmd->data;
+       struct ub_scsi_cmd *cmd;
+
+       ub_cmdtr_sense(sc, scmd, sense);
+
+       if ((cmd = ub_cmdq_peek(sc)) == NULL) {
+               printk(KERN_WARNING "%s: sense done while idle\n", sc->name);
+               return;
+       }
+       if (cmd != scmd->back) {
+               printk(KERN_WARNING "%s: "
+                   "sense done for wrong command 0x%x on device %u\n",
+                   sc->name, cmd->tag, sc->dev->devnum);
+               return;
+       }
+       if (cmd->state != UB_CMDST_SENSE) {
+               printk(KERN_WARNING "%s: "
+                   "sense done with bad cmd state %d on device %u\n",
+                   sc->name, cmd->state, sc->dev->devnum);
+               return;
+       }
+
+       ub_scsi_urb_compl(sc, cmd);
+}
+
+#if 0
+/* Determine what the maximum LUN supported is */
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+       int result;
+
+       /* issue the command */
+       result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+                                US_BULK_GET_MAX_LUN, 
+                                USB_DIR_IN | USB_TYPE_CLASS | 
+                                USB_RECIP_INTERFACE,
+                                0, us->ifnum, us->iobuf, 1, HZ);
+
+       /* 
+        * Some devices (i.e. Iomega Zip100) need this -- apparently
+        * the bulk pipes get STALLed when the GetMaxLUN request is
+        * processed.   This is, in theory, harmless to all other devices
+        * (regardless of if they stall or not).
+        */
+       if (result < 0) {
+               usb_stor_clear_halt(us, us->recv_bulk_pipe);
+               usb_stor_clear_halt(us, us->send_bulk_pipe);
+       }
+
+       US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
+                 result, us->iobuf[0]);
+
+       /* if we have a successful request, return the result */
+       if (result == 1)
+               return us->iobuf[0];
+
+       /* return the default -- no LUNs */
+       return 0;
+}
+#endif
+
+/*
+ * This is called from a process context.
+ */
+static void ub_revalidate(struct ub_dev *sc)
+{
+
+       sc->readonly = 0;       /* XXX Query this from the device */
+
+       /*
+        * XXX sd.c sets capacity to zero in such case. However, it doesn't
+        * work for us. In case of zero capacity, block layer refuses to
+        * have the /dev/uba opened (why?) Set capacity to some random value.
+        */
+       sc->capacity.nsec = 50;
+       sc->capacity.bsize = 512;
+       sc->capacity.bshift = 0;
+
+       if (ub_sync_tur(sc) != 0)
+               return;                 /* Not ready */
+       sc->changed = 0;
+
+       if (ub_sync_read_cap(sc, &sc->capacity) != 0) {
+               /*
+                * The retry here means something is wrong, either with the
+                * device, with the transport, or with our code.
+                * We keep this because sd.c has retries for capacity.
+                */
+               if (ub_sync_read_cap(sc, &sc->capacity) != 0) {
+                       sc->capacity.nsec = 100;
+                       sc->capacity.bsize = 512;
+                       sc->capacity.bshift = 0;
+               }
+       }
+}
+
+/*
+ * The open funcion.
+ * This is mostly needed to keep refcounting, but also to support
+ * media checks on removable media drives.
+ */
+static int ub_bd_open(struct inode *inode, struct file *filp)
+{
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ub_dev *sc;
+       unsigned long flags;
+       int rc;
+
+       if ((sc = disk->private_data) == NULL)
+               return -ENXIO;
+       spin_lock_irqsave(&ub_lock, flags);
+       if (atomic_read(&sc->poison)) {
+               spin_unlock_irqrestore(&ub_lock, flags);
+               return -ENXIO;
+       }
+       sc->openc++;
+       spin_unlock_irqrestore(&ub_lock, flags);
+
+       if (sc->removable || sc->readonly)
+               check_disk_change(inode->i_bdev);
+
+       /* XXX sd.c and floppy.c bail on open if media is not present. */
+
+       if (sc->readonly && (filp->f_mode & FMODE_WRITE)) {
+               rc = -EROFS;
+               goto err_open;
+       }
+
+       return 0;
+
+err_open:
+       spin_lock_irqsave(&ub_lock, flags);
+       --sc->openc;
+       if (sc->openc == 0 && atomic_read(&sc->poison))
+               ub_cleanup(sc);
+       spin_unlock_irqrestore(&ub_lock, flags);
+       return rc;
+}
+
+/*
+ */
+static int ub_bd_release(struct inode *inode, struct file *filp)
+{
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ub_dev *sc = disk->private_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ub_lock, flags);
+       --sc->openc;
+       if (sc->openc == 0 && atomic_read(&sc->poison))
+               ub_cleanup(sc);
+       spin_unlock_irqrestore(&ub_lock, flags);
+       return 0;
+}
+
+/*
+ * The ioctl interface.
+ */
+static int ub_bd_ioctl(struct inode *inode, struct file *filp,
+    unsigned int cmd, unsigned long arg)
+{
+// void __user *usermem = (void *) arg;
+// struct carm_port *port = ino->i_bdev->bd_disk->private_data;
+// struct hd_geometry geom;
+
+#if 0
+       switch (cmd) {
+       case HDIO_GETGEO:
+               if (usermem == NULL)            // XXX Bizzare. Why?
+                       return -EINVAL;
+
+               geom.heads = (u8) port->dev_geom_head;
+               geom.sectors = (u8) port->dev_geom_sect;
+               geom.cylinders = port->dev_geom_cyl;
+               geom.start = get_start_sect(ino->i_bdev);
+
+               if (copy_to_user(usermem, &geom, sizeof(geom)))
+                       return -EFAULT;
+               return 0;
+
+       default: ;
+       }
+#endif
+
+       return -ENOTTY;
+}
+
+/*
+ * This is called once a new disk was seen by the block layer or by ub_probe().
+ * The main onjective here is to discover the features of the media such as
+ * the capacity, read-only status, etc. USB storage generally does not
+ * need to be spun up, but if we needed it, this would be the place.
+ *
+ * This call can sleep.
+ *
+ * The return code is not used.
+ */
+static int ub_bd_revalidate(struct gendisk *disk)
+{
+       struct ub_dev *sc = disk->private_data;
+
+       ub_revalidate(sc);
+       /* This is pretty much a long term P3 */
+       printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
+           sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize);
+
+       set_capacity(disk, sc->capacity.nsec);
+       // set_disk_ro(sdkp->disk, sc->readonly);
+       return 0;
+}
+
+/*
+ * The check is called by the block layer to verify if the media
+ * is still available. It is supposed to be harmless, lightweight and
+ * non-intrusive in case the media was not changed.
+ *
+ * This call can sleep.
+ *
+ * The return code is bool!
+ */
+static int ub_bd_media_changed(struct gendisk *disk)
+{
+       struct ub_dev *sc = disk->private_data;
+
+       if (!sc->removable)
+               return 0;
+
+       /*
+        * We clean checks always after every command, so this is not
+        * as dangerous as it looks. If the TEST_UNIT_READY fails here,
+        * the device is actually not ready with operator or software
+        * intervention required. One dangerous item might be a drive which
+        * spins itself down, and come the time to write dirty pages, this
+        * will fail, then block layer discards the data. Since we never
+        * spin drives up, such devices simply cannot be used with ub anyway.
+        */
+       if (ub_sync_tur(sc) != 0) {
+               sc->changed = 1;
+               /* P3 */ printk("%s: made changed\n", sc->name);
+               return 1;
+       }
+
+       /* The sd.c clears this before returning (one-shot flag). Why? */
+       /* P3 */ printk("%s: %s changed\n", sc->name,
+           sc->changed? "is": "was not");
+       return sc->changed;
+}
+
+static struct block_device_operations ub_bd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ub_bd_open,
+       .release        = ub_bd_release,
+       .ioctl          = ub_bd_ioctl,
+       .media_changed  = ub_bd_media_changed,
+       .revalidate_disk = ub_bd_revalidate,
+};
+
+/*
+ * Common ->done routine for commands executed synchronously.
+ */
+static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+       struct completion *cop = cmd->back;
+       complete(cop);
+}
+
+/*
+ * Test if the device has a check condition on it, synchronously.
+ */
+static int ub_sync_tur(struct ub_dev *sc)
+{
+       struct ub_scsi_cmd *cmd;
+       enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) };
+       unsigned long flags;
+       struct completion compl;
+       int rc;
+
+       init_completion(&compl);
+
+       rc = -ENOMEM;
+       if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+               goto err_alloc;
+       memset(cmd, 0, ALLOC_SIZE);
+
+       cmd->cdb[0] = TEST_UNIT_READY;
+       cmd->cdb_len = 6;
+       cmd->dir = UB_DIR_NONE;
+       cmd->state = UB_CMDST_INIT;
+       cmd->done = ub_probe_done;
+       cmd->back = &compl;
+
+       spin_lock_irqsave(&sc->lock, flags);
+       cmd->tag = sc->tagcnt++;
+
+       rc = ub_submit_scsi(sc, cmd);
+       spin_unlock_irqrestore(&sc->lock, flags);
+
+       if (rc != 0) {
+               printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */
+               goto err_submit;
+       }
+
+       wait_for_completion(&compl);
+
+       rc = cmd->error;
+
+err_submit:
+       kfree(cmd);
+err_alloc:
+       return rc;
+}
+
+/*
+ * Read the SCSI capacity synchronously (for probing).
+ */
+static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret)
+{
+       struct ub_scsi_cmd *cmd;
+       char *p;
+       enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
+       unsigned long flags;
+       unsigned int bsize, shift;
+       unsigned long nsec;
+       struct completion compl;
+       int rc;
+
+       init_completion(&compl);
+
+       rc = -ENOMEM;
+       if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+               goto err_alloc;
+       memset(cmd, 0, ALLOC_SIZE);
+       p = (char *)cmd + sizeof(struct ub_scsi_cmd);
+
+       cmd->cdb[0] = 0x25;
+       cmd->cdb_len = 10;
+       cmd->dir = UB_DIR_READ;
+       cmd->state = UB_CMDST_INIT;
+       cmd->data = p;
+       cmd->len = 8;
+       cmd->done = ub_probe_done;
+       cmd->back = &compl;
+
+       spin_lock_irqsave(&sc->lock, flags);
+       cmd->tag = sc->tagcnt++;
+
+       rc = ub_submit_scsi(sc, cmd);
+       spin_unlock_irqrestore(&sc->lock, flags);
+
+       if (rc != 0) {
+               printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */
+               goto err_submit;
+       }
+
+       wait_for_completion(&compl);
+
+       if (cmd->error != 0) {
+               printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */
+               rc = -EIO;
+               goto err_read;
+       }
+       if (cmd->act_len != 8) {
+               printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */
+               rc = -EIO;
+               goto err_read;
+       }
+
+       /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */
+       nsec = be32_to_cpu(*(u32 *)p) + 1;
+       bsize = be32_to_cpu(*(u32 *)(p + 4));
+       switch (bsize) {
+       case 512:       shift = 0;      break;
+       case 1024:      shift = 1;      break;
+       case 2048:      shift = 2;      break;
+       case 4096:      shift = 3;      break;
+       default:
+               printk("ub: Bad sector size %u\n", bsize); /* P3 */
+               rc = -EDOM;
+               goto err_inv_bsize;
+       }
+
+       ret->bsize = bsize;
+       ret->bshift = shift;
+       ret->nsec = nsec << shift;
+       rc = 0;
+
+err_inv_bsize:
+err_read:
+err_submit:
+       kfree(cmd);
+err_alloc:
+       return rc;
+}
+
+/*
+ */
+static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt)
+{
+       struct completion *cop = urb->context;
+       complete(cop);
+}
+
+static void ub_probe_timeout(unsigned long arg)
+{
+       struct completion *cop = (struct completion *) arg;
+       complete(cop);
+}
+
+/*
+ * Clear initial stalls.
+ */
+static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
+{
+       int endp;
+       struct usb_ctrlrequest *cr;
+       struct completion compl;
+       struct timer_list timer;
+       int rc;
+
+       init_completion(&compl);
+
+       endp = usb_pipeendpoint(stalled_pipe);
+       if (usb_pipein (stalled_pipe))
+               endp |= USB_DIR_IN;
+
+       cr = &sc->work_cr;
+       cr->bRequestType = USB_RECIP_ENDPOINT;
+       cr->bRequest = USB_REQ_CLEAR_FEATURE;
+       cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);
+       cr->wIndex = cpu_to_le16(endp);
+       cr->wLength = cpu_to_le16(0);
+
+       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+           (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
+       sc->work_urb.transfer_flags = 0;
+       sc->work_urb.actual_length = 0;
+       sc->work_urb.error_count = 0;
+       sc->work_urb.status = 0;
+
+       init_timer(&timer);
+       timer.function = ub_probe_timeout;
+       timer.data = (unsigned long) &compl;
+       timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&timer);
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+               printk(KERN_WARNING
+                    "%s: Unable to submit a probe clear (%d)\n", sc->name, rc);
+               del_timer_sync(&timer);
+               return rc;
+       }
+
+       wait_for_completion(&compl);
+
+       del_timer_sync(&timer);
+       /*
+        * Most of the time, URB was done and dev set to NULL, and so
+        * the unlink bounces out with ENODEV. We do not call usb_kill_urb
+        * because we still think about a backport to 2.4.
+        */
+       usb_unlink_urb(&sc->work_urb);
+
+       /* reset the endpoint toggle */
+       usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0);
+
+       return 0;
+}
+
+/*
+ * Get the pipe settings.
+ */
+static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
+    struct usb_interface *intf)
+{
+       struct usb_host_interface *altsetting = intf->cur_altsetting;
+       struct usb_endpoint_descriptor *ep_in = NULL;
+       struct usb_endpoint_descriptor *ep_out = NULL;
+       struct usb_endpoint_descriptor *ep;
+       int i;
+
+       /*
+        * Find the endpoints we need.
+        * We are expecting a minimum of 2 endpoints - in and out (bulk).
+        * We will ignore any others.
+        */
+       for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
+               ep = &altsetting->endpoint[i].desc;
+
+               /* Is it a BULK endpoint? */
+               if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                               == USB_ENDPOINT_XFER_BULK) {
+                       /* BULK in or out? */
+                       if (ep->bEndpointAddress & USB_DIR_IN)
+                               ep_in = ep;
+                       else
+                               ep_out = ep;
+               }
+       }
+
+       if (ep_in == NULL || ep_out == NULL) {
+               printk(KERN_NOTICE "%s: device %u failed endpoint check\n",
+                   sc->name, sc->dev->devnum);
+               return -EIO;
+       }
+
+       /* Calculate and store the pipe values */
+       sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0);
+       sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0);
+       sc->send_bulk_pipe = usb_sndbulkpipe(dev,
+               ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, 
+               ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+       return 0;
+}
+
+/*
+ * Probing is done in the process context, which allows us to cheat
+ * and not to build a state machine for the discovery.
+ */
+static int ub_probe(struct usb_interface *intf,
+    const struct usb_device_id *dev_id)
+{
+       struct ub_dev *sc;
+       request_queue_t *q;
+       struct gendisk *disk;
+       int rc;
+
+       rc = -ENOMEM;
+       if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
+               goto err_core;
+       memset(sc, 0, sizeof(struct ub_dev));
+       spin_lock_init(&sc->lock);
+       usb_init_urb(&sc->work_urb);
+       tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
+       atomic_set(&sc->poison, 0);
+
+       init_timer(&sc->work_timer);
+       sc->work_timer.data = (unsigned long) sc;
+       sc->work_timer.function = ub_urb_timeout;
+
+       ub_init_completion(&sc->work_done);
+       sc->work_done.done = 1;         /* A little yuk, but oh well... */
+
+       rc = -ENOSR;
+       if ((sc->id = ub_id_get()) == -1)
+               goto err_id;
+       snprintf(sc->name, 8, DRV_NAME "%c", sc->id + 'a');
+
+       sc->dev = interface_to_usbdev(intf);
+       sc->intf = intf;
+       // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+       usb_set_intfdata(intf, sc);
+       usb_get_dev(sc->dev);
+       // usb_get_intf(sc->intf);      /* Do we need this? */
+
+       /* XXX Verify that we can handle the device (from descriptors) */
+
+       ub_get_pipes(sc, sc->dev, intf);
+
+       if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
+               goto err_diag;
+
+       /*
+        * At this point, all USB initialization is done, do upper layer.
+        * We really hate halfway initialized structures, so from the
+        * invariants perspective, this ub_dev is fully constructed at
+        * this point.
+        */
+
+       /*
+        * This is needed to clear toggles. It is a problem only if we do
+        * `rmmod ub && modprobe ub` without disconnects, but we like that.
+        */
+       ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
+       ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+
+       /*
+        * The way this is used by the startup code is a little specific.
+        * A SCSI check causes a USB stall. Our common case code sees it
+        * and clears the check, after which the device is ready for use.
+        * But if a check was not present, any command other than
+        * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE).
+        *
+        * If we neglect to clear the SCSI check, the first real command fails
+        * (which is the capacity readout). We clear that and retry, but why
+        * causing spurious retries for no reason.
+        *
+        * Revalidation may start with its own TEST_UNIT_READY, but that one
+        * has to succeed, so we clear checks with an additional one here.
+        * In any case it's not our business how revaliadation is implemented.
+        */
+       ub_sync_tur(sc);
+
+       sc->removable = 1;              /* XXX Query this from the device */
+
+       ub_revalidate(sc);
+       /* This is pretty much a long term P3 */
+       printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n",
+           sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize);
+
+       /*
+        * Just one disk per sc currently, but maybe more.
+        */
+       rc = -ENOMEM;
+       if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL)
+               goto err_diskalloc;
+
+       sc->disk = disk;
+       sprintf(disk->disk_name, DRV_NAME "%c", sc->id + 'a');
+       sprintf(disk->devfs_name, DEVFS_NAME "/%c", sc->id + 'a');
+       disk->major = UB_MAJOR;
+       disk->first_minor = sc->id * UB_MINORS_PER_MAJOR;
+       disk->fops = &ub_bd_fops;
+       disk->private_data = sc;
+       disk->driverfs_dev = &intf->dev;
+
+       rc = -ENOMEM;
+       if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
+               goto err_blkqinit;
+
+       disk->queue = q;
+
+        // blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
+       blk_queue_max_hw_segments(q, UB_MAX_REQ_SG);
+       blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
+       // blk_queue_segment_boundary(q, CARM_SG_BOUNDARY);
+       blk_queue_max_sectors(q, UB_MAX_SECTORS);
+       // blk_queue_hardsect_size(q, xxxxx);
+
+       /*
+        * This is a serious infraction, caused by a deficiency in the
+        * USB sg interface (usb_sg_wait()). We plan to remove this once
+        * we get mileage on the driver and can justify a change to USB API.
+        * See blk_queue_bounce_limit() to understand this part.
+        *
+        * XXX And I still need to be aware of the DMA mask in the HC.
+        */
+       q->bounce_pfn = blk_max_low_pfn;
+       q->bounce_gfp = GFP_NOIO;
+
+       q->queuedata = sc;
+
+       set_capacity(disk, sc->capacity.nsec);
+       if (sc->removable)
+               disk->flags |= GENHD_FL_REMOVABLE;
+
+       add_disk(disk);
+
+       return 0;
+
+err_blkqinit:
+       put_disk(disk);
+err_diskalloc:
+       device_remove_file(&sc->intf->dev, &dev_attr_diag);
+err_diag:
+       usb_set_intfdata(intf, NULL);
+       // usb_put_intf(sc->intf);
+       usb_put_dev(sc->dev);
+       spin_lock_irq(&ub_lock);
+       ub_id_put(sc->id);
+       spin_unlock_irq(&ub_lock);
+err_id:
+       kfree(sc);
+err_core:
+       return rc;
+}
+
+static void ub_disconnect(struct usb_interface *intf)
+{
+       struct ub_dev *sc = usb_get_intfdata(intf);
+       struct gendisk *disk = sc->disk;
+       request_queue_t *q = disk->queue;
+       unsigned long flags;
+
+       /*
+        * Fence stall clearnings, operations triggered by unlinkings and so on.
+        * We do not attempt to unlink any URBs, because we do not trust the
+        * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
+        */
+       atomic_set(&sc->poison, 1);
+
+       /*
+        * Blow away queued commands.
+        *
+        * Actually, this never works, because before we get here
+        * the HCD terminates outstanding URB(s). It causes our
+        * SCSI command queue to advance, commands fail to submit,
+        * and the whole queue drains. So, we just use this code to
+        * print warnings.
+        */
+       spin_lock_irqsave(&sc->lock, flags);
+       {
+               struct ub_scsi_cmd *cmd;
+               int cnt = 0;
+               while ((cmd = ub_cmdq_pop(sc)) != NULL) {
+                       cmd->error = -ENOTCONN;
+                       cmd->state = UB_CMDST_DONE;
+                       ub_cmdtr_state(sc, cmd);
+                       ub_cmdq_pop(sc);
+                       (*cmd->done)(sc, cmd);
+                       cnt++;
+               }
+               if (cnt != 0) {
+                       printk(KERN_WARNING "%s: "
+                           "%d was queued after shutdown\n", sc->name, cnt);
+               }
+       }
+       spin_unlock_irqrestore(&sc->lock, flags);
+
+       /*
+        * Unregister the upper layer, this waits for all commands to end.
+        */
+       if (disk->flags & GENHD_FL_UP)
+               del_gendisk(disk);
+       if (q)
+               blk_cleanup_queue(q);
+
+       /*
+        * If we zero disk->private_data BEFORE put_disk, we have to check
+        * for NULL all over the place in open, release, check_media and
+        * revalidate, because the block level semaphore is well inside the
+        * put_disk. But we cannot zero after the call, because *disk is gone.
+        * The sd.c is blatantly racy in this area.
+        */
+       /* disk->private_data = NULL; */
+       put_disk(disk);
+       sc->disk = NULL;
+
+       /*
+        * We really expect blk_cleanup_queue() to wait, so no amount
+        * of paranoya is too much.
+        *
+        * Taking a lock on a structure which is about to be freed
+        * is very nonsensual. Here it is largely a way to do a debug freeze,
+        * and a bracket which shows where the nonsensual code segment ends.
+        *
+        * Testing for -EINPROGRESS is always a bug, so we are bending
+        * the rules a little.
+        */
+       spin_lock_irqsave(&sc->lock, flags);
+       if (sc->work_urb.status == -EINPROGRESS) {      /* janitors: ignore */
+               printk(KERN_WARNING "%s: "
+                   "URB is active after disconnect\n", sc->name);
+       }
+       spin_unlock_irqrestore(&sc->lock, flags);
+
+       /*
+        * At this point there must be no commands coming from anyone
+        * and no URBs left in transit.
+        */
+
+       device_remove_file(&sc->intf->dev, &dev_attr_diag);
+       usb_set_intfdata(intf, NULL);
+       // usb_put_intf(sc->intf);
+       sc->intf = NULL;
+       usb_put_dev(sc->dev);
+       sc->dev = NULL;
+
+       spin_lock_irqsave(&ub_lock, flags);
+       if (sc->openc == 0)
+               ub_cleanup(sc);
+       spin_unlock_irqrestore(&ub_lock, flags);
+}
+
+struct usb_driver ub_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "ub",
+       .probe =        ub_probe,
+       .disconnect =   ub_disconnect,
+       .id_table =     ub_usb_ids,
+};
+
+static int __init ub_init(void)
+{
+       int rc;
+
+       /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu\n",
+                       sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev));
+
+       if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
+               goto err_regblkdev;
+       devfs_mk_dir(DEVFS_NAME);
+
+       if ((rc = usb_register(&ub_driver)) != 0)
+               goto err_register;
+
+       return 0;
+
+err_register:
+       devfs_remove(DEVFS_NAME);
+       unregister_blkdev(UB_MAJOR, DRV_NAME);
+err_regblkdev:
+       return rc;
+}
+
+static void __exit ub_exit(void)
+{
+       usb_deregister(&ub_driver);
+
+       devfs_remove(DEVFS_NAME);
+       unregister_blkdev(UB_MAJOR, DRV_NAME);
+}
+
+module_init(ub_init);
+module_exit(ub_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/drm/drm_core.h b/drivers/char/drm/drm_core.h
new file mode 100644 (file)
index 0000000..8ebab5a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2004 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * 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
+ * VIA, S3 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 "drm_auth.h"
+#include "drm_agpsupport.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_irq.h"
+#include "drm_drawable.h"
+#include "drm_drv.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
+#include "drm_scatter.h"
diff --git a/drivers/char/drm/i915.h b/drivers/char/drm/i915.h
new file mode 100644 (file)
index 0000000..d76d737
--- /dev/null
@@ -0,0 +1,53 @@
+/* i915.h -- Intel I915 DRM template customization -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#ifndef __I915_H__
+#define __I915_H__
+
+/* This remains constant for all DRM template files.
+ */
+#define DRM(x) i915_##x
+
+/* General customization:
+ */
+
+#define DRIVER_AUTHOR          "Tungsten Graphics, Inc."
+
+#define DRIVER_NAME            "i915"
+#define DRIVER_DESC            "Intel Graphics"
+#define DRIVER_DATE            "20040405"
+
+/* Interface history:
+ *
+ * 1.1: Original.
+ */
+#define DRIVER_MAJOR           1
+#define DRIVER_MINOR           1
+#define DRIVER_PATCHLEVEL      0
+
+#define DRIVER_IOCTLS                                                      \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT)]   = { i915_dma_init,    1, 1 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_FLUSH)]  = { i915_flush_ioctl, 1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_FLIP)]   = { i915_flip_bufs,   1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_BATCHBUFFER)] = { i915_batchbuffer, 1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_EMIT)] = { i915_irq_emit,  1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_IRQ_WAIT)] = { i915_irq_wait,  1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_GETPARAM)] = { i915_getparam,  1, 0 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_SETPARAM)] = { i915_setparam,  1, 1 }, \
+        [DRM_IOCTL_NR(DRM_IOCTL_I915_ALLOC)]   = { i915_mem_alloc,  1, 0 }, \
+        [DRM_IOCTL_NR(DRM_IOCTL_I915_FREE)]    = { i915_mem_free,    1, 0 }, \
+        [DRM_IOCTL_NR(DRM_IOCTL_I915_INIT_HEAP)] = { i915_mem_init_heap, 1, 1 }, \
+       [DRM_IOCTL_NR(DRM_IOCTL_I915_CMDBUFFER)] = { i915_cmdbuffer, 1, 0 }
+
+/* We use our own dma mechanisms, not the drm template code.  However,
+ * the shared IRQ code is useful to us:
+ */
+#define __HAVE_PM              1
+
+#endif
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
new file mode 100644 (file)
index 0000000..e33853b
--- /dev/null
@@ -0,0 +1,755 @@
+/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static inline void i915_print_status_page(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 *temp = dev_priv->hw_status_page;
+
+       if (!temp) {
+               DRM_DEBUG("no status page\n");
+               return;
+       }
+
+       DRM_DEBUG("hw_status: Interrupt Status : %x\n", temp[0]);
+       DRM_DEBUG("hw_status: LpRing Head ptr : %x\n", temp[1]);
+       DRM_DEBUG("hw_status: IRing Head ptr : %x\n", temp[2]);
+       DRM_DEBUG("hw_status: Reserved : %x\n", temp[3]);
+       DRM_DEBUG("hw_status: Driver Counter : %d\n", temp[5]);
+
+}
+
+/* Really want an OS-independent resettable timer.  Would like to have
+ * this loop run for (eg) 3 sec, but have the timer reset every time
+ * the head pointer changes, so that EBUSY only happens if the ring
+ * actually stalls for (eg) 3 seconds.
+ */
+int i915_wait_ring(drm_device_t * dev, int n, const char *caller)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+       u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+       int i;
+
+       for (i = 0; i < 10000; i++) {
+               ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+               ring->space = ring->head - (ring->tail + 8);
+               if (ring->space < 0)
+                       ring->space += ring->Size;
+               if (ring->space >= n)
+                       return 0;
+
+               dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+
+               if (ring->head != last_head)
+                       i = 0;
+
+               last_head = ring->head;
+       }
+
+       return DRM_ERR(EBUSY);
+}
+
+void i915_kernel_lost_context(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+
+       ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+       ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+       ring->space = ring->head - (ring->tail + 8);
+       if (ring->space < 0)
+               ring->space += ring->Size;
+
+       if (ring->head == ring->tail)
+               dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
+}
+
+int i915_dma_cleanup(drm_device_t * dev)
+{
+       /* Make sure interrupts are disabled here because the uninstall ioctl
+        * may not have been called from userspace and after dev_private
+        * is freed, it's too late.
+        */
+       if (dev->irq)
+               DRM(irq_uninstall) (dev);
+
+       if (dev->dev_private) {
+               drm_i915_private_t *dev_priv =
+                   (drm_i915_private_t *) dev->dev_private;
+
+               if (dev_priv->ring.virtual_start) {
+                       drm_core_ioremapfree( &dev_priv->ring.map, dev);
+               }
+
+               if (dev_priv->hw_status_page) {
+                       pci_free_consistent(dev->pdev, PAGE_SIZE,
+                                           dev_priv->hw_status_page,
+                                           dev_priv->dma_status_page);
+                       /* Need to rewrite hardware status page */
+                       I915_WRITE(0x02080, 0x1ffff000);
+               }
+
+               DRM(free) (dev->dev_private, sizeof(drm_i915_private_t),
+                          DRM_MEM_DRIVER);
+
+               dev->dev_private = NULL;
+       }
+
+       return 0;
+}
+
+static int i915_initialize(drm_device_t * dev,
+                          drm_i915_private_t * dev_priv,
+                          drm_i915_init_t * init)
+{
+       memset(dev_priv, 0, sizeof(drm_i915_private_t));
+
+       DRM_GETSAREA();
+       if (!dev_priv->sarea) {
+               DRM_ERROR("can not find sarea!\n");
+               dev->dev_private = (void *)dev_priv;
+               i915_dma_cleanup(dev);
+               return DRM_ERR(EINVAL);
+       }
+
+       dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
+       if (!dev_priv->mmio_map) {
+               dev->dev_private = (void *)dev_priv;
+               i915_dma_cleanup(dev);
+               DRM_ERROR("can not find mmio map!\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       dev_priv->sarea_priv = (drm_i915_sarea_t *)
+           ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
+
+       dev_priv->ring.Start = init->ring_start;
+       dev_priv->ring.End = init->ring_end;
+       dev_priv->ring.Size = init->ring_size;
+       dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+
+       dev_priv->ring.map.offset = init->ring_start;
+       dev_priv->ring.map.size = init->ring_size;
+       dev_priv->ring.map.type = 0;
+       dev_priv->ring.map.flags = 0;
+       dev_priv->ring.map.mtrr = 0;
+
+       drm_core_ioremap( &dev_priv->ring.map, dev );
+
+       if (dev_priv->ring.map.handle == NULL) {
+               dev->dev_private = (void *)dev_priv;
+               i915_dma_cleanup(dev);
+               DRM_ERROR("can not ioremap virtual address for"
+                         " ring buffer\n");
+               return DRM_ERR(ENOMEM);
+       }
+
+       dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
+       dev_priv->back_offset = init->back_offset;
+       dev_priv->front_offset = init->front_offset;
+       dev_priv->current_page = 0;
+       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+
+       /* We are using separate values as placeholders for mechanisms for
+        * private backbuffer/depthbuffer usage.
+        */
+       dev_priv->use_mi_batchbuffer_start = 0;
+
+       /* Allow hardware batchbuffers unless told otherwise.
+        */
+       dev_priv->allow_batchbuffer = 1;
+
+       /* Program Hardware Status Page */
+       dev_priv->hw_status_page =
+           pci_alloc_consistent(dev->pdev, PAGE_SIZE,
+                                &dev_priv->dma_status_page);
+
+       if (!dev_priv->hw_status_page) {
+               dev->dev_private = (void *)dev_priv;
+               i915_dma_cleanup(dev);
+               DRM_ERROR("Can not allocate hardware status page\n");
+               return DRM_ERR(ENOMEM);
+       }
+       memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+       DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+
+       I915_WRITE(0x02080, dev_priv->dma_status_page);
+       DRM_DEBUG("Enabled hardware status page\n");
+
+       dev->dev_private = (void *)dev_priv;
+
+       return 0;
+}
+
+static int i915_resume(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+
+       if (!dev_priv->sarea) {
+               DRM_ERROR("can not find sarea!\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       if (!dev_priv->mmio_map) {
+               DRM_ERROR("can not find mmio map!\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       if (dev_priv->ring.map.handle == NULL) {
+               DRM_ERROR("can not ioremap virtual address for"
+                         " ring buffer\n");
+               return DRM_ERR(ENOMEM);
+       }
+
+       /* Program Hardware Status Page */
+       if (!dev_priv->hw_status_page) {
+               DRM_ERROR("Can not find hardware status page\n");
+               return DRM_ERR(EINVAL);
+       }
+       DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
+
+       I915_WRITE(0x02080, dev_priv->dma_status_page);
+       DRM_DEBUG("Enabled hardware status page\n");
+
+       return 0;
+}
+
+int i915_dma_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv;
+       drm_i915_init_t init;
+       int retcode = 0;
+
+       DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data,
+                                sizeof(init));
+
+       switch (init.func) {
+       case I915_INIT_DMA:
+               dev_priv = DRM(alloc) (sizeof(drm_i915_private_t),
+                                      DRM_MEM_DRIVER);
+               if (dev_priv == NULL)
+                       return DRM_ERR(ENOMEM);
+               retcode = i915_initialize(dev, dev_priv, &init);
+               break;
+       case I915_CLEANUP_DMA:
+               retcode = i915_dma_cleanup(dev);
+               break;
+       case I915_RESUME_DMA:
+               retcode = i915_resume(dev);
+               break;
+       default:
+               retcode = -EINVAL;
+               break;
+       }
+
+       return retcode;
+}
+
+/* Implement basically the same security restrictions as hardware does
+ * for MI_BATCH_NON_SECURE.  These can be made stricter at any time.
+ *
+ * Most of the calculations below involve calculating the size of a
+ * particular instruction.  It's important to get the size right as
+ * that tells us where the next instruction to check is.  Any illegal
+ * instruction detected will be given a size of zero, which is a
+ * signal to abort the rest of the buffer.
+ */
+static int do_validate_cmd(int cmd)
+{
+       switch (((cmd >> 29) & 0x7)) {
+       case 0x0:
+               switch ((cmd >> 23) & 0x3f) {
+               case 0x0:
+                       return 1;       /* MI_NOOP */
+               case 0x4:
+                       return 1;       /* MI_FLUSH */
+               default:
+                       return 0;       /* disallow everything else */
+               }
+               break;
+       case 0x1:
+               return 0;       /* reserved */
+       case 0x2:
+               return (cmd & 0xff) + 2;        /* 2d commands */
+       case 0x3:
+               if (((cmd >> 24) & 0x1f) <= 0x18)
+                       return 1;
+
+               switch ((cmd >> 24) & 0x1f) {
+               case 0x1c:
+                       return 1;
+               case 0x1d:
+                       switch ((cmd>>16)&0xff) {
+                       case 0x3:
+                               return (cmd & 0x1f) + 2;
+                       case 0x4:
+                               return (cmd & 0xf) + 2;
+                       default:
+                               return (cmd & 0xffff) + 2;
+                       }
+               case 0x1e:
+                       if (cmd & (1 << 23))
+                               return (cmd & 0xffff) + 1;
+                       else
+                               return 1;
+               case 0x1f:
+                       if ((cmd & (1 << 23)) == 0)     /* inline vertices */
+                               return (cmd & 0x1ffff) + 2;
+                       else if (cmd & (1 << 17))       /* indirect random */
+                               if ((cmd & 0xffff) == 0)
+                                       return 0;       /* unknown length, too hard */
+                               else
+                                       return (((cmd & 0xffff) + 1) / 2) + 1;
+                       else
+                               return 2;       /* indirect sequential */
+               default:
+                       return 0;
+               }
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int validate_cmd(int cmd)
+{
+       int ret = do_validate_cmd(cmd);
+
+/*     printk("validate_cmd( %x ): %d\n", cmd, ret); */
+
+       return ret;
+}
+
+static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int i;
+       RING_LOCALS;
+
+       for (i = 0; i < dwords;) {
+               int cmd, sz;
+
+               if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
+                       return DRM_ERR(EINVAL);
+
+/*             printk("%d/%d ", i, dwords); */
+
+               if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
+                       return DRM_ERR(EINVAL);
+
+               BEGIN_LP_RING(sz);
+               OUT_RING(cmd);
+
+               while (++i, --sz) {
+                       if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
+                                                        sizeof(cmd))) {
+                               return DRM_ERR(EINVAL);
+                       }
+                       OUT_RING(cmd);
+               }
+               ADVANCE_LP_RING();
+       }
+
+       return 0;
+}
+
+static int i915_emit_box(drm_device_t * dev,
+                        drm_clip_rect_t __user * boxes,
+                        int i, int DR1, int DR4)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_clip_rect_t box;
+       RING_LOCALS;
+
+       if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
+               return EFAULT;
+       }
+
+       if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
+               DRM_ERROR("Bad box %d,%d..%d,%d\n",
+                         box.x1, box.y1, box.x2, box.y2);
+               return DRM_ERR(EINVAL);
+       }
+
+       BEGIN_LP_RING(6);
+       OUT_RING(GFX_OP_DRAWRECT_INFO);
+       OUT_RING(DR1);
+       OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+       OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+       OUT_RING(DR4);
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+
+       return 0;
+}
+
+static int i915_dispatch_cmdbuffer(drm_device_t * dev,
+                                  drm_i915_cmdbuffer_t * cmd)
+{
+       int nbox = cmd->num_cliprects;
+       int i = 0, count, ret;
+
+       if (cmd->sz & 0x3) {
+               DRM_ERROR("alignment");
+               return DRM_ERR(EINVAL);
+       }
+
+       i915_kernel_lost_context(dev);
+
+       count = nbox ? nbox : 1;
+
+       for (i = 0; i < count; i++) {
+               if (i < nbox) {
+                       ret = i915_emit_box(dev, cmd->cliprects, i,
+                                           cmd->DR1, cmd->DR4);
+                       if (ret)
+                               return ret;
+               }
+
+               ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int i915_dispatch_batchbuffer(drm_device_t * dev,
+                                    drm_i915_batchbuffer_t * batch)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_clip_rect_t __user *boxes = batch->cliprects;
+       int nbox = batch->num_cliprects;
+       int i = 0, count;
+       RING_LOCALS;
+
+       if ((batch->start | batch->used) & 0x7) {
+               DRM_ERROR("alignment");
+               return DRM_ERR(EINVAL);
+       }
+
+       i915_kernel_lost_context(dev);
+
+       count = nbox ? nbox : 1;
+
+       for (i = 0; i < count; i++) {
+               if (i < nbox) {
+                       int ret = i915_emit_box(dev, boxes, i,
+                                               batch->DR1, batch->DR4);
+                       if (ret)
+                               return ret;
+               }
+
+               if (dev_priv->use_mi_batchbuffer_start) {
+                       BEGIN_LP_RING(2);
+                       OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+                       OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+                       ADVANCE_LP_RING();
+               } else {
+                       BEGIN_LP_RING(4);
+                       OUT_RING(MI_BATCH_BUFFER);
+                       OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+                       OUT_RING(batch->start + batch->used - 4);
+                       OUT_RING(0);
+                       ADVANCE_LP_RING();
+               }
+       }
+
+       dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+       BEGIN_LP_RING(4);
+       OUT_RING(CMD_STORE_DWORD_IDX);
+       OUT_RING(20);
+       OUT_RING(dev_priv->counter);
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+
+       return 0;
+}
+
+static int i915_dispatch_flip(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+
+       DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
+                 __FUNCTION__,
+                 dev_priv->current_page,
+                 dev_priv->sarea_priv->pf_current_page);
+
+       i915_kernel_lost_context(dev);
+
+       BEGIN_LP_RING(2);
+       OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+
+       BEGIN_LP_RING(6);
+       OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
+       OUT_RING(0);
+       if (dev_priv->current_page == 0) {
+               OUT_RING(dev_priv->back_offset);
+               dev_priv->current_page = 1;
+       } else {
+               OUT_RING(dev_priv->front_offset);
+               dev_priv->current_page = 0;
+       }
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+
+       BEGIN_LP_RING(2);
+       OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+
+       dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+       BEGIN_LP_RING(4);
+       OUT_RING(CMD_STORE_DWORD_IDX);
+       OUT_RING(20);
+       OUT_RING(dev_priv->counter);
+       OUT_RING(0);
+       ADVANCE_LP_RING();
+
+       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+       return 0;
+}
+
+static int i915_quiescent(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       i915_kernel_lost_context(dev);
+       return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+}
+
+int i915_flush_ioctl(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i915_flush_ioctl called without lock held\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       return i915_quiescent(dev);
+}
+
+int i915_batchbuffer(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 *hw_status = dev_priv->hw_status_page;
+       drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
+           dev_priv->sarea_priv;
+       drm_i915_batchbuffer_t batch;
+       int ret;
+
+       if (!dev_priv->allow_batchbuffer) {
+               DRM_ERROR("Batchbuffer ioctl disabled\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data,
+                                sizeof(batch));
+
+       DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
+                 batch.start, batch.used, batch.num_cliprects);
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i915_batchbuffer called without lock held\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
+                                                      batch.num_cliprects *
+                                                      sizeof(drm_clip_rect_t)))
+               return DRM_ERR(EFAULT);
+
+       ret = i915_dispatch_batchbuffer(dev, &batch);
+
+       sarea_priv->last_dispatch = (int)hw_status[5];
+       return ret;
+}
+
+int i915_cmdbuffer(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u32 *hw_status = dev_priv->hw_status_page;
+       drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
+           dev_priv->sarea_priv;
+       drm_i915_cmdbuffer_t cmdbuf;
+       int ret;
+
+       DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data,
+                                sizeof(cmdbuf));
+
+       DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
+                 cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i915_cmdbuffer called without lock held\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       if (cmdbuf.num_cliprects &&
+           DRM_VERIFYAREA_READ(cmdbuf.cliprects,
+                               cmdbuf.num_cliprects *
+                               sizeof(drm_clip_rect_t))) {
+               DRM_ERROR("Fault accessing cliprects\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
+       if (ret) {
+               DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
+               return ret;
+       }
+
+       sarea_priv->last_dispatch = (int)hw_status[5];
+       return 0;
+}
+
+int i915_do_cleanup_pageflip(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+       if (dev_priv->current_page != 0)
+               i915_dispatch_flip(dev);
+
+       return 0;
+}
+
+int i915_flip_bufs(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i915_flip_buf called without lock held\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       return i915_dispatch_flip(dev);
+}
+
+int i915_getparam(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_getparam_t param;
+       int value;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data,
+                                sizeof(param));
+
+       switch (param.param) {
+       case I915_PARAM_IRQ_ACTIVE:
+               value = dev->irq ? 1 : 0;
+               break;
+       case I915_PARAM_ALLOW_BATCHBUFFER:
+               value = dev_priv->allow_batchbuffer ? 1 : 0;
+               break;
+       default:
+               DRM_ERROR("Unkown parameter %d\n", param.param);
+               return DRM_ERR(EINVAL);
+       }
+
+       if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+               DRM_ERROR("DRM_COPY_TO_USER failed\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
+int i915_setparam(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_setparam_t param;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data,
+                                sizeof(param));
+
+       switch (param.param) {
+       case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
+               dev_priv->use_mi_batchbuffer_start = param.value;
+               break;
+       case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
+               dev_priv->tex_lru_log_granularity = param.value;
+               break;
+       case I915_SETPARAM_ALLOW_BATCHBUFFER:
+               dev_priv->allow_batchbuffer = param.value;
+               break;
+       default:
+               DRM_ERROR("unknown parameter %d\n", param.param);
+               return DRM_ERR(EINVAL);
+       }
+
+       return 0;
+}
+
+static void i915_driver_pretakedown(drm_device_t *dev)
+{
+       if ( dev->dev_private ) {
+               drm_i915_private_t *dev_priv = dev->dev_private;
+               i915_mem_takedown( &(dev_priv->agp_heap) );
+       }
+       i915_dma_cleanup( dev );
+}
+
+static void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp)
+{
+       if ( dev->dev_private ) {
+               drm_i915_private_t *dev_priv = dev->dev_private;
+                i915_mem_release( dev, filp, dev_priv->agp_heap );
+       }
+}
+
+void i915_driver_register_fns(drm_device_t *dev)
+{
+       dev->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED;
+       dev->fn_tbl.pretakedown = i915_driver_pretakedown;
+       dev->fn_tbl.prerelease = i915_driver_prerelease;
+       dev->fn_tbl.irq_preinstall = i915_driver_irq_preinstall;
+       dev->fn_tbl.irq_postinstall = i915_driver_irq_postinstall;
+       dev->fn_tbl.irq_uninstall = i915_driver_irq_uninstall;
+       dev->fn_tbl.irq_handler = i915_driver_irq_handler;
+       
+       dev->counters += 4;
+       dev->types[6] = _DRM_STAT_IRQ;
+       dev->types[7] = _DRM_STAT_PRIMARY;
+       dev->types[8] = _DRM_STAT_SECONDARY;
+       dev->types[9] = _DRM_STAT_DMA;
+}
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
new file mode 100644 (file)
index 0000000..24f4cd6
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef _I915_DRM_H_
+#define _I915_DRM_H_
+
+/* Please note that modifications to all structs defined here are
+ * subject to backwards-compatibility constraints.
+ */
+
+#include "drm.h"
+
+/* Each region is a minimum of 16k, and there are at most 255 of them.
+ */
+#define I915_NR_TEX_REGIONS 255        /* table size 2k - maximum due to use
+                                * of chars for next/prev indices */
+#define I915_LOG_MIN_TEX_REGION_SIZE 14
+
+typedef struct _drm_i915_init {
+       enum {
+               I915_INIT_DMA = 0x01,
+               I915_CLEANUP_DMA = 0x02,
+               I915_RESUME_DMA = 0x03
+       } func;
+       unsigned int mmio_offset;
+       int sarea_priv_offset;
+       unsigned int ring_start;
+       unsigned int ring_end;
+       unsigned int ring_size;
+       unsigned int front_offset;
+       unsigned int back_offset;
+       unsigned int depth_offset;
+       unsigned int w;
+       unsigned int h;
+       unsigned int pitch;
+       unsigned int pitch_bits;
+       unsigned int back_pitch;
+       unsigned int depth_pitch;
+       unsigned int cpp;
+       unsigned int chipset;
+} drm_i915_init_t;
+
+typedef struct _drm_i915_sarea {
+       drm_tex_region_t texList[I915_NR_TEX_REGIONS + 1];
+       int last_upload;        /* last time texture was uploaded */
+       int last_enqueue;       /* last time a buffer was enqueued */
+       int last_dispatch;      /* age of the most recently dispatched buffer */
+       int ctxOwner;           /* last context to upload state */
+       int texAge;
+       int pf_enabled;         /* is pageflipping allowed? */
+       int pf_active;
+       int pf_current_page;    /* which buffer is being displayed? */
+       int perf_boxes;         /* performance boxes to be displayed */
+} drm_i915_sarea_t;
+
+/* Flags for perf_boxes
+ */
+#define I915_BOX_RING_EMPTY    0x1
+#define I915_BOX_FLIP          0x2
+#define I915_BOX_WAIT          0x4
+#define I915_BOX_TEXTURE_LOAD  0x8
+#define I915_BOX_LOST_CONTEXT  0x10
+
+/* I915 specific ioctls
+ * The device specific ioctl range is 0x40 to 0x79.
+ */
+#define DRM_IOCTL_I915_INIT            DRM_IOW( 0x40, drm_i915_init_t)
+#define DRM_IOCTL_I915_FLUSH           DRM_IO ( 0x41)
+#define DRM_IOCTL_I915_FLIP            DRM_IO ( 0x42)
+#define DRM_IOCTL_I915_BATCHBUFFER     DRM_IOW( 0x43, drm_i915_batchbuffer_t)
+#define DRM_IOCTL_I915_IRQ_EMIT         DRM_IOWR(0x44, drm_i915_irq_emit_t)
+#define DRM_IOCTL_I915_IRQ_WAIT         DRM_IOW( 0x45, drm_i915_irq_wait_t)
+#define DRM_IOCTL_I915_GETPARAM         DRM_IOWR(0x46, drm_i915_getparam_t)
+#define DRM_IOCTL_I915_SETPARAM         DRM_IOW( 0x47, drm_i915_setparam_t)
+#define DRM_IOCTL_I915_ALLOC            DRM_IOWR(0x48, drm_i915_mem_alloc_t)
+#define DRM_IOCTL_I915_FREE             DRM_IOW( 0x49, drm_i915_mem_free_t)
+#define DRM_IOCTL_I915_INIT_HEAP        DRM_IOW( 0x4a, drm_i915_mem_init_heap_t)
+#define DRM_IOCTL_I915_CMDBUFFER       DRM_IOW( 0x4b, drm_i915_cmdbuffer_t)
+
+/* Allow drivers to submit batchbuffers directly to hardware, relying
+ * on the security mechanisms provided by hardware.
+ */
+typedef struct _drm_i915_batchbuffer {
+       int start;              /* agp offset */
+       int used;               /* nr bytes in use */
+       int DR1;                /* hw flags for GFX_OP_DRAWRECT_INFO */
+       int DR4;                /* window origin for GFX_OP_DRAWRECT_INFO */
+       int num_cliprects;      /* mulitpass with multiple cliprects? */
+       drm_clip_rect_t __user *cliprects;      /* pointer to userspace cliprects */
+} drm_i915_batchbuffer_t;
+
+/* As above, but pass a pointer to userspace buffer which can be
+ * validated by the kernel prior to sending to hardware.
+ */
+typedef struct _drm_i915_cmdbuffer {
+       char __user *buf;       /* pointer to userspace command buffer */
+       int sz;                 /* nr bytes in buf */
+       int DR1;                /* hw flags for GFX_OP_DRAWRECT_INFO */
+       int DR4;                /* window origin for GFX_OP_DRAWRECT_INFO */
+       int num_cliprects;      /* mulitpass with multiple cliprects? */
+       drm_clip_rect_t __user *cliprects;      /* pointer to userspace cliprects */
+} drm_i915_cmdbuffer_t;
+
+/* Userspace can request & wait on irq's:
+ */
+typedef struct drm_i915_irq_emit {
+       int __user *irq_seq;
+} drm_i915_irq_emit_t;
+
+typedef struct drm_i915_irq_wait {
+       int irq_seq;
+} drm_i915_irq_wait_t;
+
+/* Ioctl to query kernel params:
+ */
+#define I915_PARAM_IRQ_ACTIVE            1
+#define I915_PARAM_ALLOW_BATCHBUFFER     2
+
+typedef struct drm_i915_getparam {
+       int param;
+       int __user *value;
+} drm_i915_getparam_t;
+
+/* Ioctl to set kernel params:
+ */
+#define I915_SETPARAM_USE_MI_BATCHBUFFER_START            1
+#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY             2
+#define I915_SETPARAM_ALLOW_BATCHBUFFER                   3
+
+typedef struct drm_i915_setparam {
+       int param;
+       int value;
+} drm_i915_setparam_t;
+
+/* A memory manager for regions of shared memory:
+ */
+#define I915_MEM_REGION_AGP 1
+
+typedef struct drm_i915_mem_alloc {
+       int region;
+       int alignment;
+       int size;
+       int __user *region_offset;      /* offset from start of fb or agp */
+} drm_i915_mem_alloc_t;
+
+typedef struct drm_i915_mem_free {
+       int region;
+       int region_offset;
+} drm_i915_mem_free_t;
+
+typedef struct drm_i915_mem_init_heap {
+       int region;
+       int size;
+       int start;
+} drm_i915_mem_init_heap_t;
+
+#endif                         /* _I915_DRM_H_ */
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
new file mode 100644 (file)
index 0000000..becce4d
--- /dev/null
@@ -0,0 +1,17 @@
+/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*-
+ */
+
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#include "drm_core.h"
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
new file mode 100644 (file)
index 0000000..7564cd0
--- /dev/null
@@ -0,0 +1,219 @@
+/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#ifndef _I915_DRV_H_
+#define _I915_DRV_H_
+
+typedef struct _drm_i915_ring_buffer {
+       int tail_mask;
+       unsigned long Start;
+       unsigned long End;
+       unsigned long Size;
+       u8 *virtual_start;
+       int head;
+       int tail;
+       int space;
+       drm_local_map_t map;
+} drm_i915_ring_buffer_t;
+
+struct mem_block {
+       struct mem_block *next;
+       struct mem_block *prev;
+       int start;
+       int size;
+       DRMFILE filp;           /* 0: free, -1: heap, other: real files */
+};
+
+typedef struct drm_i915_private {
+       drm_local_map_t *sarea;
+       drm_local_map_t *mmio_map;
+
+       drm_i915_sarea_t *sarea_priv;
+       drm_i915_ring_buffer_t ring;
+
+       void *hw_status_page;
+       unsigned long counter;
+       dma_addr_t dma_status_page;
+
+       int back_offset;
+       int front_offset;
+       int current_page;
+       int page_flipping;
+       int use_mi_batchbuffer_start;
+
+       wait_queue_head_t irq_queue;
+       atomic_t irq_received;
+       atomic_t irq_emitted;
+
+       int tex_lru_log_granularity;
+       int allow_batchbuffer;
+       struct mem_block *agp_heap;
+} drm_i915_private_t;
+
+                               /* i915_dma.c */
+extern int i915_dma_init(DRM_IOCTL_ARGS);
+extern int i915_dma_cleanup(drm_device_t * dev);
+extern int i915_flush_ioctl(DRM_IOCTL_ARGS);
+extern int i915_batchbuffer(DRM_IOCTL_ARGS);
+extern int i915_flip_bufs(DRM_IOCTL_ARGS);
+extern int i915_getparam(DRM_IOCTL_ARGS);
+extern int i915_setparam(DRM_IOCTL_ARGS);
+extern int i915_cmdbuffer(DRM_IOCTL_ARGS);
+extern void i915_kernel_lost_context(drm_device_t * dev);
+
+/* i915_irq.c */
+extern int i915_irq_emit(DRM_IOCTL_ARGS);
+extern int i915_irq_wait(DRM_IOCTL_ARGS);
+extern int i915_wait_irq(drm_device_t * dev, int irq_nr);
+extern int i915_emit_irq(drm_device_t * dev);
+
+extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
+extern void i915_driver_irq_preinstall(drm_device_t *dev);
+extern void i915_driver_irq_postinstall(drm_device_t *dev);
+extern void i915_driver_irq_uninstall(drm_device_t *dev);
+
+/* i915_mem.c */
+extern int i915_mem_alloc(DRM_IOCTL_ARGS);
+extern int i915_mem_free(DRM_IOCTL_ARGS);
+extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
+extern void i915_mem_takedown(struct mem_block **heap);
+extern void i915_mem_release(drm_device_t * dev,
+                            DRMFILE filp, struct mem_block *heap);
+
+#define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, reg)
+#define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, reg, val)
+#define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, reg)
+#define I915_WRITE16(reg,val)  DRM_WRITE16(dev_priv->mmio_map, reg, val)
+
+#define I915_VERBOSE 0
+
+#define RING_LOCALS    unsigned int outring, ringmask, outcount; \
+                        volatile char *virt;
+
+#define BEGIN_LP_RING(n) do {                          \
+       if (I915_VERBOSE)                               \
+               DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",  \
+                         n, __FUNCTION__);             \
+       if (dev_priv->ring.space < n*4)                 \
+               i915_wait_ring(dev, n*4, __FUNCTION__);         \
+       outcount = 0;                                   \
+       outring = dev_priv->ring.tail;                  \
+       ringmask = dev_priv->ring.tail_mask;            \
+       virt = dev_priv->ring.virtual_start;            \
+} while (0)
+
+#define OUT_RING(n) do {                                       \
+       if (I915_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));      \
+       *(volatile unsigned int *)(virt + outring) = n;         \
+        outcount++;                                            \
+       outring += 4;                                           \
+       outring &= ringmask;                                    \
+} while (0)
+
+#define ADVANCE_LP_RING() do {                                         \
+       if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring);   \
+       dev_priv->ring.tail = outring;                                  \
+       dev_priv->ring.space -= outcount * 4;                           \
+       I915_WRITE(LP_RING + RING_TAIL, outring);                       \
+} while(0)
+
+extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
+
+#define GFX_OP_USER_INTERRUPT          ((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT    ((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD                        (7<<23)
+#define CMD_STORE_DWORD_IDX            ((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT   0x00000000
+#define INST_OP_FLUSH        0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+#define BB1_START_ADDR_MASK   (~0x7)
+#define BB1_PROTECTED         (1<<0)
+#define BB1_UNPROTECTED       (0<<0)
+#define BB2_END_ADDR_MASK     (~0x7)
+
+#define I915REG_HWSTAM         0x02098
+#define I915REG_INT_IDENTITY_R 0x020a4
+#define I915REG_INT_MASK_R     0x020a8
+#define I915REG_INT_ENABLE_R   0x020a0
+
+#define SRX_INDEX              0x3c4
+#define SRX_DATA               0x3c5
+#define SR01                   1
+#define SR01_SCREEN_OFF        (1<<5)
+
+#define PPCR                   0x61204
+#define PPCR_ON                        (1<<0)
+
+#define ADPA                   0x61100
+#define ADPA_DPMS_MASK         (~(3<<10))
+#define ADPA_DPMS_ON           (0<<10)
+#define ADPA_DPMS_SUSPEND      (1<<10)
+#define ADPA_DPMS_STANDBY      (2<<10)
+#define ADPA_DPMS_OFF          (3<<10)
+
+#define NOPID                   0x2094
+#define LP_RING                0x2030
+#define HP_RING                0x2040
+#define RING_TAIL                      0x00
+#define TAIL_ADDR              0x001FFFF8
+#define RING_HEAD                      0x04
+#define HEAD_WRAP_COUNT        0xFFE00000
+#define HEAD_WRAP_ONE          0x00200000
+#define HEAD_ADDR              0x001FFFFC
+#define RING_START                     0x08
+#define START_ADDR             0x0xFFFFF000
+#define RING_LEN                       0x0C
+#define RING_NR_PAGES          0x001FF000
+#define RING_REPORT_MASK       0x00000006
+#define RING_REPORT_64K        0x00000002
+#define RING_REPORT_128K       0x00000004
+#define RING_NO_REPORT         0x00000000
+#define RING_VALID_MASK        0x00000001
+#define RING_VALID             0x00000001
+#define RING_INVALID           0x00000000
+
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR       (0x1<<1)
+#define SC_ENABLE_MASK          (0x1<<0)
+#define SC_ENABLE               (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK      (0xffff<<16)
+#define SCI_XMIN_MASK      (0xffff<<0)
+#define SCI_YMAX_MASK      (0xffff<<16)
+#define SCI_XMAX_MASK      (0xffff<<0)
+
+#define GFX_OP_SCISSOR_ENABLE   ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT     ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+
+#define MI_BATCH_BUFFER        ((0x30<<23)|1)
+#define MI_BATCH_BUFFER_START  (0x31<<23)
+#define MI_BATCH_BUFFER_END    (0xA<<23)
+#define MI_BATCH_NON_SECURE    (1)
+
+#define MI_WAIT_FOR_EVENT       ((0x3<<23))
+#define MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
+#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
+
+#define MI_LOAD_SCAN_LINES_INCL  ((0x12<<23))
+
+#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
+#define ASYNC_FLIP                (1<<22)
+
+#define CMD_OP_DESTBUFFER_INFO  ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+
+#endif
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
new file mode 100644 (file)
index 0000000..de91aba
--- /dev/null
@@ -0,0 +1,165 @@
+/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#define USER_INT_FLAG 0x2
+#define MAX_NOPID ((u32)~0)
+#define READ_BREADCRUMB(dev_priv)  (((u32*)(dev_priv->hw_status_page))[5])
+
+irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
+{
+       drm_device_t *dev = (drm_device_t *) arg;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       u16 temp;
+
+       temp = I915_READ16(I915REG_INT_IDENTITY_R);
+       temp &= USER_INT_FLAG;
+
+       DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+
+       if (temp == 0)
+               return IRQ_NONE;
+
+       I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+       DRM_WAKEUP(&dev_priv->irq_queue);
+
+       return IRQ_HANDLED;
+}
+
+int i915_emit_irq(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 ret;
+       RING_LOCALS;
+
+       i915_kernel_lost_context(dev);
+
+       DRM_DEBUG("%s\n", __FUNCTION__);
+
+       ret = dev_priv->counter;
+
+       BEGIN_LP_RING(2);
+       OUT_RING(0);
+       OUT_RING(GFX_OP_USER_INTERRUPT);
+       ADVANCE_LP_RING();
+
+       return ret;
+}
+
+int i915_wait_irq(drm_device_t * dev, int irq_nr)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int ret = 0;
+
+       DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
+                 READ_BREADCRUMB(dev_priv));
+
+       if (READ_BREADCRUMB(dev_priv) >= irq_nr)
+               return 0;
+
+       dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+
+       DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
+                   READ_BREADCRUMB(dev_priv) >= irq_nr);
+
+       if (ret == DRM_ERR(EBUSY)) {
+               DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
+                         __FUNCTION__,
+                         READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
+       }
+
+       dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+       return ret;
+}
+
+/* Needs the lock as it touches the ring.
+ */
+int i915_irq_emit(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_irq_emit_t emit;
+       int result;
+
+       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i915_irq_emit called without lock held\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
+                                sizeof(emit));
+
+       result = i915_emit_irq(dev);
+
+       if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+               DRM_ERROR("copy_to_user\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
+/* Doesn't need the hardware lock.
+ */
+int i915_irq_wait(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_irq_wait_t irqwait;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
+                                sizeof(irqwait));
+
+       return i915_wait_irq(dev, irqwait.irq_seq);
+}
+
+/* drm_dma.h hooks
+*/
+void i915_driver_irq_preinstall(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       I915_WRITE16(I915REG_HWSTAM, 0xfffe);
+       I915_WRITE16(I915REG_INT_MASK_R, 0x0);
+       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+}
+
+void i915_driver_irq_postinstall(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG);
+       DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+}
+
+void i915_driver_irq_uninstall(drm_device_t * dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       if (!dev_priv)
+               return;
+
+       I915_WRITE16(I915REG_HWSTAM, 0xffff);
+       I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
+       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+}
diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
new file mode 100644 (file)
index 0000000..42c1e35
--- /dev/null
@@ -0,0 +1,347 @@
+/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
+ */
+/**************************************************************************
+ * 
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ **************************************************************************/
+
+#include "i915.h"
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/* This memory manager is integrated into the global/local lru
+ * mechanisms used by the clients.  Specifically, it operates by
+ * setting the 'in_use' fields of the global LRU to indicate whether
+ * this region is privately allocated to a client.
+ *
+ * This does require the client to actually respect that field.
+ *
+ * Currently no effort is made to allocate 'private' memory in any
+ * clever way - the LRU information isn't used to determine which
+ * block to allocate, and the ring is drained prior to allocations --
+ * in other words allocation is expensive.
+ */
+static void mark_block(drm_device_t * dev, struct mem_block *p, int in_use)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       drm_tex_region_t *list;
+       unsigned shift, nr;
+       unsigned start;
+       unsigned end;
+       unsigned i;
+       int age;
+
+       shift = dev_priv->tex_lru_log_granularity;
+       nr = I915_NR_TEX_REGIONS;
+
+       start = p->start >> shift;
+       end = (p->start + p->size - 1) >> shift;
+
+       age = ++sarea_priv->texAge;
+       list = sarea_priv->texList;
+
+       /* Mark the regions with the new flag and update their age.  Move
+        * them to head of list to preserve LRU semantics.
+        */
+       for (i = start; i <= end; i++) {
+               list[i].in_use = in_use;
+               list[i].age = age;
+
+               /* remove_from_list(i)
+                */
+               list[(unsigned)list[i].next].prev = list[i].prev;
+               list[(unsigned)list[i].prev].next = list[i].next;
+
+               /* insert_at_head(list, i)
+                */
+               list[i].prev = nr;
+               list[i].next = list[nr].next;
+               list[(unsigned)list[nr].next].prev = i;
+               list[nr].next = i;
+       }
+}
+
+/* Very simple allocator for agp memory, working on a static range
+ * already mapped into each client's address space.  
+ */
+
+static struct mem_block *split_block(struct mem_block *p, int start, int size,
+                                    DRMFILE filp)
+{
+       /* Maybe cut off the start of an existing block */
+       if (start > p->start) {
+               struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
+               if (!newblock)
+                       goto out;
+               newblock->start = start;
+               newblock->size = p->size - (start - p->start);
+               newblock->filp = NULL;
+               newblock->next = p->next;
+               newblock->prev = p;
+               p->next->prev = newblock;
+               p->next = newblock;
+               p->size -= newblock->size;
+               p = newblock;
+       }
+
+       /* Maybe cut off the end of an existing block */
+       if (size < p->size) {
+               struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
+               if (!newblock)
+                       goto out;
+               newblock->start = start + size;
+               newblock->size = p->size - size;
+               newblock->filp = NULL;
+               newblock->next = p->next;
+               newblock->prev = p;
+               p->next->prev = newblock;
+               p->next = newblock;
+               p->size = size;
+       }
+
+      out:
+       /* Our block is in the middle */
+       p->filp = filp;
+       return p;
+}
+
+static struct mem_block *alloc_block(struct mem_block *heap, int size,
+                                    int align2, DRMFILE filp)
+{
+       struct mem_block *p;
+       int mask = (1 << align2) - 1;
+
+       for (p = heap->next; p != heap; p = p->next) {
+               int start = (p->start + mask) & ~mask;
+               if (p->filp == NULL && start + size <= p->start + p->size)
+                       return split_block(p, start, size, filp);
+       }
+
+       return NULL;
+}
+
+static struct mem_block *find_block(struct mem_block *heap, int start)
+{
+       struct mem_block *p;
+
+       for (p = heap->next; p != heap; p = p->next)
+               if (p->start == start)
+                       return p;
+
+       return NULL;
+}
+
+static void free_block(struct mem_block *p)
+{
+       p->filp = NULL;
+
+       /* Assumes a single contiguous range.  Needs a special filp in
+        * 'heap' to stop it being subsumed.
+        */
+       if (p->next->filp == NULL) {
+               struct mem_block *q = p->next;
+               p->size += q->size;
+               p->next = q->next;
+               p->next->prev = p;
+               DRM_FREE(q, sizeof(*q));
+       }
+
+       if (p->prev->filp == NULL) {
+               struct mem_block *q = p->prev;
+               q->size += p->size;
+               q->next = p->next;
+               q->next->prev = q;
+               DRM_FREE(p, sizeof(*q));
+       }
+}
+
+/* Initialize.  How to check for an uninitialized heap?
+ */
+static int init_heap(struct mem_block **heap, int start, int size)
+{
+       struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks));
+
+       if (!blocks)
+               return -ENOMEM;
+
+       *heap = DRM_MALLOC(sizeof(**heap));
+       if (!*heap) {
+               DRM_FREE(blocks, sizeof(*blocks));
+               return -ENOMEM;
+       }
+
+       blocks->start = start;
+       blocks->size = size;
+       blocks->filp = NULL;
+       blocks->next = blocks->prev = *heap;
+
+       memset(*heap, 0, sizeof(**heap));
+       (*heap)->filp = (DRMFILE) - 1;
+       (*heap)->next = (*heap)->prev = blocks;
+       return 0;
+}
+
+/* Free all blocks associated with the releasing file.
+ */
+void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap)
+{
+       struct mem_block *p;
+
+       if (!heap || !heap->next)
+               return;
+
+       for (p = heap->next; p != heap; p = p->next) {
+               if (p->filp == filp) {
+                       p->filp = NULL;
+                       mark_block(dev, p, 0);
+               }
+       }
+
+       /* Assumes a single contiguous range.  Needs a special filp in
+        * 'heap' to stop it being subsumed.
+        */
+       for (p = heap->next; p != heap; p = p->next) {
+               while (p->filp == NULL && p->next->filp == NULL) {
+                       struct mem_block *q = p->next;
+                       p->size += q->size;
+                       p->next = q->next;
+                       p->next->prev = p;
+                       DRM_FREE(q, sizeof(*q));
+               }
+       }
+}
+
+/* Shutdown.
+ */
+void i915_mem_takedown(struct mem_block **heap)
+{
+       struct mem_block *p;
+
+       if (!*heap)
+               return;
+
+       for (p = (*heap)->next; p != *heap;) {
+               struct mem_block *q = p;
+               p = p->next;
+               DRM_FREE(q, sizeof(*q));
+       }
+
+       DRM_FREE(*heap, sizeof(**heap));
+       *heap = NULL;
+}
+
+static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
+{
+       switch (region) {
+       case I915_MEM_REGION_AGP:
+               return &dev_priv->agp_heap;
+       default:
+               return NULL;
+       }
+}
+
+/* IOCTL HANDLERS */
+
+int i915_mem_alloc(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_mem_alloc_t alloc;
+       struct mem_block *block, **heap;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data,
+                                sizeof(alloc));
+
+       heap = get_heap(dev_priv, alloc.region);
+       if (!heap || !*heap)
+               return DRM_ERR(EFAULT);
+
+       /* Make things easier on ourselves: all allocations at least
+        * 4k aligned.
+        */
+       if (alloc.alignment < 12)
+               alloc.alignment = 12;
+
+       block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+
+       if (!block)
+               return DRM_ERR(ENOMEM);
+
+       mark_block(dev, block, 1);
+
+       if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+               DRM_ERROR("copy_to_user\n");
+               return DRM_ERR(EFAULT);
+       }
+
+       return 0;
+}
+
+int i915_mem_free(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_mem_free_t memfree;
+       struct mem_block *block, **heap;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data,
+                                sizeof(memfree));
+
+       heap = get_heap(dev_priv, memfree.region);
+       if (!heap || !*heap)
+               return DRM_ERR(EFAULT);
+
+       block = find_block(*heap, memfree.region_offset);
+       if (!block)
+               return DRM_ERR(EFAULT);
+
+       if (block->filp != filp)
+               return DRM_ERR(EPERM);
+
+       mark_block(dev, block, 0);
+       free_block(block);
+       return 0;
+}
+
+int i915_mem_init_heap(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_mem_init_heap_t initheap;
+       struct mem_block **heap;
+
+       if (!dev_priv) {
+               DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+               return DRM_ERR(EINVAL);
+       }
+
+       DRM_COPY_FROM_USER_IOCTL(initheap,
+                                (drm_i915_mem_init_heap_t __user *) data,
+                                sizeof(initheap));
+
+       heap = get_heap(dev_priv, initheap.region);
+       if (!heap)
+               return DRM_ERR(EFAULT);
+
+       if (*heap) {
+               DRM_ERROR("heap already initialized?");
+               return DRM_ERR(EFAULT);
+       }
+
+       return init_heap(heap, initheap.start, initheap.size);
+}
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
new file mode 100644 (file)
index 0000000..a75e860
--- /dev/null
@@ -0,0 +1,354 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : ds1302.c
+*!
+*! DESCRIPTION: Implements an interface for the DS1302 RTC
+*!
+*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+
+#include <linux/config.h>
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/bcd.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
+#if defined(CONFIG_M32R)
+#include <asm/m32r.h>
+#endif
+
+#define RTC_MAJOR_NR 121 /* local major, change later */
+
+static const char ds1302_name[] = "ds1302";
+
+/* Send 8 bits. */
+static void
+out_byte_rtc(unsigned int reg_addr, unsigned char x)
+{
+       //RST H
+       outw(0x0001,(unsigned long)PLD_RTCRSTODT);
+       //write data
+       outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA);
+       //WE
+       outw(0x0002,(unsigned long)PLD_RTCCR);
+       //wait
+       while(inw((unsigned long)PLD_RTCCR));
+
+       //RST L
+       outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+
+}
+
+static unsigned char
+in_byte_rtc(unsigned int reg_addr)
+{
+       unsigned char retval;
+
+       //RST H
+       outw(0x0001,(unsigned long)PLD_RTCRSTODT);
+       //write data
+       outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA);
+       //RE
+       outw(0x0001,(unsigned long)PLD_RTCCR);
+       //wait
+       while(inw((unsigned long)PLD_RTCCR));
+
+       //read data
+       retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8;
+
+       //RST L
+       outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+
+       return retval;
+}
+
+/* Enable writing. */
+
+static void
+ds1302_wenable(void)
+{
+       out_byte_rtc(0x8e,0x00);
+}
+
+/* Disable writing. */
+
+static void
+ds1302_wdisable(void)
+{
+       out_byte_rtc(0x8e,0x80);
+}
+
+
+
+/* Read a byte from the selected register in the DS1302. */
+
+unsigned char
+ds1302_readreg(int reg)
+{
+       unsigned char x;
+
+       x=in_byte_rtc((0x81 | (reg << 1))); /* read register */
+
+       return x;
+}
+
+/* Write a byte to the selected register. */
+
+void
+ds1302_writereg(int reg, unsigned char val)
+{
+       ds1302_wenable();
+       out_byte_rtc((0x80 | (reg << 1)),val);
+       ds1302_wdisable();
+}
+
+void
+get_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       local_irq_disable();
+
+       rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+       rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+       rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+       rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+       rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+       rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+
+       local_irq_restore(flags);
+
+       BCD_TO_BIN(rtc_tm->tm_sec);
+       BCD_TO_BIN(rtc_tm->tm_min);
+       BCD_TO_BIN(rtc_tm->tm_hour);
+       BCD_TO_BIN(rtc_tm->tm_mday);
+       BCD_TO_BIN(rtc_tm->tm_mon);
+       BCD_TO_BIN(rtc_tm->tm_year);
+
+       /*
+        * Account for differences between how the RTC uses the values
+        * and how they are defined in a struct rtc_time;
+        */
+
+       if (rtc_tm->tm_year <= 69)
+               rtc_tm->tm_year += 100;
+
+       rtc_tm->tm_mon--;
+}
+
+static unsigned char days_in_mo[] =
+    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
+
+static int
+rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+         unsigned long arg)
+{
+       unsigned long flags;
+
+       switch(cmd) {
+               case RTC_RD_TIME:       /* read the time/date from RTC  */
+               {
+                       struct rtc_time rtc_tm;
+
+                       memset(&rtc_tm, 0, sizeof (struct rtc_time));
+                       get_rtc_time(&rtc_tm);
+                       if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+               case RTC_SET_TIME:      /* set the RTC */
+               {
+                       struct rtc_time rtc_tm;
+                       unsigned char mon, day, hrs, min, sec, leap_yr;
+                       unsigned int yrs;
+
+                       if (!capable(CAP_SYS_TIME))
+                               return -EPERM;
+
+                       if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+                               return -EFAULT;
+
+                       yrs = rtc_tm.tm_year + 1900;
+                       mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+                       day = rtc_tm.tm_mday;
+                       hrs = rtc_tm.tm_hour;
+                       min = rtc_tm.tm_min;
+                       sec = rtc_tm.tm_sec;
+
+
+                       if ((yrs < 1970) || (yrs > 2069))
+                               return -EINVAL;
+
+                       leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+                       if ((mon > 12) || (day == 0))
+                               return -EINVAL;
+
+                       if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+                               return -EINVAL;
+
+                       if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+                               return -EINVAL;
+
+                       if (yrs >= 2000)
+                               yrs -= 2000;    /* RTC (0, 1, ... 69) */
+                       else
+                               yrs -= 1900;    /* RTC (70, 71, ... 99) */
+
+                       BIN_TO_BCD(sec);
+                       BIN_TO_BCD(min);
+                       BIN_TO_BCD(hrs);
+                       BIN_TO_BCD(day);
+                       BIN_TO_BCD(mon);
+                       BIN_TO_BCD(yrs);
+
+                       local_irq_save(flags);
+                       local_irq_disable();
+                       CMOS_WRITE(yrs, RTC_YEAR);
+                       CMOS_WRITE(mon, RTC_MONTH);
+                       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+                       CMOS_WRITE(hrs, RTC_HOURS);
+                       CMOS_WRITE(min, RTC_MINUTES);
+                       CMOS_WRITE(sec, RTC_SECONDS);
+                       local_irq_restore(flags);
+
+                       /* Notice that at this point, the RTC is updated but
+                        * the kernel is still running with the old time.
+                        * You need to set that separately with settimeofday
+                        * or adjtimex.
+                        */
+                       return 0;
+               }
+
+               case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
+               {
+                       int tcs_val;
+
+                       if (!capable(CAP_SYS_TIME))
+                               return -EPERM;
+
+                       if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
+                               return -EFAULT;
+
+                       tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
+                       ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
+                       return 0;
+               }
+               default:
+                       return -EINVAL;
+       }
+}
+
+int
+get_rtc_status(char *buf)
+{
+       char *p;
+       struct rtc_time tm;
+
+       p = buf;
+
+       get_rtc_time(&tm);
+
+       /*
+        * There is no way to tell if the luser has the RTC set for local
+        * time or for Universal Standard Time (GMT). Probably local though.
+        */
+
+       p += sprintf(p,
+               "rtc_time\t: %02d:%02d:%02d\n"
+               "rtc_date\t: %04d-%02d-%02d\n",
+               tm.tm_hour, tm.tm_min, tm.tm_sec,
+               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+
+       return  p - buf;
+}
+
+
+/* The various file operations we support. */
+
+static struct file_operations rtc_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = rtc_ioctl,
+};
+
+/* Probe for the chip by writing something to its RAM and try reading it back. */
+
+#define MAGIC_PATTERN 0x42
+
+static int __init
+ds1302_probe(void)
+{
+       int retval, res, baur;
+
+       baur=(boot_cpu_data.bus_clock/(2*1000*1000));
+
+       printk("%s: Set PLD_RTCBAUR = %d\n", ds1302_name,baur);
+
+       outw(0x0000,(unsigned long)PLD_RTCCR);
+       outw(0x0000,(unsigned long)PLD_RTCRSTODT);
+       outw(baur,(unsigned long)PLD_RTCBAUR);
+
+       /* Try to talk to timekeeper. */
+
+       ds1302_wenable();
+       /* write RAM byte 0 */
+       /* write something magic */
+       out_byte_rtc(0xc0,MAGIC_PATTERN);
+
+       /* read RAM byte 0 */
+       if((res = in_byte_rtc(0xc1)) == MAGIC_PATTERN) {
+               char buf[100];
+               ds1302_wdisable();
+               printk("%s: RTC found.\n", ds1302_name);
+               get_rtc_status(buf);
+               printk(buf);
+               retval = 1;
+       } else {
+               printk("%s: RTC not found.\n", ds1302_name);
+               retval = 0;
+       }
+
+       return retval;
+}
+
+
+/* Just probe for the RTC and register the device to handle the ioctl needed. */
+
+int __init
+ds1302_init(void)
+{
+       if (!ds1302_probe()) {
+               return -1;
+       }
+       return 0;
+}
+
+static int __init ds1302_register(void)
+{
+       ds1302_init();
+       if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
+               printk(KERN_INFO "%s: unable to get major %d for rtc\n",
+                      ds1302_name, RTC_MAJOR_NR);
+               return -1;
+       }
+       return 0;
+}
+
+module_init(ds1302_register);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
new file mode 100644 (file)
index 0000000..595079c
--- /dev/null
@@ -0,0 +1,1319 @@
+/*
+ * Copyright (C) 2004 Hollis Blanchard <hollisb@us.ibm.com>, IBM
+ *
+ * This 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
+ */
+
+/* Host Virtual Serial Interface (HVSI) is a protocol between the hosted OS
+ * and the service processor on IBM pSeries servers. On these servers, there
+ * are no serial ports under the OS's control, and sometimes there is no other
+ * console available either. However, the service processor has two standard
+ * serial ports, so this over-complicated protocol allows the OS to control
+ * those ports by proxy.
+ *
+ * Besides data, the procotol supports the reading/writing of the serial
+ * port's DTR line, and the reading of the CD line. This is to allow the OS to
+ * control a modem attached to the service processor's serial port. Note that
+ * the OS cannot change the speed of the port through this protocol.
+ */
+
+/* TODO:
+ * test FSP reset
+ * add udbg support for xmon/kdb
+ */
+
+#undef DEBUG
+
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/hvcall.h>
+#include <asm/hvconsole.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+#include <asm/vio.h>
+
+#define HVSI_MAJOR     229
+#define HVSI_MINOR     128
+#define MAX_NR_HVSI_CONSOLES 4
+
+#define HVSI_TIMEOUT (5*HZ)
+#define HVSI_VERSION 1
+#define HVSI_MAX_PACKET 256
+#define HVSI_MAX_READ 16
+#define HVSI_MAX_OUTGOING_DATA 12
+#define N_OUTBUF 12
+
+/*
+ * we pass data via two 8-byte registers, so we would like our char arrays
+ * properly aligned for those loads.
+ */
+#define __ALIGNED__    __attribute__((__aligned__(sizeof(long))))
+
+struct hvsi_struct {
+       struct work_struct writer;
+       wait_queue_head_t emptyq; /* woken when outbuf is emptied */
+       wait_queue_head_t stateq; /* woken when HVSI state changes */
+       spinlock_t lock;
+       int index;
+       struct tty_struct *tty;
+       unsigned int count;
+       uint8_t throttle_buf[128];
+       uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
+       /* inbuf is for packet reassembly. leave a little room for leftovers. */
+       uint8_t inbuf[HVSI_MAX_PACKET + HVSI_MAX_READ];
+       uint8_t *inbuf_end;
+       int n_throttle;
+       int n_outbuf;
+       uint32_t vtermno;
+       uint32_t virq;
+       atomic_t seqno; /* HVSI packet sequence number */
+       uint16_t mctrl;
+       uint8_t state;  /* HVSI protocol state */
+       uint8_t flags;
+#ifdef CONFIG_MAGIC_SYSRQ
+       uint8_t sysrq;
+#endif /* CONFIG_MAGIC_SYSRQ */
+};
+static struct hvsi_struct hvsi_ports[MAX_NR_HVSI_CONSOLES];
+
+static struct tty_driver *hvsi_driver;
+static int hvsi_count;
+static int (*hvsi_wait)(struct hvsi_struct *hp, int state);
+
+enum HVSI_PROTOCOL_STATE {
+       HVSI_CLOSED,
+       HVSI_WAIT_FOR_VER_RESPONSE,
+       HVSI_WAIT_FOR_VER_QUERY,
+       HVSI_OPEN,
+       HVSI_WAIT_FOR_MCTRL_RESPONSE,
+};
+#define HVSI_CONSOLE 0x1
+
+#define VS_DATA_PACKET_HEADER           0xff
+#define VS_CONTROL_PACKET_HEADER        0xfe
+#define VS_QUERY_PACKET_HEADER          0xfd
+#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc
+
+/* control verbs */
+#define VSV_SET_MODEM_CTL    1 /* to service processor only */
+#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */
+#define VSV_CLOSE_PROTOCOL   3
+
+/* query verbs */
+#define VSV_SEND_VERSION_NUMBER 1
+#define VSV_SEND_MODEM_CTL_STATUS 2
+
+/* yes, these masks are not consecutive. */
+#define HVSI_TSDTR 0x01
+#define HVSI_TSCD  0x20
+
+struct hvsi_header {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+} __attribute__((packed));
+
+struct hvsi_data {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint8_t  data[HVSI_MAX_OUTGOING_DATA];
+} __attribute__((packed));
+
+struct hvsi_control {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint16_t verb;
+       /* optional depending on verb: */
+       uint32_t word;
+       uint32_t mask;
+} __attribute__((packed));
+
+struct hvsi_query {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint16_t verb;
+} __attribute__((packed));
+
+struct hvsi_query_response {
+       uint8_t  type;
+       uint8_t  len;
+       uint16_t seqno;
+       uint16_t verb;
+       uint16_t query_seqno;
+       union {
+               uint8_t  version;
+               uint32_t mctrl_word;
+       } u;
+} __attribute__((packed));
+
+static inline int is_open(struct hvsi_struct *hp)
+{
+       /* if we're waiting for an mctrl then we're already open */
+       return (hp->state == HVSI_OPEN)
+                       || (hp->state == HVSI_WAIT_FOR_MCTRL_RESPONSE);
+}
+
+static inline void print_state(struct hvsi_struct *hp)
+{
+#ifdef DEBUG
+       static const char *state_names[] = {
+               "HVSI_CLOSED",
+               "HVSI_WAIT_FOR_VER_RESPONSE",
+               "HVSI_WAIT_FOR_VER_QUERY",
+               "HVSI_OPEN",
+               "HVSI_WAIT_FOR_MCTRL_RESPONSE",
+       };
+       const char *name = state_names[hp->state];
+
+       if (hp->state > (sizeof(state_names)/sizeof(char*)))
+               name = "UNKNOWN";
+
+       pr_debug("hvsi%i: state = %s\n", hp->index, name);
+#endif /* DEBUG */
+}
+
+static inline void __set_state(struct hvsi_struct *hp, int state)
+{
+       hp->state = state;
+       print_state(hp);
+       wake_up_all(&hp->stateq);
+}
+
+static inline void set_state(struct hvsi_struct *hp, int state)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hp->lock, flags);
+       __set_state(hp, state);
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static inline int len_packet(const uint8_t *packet)
+{
+       return (int)((struct hvsi_header *)packet)->len;
+}
+
+static inline int is_header(const uint8_t *packet)
+{
+       struct hvsi_header *header = (struct hvsi_header *)packet;
+       return header->type >= VS_QUERY_RESPONSE_PACKET_HEADER;
+}
+
+static inline int got_packet(const struct hvsi_struct *hp, uint8_t *packet)
+{
+       if (hp->inbuf_end < packet + sizeof(struct hvsi_header))
+               return 0; /* don't even have the packet header */
+
+       if (hp->inbuf_end < (packet + len_packet(packet)))
+               return 0; /* don't have the rest of the packet */
+
+       return 1;
+}
+
+/* shift remaining bytes in packetbuf down */
+static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to)
+{
+       int remaining = (int)(hp->inbuf_end - read_to);
+
+       pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining);
+
+       if (read_to != hp->inbuf)
+               memmove(hp->inbuf, read_to, remaining);
+
+       hp->inbuf_end = hp->inbuf + remaining;
+}
+
+#ifdef DEBUG
+#define dbg_dump_packet(packet) dump_packet(packet)
+#define dbg_dump_hex(data, len) dump_hex(data, len)
+#else
+#define dbg_dump_packet(packet) do { } while (0)
+#define dbg_dump_hex(data, len) do { } while (0)
+#endif
+
+static void dump_hex(const uint8_t *data, int len)
+{
+       int i;
+
+       printk("    ");
+       for (i=0; i < len; i++)
+               printk("%.2x", data[i]);
+
+       printk("\n    ");
+       for (i=0; i < len; i++) {
+               if (isprint(data[i]))
+                       printk("%c", data[i]);
+               else
+                       printk(".");
+       }
+       printk("\n");
+}
+
+static void dump_packet(uint8_t *packet)
+{
+       struct hvsi_header *header = (struct hvsi_header *)packet;
+
+       printk("type 0x%x, len %i, seqno %i:\n", header->type, header->len,
+                       header->seqno);
+
+       dump_hex(packet, header->len);
+}
+
+/* can't use hvc_get_chars because that strips CRs */
+static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
+{
+       unsigned long got;
+
+       if (plpar_hcall(H_GET_TERM_CHAR, hp->vtermno, 0, 0, 0, &got,
+                       (unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
+               return got;
+       return 0;
+}
+
+/*
+ * we can't call tty_hangup() directly here because we need to call that
+ * outside of our lock
+ */
+static struct tty_struct *hvsi_recv_control(struct hvsi_struct *hp,
+               uint8_t *packet)
+{
+       struct tty_struct *to_hangup = NULL;
+       struct hvsi_control *header = (struct hvsi_control *)packet;
+
+       switch (header->verb) {
+               case VSV_MODEM_CTL_UPDATE:
+                       if ((header->word & HVSI_TSCD) == 0) {
+                               /* CD went away; no more connection */
+                               pr_debug("hvsi%i: CD dropped\n", hp->index);
+                               hp->mctrl &= TIOCM_CD;
+                               if (!(hp->tty->flags & CLOCAL))
+                                       to_hangup = hp->tty;
+                       }
+                       break;
+               case VSV_CLOSE_PROTOCOL:
+                       printk(KERN_DEBUG
+                               "hvsi%i: service processor closed connection!\n", hp->index);
+                       __set_state(hp, HVSI_CLOSED);
+                       to_hangup = hp->tty;
+                       hp->tty = NULL;
+                       break;
+               default:
+                       printk(KERN_WARNING "hvsi%i: unknown HVSI control packet: ",
+                               hp->index);
+                       dump_packet(packet);
+                       break;
+       }
+
+       return to_hangup;
+}
+
+static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet)
+{
+       struct hvsi_query_response *resp = (struct hvsi_query_response *)packet;
+
+       switch (hp->state) {
+               case HVSI_WAIT_FOR_VER_RESPONSE:
+                       __set_state(hp, HVSI_WAIT_FOR_VER_QUERY);
+                       break;
+               case HVSI_WAIT_FOR_MCTRL_RESPONSE:
+                       hp->mctrl = 0;
+                       if (resp->u.mctrl_word & HVSI_TSDTR)
+                               hp->mctrl |= TIOCM_DTR;
+                       if (resp->u.mctrl_word & HVSI_TSCD)
+                               hp->mctrl |= TIOCM_CD;
+                       __set_state(hp, HVSI_OPEN);
+                       break;
+               default:
+                       printk(KERN_ERR "hvsi%i: unexpected query response: ", hp->index);
+                       dump_packet(packet);
+                       break;
+       }
+}
+
+/* respond to service processor's version query */
+static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno)
+{
+       struct hvsi_query_response packet __ALIGNED__;
+       int wrote;
+
+       packet.type = VS_QUERY_RESPONSE_PACKET_HEADER;
+       packet.len = sizeof(struct hvsi_query_response);
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.verb = VSV_SEND_VERSION_NUMBER;
+       packet.u.version = HVSI_VERSION;
+       packet.query_seqno = query_seqno+1;
+
+       pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (wrote != packet.len) {
+               printk(KERN_ERR "hvsi%i: couldn't send query response!\n",
+                       hp->index);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
+{
+       struct hvsi_query *query = (struct hvsi_query *)packet;
+
+       switch (hp->state) {
+               case HVSI_WAIT_FOR_VER_QUERY:
+                       __set_state(hp, HVSI_OPEN);
+                       hvsi_version_respond(hp, query->seqno);
+                       break;
+               default:
+                       printk(KERN_ERR "hvsi%i: unexpected query: ", hp->index);
+                       dump_packet(packet);
+                       break;
+       }
+}
+
+static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
+{
+       int i;
+
+       for (i=0; i < len; i++) {
+               char c = buf[i];
+#ifdef CONFIG_MAGIC_SYSRQ
+               if (c == '\0') {
+                       hp->sysrq = 1;
+                       continue;
+               } else if (hp->sysrq) {
+                       handle_sysrq(c, NULL, hp->tty);
+                       hp->sysrq = 0;
+                       continue;
+               }
+#endif /* CONFIG_MAGIC_SYSRQ */
+               tty_insert_flip_char(hp->tty, c, 0);
+       }
+}
+
+/*
+ * We could get 252 bytes of data at once here. But the tty layer only
+ * throttles us at TTY_THRESHOLD_THROTTLE (128) bytes, so we could overflow
+ * it. Accordingly we won't send more than 128 bytes at a time to the flip
+ * buffer, which will give the tty buffer a chance to throttle us. Should the
+ * value of TTY_THRESHOLD_THROTTLE change in n_tty.c, this code should be
+ * revisited.
+ */
+#define TTY_THRESHOLD_THROTTLE 128
+static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
+               const uint8_t *packet)
+{
+       const struct hvsi_header *header = (const struct hvsi_header *)packet;
+       const uint8_t *data = packet + sizeof(struct hvsi_header);
+       int datalen = header->len - sizeof(struct hvsi_header);
+       int overflow = datalen - TTY_THRESHOLD_THROTTLE;
+
+       pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
+
+       if (datalen == 0)
+               return NULL;
+
+       if (overflow > 0) {
+               pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__);
+               datalen = TTY_THRESHOLD_THROTTLE;
+       }
+
+       hvsi_insert_chars(hp, data, datalen);
+
+       if (overflow > 0) {
+               /*
+                * we still have more data to deliver, so we need to save off the
+                * overflow and send it later
+                */
+               pr_debug("%s: deferring overflow\n", __FUNCTION__);
+               memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow);
+               hp->n_throttle = overflow;
+       }
+
+       return hp->tty;
+}
+
+/*
+ * Returns true/false indicating data successfully read from hypervisor.
+ * Used both to get packets for tty connections and to advance the state
+ * machine during console handshaking (in which case tty = NULL and we ignore
+ * incoming data).
+ */
+static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
+               struct tty_struct **hangup)
+{
+       uint8_t *packet = hp->inbuf;
+       int chunklen;
+
+       *flip = NULL;
+       *hangup = NULL;
+
+       chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
+       if (chunklen == 0)
+               return 0;
+
+       pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen);
+       dbg_dump_hex(hp->inbuf_end, chunklen);
+
+       hp->inbuf_end += chunklen;
+
+       /* handle all completed packets */
+       while ((packet < hp->inbuf_end) && got_packet(hp, packet)) {
+               struct hvsi_header *header = (struct hvsi_header *)packet;
+
+               if (!is_header(packet)) {
+                       printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index);
+                       /* skip bytes until we find a header or run out of data */
+                       while ((packet < hp->inbuf_end) && (!is_header(packet)))
+                               packet++;
+                       continue;
+               }
+
+               pr_debug("%s: handling %i-byte packet\n", __FUNCTION__,
+                               len_packet(packet));
+               dbg_dump_packet(packet);
+
+               switch (header->type) {
+                       case VS_DATA_PACKET_HEADER:
+                               if (!is_open(hp))
+                                       break;
+                               if (hp->tty == NULL)
+                                       break; /* no tty buffer to put data in */
+                               *flip = hvsi_recv_data(hp, packet);
+                               break;
+                       case VS_CONTROL_PACKET_HEADER:
+                               *hangup = hvsi_recv_control(hp, packet);
+                               break;
+                       case VS_QUERY_RESPONSE_PACKET_HEADER:
+                               hvsi_recv_response(hp, packet);
+                               break;
+                       case VS_QUERY_PACKET_HEADER:
+                               hvsi_recv_query(hp, packet);
+                               break;
+                       default:
+                               printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n",
+                                               hp->index, header->type);
+                               dump_packet(packet);
+                               break;
+               }
+
+               packet += len_packet(packet);
+
+               if (*hangup) {
+                       pr_debug("%s: hangup\n", __FUNCTION__);
+                       /*
+                        * we need to send the hangup now before receiving any more data.
+                        * If we get "data, hangup, data", we can't deliver the second
+                        * data before the hangup.
+                        */
+                       break;
+               }
+       }
+
+       compact_inbuf(hp, packet);
+
+       return 1;
+}
+
+static void hvsi_send_overflow(struct hvsi_struct *hp)
+{
+       pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__,
+                       hp->n_throttle);
+
+       hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
+       hp->n_throttle = 0;
+}
+
+/*
+ * must get all pending data because we only get an irq on empty->non-empty
+ * transition
+ */
+static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)arg;
+       struct tty_struct *flip;
+       struct tty_struct *hangup;
+       unsigned long flags;
+       irqreturn_t handled = IRQ_NONE;
+       int again = 1;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       while (again) {
+               spin_lock_irqsave(&hp->lock, flags);
+               again = hvsi_load_chunk(hp, &flip, &hangup);
+               handled = IRQ_HANDLED;
+               spin_unlock_irqrestore(&hp->lock, flags);
+
+               /*
+                * we have to call tty_flip_buffer_push() and tty_hangup() outside our
+                * spinlock. But we also have to keep going until we've read all the
+                * available data.
+                */
+
+               if (flip) {
+                       /* there was data put in the tty flip buffer */
+                       tty_flip_buffer_push(flip);
+                       flip = NULL;
+               }
+
+               if (hangup) {
+                       tty_hangup(hangup);
+               }
+       }
+
+       spin_lock_irqsave(&hp->lock, flags);
+       if (hp->tty && hp->n_throttle
+                       && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
+               /* we weren't hung up and we weren't throttled, so we can deliver the
+                * rest now */
+               flip = hp->tty;
+               hvsi_send_overflow(hp);
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (flip) {
+               tty_flip_buffer_push(flip);
+       }
+
+       return handled;
+}
+
+/* for boot console, before the irq handler is running */
+static int __init poll_for_state(struct hvsi_struct *hp, int state)
+{
+       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+
+       for (;;) {
+               hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */
+
+               if (hp->state == state)
+                       return 0;
+
+               mdelay(5);
+               if (time_after(jiffies, end_jiffies))
+                       return -EIO;
+       }
+}
+
+/* wait for irq handler to change our state */
+static int wait_for_state(struct hvsi_struct *hp, int state)
+{
+       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+       unsigned long timeout;
+       int ret = 0;
+
+       DECLARE_WAITQUEUE(myself, current);
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&hp->stateq, &myself);
+
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (hp->state == state)
+                       break;
+               timeout = end_jiffies - jiffies;
+               if (time_after(jiffies, end_jiffies)) {
+                       ret = -EIO;
+                       break;
+               }
+               schedule_timeout(timeout);
+       }
+       remove_wait_queue(&hp->stateq, &myself);
+       set_current_state(TASK_RUNNING);
+
+       return ret;
+}
+
+static int hvsi_query(struct hvsi_struct *hp, uint16_t verb)
+{
+       struct hvsi_query packet __ALIGNED__;
+       int wrote;
+
+       packet.type = VS_QUERY_PACKET_HEADER;
+       packet.len = sizeof(struct hvsi_query);
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.verb = verb;
+
+       pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (wrote != packet.len) {
+               printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index,
+                       wrote);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hvsi_get_mctrl(struct hvsi_struct *hp)
+{
+       int ret;
+
+       set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE);
+       hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS);
+
+       ret = hvsi_wait(hp, HVSI_OPEN);
+       if (ret < 0) {
+               printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index);
+               set_state(hp, HVSI_OPEN);
+               return ret;
+       }
+
+       pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl);
+
+       return 0;
+}
+
+/* note that we can only set DTR */
+static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl)
+{
+       struct hvsi_control packet __ALIGNED__;
+       int wrote;
+
+       packet.type = VS_CONTROL_PACKET_HEADER,
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.len = sizeof(struct hvsi_control);
+       packet.verb = VSV_SET_MODEM_CTL;
+       packet.mask = HVSI_TSDTR;
+
+       if (mctrl & TIOCM_DTR)
+               packet.word = HVSI_TSDTR;
+
+       pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (wrote != packet.len) {
+               printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void hvsi_drain_input(struct hvsi_struct *hp)
+{
+       uint8_t buf[HVSI_MAX_READ] __ALIGNED__;
+       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+
+       while (time_before(end_jiffies, jiffies))
+               if (0 == hvsi_read(hp, buf, HVSI_MAX_READ))
+                       break;
+}
+
+static int hvsi_handshake(struct hvsi_struct *hp)
+{
+       int ret;
+
+       /*
+        * We could have a CLOSE or other data waiting for us before we even try
+        * to open; try to throw it all away so we don't get confused. (CLOSE
+        * is the first message sent up the pipe when the FSP comes online. We
+        * need to distinguish between "it came up a while ago and we're the first
+        * user" and "it was just reset before it saw our handshake packet".)
+        */
+       hvsi_drain_input(hp);
+
+       set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE);
+       ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER);
+       if (ret < 0) {
+               printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index);
+               return ret;
+       }
+
+       ret = hvsi_wait(hp, HVSI_OPEN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count)
+{
+       struct hvsi_data packet __ALIGNED__;
+       int ret;
+
+       BUG_ON(count > HVSI_MAX_OUTGOING_DATA);
+
+       packet.type = VS_DATA_PACKET_HEADER;
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.len = count + sizeof(struct hvsi_header);
+       memcpy(&packet.data, buf, count);
+
+       ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+       if (ret == packet.len) {
+               /* return the number of chars written, not the packet length */
+               return count;
+       }
+       return ret; /* return any errors */
+}
+
+static void hvsi_close_protocol(struct hvsi_struct *hp)
+{
+       struct hvsi_control packet __ALIGNED__;
+
+       packet.type = VS_CONTROL_PACKET_HEADER;
+       packet.seqno = atomic_inc_return(&hp->seqno);
+       packet.len = 6;
+       packet.verb = VSV_CLOSE_PROTOCOL;
+
+       pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+       dbg_dump_hex((uint8_t*)&packet, packet.len);
+
+       hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
+}
+
+static int hvsi_open(struct tty_struct *tty, struct file *filp)
+{
+       struct hvsi_struct *hp;
+       unsigned long flags;
+       int line = tty->index;
+       int ret;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       if (line < 0 || line >= hvsi_count)
+               return -ENODEV;
+       hp = &hvsi_ports[line];
+
+       tty->driver_data = hp;
+       tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */
+
+       spin_lock_irqsave(&hp->lock, flags);
+       hp->tty = tty;
+       hp->count++;
+       atomic_set(&hp->seqno, 0);
+       h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (hp->flags & HVSI_CONSOLE)
+               return 0; /* this has already been handshaked as the console */
+
+       ret = hvsi_handshake(hp);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name);
+               return ret;
+       }
+
+       ret = hvsi_get_mctrl(hp);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name);
+               return ret;
+       }
+
+       ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: couldn't set DTR\n", tty->name);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* wait for hvsi_write_worker to empty hp->outbuf */
+static void hvsi_flush_output(struct hvsi_struct *hp)
+{
+       unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
+       unsigned long timeout;
+
+       DECLARE_WAITQUEUE(myself, current);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(&hp->emptyq, &myself);
+
+       for (;;) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (hp->n_outbuf <= 0)
+                       break;
+               timeout = end_jiffies - jiffies;
+               if (time_after(jiffies, end_jiffies))
+                       break;
+               schedule_timeout(timeout);
+       }
+       remove_wait_queue(&hp->emptyq, &myself);
+       set_current_state(TASK_RUNNING);
+
+       /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */
+       cancel_delayed_work(&hp->writer);
+       flush_scheduled_work();
+
+       /*
+        * it's also possible that our timeout expired and hvsi_write_worker
+        * didn't manage to push outbuf. poof.
+        */
+       hp->n_outbuf = 0;
+}
+
+static void hvsi_close(struct tty_struct *tty, struct file *filp)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       unsigned long flags;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       if (tty_hung_up_p(filp))
+               return;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       if (--hp->count == 0) {
+               hp->tty = NULL;
+               hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
+
+               /* only close down connection if it is not the console */
+               if (!(hp->flags & HVSI_CONSOLE)) {
+                       h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); /* no more irqs */
+                       __set_state(hp, HVSI_CLOSED);
+                       /*
+                        * any data delivered to the tty layer after this will be
+                        * discarded (except for XON/XOFF)
+                        */
+                       tty->closing = 1;
+
+                       spin_unlock_irqrestore(&hp->lock, flags);
+
+                       /* let any existing irq handlers finish. no more will start. */
+                       synchronize_irq(hp->virq);
+
+                       /* hvsi_write_worker will re-schedule until outbuf is empty. */
+                       hvsi_flush_output(hp);
+
+                       /* tell FSP to stop sending data */
+                       hvsi_close_protocol(hp);
+
+                       /*
+                        * drain anything FSP is still in the middle of sending, and let
+                        * hvsi_handshake drain the rest on the next open.
+                        */
+                       hvsi_drain_input(hp);
+
+                       spin_lock_irqsave(&hp->lock, flags);
+               }
+       } else if (hp->count < 0)
+               printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
+                      hp - hvsi_ports, hp->count);
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static void hvsi_hangup(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       hp->count = 0;
+       hp->tty = NULL;
+}
+
+/* called with hp->lock held */
+static void hvsi_push(struct hvsi_struct *hp)
+{
+       int n;
+
+       if (hp->n_outbuf <= 0)
+               return;
+
+       n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf);
+       if (n != 0) {
+               /*
+                * either all data was sent or there was an error, and we throw away
+                * data on error.
+                */
+               hp->n_outbuf = 0;
+       }
+}
+
+/* hvsi_write_worker will keep rescheduling itself until outbuf is empty */
+static void hvsi_write_worker(void *arg)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)arg;
+       unsigned long flags;
+#ifdef DEBUG
+       static long start_j = 0;
+
+       if (start_j == 0)
+               start_j = jiffies;
+#endif /* DEBUG */
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       hvsi_push(hp);
+       if (hp->n_outbuf > 0)
+               schedule_delayed_work(&hp->writer, 10);
+       else {
+#ifdef DEBUG
+               pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__,
+                               jiffies - start_j);
+               start_j = 0;
+#endif /* DEBUG */
+               wake_up_all(&hp->emptyq);
+               if (test_bit(TTY_DO_WRITE_WAKEUP, &hp->tty->flags)
+                               && hp->tty->ldisc.write_wakeup)
+                       hp->tty->ldisc.write_wakeup(hp->tty);
+               wake_up_interruptible(&hp->tty->write_wait);
+       }
+
+       spin_unlock_irqrestore(&hp->lock, flags);
+}
+
+static int hvsi_write_room(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+
+       return N_OUTBUF - hp->n_outbuf;
+}
+
+static int hvsi_chars_in_buffer(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+
+       return hp->n_outbuf;
+}
+
+static int hvsi_write(struct tty_struct *tty, int from_user,
+                    const unsigned char *buf, int count)
+{
+       struct hvsi_struct *hp = tty->driver_data;
+       const char *source = buf;
+       char *kbuf = NULL;
+       unsigned long flags;
+       int total = 0;
+       int origcount = count;
+
+       if (from_user) {
+               kbuf = kmalloc(count, GFP_KERNEL);
+               if (kbuf == NULL)
+                       return -ENOMEM;
+               if (copy_from_user(kbuf, buf, count)) {
+                       kfree(kbuf);
+                       return -EFAULT;
+               }
+               source = kbuf;
+       }
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       if (!is_open(hp)) {
+               /* we're either closing or not yet open; don't accept data */
+               pr_debug("%s: not open\n", __FUNCTION__);
+               goto out;
+       }
+
+       /*
+        * when the hypervisor buffer (16K) fills, data will stay in hp->outbuf
+        * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
+        * will see there is no room in outbuf and return.
+        */
+       while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
+               int chunksize = min(count, hvsi_write_room(hp->tty));
+
+               BUG_ON(hp->n_outbuf < 0);
+               memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
+               hp->n_outbuf += chunksize;
+
+               total += chunksize;
+               source += chunksize;
+               count -= chunksize;
+               hvsi_push(hp);
+       }
+
+       if (hp->n_outbuf > 0) {
+               /*
+                * we weren't able to write it all to the hypervisor.
+                * schedule another push attempt.
+                */
+               schedule_delayed_work(&hp->writer, 10);
+       }
+
+out:
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (from_user)
+               kfree(kbuf);
+
+       if (total != origcount)
+               pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount,
+                       total);
+
+       return total;
+}
+
+/*
+ * I have never seen throttle or unthrottle called, so this little throttle
+ * buffering scheme may or may not work.
+ */
+static void hvsi_throttle(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE);
+}
+
+static void hvsi_unthrottle(struct tty_struct *tty)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       unsigned long flags;
+       int shouldflip = 0;
+
+       pr_debug("%s\n", __FUNCTION__);
+
+       spin_lock_irqsave(&hp->lock, flags);
+       if (hp->n_throttle) {
+               hvsi_send_overflow(hp);
+               shouldflip = 1;
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       if (shouldflip)
+               tty_flip_buffer_push(hp->tty);
+
+       h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
+}
+
+static int hvsi_tiocmget(struct tty_struct *tty, struct file *file)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+
+       hvsi_get_mctrl(hp);
+       return hp->mctrl;
+}
+
+static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
+               unsigned int set, unsigned int clear)
+{
+       struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
+       unsigned long flags;
+       uint16_t new_mctrl;
+
+       /* we can only alter DTR */
+       clear &= TIOCM_DTR;
+       set &= TIOCM_DTR;
+
+       spin_lock_irqsave(&hp->lock, flags);
+
+       new_mctrl = (hp->mctrl & ~clear) | set;
+
+       if (hp->mctrl != new_mctrl) {
+               hvsi_set_mctrl(hp, new_mctrl);
+               hp->mctrl = new_mctrl;
+       }
+       spin_unlock_irqrestore(&hp->lock, flags);
+
+       return 0;
+}
+
+
+static struct tty_operations hvsi_ops = {
+       .open = hvsi_open,
+       .close = hvsi_close,
+       .write = hvsi_write,
+       .hangup = hvsi_hangup,
+       .write_room = hvsi_write_room,
+       .chars_in_buffer = hvsi_chars_in_buffer,
+       .throttle = hvsi_throttle,
+       .unthrottle = hvsi_unthrottle,
+       .tiocmget = hvsi_tiocmget,
+       .tiocmset = hvsi_tiocmset,
+};
+
+static int __init hvsi_init(void)
+{
+       int i;
+
+       hvsi_driver = alloc_tty_driver(hvsi_count);
+       if (!hvsi_driver)
+               return -ENOMEM;
+
+       hvsi_driver->owner = THIS_MODULE;
+       hvsi_driver->devfs_name = "hvsi/";
+       hvsi_driver->driver_name = "hvsi";
+       hvsi_driver->name = "hvsi";
+       hvsi_driver->major = HVSI_MAJOR;
+       hvsi_driver->minor_start = HVSI_MINOR;
+       hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+       hvsi_driver->init_termios = tty_std_termios;
+       hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+       hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
+       tty_set_operations(hvsi_driver, &hvsi_ops);
+
+       for (i=0; i < hvsi_count; i++) {
+               struct hvsi_struct *hp = &hvsi_ports[i];
+               int ret = 1;
+
+               ret = request_irq(hp->virq, hvsi_interrupt, SA_INTERRUPT, "hvsi", hp);
+               if (ret)
+                       printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
+                               hp->virq, ret);
+       }
+       hvsi_wait = wait_for_state; /* irqs active now */
+
+       if (tty_register_driver(hvsi_driver))
+               panic("Couldn't register hvsi console driver\n");
+
+       printk(KERN_INFO "HVSI: registered %i devices\n", hvsi_count);
+
+       return 0;
+}
+device_initcall(hvsi_init);
+
+/***** console (not tty) code: *****/
+
+static void hvsi_console_print(struct console *console, const char *buf,
+               unsigned int count)
+{
+       struct hvsi_struct *hp = &hvsi_ports[console->index];
+       char c[HVSI_MAX_OUTGOING_DATA] __ALIGNED__;
+       unsigned int i = 0, n = 0;
+       int ret, donecr = 0;
+
+       mb();
+       if (!is_open(hp))
+               return;
+
+       /*
+        * ugh, we have to translate LF -> CRLF ourselves, in place.
+        * copied from hvc_console.c:
+        */
+       while (count > 0 || i > 0) {
+               if (count > 0 && i < sizeof(c)) {
+                       if (buf[n] == '\n' && !donecr) {
+                               c[i++] = '\r';
+                               donecr = 1;
+                       } else {
+                               c[i++] = buf[n++];
+                               donecr = 0;
+                               --count;
+                       }
+               } else {
+                       ret = hvsi_put_chars(hp, c, i);
+                       if (ret < 0)
+                               i = 0;
+                       i -= ret;
+               }
+       }
+}
+
+static struct tty_driver *hvsi_console_device(struct console *console,
+       int *index)
+{
+       *index = console->index;
+       return hvsi_driver;
+}
+
+static int __init hvsi_console_setup(struct console *console, char *options)
+{
+       struct hvsi_struct *hp = &hvsi_ports[console->index];
+       int ret;
+
+       if (console->index < 0 || console->index >= hvsi_count)
+               return -1;
+
+       /* give the FSP a chance to change the baud rate when we re-open */
+       hvsi_close_protocol(hp);
+
+       ret = hvsi_handshake(hp);
+       if (ret < 0)
+               return ret;
+
+       ret = hvsi_get_mctrl(hp);
+       if (ret < 0)
+               return ret;
+
+       ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR);
+       if (ret < 0)
+               return ret;
+
+       hp->flags |= HVSI_CONSOLE;
+
+       return 0;
+}
+
+static struct console hvsi_con_driver = {
+       .name           = "hvsi",
+       .write          = hvsi_console_print,
+       .device         = hvsi_console_device,
+       .setup          = hvsi_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+static int __init hvsi_console_init(void)
+{
+       struct device_node *vty;
+
+       hvsi_wait = poll_for_state; /* no irqs yet; must poll */
+
+       /* search device tree for vty nodes */
+       for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol");
+                       vty != NULL;
+                       vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
+               struct hvsi_struct *hp;
+               uint32_t *vtermno;
+               uint32_t *irq;
+
+               vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+               irq = (uint32_t *)get_property(vty, "interrupts", NULL);
+               if (!vtermno || !irq)
+                       continue;
+
+               if (hvsi_count >= MAX_NR_HVSI_CONSOLES) {
+                       of_node_put(vty);
+                       break;
+               }
+
+               hp = &hvsi_ports[hvsi_count];
+               INIT_WORK(&hp->writer, hvsi_write_worker, hp);
+               init_waitqueue_head(&hp->emptyq);
+               init_waitqueue_head(&hp->stateq);
+               hp->lock = SPIN_LOCK_UNLOCKED;
+               hp->index = hvsi_count;
+               hp->inbuf_end = hp->inbuf;
+               hp->state = HVSI_CLOSED;
+               hp->vtermno = *vtermno;
+               hp->virq = virt_irq_create_mapping(irq[0]);
+               if (hp->virq == NO_IRQ) {
+                       printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
+                               __FUNCTION__, hp->virq);
+                       continue;
+               } else
+                       hp->virq = irq_offset_up(hp->virq);
+
+               hvsi_count++;
+       }
+
+       if (hvsi_count)
+               register_console(&hvsi_con_driver);
+       return 0;
+}
+console_initcall(hvsi_console_init);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
new file mode 100644 (file)
index 0000000..ade8729
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * ipmi_poweroff.c
+ *
+ * MontaVista IPMI Poweroff extension to sys_reboot
+ *
+ * Author: MontaVista Software, Inc.
+ *         Steven Dake <sdake@mvista.com>
+ *         Corey Minyard <cminyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002,2004 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  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 AUTHOR 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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <asm/semaphore.h>
+#include <linux/kdev_t.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+
+#define PFX "IPMI poweroff: "
+#define IPMI_POWEROFF_VERSION  "v33"
+
+/* Where to we insert our poweroff function? */
+extern void (*pm_power_off)(void);
+
+/* Stuff from the get device id command. */
+unsigned int mfg_id;
+unsigned int prod_id;
+unsigned char capabilities;
+
+/* We use our own messages for this operation, we don't let the system
+   allocate them, since we may be in a panic situation.  The whole
+   thing is single-threaded, anyway, so multiple messages are not
+   required. */
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+}
+static struct ipmi_smi_msg halt_smi_msg =
+{
+       .done = dummy_smi_free
+};
+static struct ipmi_recv_msg halt_recv_msg =
+{
+       .done = dummy_recv_free
+};
+
+
+/*
+ * Code to send a message and wait for the reponse.
+ */
+
+static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
+{
+       struct semaphore *sem = recv_msg->user_msg_data;
+
+       if (sem)
+               up(sem);
+}
+
+static struct ipmi_user_hndl ipmi_poweroff_handler =
+{
+       .ipmi_recv_hndl = receive_handler
+};
+
+
+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;
+
+       sema_init (&sem, 0);
+
+       rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem,
+                                     &halt_smi_msg, &halt_recv_msg, 0);
+       if (rv)
+               return rv;
+
+       down (&sem);
+
+       return halt_recv_msg.msg.data[0];
+}
+
+/* We are in run-to-completion mode, no semaphore 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;
+
+       rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
+                                     &halt_smi_msg, &halt_recv_msg, 0);
+       if (rv)
+               return rv;
+
+       return halt_recv_msg.msg.data[0];
+}
+
+/*
+ * ATCA Support
+ */
+
+#define IPMI_NETFN_ATCA                        0x2c
+#define IPMI_ATCA_SET_POWER_CMD                0x11
+#define IPMI_ATCA_GET_ADDR_INFO_CMD    0x01
+#define IPMI_PICMG_ID                  0
+
+static int ipmi_atca_detect (ipmi_user_t user)
+{
+       struct ipmi_system_interface_addr smi_addr;
+       struct kernel_ipmi_msg            send_msg;
+       int                               rv;
+       unsigned char                     data[1];
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+       /*
+        * Use get address info to check and see if we are ATCA
+        */
+       send_msg.netfn = IPMI_NETFN_ATCA;
+       send_msg.cmd = IPMI_ATCA_GET_ADDR_INFO_CMD;
+       data[0] = IPMI_PICMG_ID;
+       send_msg.data = data;
+       send_msg.data_len = sizeof(data);
+       rv = ipmi_request_wait_for_response(user,
+                                           (struct ipmi_addr *) &smi_addr,
+                                           &send_msg);
+       return !rv;
+}
+
+static void ipmi_poweroff_atca (ipmi_user_t user)
+{
+       struct ipmi_system_interface_addr smi_addr;
+       struct kernel_ipmi_msg            send_msg;
+       int                               rv;
+       unsigned char                     data[4];
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+       printk(KERN_INFO PFX "Powering down via ATCA power command\n");
+
+       /*
+        * Power down
+        */
+       send_msg.netfn = IPMI_NETFN_ATCA;
+       send_msg.cmd = IPMI_ATCA_SET_POWER_CMD;
+       data[0] = IPMI_PICMG_ID;
+       data[1] = 0; /* FRU id */
+       data[2] = 0; /* Power Level */
+       data[3] = 0; /* Don't change saved presets */
+       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 ATCA powerdown message,"
+                      " IPMI error 0x%x\n", rv);
+               goto out;
+       }
+
+ out:
+       return;
+}
+
+/*
+ * CPI1 Support
+ */
+
+#define IPMI_NETFN_OEM_1                               0xf8
+#define OEM_GRP_CMD_SET_RESET_STATE            0x84
+#define OEM_GRP_CMD_SET_POWER_STATE            0x82
+#define IPMI_NETFN_OEM_8                               0xf8
+#define OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL       0x80
+#define OEM_GRP_CMD_GET_SLOT_GA                        0xa3
+#define IPMI_NETFN_SENSOR_EVT                  0x10
+#define IPMI_CMD_GET_EVENT_RECEIVER            0x01
+
+#define IPMI_CPI1_PRODUCT_ID           0x000157
+#define IPMI_CPI1_MANUFACTURER_ID      0x0108
+
+static int ipmi_cpi1_detect (ipmi_user_t user)
+{
+       return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
+               && (prod_id == IPMI_CPI1_PRODUCT_ID));
+}
+
+static void ipmi_poweroff_cpi1 (ipmi_user_t user)
+{
+       struct ipmi_system_interface_addr smi_addr;
+       struct ipmi_ipmb_addr             ipmb_addr;
+       struct kernel_ipmi_msg            send_msg;
+       int                               rv;
+       unsigned char                     data[1];
+       int                               slot;
+       unsigned char                     hotswap_ipmb;
+       unsigned char                     aer_addr;
+       unsigned char                     aer_lun;
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+       printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
+
+       /*
+        * Get IPMI ipmb address
+        */
+       send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
+       send_msg.cmd = OEM_GRP_CMD_GET_SLOT_GA;
+       send_msg.data = NULL;
+       send_msg.data_len = 0;
+       rv = ipmi_request_in_rc_mode(user,
+                                    (struct ipmi_addr *) &smi_addr,
+                                    &send_msg);
+       if (rv)
+               goto out;
+       slot = halt_recv_msg.msg.data[1];
+       hotswap_ipmb = (slot > 9) ? (0xb0 + 2 * slot) : (0xae + 2 * slot);
+
+       /*
+        * Get active event receiver
+        */
+       send_msg.netfn = IPMI_NETFN_SENSOR_EVT >> 2;
+       send_msg.cmd = IPMI_CMD_GET_EVENT_RECEIVER;
+       send_msg.data = NULL;
+       send_msg.data_len = 0;
+       rv = ipmi_request_in_rc_mode(user,
+                                    (struct ipmi_addr *) &smi_addr,
+                                    &send_msg);
+       if (rv)
+               goto out;
+       aer_addr = halt_recv_msg.msg.data[1];
+       aer_lun = halt_recv_msg.msg.data[2];
+
+       /*
+        * Setup IPMB address target instead of local target
+        */
+       ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
+       ipmb_addr.channel = 0;
+       ipmb_addr.slave_addr = aer_addr;
+       ipmb_addr.lun = aer_lun;
+
+       /*
+        * Send request hotswap control to remove blade from dpv
+        */
+       send_msg.netfn = IPMI_NETFN_OEM_8 >> 2;
+       send_msg.cmd = OEM_GRP_CMD_REQUEST_HOTSWAP_CTRL;
+       send_msg.data = &hotswap_ipmb;
+       send_msg.data_len = 1;
+       ipmi_request_in_rc_mode(user,
+                               (struct ipmi_addr *) &ipmb_addr,
+                               &send_msg);
+
+       /*
+        * Set reset asserted
+        */
+       send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
+       send_msg.cmd = OEM_GRP_CMD_SET_RESET_STATE;
+       send_msg.data = data;
+       data[0] = 1; /* Reset asserted state */
+       send_msg.data_len = 1;
+       rv = ipmi_request_in_rc_mode(user,
+                                    (struct ipmi_addr *) &smi_addr,
+                                    &send_msg);
+       if (rv)
+               goto out;
+
+       /*
+        * Power down
+        */
+       send_msg.netfn = IPMI_NETFN_OEM_1 >> 2;
+       send_msg.cmd = OEM_GRP_CMD_SET_POWER_STATE;
+       send_msg.data = data;
+       data[0] = 1; /* Power down state */
+       send_msg.data_len = 1;
+       rv = ipmi_request_in_rc_mode(user,
+                                    (struct ipmi_addr *) &smi_addr,
+                                    &send_msg);
+       if (rv)
+               goto out;
+
+ out:
+       return;
+}
+
+/*
+ * Standard chassis support
+ */
+
+#define IPMI_NETFN_CHASSIS_REQUEST     0
+#define IPMI_CHASSIS_CONTROL_CMD       0x02
+
+static int ipmi_chassis_detect (ipmi_user_t user)
+{
+       /* Chassis support, use it. */
+       return (capabilities & 0x80);
+}
+
+static void ipmi_poweroff_chassis (ipmi_user_t user)
+{
+       struct ipmi_system_interface_addr smi_addr;
+       struct kernel_ipmi_msg            send_msg;
+       int                               rv;
+       unsigned char                     data[1];
+
+        /*
+         * Configure IPMI address for local access
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+       printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
+
+       /*
+        * Power down
+        */
+       send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
+       send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
+       data[0] = 0; /* Power down */
+       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;
+       }
+
+ out:
+       return;
+}
+
+
+/* Table of possible power off functions. */
+struct poweroff_function {
+       char *platform_type;
+       int  (*detect)(ipmi_user_t user);
+       void (*poweroff_func)(ipmi_user_t user);
+};
+
+static struct poweroff_function poweroff_functions[] = {
+       { "ATCA",    ipmi_atca_detect, ipmi_poweroff_atca },
+       { "CPI1",    ipmi_cpi1_detect, ipmi_poweroff_cpi1 },
+       /* Chassis should generally be last, other things should override
+          it. */
+       { "chassis", ipmi_chassis_detect, ipmi_poweroff_chassis },
+};
+#define NUM_PO_FUNCS (sizeof(poweroff_functions) \
+                     / sizeof(struct poweroff_function))
+
+
+/* Our local state. */
+static int ready = 0;
+static ipmi_user_t ipmi_user;
+static void (*specific_poweroff_func)(ipmi_user_t user) = NULL;
+
+/* Holds the old poweroff function so we can restore it on removal. */
+static void (*old_poweroff_func)(void);
+
+
+/* Called on a powerdown request. */
+static void ipmi_poweroff_function (void)
+{
+       if (!ready)
+               return;
+
+       /* Use run-to-completion mode, since interrupts may be off. */
+       ipmi_user_set_run_to_completion(ipmi_user, 1);
+       specific_poweroff_func(ipmi_user);
+       ipmi_user_set_run_to_completion(ipmi_user, 0);
+}
+
+/* Wait for an IPMI interface to be installed, the first one installed
+   will be grabbed by this code and used to perform the powerdown. */
+static void ipmi_po_new_smi(int if_num)
+{
+       struct ipmi_system_interface_addr smi_addr;
+       struct kernel_ipmi_msg            send_msg;
+       int                               rv;
+       int                               i;
+
+       if (ready)
+               return;
+
+       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);
+               return;
+       }
+
+        /*
+         * Do a get device ide and store some results, since this is
+        * used by several functions.
+         */
+        smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+        smi_addr.channel = IPMI_BMC_CHANNEL;
+        smi_addr.lun = 0;
+
+       send_msg.netfn = IPMI_NETFN_APP_REQUEST;
+       send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
+       send_msg.data = NULL;
+       send_msg.data_len = 0;
+       rv = ipmi_request_wait_for_response(ipmi_user,
+                                           (struct ipmi_addr *) &smi_addr,
+                                           &send_msg);
+       if (rv) {
+               printk(KERN_ERR PFX "Unable to send IPMI get device id info,"
+                      " IPMI error 0x%x\n", rv);
+               goto out_err;
+       }
+
+       if (halt_recv_msg.msg.data_len < 12) {
+               printk(KERN_ERR PFX "(chassis) IPMI get device id info too,"
+                      " short, was %d bytes, needed %d bytes\n",
+                      halt_recv_msg.msg.data_len, 12);
+               goto out_err;
+       }
+
+       mfg_id = (halt_recv_msg.msg.data[7]
+                 | (halt_recv_msg.msg.data[8] << 8)
+                 | (halt_recv_msg.msg.data[9] << 16));
+       prod_id = (halt_recv_msg.msg.data[10]
+                  | (halt_recv_msg.msg.data[11] << 8));
+       capabilities = halt_recv_msg.msg.data[6];
+
+
+       /* Scan for a poweroff method */
+       for (i=0; i<NUM_PO_FUNCS; i++) {
+               if (poweroff_functions[i].detect(ipmi_user))
+                       goto found;
+       }
+
+ out_err:
+       printk(KERN_ERR PFX "Unable to find a poweroff function that"
+              " will work, giving up\n");
+       ipmi_destroy_user(ipmi_user);
+       return;
+
+ found:
+       printk(KERN_INFO PFX "Found a %s style poweroff function\n",
+              poweroff_functions[i].platform_type);
+       specific_poweroff_func = poweroff_functions[i].poweroff_func;
+       old_poweroff_func = pm_power_off;
+       pm_power_off = ipmi_poweroff_function;
+       ready = 1;
+}
+
+static void ipmi_po_smi_gone(int if_num)
+{
+       /* This can never be called, because once poweroff driver is
+          registered, the interface can't go away until the power
+          driver is unregistered. */
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+       .owner    = THIS_MODULE,
+       .new_smi  = ipmi_po_new_smi,
+       .smi_gone = ipmi_po_smi_gone
+};
+
+
+/*
+ * Startup and shutdown functions.
+ */
+static int ipmi_poweroff_init (void)
+{
+       int rv;
+
+       printk ("Copyright (C) 2004 MontaVista Software -"
+               " IPMI Powerdown via sys_reboot version "
+               IPMI_POWEROFF_VERSION ".\n");
+
+       rv = ipmi_smi_watcher_register(&smi_watcher);
+       if (rv)
+               printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+
+       return rv;
+}
+
+#ifdef MODULE
+static __exit void ipmi_poweroff_cleanup(void)
+{
+       int rv;
+
+       ipmi_smi_watcher_unregister(&smi_watcher);
+
+       if (ready) {
+               rv = ipmi_destroy_user(ipmi_user);
+               if (rv)
+                       printk(KERN_ERR PFX "could not cleanup the IPMI"
+                              " user: 0x%x\n", rv);
+               pm_power_off = old_poweroff_func;
+       }
+}
+module_exit(ipmi_poweroff_cleanup);
+#endif
+
+module_init(ipmi_poweroff_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
new file mode 100644 (file)
index 0000000..20aa170
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Intel Multimedia Timer device implementation for SGI SN platforms.
+ *
+ * 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-2004 Silicon Graphics, Inc.  All rights reserved.
+ *
+ * This driver exports an API that should be supportable by any HPET or IA-PC
+ * multimedia timer.  The code below is currently specific to the SGI Altix
+ * SHub RTC, however.
+ *
+ * 11/01/01 - jbarnes - initial revision
+ * 9/10/04 - Christoph Lameter - remove interrupt support for kernel inclusion
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/mmtimer.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+
+MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>");
+MODULE_DESCRIPTION("Multimedia timer support");
+MODULE_LICENSE("GPL");
+
+/* name of the device, usually in /dev */
+#define MMTIMER_NAME "mmtimer"
+#define MMTIMER_DESC "IA-PC Multimedia Timer"
+#define MMTIMER_VERSION "1.0"
+
+#define RTC_BITS 55 /* 55 bits for this implementation */
+
+static int mmtimer_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg);
+static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
+
+/*
+ * Period in femtoseconds (10^-15 s)
+ */
+static unsigned long mmtimer_femtoperiod = 0;
+
+static struct file_operations mmtimer_fops = {
+       .owner =        THIS_MODULE,
+       .mmap =         mmtimer_mmap,
+       .ioctl =        mmtimer_ioctl,
+};
+
+/**
+ * mmtimer_ioctl - ioctl interface for /dev/mmtimer
+ * @inode: inode of the device
+ * @file: file structure for the device
+ * @cmd: command to execute
+ * @arg: optional argument to command
+ *
+ * Executes the command specified by @cmd.  Returns 0 for success, < 0 for
+ * failure.
+ *
+ * Valid commands:
+ *
+ * %MMTIMER_GETOFFSET - Should return the offset (relative to the start
+ * of the page where the registers are mapped) for the counter in question.
+ *
+ * %MMTIMER_GETRES - Returns the resolution of the clock in femto (10^-15)
+ * seconds
+ *
+ * %MMTIMER_GETFREQ - Copies the frequency of the clock in Hz to the address
+ * specified by @arg
+ *
+ * %MMTIMER_GETBITS - Returns the number of bits in the clock's counter
+ *
+ * %MMTIMER_MMAPAVAIL - Returns 1 if the registers can be mmap'd into userspace
+ *
+ * %MMTIMER_GETCOUNTER - Gets the current value in the counter and places it
+ * in the address specified by @arg.
+ */
+static int mmtimer_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       case MMTIMER_GETOFFSET: /* offset of the counter */
+               /*
+                * SN RTC registers are on their own 64k page
+                */
+               if(PAGE_SIZE <= (1 << 16))
+                       ret = (((long)RTC_COUNTER_ADDR) & (PAGE_SIZE-1)) / 8;
+               else
+                       ret = -ENOSYS;
+               break;
+
+       case MMTIMER_GETRES: /* resolution of the clock in 10^-15 s */
+               if(copy_to_user((unsigned long *)arg, &mmtimer_femtoperiod,
+                               sizeof(unsigned long)))
+                       return -EFAULT;
+               break;
+
+       case MMTIMER_GETFREQ: /* frequency in Hz */
+               if(copy_to_user((unsigned long *)arg,
+                               &sn_rtc_cycles_per_second,
+                               sizeof(unsigned long)))
+                       return -EFAULT;
+               ret = 0;
+               break;
+
+       case MMTIMER_GETBITS: /* number of bits in the clock */
+               ret = RTC_BITS;
+               break;
+
+       case MMTIMER_MMAPAVAIL: /* can we mmap the clock into userspace? */
+               ret = (PAGE_SIZE <= (1 << 16)) ? 1 : 0;
+               break;
+
+       case MMTIMER_GETCOUNTER:
+               if(copy_to_user((unsigned long *)arg, RTC_COUNTER_ADDR,
+                               sizeof(unsigned long)))
+                       return -EFAULT;
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * mmtimer_mmap - maps the clock's registers into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ *
+ * Calls remap_page_range() to map the clock's registers into
+ * the calling process' address space.
+ */
+static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       unsigned long mmtimer_addr;
+
+       if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+               return -EINVAL;
+
+       if (vma->vm_flags & VM_WRITE)
+               return -EPERM;
+
+       if (PAGE_SIZE > (1 << 16))
+               return -ENOSYS;
+
+       vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       mmtimer_addr = __pa(RTC_COUNTER_ADDR);
+       mmtimer_addr &= ~(PAGE_SIZE - 1);
+       mmtimer_addr &= 0xfffffffffffffffUL;
+
+       if (remap_page_range(vma, vma->vm_start, mmtimer_addr, PAGE_SIZE,
+                            vma->vm_page_prot)) {
+               printk(KERN_ERR "remap_page_range failed in mmtimer.c\n");
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+static struct miscdevice mmtimer_miscdev = {
+       SGI_MMTIMER,
+       MMTIMER_NAME,
+       &mmtimer_fops
+};
+
+/**
+ * mmtimer_init - device initialization routine
+ *
+ * Does initial setup for the mmtimer device.
+ */
+static int __init mmtimer_init(void)
+{
+       if (!ia64_platform_is("sn2"))
+               return -1;
+
+       /*
+        * Sanity check the cycles/sec variable
+        */
+       if (sn_rtc_cycles_per_second < 100000) {
+               printk(KERN_ERR "%s: unable to determine clock frequency\n",
+                      MMTIMER_NAME);
+               return -1;
+       }
+
+       mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second /
+                              2) / sn_rtc_cycles_per_second;
+
+       strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME);
+       if (misc_register(&mmtimer_miscdev)) {
+               printk(KERN_ERR "%s: failed to register device\n",
+                      MMTIMER_NAME);
+               return -1;
+       }
+
+       printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION,
+              sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+       return 0;
+}
+
+module_init(mmtimer_init);
+
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
new file mode 100644 (file)
index 0000000..e7fd0b0
--- /dev/null
@@ -0,0 +1,450 @@
+#ifndef _MXSER_H
+#define _MXSER_H
+
+/*
+ *     Semi-public control interfaces
+ */
+/*
+ *     MOXA ioctls
+ */
+
+#define MOXA                   0x400
+#define MOXA_GETDATACOUNT      (MOXA + 23)
+#define        MOXA_GET_CONF           (MOXA + 35)
+#define MOXA_DIAGNOSE          (MOXA + 50)
+#define MOXA_CHKPORTENABLE     (MOXA + 60)
+#define MOXA_HighSpeedOn       (MOXA + 61)
+#define MOXA_GET_MAJOR         (MOXA + 63)
+#define MOXA_GET_CUMAJOR       (MOXA + 64)
+#define MOXA_GETMSTATUS                (MOXA + 65)
+#define MOXA_SET_OP_MODE       (MOXA + 66)
+#define MOXA_GET_OP_MODE       (MOXA + 67)
+
+#define RS232_MODE             0
+#define RS485_2WIRE_MODE       1
+#define RS422_MODE             2
+#define RS485_4WIRE_MODE       3
+#define OP_MODE_MASK           3
+// above add by Victor Yu. 01-05-2004
+
+#define TTY_THRESHOLD_THROTTLE  128
+
+#define LO_WATER               (TTY_FLIPBUF_SIZE)
+#define HI_WATER               (TTY_FLIPBUF_SIZE*2*3/4)
+
+// added by James. 03-11-2004.
+#define MOXA_SDS_GETICOUNTER   (MOXA + 68)
+#define MOXA_SDS_RSTICOUNTER   (MOXA + 69)
+// (above) added by James.
+
+#define MOXA_ASPP_OQUEUE       (MOXA + 70)
+#define MOXA_ASPP_SETBAUD      (MOXA + 71)
+#define MOXA_ASPP_GETBAUD      (MOXA + 72)
+#define MOXA_ASPP_MON          (MOXA + 73)
+#define MOXA_ASPP_LSTATUS      (MOXA + 74)
+#define MOXA_ASPP_MON_EXT      (MOXA + 75)
+#define MOXA_SET_BAUD_METHOD   (MOXA + 76)
+
+
+/* --------------------------------------------------- */
+
+#define NPPI_NOTIFY_PARITY     0x01
+#define NPPI_NOTIFY_FRAMING    0x02
+#define NPPI_NOTIFY_HW_OVERRUN 0x04
+#define NPPI_NOTIFY_SW_OVERRUN 0x08
+#define NPPI_NOTIFY_BREAK      0x10
+
+#define NPPI_NOTIFY_CTSHOLD         0x01       // Tx hold by CTS low
+#define NPPI_NOTIFY_DSRHOLD         0x02       // Tx hold by DSR low
+#define NPPI_NOTIFY_XOFFHOLD        0x08       // Tx hold by Xoff received
+#define NPPI_NOTIFY_XOFFXENT        0x10       // Xoff Sent
+
+//CheckIsMoxaMust return value
+#define MOXA_OTHER_UART                        0x00
+#define MOXA_MUST_MU150_HWID           0x01
+#define MOXA_MUST_MU860_HWID           0x02
+
+// follow just for Moxa Must chip define.
+//
+// when LCR register (offset 0x03) write following value,
+// the Must chip will enter enchance mode. And write value
+// on EFR (offset 0x02) bit 6,7 to change bank.
+#define MOXA_MUST_ENTER_ENCHANCE       0xBF
+
+// when enhance mode enable, access on general bank register
+#define MOXA_MUST_GDL_REGISTER         0x07
+#define MOXA_MUST_GDL_MASK             0x7F
+#define MOXA_MUST_GDL_HAS_BAD_DATA     0x80
+
+#define MOXA_MUST_LSR_RERR             0x80    // error in receive FIFO
+// enchance register bank select and enchance mode setting register
+// when LCR register equal to 0xBF
+#define MOXA_MUST_EFR_REGISTER         0x02
+// enchance mode enable
+#define MOXA_MUST_EFR_EFRB_ENABLE      0x10
+// enchance reister bank set 0, 1, 2
+#define MOXA_MUST_EFR_BANK0            0x00
+#define MOXA_MUST_EFR_BANK1            0x40
+#define MOXA_MUST_EFR_BANK2            0x80
+#define MOXA_MUST_EFR_BANK3            0xC0
+#define MOXA_MUST_EFR_BANK_MASK                0xC0
+
+// set XON1 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XON1_REGISTER                0x04
+
+// set XON2 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XON2_REGISTER                0x05
+
+// set XOFF1 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XOFF1_REGISTER       0x06
+
+// set XOFF2 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XOFF2_REGISTER       0x07
+
+#define MOXA_MUST_RBRTL_REGISTER       0x04
+#define MOXA_MUST_RBRTH_REGISTER       0x05
+#define MOXA_MUST_RBRTI_REGISTER       0x06
+#define MOXA_MUST_THRTL_REGISTER       0x07
+#define MOXA_MUST_ENUM_REGISTER                0x04
+#define MOXA_MUST_HWID_REGISTER                0x05
+#define MOXA_MUST_ECR_REGISTER         0x06
+#define MOXA_MUST_CSR_REGISTER         0x07
+
+// good data mode enable
+#define MOXA_MUST_FCR_GDA_MODE_ENABLE  0x20
+// only good data put into RxFIFO
+#define MOXA_MUST_FCR_GDA_ONLY_ENABLE  0x10
+
+// enable CTS interrupt
+#define MOXA_MUST_IER_ECTSI            0x80
+// eanble RTS interrupt
+#define MOXA_MUST_IER_ERTSI            0x40
+// enable Xon/Xoff interrupt
+#define MOXA_MUST_IER_XINT             0x20
+// enable GDA interrupt
+#define MOXA_MUST_IER_EGDAI            0x10
+
+#define MOXA_MUST_RECV_ISR             (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
+
+// GDA interrupt pending
+#define MOXA_MUST_IIR_GDA              0x1C
+#define MOXA_MUST_IIR_RDA              0x04
+#define MOXA_MUST_IIR_RTO              0x0C
+#define MOXA_MUST_IIR_LSR              0x06
+
+// recieved Xon/Xoff or specical interrupt pending
+#define MOXA_MUST_IIR_XSC              0x10
+
+// RTS/CTS change state interrupt pending
+#define MOXA_MUST_IIR_RTSCTS           0x20
+#define MOXA_MUST_IIR_MASK             0x3E
+
+#define MOXA_MUST_MCR_XON_FLAG         0x40
+#define MOXA_MUST_MCR_XON_ANY          0x80
+#define MOXA_MUST_MCR_TX_XON           0x08
+
+
+// software flow control on chip mask value
+#define MOXA_MUST_EFR_SF_MASK          0x0F
+// send Xon1/Xoff1
+#define MOXA_MUST_EFR_SF_TX1           0x08
+// send Xon2/Xoff2
+#define MOXA_MUST_EFR_SF_TX2           0x04
+// send Xon1,Xon2/Xoff1,Xoff2
+#define MOXA_MUST_EFR_SF_TX12          0x0C
+// don't send Xon/Xoff
+#define MOXA_MUST_EFR_SF_TX_NO         0x00
+// Tx software flow control mask
+#define MOXA_MUST_EFR_SF_TX_MASK       0x0C
+// don't receive Xon/Xoff
+#define MOXA_MUST_EFR_SF_RX_NO         0x00
+// receive Xon1/Xoff1
+#define MOXA_MUST_EFR_SF_RX1           0x02
+// receive Xon2/Xoff2
+#define MOXA_MUST_EFR_SF_RX2           0x01
+// receive Xon1,Xon2/Xoff1,Xoff2
+#define MOXA_MUST_EFR_SF_RX12          0x03
+// Rx software flow control mask
+#define MOXA_MUST_EFR_SF_RX_MASK       0x03
+
+//#define MOXA_MUST_MIN_XOFFLIMIT               66
+//#define MOXA_MUST_MIN_XONLIMIT                20
+//#define ID1_RX_TRIG                   120
+
+
+#define CHECK_MOXA_MUST_XOFFLIMIT(info) {      \
+       if ( (info)->IsMoxaMustChipFlag &&      \
+        (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) {       \
+               (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT;   \
+               (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT;     \
+       }       \
+}
+
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr |= MOXA_MUST_EFR_EFRB_ENABLE;     \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) {      \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;    \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) {      \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK0;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER);    \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) {      \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK0;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER);    \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) {     \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK0;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) {     \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK0;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) {     \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK1;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) {     \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK1;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) {     \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK1;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) {     \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK1;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+//#define MOXA_MUST_RBRL_VALUE  4
+#define SET_MOXA_MUST_FIFO_VALUE(info) {       \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((info)->base+UART_LCR);  \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (info)->base+UART_LCR);  \
+       __efr = inb((info)->base+MOXA_MUST_EFR_REGISTER);       \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK1;   \
+       outb(__efr, (info)->base+MOXA_MUST_EFR_REGISTER);       \
+       outb((u8)((info)->rx_high_water), (info)->base+MOXA_MUST_RBRTH_REGISTER);       \
+       outb((u8)((info)->rx_trigger), (info)->base+MOXA_MUST_RBRTI_REGISTER);  \
+       outb((u8)((info)->rx_low_water), (info)->base+MOXA_MUST_RBRTL_REGISTER);        \
+       outb(__oldlcr, (info)->base+UART_LCR);  \
+}
+
+
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) {      \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK2;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER);    \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) {       \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_BANK_MASK;      \
+       __efr |= MOXA_MUST_EFR_BANK2;   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) {       \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) {  \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
+       __efr |= MOXA_MUST_EFR_SF_TX1;  \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) {    \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;     \
+       __efr |= MOXA_MUST_EFR_SF_TX1;  \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) {   \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_TX_MASK;     \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) {  \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
+       __efr |= MOXA_MUST_EFR_SF_RX1;  \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) {    \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;     \
+       __efr |= MOXA_MUST_EFR_SF_RX1;  \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) {   \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_RX_MASK;     \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+       u8      __oldlcr, __efr;        \
+       __oldlcr = inb((baseio)+UART_LCR);      \
+       outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR);      \
+       __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER);   \
+       __efr &= ~MOXA_MUST_EFR_SF_MASK;        \
+       __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1);   \
+       outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER);   \
+       outb(__oldlcr, (baseio)+UART_LCR);      \
+}
+
+#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) {        \
+       u8      __oldmcr;       \
+       __oldmcr = inb((baseio)+UART_MCR);      \
+       __oldmcr |= MOXA_MUST_MCR_XON_ANY;      \
+       outb(__oldmcr, (baseio)+UART_MCR);      \
+}
+
+#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) {       \
+       u8      __oldmcr;       \
+       __oldmcr = inb((baseio)+UART_MCR);      \
+       __oldmcr &= ~MOXA_MUST_MCR_XON_ANY;     \
+       outb(__oldmcr, (baseio)+UART_MCR);      \
+}
+
+#define READ_MOXA_MUST_GDL(baseio)     inb((baseio)+MOXA_MUST_GDL_REGISTER)
+
+
+#ifndef INIT_WORK
+#define INIT_WORK(_work, _func, _data){        \
+       _data->tqueue.routine = _func;\
+       _data->tqueue.data = _data;\
+       }
+#endif
+
+#endif
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
new file mode 100644 (file)
index 0000000..687d9fa
--- /dev/null
@@ -0,0 +1,587 @@
+/* drivers/char/s3c2410_rtc.c
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 Internal RTC Driver
+ *
+ *  Changelog:
+ *     08-Nov-2004     BJD     Initial creation
+ *     12-Nov-2004     BJD     Added periodic IRQ and PM code
+ *     22-Nov-2004     BJD     Sign-test on alarm code to check for <0
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+#include <asm/hardware/clock.h>
+#include <asm/arch/regs-rtc.h>
+
+/* need this for the RTC_AF definitions */
+#include <linux/mc146818rtc.h>
+
+#undef S3C2410_VA_RTC
+#define S3C2410_VA_RTC s3c2410_rtc_base
+
+static struct resource *s3c2410_rtc_mem;
+
+static void __iomem *s3c2410_rtc_base;
+static int s3c2410_rtc_alarmno = NO_IRQ;
+static int s3c2410_rtc_tickno  = NO_IRQ;
+static int s3c2410_rtc_freq    = 1;
+
+static spinlock_t s3c2410_rtc_pie_lock = SPIN_LOCK_UNLOCKED;
+
+/* IRQ Handlers */
+
+static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
+{
+       rtc_update(1, RTC_AF | RTC_IRQF);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r)
+{
+       rtc_update(1, RTC_PF | RTC_IRQF);
+       return IRQ_HANDLED;
+}
+
+/* Update control registers */
+static void s3c2410_rtc_setaie(int to)
+{
+       unsigned int tmp;
+
+       pr_debug("%s: aie=%d\n", __FUNCTION__, to);
+
+       tmp = readb(S3C2410_RTCALM);
+
+       if (to)
+               tmp |= S3C2410_RTCALM_ALMEN;
+       else
+               tmp &= ~S3C2410_RTCALM_ALMEN;
+
+
+       writeb(tmp, S3C2410_RTCALM);
+}
+
+static void s3c2410_rtc_setpie(int to)
+{
+       unsigned int tmp;
+
+       pr_debug("%s: pie=%d\n", __FUNCTION__, to);
+
+       spin_lock_irq(&s3c2410_rtc_pie_lock);
+       tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
+
+       if (to)
+               tmp |= S3C2410_TICNT_ENABLE;
+
+       writeb(tmp, S3C2410_TICNT);
+       spin_unlock_irq(&s3c2410_rtc_pie_lock);
+}
+
+static void s3c2410_rtc_setfreq(int freq)
+{
+       unsigned int tmp;
+
+       spin_lock_irq(&s3c2410_rtc_pie_lock);
+       tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
+
+       s3c2410_rtc_freq = freq;
+
+       tmp |= (128 / freq)-1;
+
+       writeb(tmp, S3C2410_TICNT);
+       spin_unlock_irq(&s3c2410_rtc_pie_lock);
+}
+
+/* Time read/write */
+
+static void s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
+{
+       unsigned int have_retried = 0;
+
+ retry_get_time:
+       rtc_tm->tm_min  = readb(S3C2410_RTCMIN);
+       rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
+       rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
+       rtc_tm->tm_mon  = readb(S3C2410_RTCMON);
+       rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
+       rtc_tm->tm_sec  = readb(S3C2410_RTCSEC);
+
+       /* the only way to work out wether the system was mid-update
+        * when we read it is to check the second counter, and if it
+        * is zero, then we re-try the entire read
+        */
+
+       if (rtc_tm->tm_sec == 0 && !have_retried) {
+               have_retried = 1;
+               goto retry_get_time;
+       }
+
+       pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
+                rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+                rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
+       BCD_TO_BIN(rtc_tm->tm_sec);
+       BCD_TO_BIN(rtc_tm->tm_min);
+       BCD_TO_BIN(rtc_tm->tm_hour);
+       BCD_TO_BIN(rtc_tm->tm_mday);
+       BCD_TO_BIN(rtc_tm->tm_mon);
+       BCD_TO_BIN(rtc_tm->tm_year);
+
+       rtc_tm->tm_year += 100;
+       rtc_tm->tm_mon -= 1;
+}
+
+
+static int s3c2410_rtc_settime(struct rtc_time *tm)
+{
+       /* the rtc gets round the y2k problem by just not supporting it */
+
+       if (tm->tm_year < 100)
+               return -EINVAL;
+
+       writeb(BIN2BCD(tm->tm_sec),  S3C2410_RTCSEC);
+       writeb(BIN2BCD(tm->tm_min),  S3C2410_RTCMIN);
+       writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
+       writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
+       writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
+       writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);
+
+       return 0;
+}
+
+static void s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
+{
+       struct rtc_time *alm_tm = &alrm->time;
+       unsigned int alm_en;
+
+       alm_tm->tm_sec  = readb(S3C2410_ALMSEC);
+       alm_tm->tm_min  = readb(S3C2410_ALMMIN);
+       alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
+       alm_tm->tm_mon  = readb(S3C2410_ALMMON);
+       alm_tm->tm_mday = readb(S3C2410_ALMDATE);
+       alm_tm->tm_year = readb(S3C2410_ALMYEAR);
+
+       alm_en = readb(S3C2410_RTCALM);
+
+       pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
+                alm_en,
+                alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+                alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+
+
+       /* decode the alarm enable field */
+
+       if (alm_en & S3C2410_RTCALM_SECEN) {
+               BCD_TO_BIN(alm_tm->tm_sec);
+       } else {
+               alm_tm->tm_sec = 0xff;
+       }
+
+       if (alm_en & S3C2410_RTCALM_MINEN) {
+               BCD_TO_BIN(alm_tm->tm_min);
+       } else {
+               alm_tm->tm_min = 0xff;
+       }
+
+       if (alm_en & S3C2410_RTCALM_HOUREN) {
+               BCD_TO_BIN(alm_tm->tm_hour);
+       } else {
+               alm_tm->tm_hour = 0xff;
+       }
+
+       if (alm_en & S3C2410_RTCALM_DAYEN) {
+               BCD_TO_BIN(alm_tm->tm_mday);
+       } else {
+               alm_tm->tm_mday = 0xff;
+       }
+
+       if (alm_en & S3C2410_RTCALM_MONEN) {
+               BCD_TO_BIN(alm_tm->tm_mon);
+               alm_tm->tm_mon -= 1;
+       } else {
+               alm_tm->tm_mon = 0xff;
+       }
+
+       if (alm_en & S3C2410_RTCALM_YEAREN) {
+               BCD_TO_BIN(alm_tm->tm_year);
+       } else {
+               alm_tm->tm_year = 0xffff;
+       }
+
+       /* todo - set alrm->enabled ? */
+}
+
+static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
+{
+       struct rtc_time *tm = &alrm->time;
+       unsigned int alrm_en;
+
+       pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
+                alrm->enabled,
+                tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
+                tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
+
+       if (alrm->enabled || 1) {
+               alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
+               writeb(0x00, S3C2410_RTCALM);
+
+               if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
+                       alrm_en |= S3C2410_RTCALM_SECEN;
+                       writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
+               }
+
+               if (tm->tm_min < 60 && tm->tm_min >= 0) {
+                       alrm_en |= S3C2410_RTCALM_MINEN;
+                       writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
+               }
+
+               if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
+                       alrm_en |= S3C2410_RTCALM_HOUREN;
+                       writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
+               }
+
+               pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
+
+               writeb(alrm_en, S3C2410_RTCALM);
+               enable_irq_wake(s3c2410_rtc_alarmno);
+       } else {
+               alrm_en = readb(S3C2410_RTCALM);
+               alrm_en &= ~S3C2410_RTCALM_ALMEN;
+               writeb(alrm_en, S3C2410_RTCALM);
+               disable_irq_wake(s3c2410_rtc_alarmno);
+       }
+
+       return 0;
+}
+
+static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case RTC_AIE_OFF:
+       case RTC_AIE_ON:
+               s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
+               return 0;
+
+       case RTC_PIE_OFF:
+       case RTC_PIE_ON:
+               s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
+               return 0;
+
+       case RTC_IRQP_READ:
+               return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg);
+
+       case RTC_IRQP_SET:
+               if (arg < 1 || arg > 64)
+                       return -EINVAL;
+
+               if (!capable(CAP_SYS_RESOURCE))
+                       return -EACCES;
+
+               /* check for power of 2 */
+
+               if ((arg & (arg-1)) != 0)
+                       return -EINVAL;
+
+               pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
+
+               s3c2410_rtc_setfreq(arg);
+               return 0;
+
+       case RTC_UIE_ON:
+       case RTC_UIE_OFF:
+               return -EINVAL;
+       }
+
+       return -EINVAL;
+}
+
+static int s3c2410_rtc_proc(char *buf)
+{
+       unsigned int rtcalm = readb(S3C2410_RTCALM);
+       unsigned int ticnt = readb (S3C2410_TICNT);
+       char *p = buf;
+
+       p += sprintf(p, "alarm_IRQ\t: %s\n",
+                    (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
+       p += sprintf(p, "periodic_IRQ\t: %s\n",
+                    (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+       p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq);
+
+       return p - buf;
+}
+
+static int s3c2410_rtc_open(void)
+{
+       int ret;
+
+       ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq,
+                         SA_INTERRUPT,  "s3c2410-rtc alarm", NULL);
+
+       if (ret)
+               printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno);
+
+       ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq,
+                         SA_INTERRUPT,  "s3c2410-rtc tick", NULL);
+
+       if (ret) {
+               printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno);
+               goto tick_err;
+       }
+
+       return ret;
+
+ tick_err:
+       free_irq(s3c2410_rtc_alarmno, NULL);
+       return ret;
+}
+
+static void s3c2410_rtc_release(void)
+{
+       /* do not clear AIE here, it may be needed for wake */
+
+       s3c2410_rtc_setpie(0);
+       free_irq(s3c2410_rtc_alarmno, NULL);
+       free_irq(s3c2410_rtc_tickno, NULL);
+}
+
+static struct rtc_ops s3c2410_rtcops = {
+       .owner          = THIS_MODULE,
+       .open           = s3c2410_rtc_open,
+       .release        = s3c2410_rtc_release,
+       .ioctl          = s3c2410_rtc_ioctl,
+       .read_time      = s3c2410_rtc_gettime,
+       .set_time       = s3c2410_rtc_settime,
+       .read_alarm     = s3c2410_rtc_getalarm,
+       .set_alarm      = s3c2410_rtc_setalarm,
+       .proc           = s3c2410_rtc_proc,
+};
+
+static void s3c2410_rtc_enable(struct device *dev, int en)
+{
+       unsigned int tmp;
+
+       if (s3c2410_rtc_base == NULL)
+               return;
+
+       if (!en) {
+               tmp = readb(S3C2410_RTCCON);
+               writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);
+
+               tmp = readb(S3C2410_TICNT);
+               writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
+       } else {
+               /* re-enable the device, and check it is ok */
+
+               if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
+                       dev_info(dev, "rtc disabled, re-enabling\n");
+
+                       tmp = readb(S3C2410_RTCCON);
+                       writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
+               }
+
+               if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
+                       dev_info(dev, "removing S3C2410_RTCCON_CNTSEL\n");
+
+                       tmp = readb(S3C2410_RTCCON);
+                       writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
+               }
+
+               if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
+                       dev_info(dev, "removing S3C2410_RTCCON_CLKRST\n");
+
+                       tmp = readb(S3C2410_RTCCON);
+                       writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
+               }
+       }
+}
+
+static int s3c2410_rtc_remove(struct device *dev)
+{
+       unregister_rtc(&s3c2410_rtcops);
+
+       s3c2410_rtc_setpie(0);
+       s3c2410_rtc_setaie(0);
+
+       if (s3c2410_rtc_mem != NULL) {
+               pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n");
+               iounmap(s3c2410_rtc_base);
+               release_resource(s3c2410_rtc_mem);
+               kfree(s3c2410_rtc_mem);
+       }
+
+       return 0;
+}
+
+static int s3c2410_rtc_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct resource *res;
+       int ret;
+
+       pr_debug("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
+
+       /* find the IRQs */
+
+       s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
+       if (s3c2410_rtc_tickno <= 0) {
+               dev_err(dev, "no irq for rtc tick\n");
+               return -ENOENT;
+       }
+
+       s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
+       if (s3c2410_rtc_alarmno <= 0) {
+               dev_err(dev, "no irq for alarm\n");
+               return -ENOENT;
+       }
+
+       pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
+                s3c2410_rtc_tickno, s3c2410_rtc_alarmno);
+
+       /* get the memory region */
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "failed to get memory region resource\n");
+               return -ENOENT;
+       }
+
+       s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,
+                                    pdev->name);
+
+       if (s3c2410_rtc_mem == NULL) {
+               dev_err(dev, "failed to reserve memory region\n");
+               ret = -ENOENT;
+               goto exit_err;
+       }
+
+       s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
+       if (s3c2410_rtc_base == NULL) {
+               dev_err(dev, "failed ioremap()\n");
+               ret = -EINVAL;
+               goto exit_err;
+       }
+
+       s3c2410_rtc_mem = res;
+       pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);
+
+       pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
+
+       /* check to see if everything is setup correctly */
+
+       s3c2410_rtc_enable(dev, 1);
+
+       pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
+
+       s3c2410_rtc_setfreq(s3c2410_rtc_freq);
+
+       /* register RTC and exit */
+
+       register_rtc(&s3c2410_rtcops);
+       return 0;
+
+ exit_err:
+       dev_err(dev, "error %d during initialisation\n", ret);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM
+
+/* S3C2410 RTC Power management control */
+
+static struct timespec s3c2410_rtc_delta;
+
+static int ticnt_save;
+
+static int s3c2410_rtc_suspend(struct device *dev, u32 state, u32 level)
+{
+       struct rtc_time tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+
+       if (level == SUSPEND_POWER_DOWN) {
+               /* save TICNT for anyone using periodic interrupts */
+
+               ticnt_save = readb(S3C2410_TICNT);
+
+               /* calculate time delta for suspend */
+
+               s3c2410_rtc_gettime(&tm);
+               rtc_tm_to_time(&tm, &time.tv_sec);
+               save_time_delta(&s3c2410_rtc_delta, &time);
+               s3c2410_rtc_enable(dev, 0);
+       }
+
+       return 0;
+}
+
+static int s3c2410_rtc_resume(struct device *dev, u32 level)
+{
+       struct rtc_time tm;
+       struct timespec time;
+
+       time.tv_nsec = 0;
+
+       s3c2410_rtc_enable(dev, 1);
+       s3c2410_rtc_gettime(&tm);
+       rtc_tm_to_time(&tm, &time.tv_sec);
+       restore_time_delta(&s3c2410_rtc_delta, &time);
+
+       writeb(ticnt_save, S3C2410_TICNT);
+       return 0;
+}
+#else
+#define s3c2410_rtc_suspend NULL
+#define s3c2410_rtc_resume  NULL
+#endif
+
+static struct device_driver s3c2410_rtcdrv = {
+       .name           = "s3c2410-rtc",
+       .bus            = &platform_bus_type,
+       .probe          = s3c2410_rtc_probe,
+       .remove         = s3c2410_rtc_remove,
+       .suspend        = s3c2410_rtc_suspend,
+       .resume         = s3c2410_rtc_resume,
+};
+
+static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";
+
+static int __init s3c2410_rtc_init(void)
+{
+       printk(banner);
+       return driver_register(&s3c2410_rtcdrv);
+}
+
+static void __exit s3c2410_rtc_exit(void)
+{
+       driver_unregister(&s3c2410_rtcdrv);
+}
+
+module_init(s3c2410_rtc_init);
+module_exit(s3c2410_rtc_exit);
+
+MODULE_DESCRIPTION("S3C24XX RTC Driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
new file mode 100644 (file)
index 0000000..25917e0
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * SN Platform system controller communication 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) 2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * System controller communication driver
+ *
+ * This driver allows a user process to communicate with the system
+ * controller (a.k.a. "IRouter") network in an SGI SN system.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/nodepda.h>
+#include "snsc.h"
+
+#define SYSCTL_BASENAME        "snsc"
+
+#define SCDRV_BUFSZ    2048
+#define SCDRV_TIMEOUT  1000
+
+static irqreturn_t
+scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs)
+{
+       struct subch_data_s *sd = subch_data;
+       unsigned long flags;
+       int status;
+
+       spin_lock_irqsave(&sd->sd_rlock, flags);
+       spin_lock(&sd->sd_wlock);
+       status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
+
+       if (status > 0) {
+               if (status & SAL_IROUTER_INTR_RECV) {
+                       wake_up(&sd->sd_rq);
+               }
+               if (status & SAL_IROUTER_INTR_XMIT) {
+                       ia64_sn_irtr_intr_disable
+                           (sd->sd_nasid, sd->sd_subch,
+                            SAL_IROUTER_INTR_XMIT);
+                       wake_up(&sd->sd_wq);
+               }
+       }
+       spin_unlock(&sd->sd_wlock);
+       spin_unlock_irqrestore(&sd->sd_rlock, flags);
+       return IRQ_HANDLED;
+}
+
+/*
+ * scdrv_open
+ *
+ * Reserve a subchannel for system controller communication.
+ */
+
+static int
+scdrv_open(struct inode *inode, struct file *file)
+{
+       struct sysctl_data_s *scd;
+       struct subch_data_s *sd;
+       int rv;
+
+       /* look up device info for this device file */
+       scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev);
+
+       /* allocate memory for subchannel data */
+       sd = kmalloc(sizeof (struct subch_data_s), GFP_KERNEL);
+       if (sd == NULL) {
+               printk("%s: couldn't allocate subchannel data\n",
+                      __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       /* initialize subch_data_s fields */
+       memset(sd, 0, sizeof (struct subch_data_s));
+       sd->sd_nasid = scd->scd_nasid;
+       sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid);
+
+       if (sd->sd_subch < 0) {
+               kfree(sd);
+               printk("%s: couldn't allocate subchannel\n", __FUNCTION__);
+               return -EBUSY;
+       }
+
+       spin_lock_init(&sd->sd_rlock);
+       spin_lock_init(&sd->sd_wlock);
+       init_waitqueue_head(&sd->sd_rq);
+       init_waitqueue_head(&sd->sd_wq);
+       sema_init(&sd->sd_rbs, 1);
+       sema_init(&sd->sd_wbs, 1);
+
+       file->private_data = sd;
+
+       /* hook this subchannel up to the system controller interrupt */
+       rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt,
+                        SA_SHIRQ | SA_INTERRUPT,
+                        SYSCTL_BASENAME, sd);
+       if (rv) {
+               ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
+               kfree(sd);
+               printk("%s: irq request failed (%d)\n", __FUNCTION__, rv);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/*
+ * scdrv_release
+ *
+ * Release a previously-reserved subchannel.
+ */
+
+static int
+scdrv_release(struct inode *inode, struct file *file)
+{
+       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
+       int rv;
+
+       /* free the interrupt */
+       free_irq(SGI_UART_VECTOR, sd);
+
+       /* ask SAL to close the subchannel */
+       rv = ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
+
+       kfree(sd);
+       return rv;
+}
+
+/*
+ * scdrv_read
+ *
+ * Called to read bytes from the open IRouter pipe.
+ *
+ */
+
+static inline int
+read_status_check(struct subch_data_s *sd, int *len)
+{
+       return ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, sd->sd_rb, len);
+}
+
+static ssize_t
+scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
+{
+       int status;
+       int len;
+       unsigned long flags;
+       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
+
+       /* try to get control of the read buffer */
+       if (down_trylock(&sd->sd_rbs)) {
+               /* somebody else has it now;
+                * if we're non-blocking, then exit...
+                */
+               if (file->f_flags & O_NONBLOCK) {
+                       return -EAGAIN;
+               }
+               /* ...or if we want to block, then do so here */
+               if (down_interruptible(&sd->sd_rbs)) {
+                       /* something went wrong with wait */
+                       return -ERESTARTSYS;
+               }
+       }
+
+       /* anything to read? */
+       len = CHUNKSIZE;
+       spin_lock_irqsave(&sd->sd_rlock, flags);
+       status = read_status_check(sd, &len);
+
+       /* if not, and we're blocking I/O, loop */
+       while (status < 0) {
+               DECLARE_WAITQUEUE(wait, current);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       spin_unlock_irqrestore(&sd->sd_rlock, flags);
+                       up(&sd->sd_rbs);
+                       return -EAGAIN;
+               }
+
+               len = CHUNKSIZE;
+               add_wait_queue(&sd->sd_rq, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_unlock_irqrestore(&sd->sd_rlock, flags);
+
+               schedule_timeout(SCDRV_TIMEOUT);
+
+               remove_wait_queue(&sd->sd_rq, &wait);
+               if (signal_pending(current)) {
+                       /* wait was interrupted */
+                       up(&sd->sd_rbs);
+                       return -ERESTARTSYS;
+               }
+
+               spin_lock_irqsave(&sd->sd_rlock, flags);
+               status = read_status_check(sd, &len);
+       }
+       spin_unlock_irqrestore(&sd->sd_rlock, flags);
+
+       if (len > 0) {
+               /* we read something in the last read_status_check(); copy
+                * it out to user space
+                */
+               if (count < len) {
+                       pr_debug("%s: only accepting %d of %d bytes\n",
+                                __FUNCTION__, (int) count, len);
+               }
+               len = min((int) count, len);
+               if (copy_to_user(buf, sd->sd_rb, len))
+                       len = -EFAULT;
+       }
+
+       /* release the read buffer and wake anyone who might be
+        * waiting for it
+        */
+       up(&sd->sd_rbs);
+
+       /* return the number of characters read in */
+       return len;
+}
+
+/*
+ * scdrv_write
+ *
+ * Writes a chunk of an IRouter packet (or other system controller data)
+ * to the system controller.
+ *
+ */
+static inline int
+write_status_check(struct subch_data_s *sd, int count)
+{
+       return ia64_sn_irtr_send(sd->sd_nasid, sd->sd_subch, sd->sd_wb, count);
+}
+
+static ssize_t
+scdrv_write(struct file *file, const char __user *buf,
+           size_t count, loff_t *f_pos)
+{
+       unsigned long flags;
+       int status;
+       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
+
+       /* try to get control of the write buffer */
+       if (down_trylock(&sd->sd_wbs)) {
+               /* somebody else has it now;
+                * if we're non-blocking, then exit...
+                */
+               if (file->f_flags & O_NONBLOCK) {
+                       return -EAGAIN;
+               }
+               /* ...or if we want to block, then do so here */
+               if (down_interruptible(&sd->sd_wbs)) {
+                       /* something went wrong with wait */
+                       return -ERESTARTSYS;
+               }
+       }
+
+       count = min((int) count, CHUNKSIZE);
+       if (copy_from_user(sd->sd_wb, buf, count)) {
+               up(&sd->sd_wbs);
+               return -EFAULT;
+       }
+
+       /* try to send the buffer */
+       spin_lock_irqsave(&sd->sd_wlock, flags);
+       status = write_status_check(sd, count);
+
+       /* if we failed, and we want to block, then loop */
+       while (status <= 0) {
+               DECLARE_WAITQUEUE(wait, current);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       spin_unlock(&sd->sd_wlock);
+                       up(&sd->sd_wbs);
+                       return -EAGAIN;
+               }
+
+               add_wait_queue(&sd->sd_wq, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_unlock_irqrestore(&sd->sd_wlock, flags);
+
+               schedule_timeout(SCDRV_TIMEOUT);
+
+               remove_wait_queue(&sd->sd_wq, &wait);
+               if (signal_pending(current)) {
+                       /* wait was interrupted */
+                       up(&sd->sd_wbs);
+                       return -ERESTARTSYS;
+               }
+
+               spin_lock_irqsave(&sd->sd_wlock, flags);
+               status = write_status_check(sd, count);
+       }
+       spin_unlock_irqrestore(&sd->sd_wlock, flags);
+
+       /* release the write buffer and wake anyone who's waiting for it */
+       up(&sd->sd_wbs);
+
+       /* return the number of characters accepted (should be the complete
+        * "chunk" as requested)
+        */
+       if ((status >= 0) && (status < count)) {
+               pr_debug("Didn't accept the full chunk; %d of %d\n",
+                        status, (int) count);
+       }
+       return status;
+}
+
+static unsigned int
+scdrv_poll(struct file *file, struct poll_table_struct *wait)
+{
+       unsigned int mask = 0;
+       int status = 0;
+       struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
+       unsigned long flags;
+
+       poll_wait(file, &sd->sd_rq, wait);
+       poll_wait(file, &sd->sd_wq, wait);
+
+       spin_lock_irqsave(&sd->sd_rlock, flags);
+       spin_lock(&sd->sd_wlock);
+       status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
+       spin_unlock(&sd->sd_wlock);
+       spin_unlock_irqrestore(&sd->sd_rlock, flags);
+
+       if (status > 0) {
+               if (status & SAL_IROUTER_INTR_RECV) {
+                       mask |= POLLIN | POLLRDNORM;
+               }
+               if (status & SAL_IROUTER_INTR_XMIT) {
+                       mask |= POLLOUT | POLLWRNORM;
+               }
+       }
+
+       return mask;
+}
+
+static struct file_operations scdrv_fops = {
+       .owner =        THIS_MODULE,
+       .read =         scdrv_read,
+       .write =        scdrv_write,
+       .poll =         scdrv_poll,
+       .open =         scdrv_open,
+       .release =      scdrv_release,
+};
+
+/*
+ * scdrv_init
+ *
+ * Called at boot time to initialize the system controller communication
+ * facility.
+ */
+int __init
+scdrv_init(void)
+{
+       geoid_t geoid;
+       cmoduleid_t cmod;
+       int i;
+       char devname[32];
+       char *devnamep;
+       module_t *m;
+       struct sysctl_data_s *scd;
+       void *salbuf;
+       struct class_simple *snsc_class;
+       dev_t first_dev, dev;
+
+       if (alloc_chrdev_region(&first_dev, 0, (MAX_SLABS*nummodules),
+                               SYSCTL_BASENAME) < 0) {
+               printk("%s: failed to register SN system controller device\n",
+                      __FUNCTION__);
+               return -ENODEV;
+       }
+       snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME);
+
+       for (cmod = 0; cmod < nummodules; cmod++) {
+               m = sn_modules[cmod];
+               for (i = 0; i <= MAX_SLABS; i++) {
+
+                       if (m->nodes[i] == -1) {
+                               /* node is not alive in module */
+                               continue;
+                       }
+
+                       geoid = m->geoid[i];
+                       devnamep = devname;
+                       format_module_id(devnamep, geo_module(geoid),
+                                        MODULE_FORMAT_BRIEF);
+                       devnamep = devname + strlen(devname);
+                       sprintf(devnamep, "#%d", geo_slab(geoid));
+
+                       /* allocate sysctl device data */
+                       scd = kmalloc(sizeof (struct sysctl_data_s),
+                                     GFP_KERNEL);
+                       if (!scd) {
+                               printk("%s: failed to allocate device info"
+                                      "for %s/%s\n", __FUNCTION__,
+                                      SYSCTL_BASENAME, devname);
+                               continue;
+                       }
+                       memset(scd, 0, sizeof (struct sysctl_data_s));
+
+                       /* initialize sysctl device data fields */
+                       scd->scd_nasid = cnodeid_to_nasid(m->nodes[i]);
+                       if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
+                               printk("%s: failed to allocate driver buffer"
+                                      "(%s%s)\n", __FUNCTION__,
+                                      SYSCTL_BASENAME, devname);
+                               kfree(scd);
+                               continue;
+                       }
+
+                       if (ia64_sn_irtr_init(scd->scd_nasid, salbuf,
+                                             SCDRV_BUFSZ) < 0) {
+                               printk
+                                   ("%s: failed to initialize SAL for"
+                                    " system controller communication"
+                                    " (%s/%s): outdated PROM?\n",
+                                    __FUNCTION__, SYSCTL_BASENAME, devname);
+                               kfree(scd);
+                               kfree(salbuf);
+                               continue;
+                       }
+
+                       dev = first_dev + m->nodes[i];
+                       cdev_init(&scd->scd_cdev, &scdrv_fops);
+                       if (cdev_add(&scd->scd_cdev, dev, 1)) {
+                               printk("%s: failed to register system"
+                                      " controller device (%s%s)\n",
+                                      __FUNCTION__, SYSCTL_BASENAME, devname);
+                               kfree(scd);
+                               kfree(salbuf);
+                               continue;
+                       }
+
+                       class_simple_device_add(snsc_class, dev, NULL,
+                                               "%s", devname);
+
+                       ia64_sn_irtr_intr_enable(scd->scd_nasid,
+                                                0 /*ignored */ ,
+                                                SAL_IROUTER_INTR_RECV);
+               }
+       }
+       return 0;
+}
+
+module_init(scdrv_init);
diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h
new file mode 100644 (file)
index 0000000..c22c6c5
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SN Platform system controller communication 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) 2004 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * This file contains macros and data types for communication with the
+ * system controllers in SGI SN systems.
+ */
+
+#ifndef _SN_SYSCTL_H_
+#define _SN_SYSCTL_H_
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/kobject.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <asm/sn/types.h>
+#include <asm/semaphore.h>
+
+#define CHUNKSIZE 127
+
+/* This structure is used to track an open subchannel. */
+struct subch_data_s {
+       nasid_t sd_nasid;       /* node on which the subchannel was opened */
+       int sd_subch;           /* subchannel number */
+       spinlock_t sd_rlock;    /* monitor lock for rsv */
+       spinlock_t sd_wlock;    /* monitor lock for wsv */
+       wait_queue_head_t sd_rq;        /* wait queue for readers */
+       wait_queue_head_t sd_wq;        /* wait queue for writers */
+       struct semaphore sd_rbs;        /* semaphore for read buffer */
+       struct semaphore sd_wbs;        /* semaphore for write buffer */
+
+       char sd_rb[CHUNKSIZE];  /* read buffer */
+       char sd_wb[CHUNKSIZE];  /* write buffer */
+};
+
+struct sysctl_data_s {
+       struct cdev scd_cdev;   /* Character device info */
+       nasid_t scd_nasid;      /* Node on which subchannels are opened. */
+};
+
+#endif /* _SN_SYSCTL_H_ */
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
new file mode 100644 (file)
index 0000000..56d62ba
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
+ *
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/8xx_immap.h>
+#include <asm/uaccess.h>
+#include <syslib/m8xx_wdt.h>
+
+static unsigned long wdt_opened;
+static int wdt_status;
+
+static void mpc8xx_wdt_handler_disable(void)
+{
+       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+       imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+
+       printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
+}
+
+static void mpc8xx_wdt_handler_enable(void)
+{
+       volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+       imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+
+       printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
+}
+
+static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &wdt_opened))
+               return -EBUSY;
+
+       m8xx_wdt_reset();
+       mpc8xx_wdt_handler_disable();
+
+       return 0;
+}
+
+static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
+{
+       m8xx_wdt_reset();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+       mpc8xx_wdt_handler_enable();
+#endif
+
+       clear_bit(0, &wdt_opened);
+
+       return 0;
+}
+
+static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
+                               loff_t * ppos)
+{
+       if (ppos != &file->f_pos)
+               return -ESPIPE;
+
+       if (len)
+               m8xx_wdt_reset();
+
+       return len;
+}
+
+static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       int timeout;
+       static struct watchdog_info info = {
+               .options = WDIOF_KEEPALIVEPING,
+               .firmware_version = 0,
+               .identity = "MPC8xx watchdog",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user((void *)arg, &info, sizeof(info)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               if (put_user(wdt_status, (int *)arg))
+                       return -EFAULT;
+               wdt_status &= ~WDIOF_KEEPALIVEPING;
+               break;
+
+       case WDIOC_GETTEMP:
+               return -EOPNOTSUPP;
+
+       case WDIOC_SETOPTIONS:
+               return -EOPNOTSUPP;
+
+       case WDIOC_KEEPALIVE:
+               m8xx_wdt_reset();
+               wdt_status |= WDIOF_KEEPALIVEPING;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               return -EOPNOTSUPP;
+
+       case WDIOC_GETTIMEOUT:
+               timeout = m8xx_wdt_get_timeout();
+               if (put_user(timeout, (int *)arg))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static struct file_operations mpc8xx_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = mpc8xx_wdt_write,
+       .ioctl = mpc8xx_wdt_ioctl,
+       .open = mpc8xx_wdt_open,
+       .release = mpc8xx_wdt_release,
+};
+
+static struct miscdevice mpc8xx_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &mpc8xx_wdt_fops,
+};
+
+static int __init mpc8xx_wdt_init(void)
+{
+       return misc_register(&mpc8xx_wdt_miscdev);
+}
+
+static void __exit mpc8xx_wdt_exit(void)
+{
+       misc_deregister(&mpc8xx_wdt_miscdev);
+
+       m8xx_wdt_reset();
+       mpc8xx_wdt_handler_enable();
+}
+
+module_init(mpc8xx_wdt_init);
+module_exit(mpc8xx_wdt_exit);
+
+MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
+MODULE_DESCRIPTION("MPC8xx watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
new file mode 100644 (file)
index 0000000..47480f8
--- /dev/null
@@ -0,0 +1,516 @@
+/* linux/drivers/char/watchdog/s3c2410_wdt.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Watchdog Timer Support
+ *
+ * Based on, softdog.c by Alan Cox,
+ *     (c) Copyright 1996 Alan Cox <alan@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.
+ *
+ * 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
+ *
+ * Changelog:
+ *     05-Oct-2004     BJD     Added semaphore init to stop crashes on open
+ *                             Fixed tmr_count / wdt_count confusion
+ *                             Added configurable debug
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <asm/arch/map.h>
+#include <asm/hardware/clock.h>
+
+#undef S3C2410_VA_WATCHDOG
+#define S3C2410_VA_WATCHDOG (0)
+
+#include <asm/arch/regs-watchdog.h>
+
+#define PFX "s3c2410-wdt: "
+
+#define CONFIG_S3C2410_WATCHDOG_ATBOOT         (0)
+#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME   (15)
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+static int tmr_margin  = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
+static int tmr_atboot  = CONFIG_S3C2410_WATCHDOG_ATBOOT;
+static int soft_noboot = 0;
+static int debug       = 0;
+
+module_param(tmr_margin,  int, 0);
+module_param(tmr_atboot,  int, 0);
+module_param(nowayout,    int, 0);
+module_param(soft_noboot, int, 0);
+module_param(debug,      int, 0);
+
+MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
+
+MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
+
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
+
+MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
+
+
+typedef enum close_state {
+       CLOSE_STATE_NOT,
+       CLOSE_STATE_ALLOW=0x4021
+} close_state_t;
+
+static DECLARE_MUTEX(open_lock);
+
+static struct resource *wdt_mem;
+static struct resource *wdt_irq;
+static struct clk      *wdt_clock;
+static void __iomem    *wdt_base;
+static unsigned int     wdt_count;
+static close_state_t    allow_close;
+
+/* watchdog control routines */
+
+#define DBG(msg...) do { \
+       if (debug) \
+               printk(KERN_INFO msg); \
+       } while(0)
+
+/* functions */
+
+static int s3c2410wdt_keepalive(void)
+{
+       writel(wdt_count, wdt_base + S3C2410_WTCNT);
+       return 0;
+}
+
+static int s3c2410wdt_stop(void)
+{
+       unsigned long wtcon;
+
+       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
+       writel(wtcon, wdt_base + S3C2410_WTCON);
+
+       return 0;
+}
+
+static int s3c2410wdt_start(void)
+{
+       unsigned long wtcon;
+
+       s3c2410wdt_stop();
+
+       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
+
+       if (soft_noboot) {
+               wtcon |= S3C2410_WTCON_INTEN;
+               wtcon &= ~S3C2410_WTCON_RSTEN;
+       } else {
+               wtcon &= ~S3C2410_WTCON_INTEN;
+               wtcon |= S3C2410_WTCON_RSTEN;
+       }
+
+       DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
+           __FUNCTION__, wdt_count, wtcon);
+
+       writel(wdt_count, wdt_base + S3C2410_WTDAT);
+       writel(wdt_count, wdt_base + S3C2410_WTCNT);
+       writel(wtcon, wdt_base + S3C2410_WTCON);
+
+       return 0;
+}
+
+static int s3c2410wdt_set_heartbeat(int timeout)
+{
+       unsigned int freq = clk_get_rate(wdt_clock);
+       unsigned int count;
+       unsigned int divisor = 1;
+       unsigned long wtcon;
+
+       if (timeout < 1)
+               return -EINVAL;
+
+       /* I think someone must have missed a divide-by-2 in the 2410,
+        * as a divisor of 128 gives half the calculated delay...
+        */
+
+       freq /= 128/2;
+       count = timeout * freq;
+
+       DBG("%s: count=%d, timeout=%d, freq=%d\n",
+           __FUNCTION__, count, timeout, freq);
+
+       /* if the count is bigger than the watchdog register,
+          then work out what we need to do (and if) we can
+          actually make this value
+       */
+
+       if (count >= 0x10000) {
+               for (divisor = 1; divisor <= 0x100; divisor++) {
+                       if ((count / divisor) < 0x10000)
+                               break;
+               }
+
+               if ((count / divisor) >= 0x10000) {
+                       printk(KERN_ERR PFX "timeout %d too big\n", timeout);
+                       return -EINVAL;
+               }
+       }
+
+       tmr_margin = timeout;
+
+       DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
+           __FUNCTION__, timeout, divisor, count, count/divisor);
+
+       count /= divisor;
+       wdt_count = count;
+
+       /* update the pre-scaler */
+       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
+       wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
+
+       writel(count, wdt_base + S3C2410_WTDAT);
+       writel(wtcon, wdt_base + S3C2410_WTCON);
+
+       return 0;
+}
+
+/*
+ *     /dev/watchdog handling
+ */
+
+static int s3c2410wdt_open(struct inode *inode, struct file *file)
+{
+       if(down_trylock(&open_lock))
+               return -EBUSY;
+
+       if (nowayout) {
+               __module_get(THIS_MODULE);
+       } else {
+               allow_close = CLOSE_STATE_ALLOW;
+       }
+
+       /* start the timer */
+       s3c2410wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+static int s3c2410wdt_release(struct inode *inode, struct file *file)
+{
+       /*
+        *      Shut off the timer.
+        *      Lock it in if it's a module and we set nowayout
+        */
+       if (allow_close == CLOSE_STATE_ALLOW) {
+               s3c2410wdt_stop();
+       } else {
+               printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+               s3c2410wdt_keepalive();
+       }
+
+       allow_close = CLOSE_STATE_NOT;
+       up(&open_lock);
+       return 0;
+}
+
+static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,
+                               size_t len, loff_t *ppos)
+{
+       /*
+        *      Refresh the timer.
+        */
+       if(len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       allow_close = CLOSE_STATE_NOT;
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       allow_close = CLOSE_STATE_ALLOW;
+                       }
+               }
+
+               s3c2410wdt_keepalive();
+       }
+       return len;
+}
+
+#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
+
+static struct watchdog_info s3c2410_wdt_ident = {
+       .options          =     OPTIONS,
+       .firmware_version =     0,
+       .identity         =     "S3C2410 Watchdog",
+};
+
+
+static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
+       unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_margin;
+
+       switch (cmd) {
+               default:
+                       return -ENOIOCTLCMD;
+
+               case WDIOC_GETSUPPORT:
+                       return copy_to_user(argp, &s3c2410_wdt_ident,
+                               sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;
+
+               case WDIOC_GETSTATUS:
+               case WDIOC_GETBOOTSTATUS:
+                       return put_user(0, p);
+
+               case WDIOC_KEEPALIVE:
+                       s3c2410wdt_keepalive();
+                       return 0;
+
+               case WDIOC_SETTIMEOUT:
+                       if (get_user(new_margin, p))
+                               return -EFAULT;
+
+                       if (s3c2410wdt_set_heartbeat(new_margin))
+                               return -EINVAL;
+
+                       s3c2410wdt_keepalive();
+                       return put_user(tmr_margin, p);
+
+               case WDIOC_GETTIMEOUT:
+                       return put_user(tmr_margin, p);
+       }
+}
+
+/*
+ *     Notifier for system down
+ */
+
+static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code,
+                             void *unused)
+{
+       if(code==SYS_DOWN || code==SYS_HALT) {
+               /* Turn the WDT off */
+               s3c2410wdt_stop();
+       }
+       return NOTIFY_DONE;
+}
+
+/* kernel interface */
+
+static struct file_operations s3c2410wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = s3c2410wdt_write,
+       .ioctl          = s3c2410wdt_ioctl,
+       .open           = s3c2410wdt_open,
+       .release        = s3c2410wdt_release,
+};
+
+static struct miscdevice s3c2410wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &s3c2410wdt_fops,
+};
+
+static struct notifier_block s3c2410wdt_notifier = {
+       .notifier_call  = s3c2410wdt_notify_sys,
+};
+
+/* interrupt handler code */
+
+static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
+                                 struct pt_regs *regs)
+{
+       printk(KERN_INFO PFX "Watchdog timer expired!\n");
+
+       s3c2410wdt_keepalive();
+       return IRQ_HANDLED;
+}
+/* device interface */
+
+static int s3c2410wdt_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct resource *res;
+       int started = 0;
+       int ret;
+       int size;
+
+       DBG("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
+
+       /* get the memory region for the watchdog timer */
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               printk(KERN_INFO PFX "failed to get memory region resouce\n");
+               return -ENOENT;
+       }
+
+       size = (res->end-res->start)+1;
+       wdt_mem = request_mem_region(res->start, size, pdev->name);
+       if (wdt_mem == NULL) {
+               printk(KERN_INFO PFX "failed to get memory region\n");
+               return -ENOENT;
+       }
+
+       wdt_base = ioremap(res->start, size);
+       if (wdt_base == 0) {
+               printk(KERN_INFO PFX "failed to ioremap() region\n");
+               return -EINVAL;
+       }
+
+       DBG("probe: mapped wdt_base=%p\n", wdt_base);
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               printk(KERN_INFO PFX "failed to get irq resource\n");
+               return -ENOENT;
+       }
+
+       ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, dev);
+       if (ret != 0) {
+               printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
+               return ret;
+       }
+
+       wdt_clock = clk_get(dev, "watchdog");
+       if (wdt_clock == NULL) {
+               printk(KERN_INFO PFX "failed to find watchdog clock source\n");
+               return -ENOENT;
+       }
+
+       clk_use(wdt_clock);
+       clk_enable(wdt_clock);
+
+       /* see if we can actually set the requested timer margin, and if
+        * not, try the default value */
+
+       if (s3c2410wdt_set_heartbeat(tmr_margin)) {
+               started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
+
+               if (started == 0) {
+                       printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
+                              CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
+               } else {
+                       printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
+               }
+       }
+
+       ret = register_reboot_notifier(&s3c2410wdt_notifier);
+       if (ret) {
+               printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n",
+                       ret);
+               return ret;
+       }
+
+       ret = misc_register(&s3c2410wdt_miscdev);
+       if (ret) {
+               printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
+                       WATCHDOG_MINOR, ret);
+               unregister_reboot_notifier(&s3c2410wdt_notifier);
+               return ret;
+       }
+
+       if (tmr_atboot && started == 0) {
+               printk(KERN_INFO PFX "Starting Watchdog Timer\n");
+               s3c2410wdt_start();
+       }
+
+       return 0;
+}
+
+static int s3c2410wdt_remove(struct device *dev)
+{
+       if (wdt_mem != NULL) {
+               release_resource(wdt_mem);
+               kfree(wdt_mem);
+               wdt_mem = NULL;
+       }
+
+       if (wdt_irq != NULL) {
+               free_irq(wdt_irq->start, dev);
+               wdt_irq = NULL;
+       }
+
+       if (wdt_clock != NULL) {
+               clk_disable(wdt_clock);
+               clk_unuse(wdt_clock);
+               clk_put(wdt_clock);
+               wdt_clock = NULL;
+       }
+
+       misc_deregister(&s3c2410wdt_miscdev);
+       return 0;
+}
+
+static struct device_driver s3c2410wdt_driver = {
+       .name           = "s3c2410-wdt",
+       .bus            = &platform_bus_type,
+       .probe          = s3c2410wdt_probe,
+       .remove         = s3c2410wdt_remove,
+};
+
+
+
+static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
+
+static int __init watchdog_init(void)
+{
+       printk(banner);
+       return driver_register(&s3c2410wdt_driver);
+}
+
+static void __exit watchdog_exit(void)
+{
+       driver_unregister(&s3c2410wdt_driver);
+       unregister_reboot_notifier(&s3c2410wdt_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
new file mode 100644 (file)
index 0000000..a9320ae
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ *  drivers/cpufreq/cpufreq_ondemand.c
+ *
+ *  Copyright (C)  2001 Russell King
+ *            (C)  2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
+ *                      Jun Nakajima <jun.nakajima@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/cpufreq.h>
+#include <linux/sysctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/config.h>
+#include <linux/kernel_stat.h>
+#include <linux/percpu.h>
+
+/*
+ * dbs is used in this file as a shortform for demandbased switching
+ * It helps to keep variable names smaller, simpler
+ */
+
+#define DEF_FREQUENCY_UP_THRESHOLD             (80)
+#define MIN_FREQUENCY_UP_THRESHOLD             (0)
+#define MAX_FREQUENCY_UP_THRESHOLD             (100)
+
+#define DEF_FREQUENCY_DOWN_THRESHOLD           (20)
+#define MIN_FREQUENCY_DOWN_THRESHOLD           (0)
+#define MAX_FREQUENCY_DOWN_THRESHOLD           (100)
+
+/* 
+ * The polling frequency of this governor depends on the capability of 
+ * the processor. Default polling frequency is 1000 times the transition
+ * latency of the processor. The governor will work on any processor with 
+ * transition latency <= 10mS, using appropriate sampling 
+ * rate.
+ * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work.
+ * All times here are in uS.
+ */
+static unsigned int                            def_sampling_rate;
+#define MIN_SAMPLING_RATE                      (def_sampling_rate / 2)
+#define MAX_SAMPLING_RATE                      (500 * def_sampling_rate)
+#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
+#define DEF_SAMPLING_DOWN_FACTOR               (10)
+#define TRANSITION_LATENCY_LIMIT               (10 * 1000)
+#define sampling_rate_in_HZ(x)                 (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000)))
+
+static void do_dbs_timer(void *data);
+
+struct cpu_dbs_info_s {
+       struct cpufreq_policy   *cur_policy;
+       unsigned int            prev_cpu_idle_up;
+       unsigned int            prev_cpu_idle_down;
+       unsigned int            enable;
+};
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+
+static unsigned int dbs_enable;        /* number of CPUs using this policy */
+
+static DECLARE_MUTEX   (dbs_sem);
+static DECLARE_WORK    (dbs_work, do_dbs_timer, NULL);
+
+struct dbs_tuners {
+       unsigned int            sampling_rate;
+       unsigned int            sampling_down_factor;
+       unsigned int            up_threshold;
+       unsigned int            down_threshold;
+};
+
+struct dbs_tuners dbs_tuners_ins = {
+       .up_threshold           = DEF_FREQUENCY_UP_THRESHOLD,
+       .down_threshold         = DEF_FREQUENCY_DOWN_THRESHOLD,
+       .sampling_down_factor   = DEF_SAMPLING_DOWN_FACTOR,
+};
+
+/************************** sysfs interface ************************/
+static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+{
+       return sprintf (buf, "%u\n", MAX_SAMPLING_RATE);
+}
+
+static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
+{
+       return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
+}
+
+#define define_one_ro(_name)                                   \
+static struct freq_attr _name = {                              \
+       .attr = { .name = __stringify(_name), .mode = 0444 },   \
+       .show = show_##_name,                                   \
+}
+
+define_one_ro(sampling_rate_max);
+define_one_ro(sampling_rate_min);
+
+/* cpufreq_ondemand Governor Tunables */
+#define show_one(file_name, object)                                    \
+static ssize_t show_##file_name                                                \
+(struct cpufreq_policy *unused, char *buf)                             \
+{                                                                      \
+       return sprintf(buf, "%u\n", dbs_tuners_ins.object);             \
+}
+show_one(sampling_rate, sampling_rate);
+show_one(sampling_down_factor, sampling_down_factor);
+show_one(up_threshold, up_threshold);
+show_one(down_threshold, down_threshold);
+
+static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, 
+               const char *buf, size_t count)
+{
+       unsigned int input;
+       int ret;
+       ret = sscanf (buf, "%u", &input);
+       down(&dbs_sem);
+       if (ret != 1 )
+               goto out;
+
+       dbs_tuners_ins.sampling_down_factor = input;
+out:
+       up(&dbs_sem);
+       return count;
+}
+
+static ssize_t store_sampling_rate(struct cpufreq_policy *unused, 
+               const char *buf, size_t count)
+{
+       unsigned int input;
+       int ret;
+       ret = sscanf (buf, "%u", &input);
+       down(&dbs_sem);
+       if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE)
+               goto out;
+
+       dbs_tuners_ins.sampling_rate = input;
+out:
+       up(&dbs_sem);
+       return count;
+}
+
+static ssize_t store_up_threshold(struct cpufreq_policy *unused, 
+               const char *buf, size_t count)
+{
+       unsigned int input;
+       int ret;
+       ret = sscanf (buf, "%u", &input);
+       down(&dbs_sem);
+       if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || 
+                       input < MIN_FREQUENCY_UP_THRESHOLD ||
+                       input <= dbs_tuners_ins.down_threshold)
+               goto out;
+
+       dbs_tuners_ins.up_threshold = input;
+out:
+       up(&dbs_sem);
+       return count;
+}
+
+static ssize_t store_down_threshold(struct cpufreq_policy *unused, 
+               const char *buf, size_t count)
+{
+       unsigned int input;
+       int ret;
+       ret = sscanf (buf, "%u", &input);
+       down(&dbs_sem);
+       if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || 
+                       input < MIN_FREQUENCY_DOWN_THRESHOLD ||
+                       input >= dbs_tuners_ins.up_threshold)
+               goto out;
+
+       dbs_tuners_ins.down_threshold = input;
+out:
+       up(&dbs_sem);
+       return count;
+}
+
+#define define_one_rw(_name)                                   \
+static struct freq_attr _name = {                              \
+       .attr = { .name = __stringify(_name), .mode = 0644 },   \
+       .show = show_##_name,                                   \
+       .store = store_##_name,                                 \
+}
+
+define_one_rw(sampling_rate);
+define_one_rw(sampling_down_factor);
+define_one_rw(up_threshold);
+define_one_rw(down_threshold);
+
+static struct attribute * dbs_attributes[] = {
+       &sampling_rate_max.attr,
+       &sampling_rate_min.attr,
+       &sampling_rate.attr,
+       &sampling_down_factor.attr,
+       &up_threshold.attr,
+       &down_threshold.attr,
+       NULL
+};
+
+static struct attribute_group dbs_attr_group = {
+       .attrs = dbs_attributes,
+       .name = "ondemand",
+};
+
+/************************** sysfs end ************************/
+
+static void dbs_check_cpu(int cpu)
+{
+       unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
+       unsigned int total_idle_ticks;
+       unsigned int freq_down_step;
+       unsigned int freq_down_sampling_rate;
+       static int down_skip[NR_CPUS];
+       struct cpu_dbs_info_s *this_dbs_info;
+
+       this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+       if (!this_dbs_info->enable)
+               return;
+
+       /* 
+        * The default safe range is 20% to 80% 
+        * Every sampling_rate, we check
+        *      - If current idle time is less than 20%, then we try to 
+        *        increase frequency
+        * Every sampling_rate*sampling_down_factor, we check
+        *      - If current idle time is more than 80%, then we try to
+        *        decrease frequency
+        *
+        * Any frequency increase takes it to the maximum frequency. 
+        * Frequency reduction happens at minimum steps of 
+        * 5% of max_frequency 
+        */
+       /* Check for frequency increase */
+       total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
+               kstat_cpu(cpu).cpustat.iowait;
+       idle_ticks = total_idle_ticks -
+               this_dbs_info->prev_cpu_idle_up;
+       this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+
+       /* Scale idle ticks by 100 and compare with up and down ticks */
+       idle_ticks *= 100;
+       up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
+                       sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
+
+       if (idle_ticks < up_idle_ticks) {
+               __cpufreq_driver_target(this_dbs_info->cur_policy,
+                       this_dbs_info->cur_policy->max, 
+                       CPUFREQ_RELATION_H);
+               down_skip[cpu] = 0;
+               this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+               return;
+       }
+
+       /* Check for frequency decrease */
+       down_skip[cpu]++;
+       if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
+               return;
+
+       idle_ticks = total_idle_ticks -
+               this_dbs_info->prev_cpu_idle_down;
+       /* Scale idle ticks by 100 and compare with up and down ticks */
+       idle_ticks *= 100;
+       down_skip[cpu] = 0;
+       this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+
+       freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
+               dbs_tuners_ins.sampling_down_factor;
+       down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
+                       sampling_rate_in_HZ(freq_down_sampling_rate);
+
+       if (idle_ticks > down_idle_ticks ) {
+               freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100;
+
+               /* max freq cannot be less than 100. But who knows.... */
+               if (unlikely(freq_down_step == 0))
+                       freq_down_step = 5;
+
+               __cpufreq_driver_target(this_dbs_info->cur_policy,
+                       this_dbs_info->cur_policy->cur - freq_down_step, 
+                       CPUFREQ_RELATION_H);
+               return;
+       }
+}
+
+static void do_dbs_timer(void *data)
+{ 
+       int i;
+       down(&dbs_sem);
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_online(i))
+                       dbs_check_cpu(i);
+       schedule_delayed_work(&dbs_work, 
+                       sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+       up(&dbs_sem);
+} 
+
+static inline void dbs_timer_init(void)
+{
+       INIT_WORK(&dbs_work, do_dbs_timer, NULL);
+       schedule_work(&dbs_work);
+       return;
+}
+
+static inline void dbs_timer_exit(void)
+{
+       cancel_delayed_work(&dbs_work);
+       return;
+}
+
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+                                  unsigned int event)
+{
+       unsigned int cpu = policy->cpu;
+       struct cpu_dbs_info_s *this_dbs_info;
+
+       this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+       switch (event) {
+       case CPUFREQ_GOV_START:
+               if ((!cpu_online(cpu)) || 
+                   (!policy->cur))
+                       return -EINVAL;
+
+               if (policy->cpuinfo.transition_latency >
+                               (TRANSITION_LATENCY_LIMIT * 1000))
+                       return -EINVAL;
+               if (this_dbs_info->enable) /* Already enabled */
+                       break;
+                
+               down(&dbs_sem);
+               this_dbs_info->cur_policy = policy;
+               
+               this_dbs_info->prev_cpu_idle_up = 
+                               kstat_cpu(cpu).cpustat.idle +
+                               kstat_cpu(cpu).cpustat.iowait;
+               this_dbs_info->prev_cpu_idle_down = 
+                               kstat_cpu(cpu).cpustat.idle +
+                               kstat_cpu(cpu).cpustat.iowait;
+               this_dbs_info->enable = 1;
+               sysfs_create_group(&policy->kobj, &dbs_attr_group);
+               dbs_enable++;
+               /*
+                * Start the timerschedule work, when this governor
+                * is used for first time
+                */
+               if (dbs_enable == 1) {
+                       unsigned int latency;
+                       /* policy latency is in nS. Convert it to uS first */
+
+                       latency = policy->cpuinfo.transition_latency;
+                       if (latency < 1000)
+                               latency = 1000;
+
+                       def_sampling_rate = (latency / 1000) *
+                                       DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
+                       dbs_tuners_ins.sampling_rate = def_sampling_rate;
+
+                       dbs_timer_init();
+               }
+               
+               up(&dbs_sem);
+               break;
+
+       case CPUFREQ_GOV_STOP:
+               down(&dbs_sem);
+               this_dbs_info->enable = 0;
+               sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+               dbs_enable--;
+               /*
+                * Stop the timerschedule work, when this governor
+                * is used for first time
+                */
+               if (dbs_enable == 0) 
+                       dbs_timer_exit();
+               
+               up(&dbs_sem);
+
+               break;
+
+       case CPUFREQ_GOV_LIMITS:
+               down(&dbs_sem);
+               if (policy->max < this_dbs_info->cur_policy->cur)
+                       __cpufreq_driver_target(
+                                       this_dbs_info->cur_policy,
+                                       policy->max, CPUFREQ_RELATION_H);
+               else if (policy->min > this_dbs_info->cur_policy->cur)
+                       __cpufreq_driver_target(
+                                       this_dbs_info->cur_policy,
+                                       policy->min, CPUFREQ_RELATION_L);
+               up(&dbs_sem);
+               break;
+       }
+       return 0;
+}
+
+struct cpufreq_governor cpufreq_gov_dbs = {
+       .name           = "ondemand",
+       .governor       = cpufreq_governor_dbs,
+       .owner          = THIS_MODULE,
+};
+EXPORT_SYMBOL(cpufreq_gov_dbs);
+
+static int __init cpufreq_gov_dbs_init(void)
+{
+       return cpufreq_register_governor(&cpufreq_gov_dbs);
+}
+
+static void __exit cpufreq_gov_dbs_exit(void)
+{
+       /* Make sure that the scheduled work is indeed not running */
+       flush_scheduled_work();
+
+       cpufreq_unregister_governor(&cpufreq_gov_dbs);
+}
+
+
+MODULE_AUTHOR ("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
+MODULE_DESCRIPTION ("'cpufreq_ondemand' - A dynamic cpufreq governor for "
+               "Low Latency Frequency Transition capable processors");
+MODULE_LICENSE ("GPL");
+
+module_init(cpufreq_gov_dbs_init);
+module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/dio/dio-driver.c b/drivers/dio/dio-driver.c
new file mode 100644 (file)
index 0000000..ffe6f44
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ *  DIO Driver Services
+ *
+ *  Copyright (C) 2004 Jochen Friedrich
+ *
+ *  Loosely based on drivers/pci/pci-driver.c and drivers/zorro/zorro-driver.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/dio.h>
+
+
+       /**
+        *  dio_match_device - Tell if a DIO device structure has a matching
+        *                     DIO device id structure
+        *  @ids: array of DIO device id structures to search in
+        *  @dev: the DIO device structure to match against
+        *
+        *  Used by a driver to check whether a DIO device present in the
+        *  system is in its list of supported devices. Returns the matching
+        *  dio_device_id structure or %NULL if there is no match.
+        */
+
+const struct dio_device_id *
+dio_match_device(const struct dio_device_id *ids,
+                  const struct dio_dev *d)
+{
+       while (ids->id) {
+               if (ids->id == DIO_WILDCARD)
+                       return ids;
+               if (DIO_NEEDSSECID(ids->id & 0xff)) {
+                       if (ids->id == d->id)
+                               return ids;
+               } else {
+                       if ((ids->id & 0xff) == (d->id & 0xff))
+                               return ids;
+               }
+               ids++;
+       }
+       return NULL;
+}
+
+static int dio_device_probe(struct device *dev)
+{
+       int error = 0;
+       struct dio_driver *drv = to_dio_driver(dev->driver);
+       struct dio_dev *d = to_dio_dev(dev);
+
+       if (!d->driver && drv->probe) {
+               const struct dio_device_id *id;
+
+               id = dio_match_device(drv->id_table, d);
+               if (id)
+                       error = drv->probe(d, id);
+               if (error >= 0) {
+                       d->driver = drv;
+                       error = 0;
+               }
+       }
+       return error;
+}
+
+
+       /**
+        *  dio_register_driver - register a new DIO driver
+        *  @drv: the driver structure to register
+        *
+        *  Adds the driver structure to the list of registered drivers
+        *  Returns the number of DIO devices which were claimed by the driver
+        *  during registration.  The driver remains registered even if the
+        *  return value is zero.
+        */
+
+int dio_register_driver(struct dio_driver *drv)
+{
+       int count = 0;
+
+       /* initialize common driver fields */
+       drv->driver.name = drv->name;
+       drv->driver.bus = &dio_bus_type;
+       drv->driver.probe = dio_device_probe;
+
+       /* register with core */
+       count = driver_register(&drv->driver);
+       return count ? count : 1;
+}
+
+
+       /**
+        *  dio_unregister_driver - unregister a DIO driver
+        *  @drv: the driver structure to unregister
+        *
+        *  Deletes the driver structure from the list of registered DIO drivers,
+        *  gives it a chance to clean up by calling its remove() function for
+        *  each device it was responsible for, and marks those devices as
+        *  driverless.
+        */
+
+void dio_unregister_driver(struct dio_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+
+
+       /**
+        *  dio_bus_match - Tell if a DIO device structure has a matching DIO
+        *                  device id structure
+        *  @ids: array of DIO device id structures to search in
+        *  @dev: the DIO device structure to match against
+        *
+        *  Used by a driver to check whether a DIO device present in the
+        *  system is in its list of supported devices. Returns the matching
+        *  dio_device_id structure or %NULL if there is no match.
+        */
+
+static int dio_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct dio_dev *d = to_dio_dev(dev);
+       struct dio_driver *dio_drv = to_dio_driver(drv);
+       const struct dio_device_id *ids = dio_drv->id_table;
+
+       if (!ids)
+               return 0;
+
+       while (ids->id) {
+               if (ids->id == DIO_WILDCARD)
+                       return 1;
+               if (DIO_NEEDSSECID(ids->id & 0xff)) {
+                       if (ids->id == d->id)
+                               return 1;
+               } else {
+                       if ((ids->id & 0xff) == (d->id & 0xff))
+                               return 1;
+               }
+               ids++;
+       }
+       return 0;
+}
+
+
+struct bus_type dio_bus_type = {
+       .name   = "dio",
+       .match  = dio_bus_match
+};
+
+
+static int __init dio_driver_init(void)
+{
+       return bus_register(&dio_bus_type);
+}
+
+postcore_initcall(dio_driver_init);
+
+EXPORT_SYMBOL(dio_match_device);
+EXPORT_SYMBOL(dio_register_driver);
+EXPORT_SYMBOL(dio_unregister_driver);
+EXPORT_SYMBOL(dio_dev_driver);
+EXPORT_SYMBOL(dio_bus_type);
diff --git a/drivers/dio/dio-sysfs.c b/drivers/dio/dio-sysfs.c
new file mode 100644 (file)
index 0000000..d30591f
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  File Attributes for DIO Devices
+ *
+ *  Copyright (C) 2004 Jochen Friedrich
+ *
+ *  Loosely based on drivers/pci/pci-sysfs.c and drivers/zorro/zorro-sysfs.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.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/dio.h>
+#include <linux/stat.h>
+
+/* show configuration fields */
+
+static ssize_t dio_show_id(struct device *dev, char *buf)
+{
+       struct dio_dev *d;
+
+       d = to_dio_dev(dev);
+       return sprintf(buf, "0x%02x\n", (d->id & 0xff));
+}
+static DEVICE_ATTR(id, S_IRUGO, dio_show_id, NULL);
+
+static ssize_t dio_show_ipl(struct device *dev, char *buf)
+{
+       struct dio_dev *d;
+
+       d = to_dio_dev(dev);
+       return sprintf(buf, "0x%02x\n", d->ipl);
+}
+static DEVICE_ATTR(ipl, S_IRUGO, dio_show_ipl, NULL);
+
+static ssize_t dio_show_secid(struct device *dev, char *buf)
+{
+       struct dio_dev *d;
+
+       d = to_dio_dev(dev);
+       return sprintf(buf, "0x%02x\n", ((d->id >> 8)& 0xff));
+}
+static DEVICE_ATTR(secid, S_IRUGO, dio_show_secid, NULL);
+
+static ssize_t dio_show_name(struct device *dev, char *buf)
+{
+       struct dio_dev *d;
+
+       d = to_dio_dev(dev);
+       return sprintf(buf, "%s\n", d->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, dio_show_name, NULL);
+
+static ssize_t dio_show_resource(struct device *dev, char *buf)
+{
+       struct dio_dev *d = to_dio_dev(dev);
+
+       return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
+                      dio_resource_start(d), dio_resource_end(d),
+                      dio_resource_flags(d));
+}
+static DEVICE_ATTR(resource, S_IRUGO, dio_show_resource, NULL);
+
+void dio_create_sysfs_dev_files(struct dio_dev *d)
+{
+       struct device *dev = &d->dev;
+
+       /* current configuration's attributes */
+       device_create_file(dev, &dev_attr_id);
+       device_create_file(dev, &dev_attr_ipl);
+       device_create_file(dev, &dev_attr_secid);
+       device_create_file(dev, &dev_attr_name);
+       device_create_file(dev, &dev_attr_resource);
+}
+
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
new file mode 100644 (file)
index 0000000..38092b7
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ *  i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters                
+ *    Copyright (C) 2004 Arcom Control Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+#include "i2c-algo-pca.h"
+
+#define DRIVER "i2c-algo-pca"
+
+#define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0)
+#define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0)
+#define DEB3(fmt, args...) do { if (i2c_debug>=3) printk(fmt, ## args); } while(0)
+
+static int i2c_debug=0;
+
+#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val)
+#define pca_inw(adap, reg) adap->read_byte(adap, reg)
+
+#define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
+#define pca_clock(adap) adap->get_clock(adap)
+#define pca_own(adap) adap->get_own(adap)
+#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
+#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
+#define pca_wait(adap) adap->wait_for_interrupt(adap)
+
+/*
+ * Generate a start condition on the i2c bus.
+ *
+ * returns after the start condition has occured
+ */
+static void pca_start(struct i2c_algo_pca_data *adap)
+{
+       int sta = pca_get_con(adap);
+       DEB2("=== START\n");
+       sta |= I2C_PCA_CON_STA;
+       sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+       pca_set_con(adap, sta);
+       pca_wait(adap);
+}
+
+/*
+ * Generate a repeated start condition on the i2c bus 
+ *
+ * return after the repeated start condition has occured
+ */
+static void pca_repeated_start(struct i2c_algo_pca_data *adap)
+{
+       int sta = pca_get_con(adap);
+       DEB2("=== REPEATED START\n");
+       sta |= I2C_PCA_CON_STA;
+       sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+       pca_set_con(adap, sta);
+       pca_wait(adap);
+}
+
+/*
+ * Generate a stop condition on the i2c bus
+ *
+ * returns after the stop condition has been generated
+ *
+ * STOPs do not generate an interrupt or set the SI flag, since the
+ * part returns the the idle state (0xf8). Hence we don't need to
+ * pca_wait here.
+ */
+static void pca_stop(struct i2c_algo_pca_data *adap)
+{
+       int sta = pca_get_con(adap);
+       DEB2("=== STOP\n");
+       sta |= I2C_PCA_CON_STO;
+       sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+       pca_set_con(adap, sta);
+}
+
+/*
+ * Send the slave address and R/W bit
+ *
+ * returns after the address has been sent
+ */
+static void pca_address(struct i2c_algo_pca_data *adap, 
+                       struct i2c_msg *msg)
+{
+       int sta = pca_get_con(adap);
+       int addr;
+
+       addr = ( (0x7f & msg->addr) << 1 );
+       if (msg->flags & I2C_M_RD )
+               addr |= 1;
+       DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n", 
+            msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
+       
+       pca_outw(adap, I2C_PCA_DAT, addr);
+
+       sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+       pca_set_con(adap, sta);
+
+       pca_wait(adap);
+}
+
+/*
+ * Transmit a byte.
+ *
+ * Returns after the byte has been transmitted
+ */
+static void pca_tx_byte(struct i2c_algo_pca_data *adap, 
+                       __u8 b)
+{
+       int sta = pca_get_con(adap);
+       DEB2("=== WRITE %#04x\n", b);
+       pca_outw(adap, I2C_PCA_DAT, b);
+
+       sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+       pca_set_con(adap, sta);
+
+       pca_wait(adap);
+}
+
+/*
+ * Receive a byte
+ *
+ * returns immediately.
+ */
+static void pca_rx_byte(struct i2c_algo_pca_data *adap, 
+                       __u8 *b, int ack)
+{
+       *b = pca_inw(adap, I2C_PCA_DAT);
+       DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
+}
+
+/* 
+ * Setup ACK or NACK for next received byte and wait for it to arrive.
+ *
+ * Returns after next byte has arrived.
+ */
+static void pca_rx_ack(struct i2c_algo_pca_data *adap, 
+                      int ack)
+{
+       int sta = pca_get_con(adap);
+
+       sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA);
+
+       if ( ack )
+               sta |= I2C_PCA_CON_AA;
+
+       pca_set_con(adap, sta);
+       pca_wait(adap);
+}
+
+/* 
+ * Reset the i2c bus / SIO 
+ */
+static void pca_reset(struct i2c_algo_pca_data *adap)
+{
+       /* apparently only an external reset will do it. not a lot can be done */
+       printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n");
+}
+
+static int pca_xfer(struct i2c_adapter *i2c_adap,
+                    struct i2c_msg msgs[],
+                    int num)
+{
+        struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
+        struct i2c_msg *msg = NULL;
+        int curmsg;
+       int numbytes = 0;
+       int state;
+
+       state = pca_status(adap);
+       if ( state != 0xF8 ) {
+               printk(KERN_ERR DRIVER ": bus is not idle. status is %#04x\n", state );
+               /* FIXME: what to do. Force stop ? */
+               return -EREMOTEIO;
+       }
+
+       DEB1("{{{ XFER %d messages\n", num);
+
+       if (i2c_debug>=2) {
+               for (curmsg = 0; curmsg < num; curmsg++) {
+                       int addr, i;
+                       msg = &msgs[curmsg];
+                       
+                       addr = (0x7f & msg->addr) ;
+               
+                       if (msg->flags & I2C_M_RD )
+                               printk(KERN_INFO "    [%02d] RD %d bytes from %#02x [%#02x, ...]\n", 
+                                      curmsg, msg->len, addr, (addr<<1) | 1);
+                       else {
+                               printk(KERN_INFO "    [%02d] WR %d bytes to %#02x [%#02x%s", 
+                                      curmsg, msg->len, addr, addr<<1,
+                                      msg->len == 0 ? "" : ", ");
+                               for(i=0; i < msg->len; i++)
+                                       printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", ");
+                               printk("]\n");
+                       }
+               }
+       }
+
+       curmsg = 0;
+       while (curmsg < num) {
+               state = pca_status(adap);
+
+               DEB3("STATE is 0x%02x\n", state);
+               msg = &msgs[curmsg];
+
+               switch (state) {
+               case 0xf8: /* On reset or stop the bus is idle */
+                       pca_start(adap);
+                       break;
+
+               case 0x08: /* A START condition has been transmitted */
+               case 0x10: /* A repeated start condition has been transmitted */
+                       pca_address(adap, msg);
+                       break;
+                       
+               case 0x18: /* SLA+W has been transmitted; ACK has been received */
+               case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
+                       if (numbytes < msg->len) {
+                               pca_tx_byte(adap, msg->buf[numbytes]);
+                               numbytes++;
+                               break;
+                       }
+                       curmsg++; numbytes = 0;
+                       if (curmsg == num)
+                               pca_stop(adap);
+                       else
+                               pca_repeated_start(adap);
+                       break;
+
+               case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
+                       DEB2("NOT ACK recieved after SLA+W\n");
+                       pca_stop(adap);
+                       return -EREMOTEIO;
+
+               case 0x40: /* SLA+R has been transmitted; ACK has been received */
+                       pca_rx_ack(adap, msg->len > 1);
+                       break;
+
+               case 0x50: /* Data bytes has been received; ACK has been returned */
+                       if (numbytes < msg->len) {
+                               pca_rx_byte(adap, &msg->buf[numbytes], 1);
+                               numbytes++;
+                               pca_rx_ack(adap, numbytes < msg->len - 1);
+                               break;
+                       } 
+                       curmsg++; numbytes = 0;
+                       if (curmsg == num)
+                               pca_stop(adap);
+                       else
+                               pca_repeated_start(adap);
+                       break;
+
+               case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
+                       DEB2("NOT ACK received after SLA+R\n");
+                       pca_stop(adap);
+                       return -EREMOTEIO;
+
+               case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
+                       DEB2("NOT ACK recieved after data byte\n");
+                       return -EREMOTEIO;
+
+               case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
+                       DEB2("Arbitration lost\n");
+                       return -EREMOTEIO;
+                       
+               case 0x58: /* Data byte has been received; NOT ACK has been returned */
+                       if ( numbytes == msg->len - 1 ) {
+                               pca_rx_byte(adap, &msg->buf[numbytes], 0);
+                               curmsg++; numbytes = 0;
+                               if (curmsg == num)
+                                       pca_stop(adap);
+                               else
+                                       pca_repeated_start(adap);
+                       } else {
+                               DEB2("NOT ACK sent after data byte received. "
+                                    "Not final byte. numbytes %d. len %d\n",
+                                    numbytes, msg->len);
+                               pca_stop(adap);
+                               return -EREMOTEIO;
+                       }
+                       break;
+               case 0x70: /* Bus error - SDA stuck low */
+                       DEB2("BUS ERROR - SDA Stuck low\n");
+                       pca_reset(adap);
+                       return -EREMOTEIO;
+               case 0x90: /* Bus error - SCL stuck low */
+                       DEB2("BUS ERROR - SCL Stuck low\n");
+                       pca_reset(adap);
+                       return -EREMOTEIO;
+               case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
+                       DEB2("BUS ERROR - Illegal START or STOP\n");
+                       pca_reset(adap);
+                       return -EREMOTEIO;
+               default:
+                       printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state);
+                       break;
+               }
+               
+       }
+
+       DEB1(KERN_CRIT "}}} transfered %d messages. "
+            "status is %#04x. control is %#04x\n", 
+            num, pca_status(adap),
+            pca_get_con(adap));
+       return curmsg;
+}
+
+static u32 pca_func(struct i2c_adapter *adap)
+{
+        return I2C_FUNC_SMBUS_EMUL;
+}
+
+static int pca_init(struct i2c_algo_pca_data *adap)
+{
+       static int freqs[] = {330,288,217,146,88,59,44,36};
+       int own, clock;
+
+       own = pca_own(adap);
+       clock = pca_clock(adap);
+       DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own);
+       DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]);
+
+       pca_outw(adap, I2C_PCA_ADR, own << 1);
+
+       pca_set_con(adap, I2C_PCA_CON_ENSIO | clock);
+       udelay(500); /* 500 Âµs for oscilator to stabilise */
+
+       return 0;
+}
+
+static struct i2c_algorithm pca_algo = {
+       .name           = "PCA9564 algorithm",
+       .id             = I2C_ALGO_PCA,
+       .master_xfer    = pca_xfer,
+       .functionality  = pca_func,
+};
+
+/* 
+ * registering functions to load algorithms at runtime 
+ */
+int i2c_pca_add_bus(struct i2c_adapter *adap)
+{
+       struct i2c_algo_pca_data *pca_adap = adap->algo_data;
+       int rval;
+
+       /* register new adapter to i2c module... */
+
+       adap->id |= pca_algo.id;
+       adap->algo = &pca_algo;
+
+       adap->timeout = 100;            /* default values, should       */
+       adap->retries = 3;              /* be replaced by defines       */
+
+       rval = pca_init(pca_adap);
+
+       if (!rval)
+               i2c_add_adapter(adap);
+
+       return rval;
+}
+
+int i2c_pca_del_bus(struct i2c_adapter *adap)
+{
+       return i2c_del_adapter(adap);
+}
+
+EXPORT_SYMBOL(i2c_pca_add_bus);
+EXPORT_SYMBOL(i2c_pca_del_bus);
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, 0);
diff --git a/drivers/i2c/algos/i2c-algo-pca.h b/drivers/i2c/algos/i2c-algo-pca.h
new file mode 100644 (file)
index 0000000..2fee07e
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef I2C_PCA9564_H
+#define I2C_PCA9564_H 1
+
+#define I2C_PCA_STA            0x00 /* STATUS  Read Only  */
+#define I2C_PCA_TO             0x00 /* TIMEOUT Write Only */
+#define I2C_PCA_DAT            0x01 /* DATA    Read/Write */
+#define I2C_PCA_ADR            0x02 /* OWN ADR Read/Write */
+#define I2C_PCA_CON            0x03 /* CONTROL Read/Write */
+
+#define I2C_PCA_CON_AA         0x80 /* Assert Acknowledge */
+#define I2C_PCA_CON_ENSIO      0x40 /* Enable */
+#define I2C_PCA_CON_STA                0x20 /* Start */
+#define I2C_PCA_CON_STO                0x10 /* Stop */
+#define I2C_PCA_CON_SI         0x08 /* Serial Interrupt */
+#define I2C_PCA_CON_CR         0x07 /* Clock Rate (MASK) */
+
+#define I2C_PCA_CON_330kHz     0x00
+#define I2C_PCA_CON_288kHz     0x01
+#define I2C_PCA_CON_217kHz     0x02
+#define I2C_PCA_CON_146kHz     0x03
+#define I2C_PCA_CON_88kHz      0x04
+#define I2C_PCA_CON_59kHz      0x05
+#define I2C_PCA_CON_44kHz      0x06
+#define I2C_PCA_CON_36kHz      0x07
+
+#endif /* I2C_PCA9564_H */
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
new file mode 100644 (file)
index 0000000..4e553e8
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
+ *
+ * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4, and 0x4c (LM63)
+ * located on multiplexed channels 0 and 5-7. We define one
+ * virtual adapter per CPU, which corresponds to two multiplexed
+ * channels:
+ *   CPU0: virtual adapter 1, channels 1 and 0
+ *   CPU1: virtual adapter 2, channels 2 and 5
+ *   CPU2: virtual adapter 3, channels 3 and 6
+ *   CPU3: virtual adapter 4, channels 4 and 7
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+extern struct i2c_adapter amd756_smbus;
+
+static struct i2c_adapter *s4882_adapter;
+static struct i2c_algorithm *s4882_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static struct semaphore amd756_lock;
+
+static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
+                              unsigned short flags, char read_write,
+                              u8 command, int size,
+                              union i2c_smbus_data * data)
+{
+       int error;
+
+       /* We exclude the multiplexed addresses */
+       if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+        || addr == 0x18)
+               return -1;
+
+       down(&amd756_lock);
+
+       error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+                                             command, size, data);
+
+       up(&amd756_lock);
+
+       return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+   channels when it is really needed. This greatly reduces the SMBus
+   overhead, but also assumes that nobody will be writing to the PCA9556
+   in our back. */
+static u8 last_channels;
+
+static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
+                                       unsigned short flags, char read_write,
+                                       u8 command, int size,
+                                       union i2c_smbus_data * data,
+                                       u8 channels)
+{
+       int error;
+
+       /* We exclude the non-multiplexed addresses */
+       if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+               return -1;
+
+       down(&amd756_lock);
+
+       if (last_channels != channels) {
+               union i2c_smbus_data mplxdata;
+               mplxdata.byte = channels;
+
+               error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
+                                                     I2C_SMBUS_WRITE, 0x01,
+                                                     I2C_SMBUS_BYTE_DATA,
+                                                     &mplxdata);
+               if (error)
+                       goto UNLOCK;
+               last_channels = channels;
+       }
+       error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+                                             command, size, data);
+
+UNLOCK:
+       up(&amd756_lock);
+       return error;
+}
+
+static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
+                              unsigned short flags, char read_write,
+                              u8 command, int size,
+                              union i2c_smbus_data * data)
+{
+       /* CPU0: channels 1 and 0 enabled */
+       return amd756_access_channel(adap, addr, flags, read_write, command,
+                                    size, data, 0x03);
+}
+
+static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
+                              unsigned short flags, char read_write,
+                              u8 command, int size,
+                              union i2c_smbus_data * data)
+{
+       /* CPU1: channels 2 and 5 enabled */
+       return amd756_access_channel(adap, addr, flags, read_write, command,
+                                    size, data, 0x24);
+}
+
+static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
+                              unsigned short flags, char read_write,
+                              u8 command, int size,
+                              union i2c_smbus_data * data)
+{
+       /* CPU2: channels 3 and 6 enabled */
+       return amd756_access_channel(adap, addr, flags, read_write, command,
+                                    size, data, 0x48);
+}
+
+static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
+                              unsigned short flags, char read_write,
+                              u8 command, int size,
+                              union i2c_smbus_data * data)
+{
+       /* CPU3: channels 4 and 7 enabled */
+       return amd756_access_channel(adap, addr, flags, read_write, command,
+                                    size, data, 0x90);
+}
+
+static int __init amd756_s4882_init(void)
+{
+       int i, error;
+       union i2c_smbus_data ioconfig;
+
+       /* Unregister physical bus */
+       error = i2c_del_adapter(&amd756_smbus);
+       if (error) {
+               if (error == -EINVAL)
+                       error = -ENODEV;
+               else
+                       dev_err(&amd756_smbus.dev, "Physical bus removal "
+                               "failed\n");
+               goto ERROR0;
+       }
+
+       printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
+       init_MUTEX(&amd756_lock);
+
+       /* Define the 5 virtual adapters and algorithms structures */
+       if (!(s4882_adapter = kmalloc(5 * sizeof(struct i2c_adapter),
+                                     GFP_KERNEL))) {
+               error = -ENOMEM;
+               goto ERROR1;
+       }
+       if (!(s4882_algo = kmalloc(5 * sizeof(struct i2c_algorithm),
+                                  GFP_KERNEL))) {
+               error = -ENOMEM;
+               goto ERROR2;
+       }
+
+       /* Fill in the new structures */
+       s4882_algo[0] = *(amd756_smbus.algo);
+       s4882_algo[0].smbus_xfer = amd756_access_virt0;
+       s4882_adapter[0] = amd756_smbus;
+       s4882_adapter[0].algo = s4882_algo;
+       for (i = 1; i < 5; i++) {
+               s4882_algo[i] = *(amd756_smbus.algo);
+               s4882_adapter[i] = amd756_smbus;
+               sprintf(s4882_adapter[i].name,
+                       "SMBus 8111 adapter (CPU%d)", i-1);
+               s4882_adapter[i].algo = s4882_algo+i;
+       }
+       s4882_algo[1].smbus_xfer = amd756_access_virt1;
+       s4882_algo[2].smbus_xfer = amd756_access_virt2;
+       s4882_algo[3].smbus_xfer = amd756_access_virt3;
+       s4882_algo[4].smbus_xfer = amd756_access_virt4;
+
+       /* Configure the PCA9556 multiplexer */
+       ioconfig.byte = 0x00; /* All I/O to output mode */
+       error = amd756_smbus.algo->smbus_xfer(&amd756_smbus, 0x18, 0,
+                                             I2C_SMBUS_WRITE, 0x03,
+                                             I2C_SMBUS_BYTE_DATA, &ioconfig);
+       if (error) {
+               dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
+               error = -EIO;
+               goto ERROR3;
+       }
+
+       /* Register virtual adapters */
+       for (i = 0; i < 5; i++) {
+               error = i2c_add_adapter(s4882_adapter+i);
+               if (error) {
+                       dev_err(&amd756_smbus.dev,
+                              "Virtual adapter %d registration "
+                              "failed, module not inserted\n", i);
+                       for (i--; i >= 0; i--)
+                               i2c_del_adapter(s4882_adapter+i);
+                       goto ERROR3;
+               }
+       }
+
+       return 0;
+
+ERROR3:
+       kfree(s4882_algo);
+       s4882_algo = NULL;
+ERROR2:
+       kfree(s4882_adapter);
+       s4882_adapter = NULL;
+ERROR1:
+       i2c_del_adapter(&amd756_smbus);
+ERROR0:
+       return error;
+}
+
+static void __exit amd756_s4882_exit(void)
+{
+       if (s4882_adapter) {
+               int i;
+
+               for (i = 0; i < 5; i++)
+                       i2c_del_adapter(s4882_adapter+i);
+               kfree(s4882_adapter);
+               s4882_adapter = NULL;
+       }
+       if (s4882_algo) {
+               kfree(s4882_algo);
+               s4882_algo = NULL;
+       }
+
+       /* Restore physical bus */
+       if (i2c_add_adapter(&amd756_smbus))
+               dev_err(&amd756_smbus.dev, "Physical bus restoration "
+                       "failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("S4882 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(amd756_s4882_init);
+module_exit(amd756_s4882_exit);
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
new file mode 100644 (file)
index 0000000..21cd54d
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * drivers/i2c/busses/i2c-ixp2000.c
+ *
+ * I2C adapter for IXP2000 systems using GPIOs for I2C bus
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ * Based on IXDP2400 code by: Naeem M. Afzal <naeem.m.afzal@intel.com>
+ * Made generic by: Jeff Daly <jeffrey.daly@intel.com>
+ *
+ * Copyright (c) 2003-2004 MontaVista Software Inc.
+ *
+ * This file is licensed under  the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ *
+ * From Jeff Daly:
+ *
+ * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any
+ * IXP2000 platform if it uses the HW GPIO in the same manner.  Basically, 
+ * SDA and SCL GPIOs have external pullups.  Setting the respective GPIO to 
+ * an input will make the signal a '1' via the pullup.  Setting them to 
+ * outputs will pull them down. 
+ *
+ * The GPIOs are open drain signals and are used as configuration strap inputs
+ * during power-up so there's generally a buffer on the board that needs to be 
+ * 'enabled' to drive the GPIOs.
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_I2C_DEBUG_BUS
+#define DEBUG  1
+#endif
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/hardware.h>      /* Pick up IXP42000-specific bits */
+
+static inline int ixp2000_scl_pin(void *data)
+{
+       return ((struct ixp2000_i2c_pins*)data)->scl_pin;
+}
+
+static inline int ixp2000_sda_pin(void *data)
+{
+       return ((struct ixp2000_i2c_pins*)data)->sda_pin;
+}
+
+
+static void ixp2000_bit_setscl(void *data, int val)
+{
+       int i = 5000;
+
+       if (val) {
+               gpio_line_config(ixp2000_scl_pin(data), GPIO_IN);
+               while(!gpio_line_get(ixp2000_scl_pin(data)) && i--);
+       } else {
+               gpio_line_config(ixp2000_scl_pin(data), GPIO_OUT);
+       }
+}
+
+static void ixp2000_bit_setsda(void *data, int val)
+{
+       if (val) {
+               gpio_line_config(ixp2000_sda_pin(data), GPIO_IN);
+       } else {
+               gpio_line_config(ixp2000_sda_pin(data), GPIO_OUT);
+       }
+}
+
+static int ixp2000_bit_getscl(void *data)
+{
+       return gpio_line_get(ixp2000_scl_pin(data));
+}
+
+static int ixp2000_bit_getsda(void *data)
+{
+       return gpio_line_get(ixp2000_sda_pin(data));
+}
+
+struct ixp2000_i2c_data {
+       struct ixp2000_i2c_pins *gpio_pins;
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo_data;
+};
+
+static int ixp2000_i2c_remove(struct device *dev)
+{
+       struct platform_device *plat_dev = to_platform_device(dev);
+       struct ixp2000_i2c_data *drv_data = dev_get_drvdata(&plat_dev->dev);
+
+       dev_set_drvdata(&plat_dev->dev, NULL);
+
+       i2c_bit_del_bus(&drv_data->adapter);
+
+       kfree(drv_data);
+
+       return 0;
+}
+
+static int ixp2000_i2c_probe(struct device *dev)
+{
+       int err;
+       struct platform_device *plat_dev = to_platform_device(dev);
+       struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data;
+       struct ixp2000_i2c_data *drv_data = 
+               kmalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL);
+
+       if (!drv_data)
+               return -ENOMEM;
+       memzero(drv_data, sizeof(*drv_data));
+       drv_data->gpio_pins = gpio;
+
+       drv_data->algo_data.data = gpio;
+       drv_data->algo_data.setsda = ixp2000_bit_setsda;
+       drv_data->algo_data.setscl = ixp2000_bit_setscl;
+       drv_data->algo_data.getsda = ixp2000_bit_getsda;
+       drv_data->algo_data.getscl = ixp2000_bit_getscl;
+       drv_data->algo_data.udelay = 6;
+       drv_data->algo_data.mdelay = 6;
+       drv_data->algo_data.timeout = 100;
+
+       drv_data->adapter.id = I2C_HW_B_IXP2000,
+       drv_data->adapter.algo_data = &drv_data->algo_data,
+
+       drv_data->adapter.dev.parent = &plat_dev->dev;
+
+       gpio_line_config(gpio->sda_pin, GPIO_IN);
+       gpio_line_config(gpio->scl_pin, GPIO_IN);
+       gpio_line_set(gpio->scl_pin, 0);
+       gpio_line_set(gpio->sda_pin, 0);
+
+       if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) {
+               dev_err(dev, "Could not install, error %d\n", err);
+               kfree(drv_data);
+               return err;
+       } 
+
+       dev_set_drvdata(&plat_dev->dev, drv_data);
+
+       return 0;
+}
+
+static struct device_driver ixp2000_i2c_driver = {
+       .name           = "IXP2000-I2C",
+       .bus            = &platform_bus_type,
+       .probe          = ixp2000_i2c_probe,
+       .remove         = ixp2000_i2c_remove,
+};
+
+static int __init ixp2000_i2c_init(void)
+{
+       return driver_register(&ixp2000_i2c_driver);
+}
+
+static void __exit ixp2000_i2c_exit(void)
+{
+       driver_unregister(&ixp2000_i2c_driver);
+}
+
+module_init(ixp2000_i2c_init);
+module_exit(ixp2000_i2c_exit);
+
+MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
new file mode 100644 (file)
index 0000000..f77245e
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx). 
+ *
+ * Release 0.6
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/ocp.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+
+#define MPC_I2C_ADDR  0x00
+#define MPC_I2C_FDR    0x04
+#define MPC_I2C_CR     0x08
+#define MPC_I2C_SR     0x0c
+#define MPC_I2C_DR     0x10
+#define MPC_I2C_DFSRR 0x14
+#define MPC_I2C_REGION 0x20
+
+#define CCR_MEN  0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX  0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+
+#define CSR_MCF  0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB  0x20
+#define CSR_MAL  0x10
+#define CSR_SRW  0x04
+#define CSR_MIF  0x02
+#define CSR_RXAK 0x01
+
+struct mpc_i2c {
+       char *base;
+       struct ocp_def *ocpdef;
+       u32 interrupt;
+       wait_queue_head_t queue;
+       struct i2c_adapter adap;
+};
+
+static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
+{
+       writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct mpc_i2c *i2c = dev_id;
+       if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+               /* Read again to allow register to stabilise */
+               i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+               writeb(0, i2c->base + MPC_I2C_SR);
+               wake_up_interruptible(&i2c->queue);
+       }
+       return IRQ_HANDLED;
+}
+
+static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long orig_jiffies = jiffies;
+       u32 x;
+       int result = 0;
+
+       if (i2c->ocpdef->irq == OCP_IRQ_NA) {
+               while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+                       schedule();
+                       if (time_after(jiffies, orig_jiffies + timeout)) {
+                               pr_debug("I2C: timeout\n");
+                               result = -EIO;
+                               break;
+                       }
+               }
+               x = readb(i2c->base + MPC_I2C_SR);
+               writeb(0, i2c->base + MPC_I2C_SR);
+       } else {
+               add_wait_queue(&i2c->queue, &wait);
+               while (!(i2c->interrupt & CSR_MIF)) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (signal_pending(current)) {
+                               pr_debug("I2C: Interrupted\n");
+                               result = -EINTR;
+                               break;
+                       }
+                       if (time_after(jiffies, orig_jiffies + timeout)) {
+                               pr_debug("I2C: timeout\n");
+                               result = -EIO;
+                               break;
+                       }
+                       schedule_timeout(timeout);
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&i2c->queue, &wait);
+               x = i2c->interrupt;
+               i2c->interrupt = 0;
+       }
+
+       if (result < -0)
+               return result;
+
+       if (!(x & CSR_MCF)) {
+               pr_debug("I2C: unfinished\n");
+               return -EIO;
+       }
+
+       if (x & CSR_MAL) {
+               pr_debug("I2C: MAL\n");
+               return -EIO;
+       }
+
+       if (writing && (x & CSR_RXAK)) {
+               pr_debug("I2C: No RXAK\n");
+               /* generate stop */
+               writeccr(i2c, CCR_MEN);
+               return -EIO;
+       }
+       return 0;
+}
+
+static void mpc_i2c_setclock(struct mpc_i2c *i2c)
+{
+       struct ocp_fs_i2c_data *i2c_data = i2c->ocpdef->additions;
+       /* Set clock and filters */
+       if (i2c_data && (i2c_data->flags & FS_I2C_SEPARATE_DFSRR)) {
+               writeb(0x31, i2c->base + MPC_I2C_FDR);
+               writeb(0x10, i2c->base + MPC_I2C_DFSRR);
+       } else if (i2c_data && (i2c_data->flags & FS_I2C_CLOCK_5200))
+               writeb(0x3f, i2c->base + MPC_I2C_FDR);
+       else
+               writel(0x1031, i2c->base + MPC_I2C_FDR);
+}
+
+static void mpc_i2c_start(struct mpc_i2c *i2c)
+{
+       /* Clear arbitration */
+       writeb(0, i2c->base + MPC_I2C_SR);
+       /* Start with MEN */
+       writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_stop(struct mpc_i2c *i2c)
+{
+       writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_write(struct mpc_i2c *i2c, int target,
+                    const u8 * data, int length, int restart)
+{
+       int i;
+       unsigned timeout = HZ;
+       u32 flags = restart ? CCR_RSTA : 0;
+
+       /* Start with MEN */
+       if (!restart)
+               writeccr(i2c, CCR_MEN);
+       /* Start as master */
+       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+       /* Write target byte */
+       writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+       if (i2c_wait(i2c, timeout, 1) < 0)
+               return -1;
+
+       for (i = 0; i < length; i++) {
+               /* Write data byte */
+               writeb(data[i], i2c->base + MPC_I2C_DR);
+
+               if (i2c_wait(i2c, timeout, 1) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int mpc_read(struct mpc_i2c *i2c, int target,
+                   u8 * data, int length, int restart)
+{
+       unsigned timeout = HZ;
+       int i;
+       u32 flags = restart ? CCR_RSTA : 0;
+
+       /* Start with MEN */
+       if (!restart)
+               writeccr(i2c, CCR_MEN);
+       /* Switch to read - restart */
+       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+       /* Write target address byte - this time with the read flag set */
+       writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+       if (i2c_wait(i2c, timeout, 1) < 0)
+               return -1;
+
+       if (length) {
+               if (length == 1)
+                       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+               else
+                       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+               /* Dummy read */
+               readb(i2c->base + MPC_I2C_DR);
+       }
+
+       for (i = 0; i < length; i++) {
+               if (i2c_wait(i2c, timeout, 0) < 0)
+                       return -1;
+
+               /* Generate txack on next to last byte */
+               if (i == length - 2)
+                       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+               /* Generate stop on last byte */
+               if (i == length - 1)
+                       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
+               data[i] = readb(i2c->base + MPC_I2C_DR);
+       }
+
+       return length;
+}
+
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+       struct i2c_msg *pmsg;
+       int i;
+       int ret = 0;
+       unsigned long orig_jiffies = jiffies;
+       struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+       mpc_i2c_start(i2c);
+
+       /* Allow bus up to 1s to become not busy */
+       while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+               if (signal_pending(current)) {
+                       pr_debug("I2C: Interrupted\n");
+                       return -EINTR;
+               }
+               if (time_after(jiffies, orig_jiffies + HZ)) {
+                       pr_debug("I2C: timeout\n");
+                       return -EIO;
+               }
+               schedule();
+       }
+
+       for (i = 0; ret >= 0 && i < num; i++) {
+               pmsg = &msgs[i];
+               pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+                        pmsg->flags & I2C_M_RD ? "read" : "write",
+                        pmsg->len, pmsg->addr, i + 1, num);
+               if (pmsg->flags & I2C_M_RD)
+                       ret =
+                           mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+               else
+                       ret =
+                           mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+       }
+       mpc_i2c_stop(i2c);
+       return (ret < 0) ? ret : num;
+}
+
+static u32 mpc_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm mpc_algo = {
+       .name = "MPC algorithm",
+       .id = I2C_ALGO_MPC107,
+       .master_xfer = mpc_xfer,
+       .functionality = mpc_functionality,
+};
+
+static struct i2c_adapter mpc_ops = {
+       .owner = THIS_MODULE,
+       .name = "MPC adapter",
+       .id = I2C_ALGO_MPC107 | I2C_HW_MPC107,
+       .algo = &mpc_algo,
+       .class = I2C_CLASS_HWMON,
+       .timeout = 1,
+       .retries = 1
+};
+
+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;
+       }
+       i2c->ocpdef = ocp->def;
+       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 (ocp->def->irq != OCP_IRQ_NA)
+               if ((result = request_irq(ocp->def->irq, mpc_i2c_isr,
+                                         0, "i2c-mpc", i2c)) < 0) {
+                       printk(KERN_ERR
+                              "i2c-mpc - failed to attach interrupt\n");
+                       goto fail_irq;
+               }
+
+       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;
+       }
+
+       mpc_i2c_setclock(i2c);
+       ocp_set_drvdata(ocp, i2c);
+       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);
+       ocp_set_drvdata(ocp, NULL);
+       i2c_del_adapter(&i2c->adap);
+
+       if (ocp->def->irq != OCP_IRQ_NA)
+               free_irq(i2c->ocpdef->irq, i2c);
+       iounmap(i2c->base);
+       release_mem_region(i2c->ocpdef->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);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION
+    ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
new file mode 100644 (file)
index 0000000..9c61113
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *  i2c-pca-isa.c driver for PCA9564 on ISA boards
+ *    Copyright (C) 2004 Arcom Control Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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/config.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "../algos/i2c-algo-pca.h"
+
+#define IO_SIZE 4
+
+#undef DEBUG_IO
+//#define DEBUG_IO
+
+static unsigned long base   = 0x330;
+static int irq           = 10;
+
+/* Data sheet recommends 59kHz for 100kHz operation due to variation
+ * in the actual clock rate */
+static int clock  = I2C_PCA_CON_59kHz;
+
+static int own    = 0x55;
+
+static wait_queue_head_t pca_wait;
+
+static int pca_isa_getown(struct i2c_algo_pca_data *adap)
+{
+       return (own);
+}
+
+static int pca_isa_getclock(struct i2c_algo_pca_data *adap)
+{
+       return (clock);
+}
+
+static void
+pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
+{
+#ifdef DEBUG_IO
+       static char *names[] = { "T/O", "DAT", "ADR", "CON" };
+       printk("*** write %s at %#lx <= %#04x\n", names[reg], base+reg, val);
+#endif
+       outb(val, base+reg);
+}
+
+static int
+pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg)
+{
+       int res = inb(base+reg);
+#ifdef DEBUG_IO
+       {
+               static char *names[] = { "STA", "DAT", "ADR", "CON" };  
+               printk("*** read  %s => %#04x\n", names[reg], res);
+       }
+#endif
+       return res;
+}
+
+static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap)
+{
+       int ret = 0;
+
+       if (irq > -1) {
+               ret = wait_event_interruptible(pca_wait,
+                                              pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI);
+       } else {
+               while ((pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) 
+                       udelay(100);
+       }
+       return ret;
+}
+
+static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+       wake_up_interruptible(&pca_wait);
+       return IRQ_HANDLED;
+}
+
+static struct i2c_algo_pca_data pca_isa_data = {
+       .get_own                = pca_isa_getown,
+       .get_clock              = pca_isa_getclock,
+       .write_byte             = pca_isa_writebyte,
+       .read_byte              = pca_isa_readbyte,
+       .wait_for_interrupt     = pca_isa_waitforinterrupt,
+};
+
+static struct i2c_adapter pca_isa_ops = {
+       .owner          = THIS_MODULE,
+       .id             = I2C_HW_A_ISA,
+       .algo_data      = &pca_isa_data,
+       .name           = "PCA9564 ISA Adapter",
+};
+
+static int __init pca_isa_init(void)
+{
+
+       init_waitqueue_head(&pca_wait);
+
+       printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq);
+
+       if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
+               printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base);
+               goto out;
+       }
+
+       if (irq > -1) {
+               if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
+                       printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq);
+                       goto out_region;
+               }
+       }
+
+       if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
+               printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n");
+               goto out_irq;
+       }
+
+       return 0;
+
+ out_irq:
+       if (irq > -1)
+               free_irq(irq, &pca_isa_ops);
+ out_region:
+       release_region(base, IO_SIZE);
+ out:
+       return -ENODEV;
+}
+
+static void pca_isa_exit(void)
+{
+       i2c_pca_del_bus(&pca_isa_ops);
+
+       if (irq > 0) {
+               disable_irq(irq);
+               free_irq(irq, &pca_isa_ops);
+       }
+       release_region(base, IO_SIZE);
+}
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_DESCRIPTION("ISA base PCA9564 driver");
+MODULE_LICENSE("GPL");
+
+module_param(base, ulong, 0);
+MODULE_PARM_DESC(base, "I/O base address");
+
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "IRQ");
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet");
+
+module_param(own, int, 0); /* the driver can't do slave mode, so there's no real point in this */
+
+module_init(pca_isa_init);
+module_exit(pca_isa_exit);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
new file mode 100644 (file)
index 0000000..9cb6974
--- /dev/null
@@ -0,0 +1,926 @@
+/* linux/drivers/i2c/busses/i2c-s3c2410.c
+ *
+ * Copyright (C) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 I2C Controller
+ *
+ * This 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/module.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/hardware/clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-iic.h>
+#include <asm/arch/iic.h>
+
+/* i2c controller state */
+
+enum s3c24xx_i2c_state {
+       STATE_IDLE,
+       STATE_START,
+       STATE_READ,
+       STATE_WRITE,
+       STATE_STOP
+};
+
+struct s3c24xx_i2c {
+       spinlock_t              lock;
+       wait_queue_head_t       wait;
+
+       struct i2c_msg          *msg;
+       unsigned int            msg_num;
+       unsigned int            msg_idx;
+       unsigned int            msg_ptr;
+
+       enum s3c24xx_i2c_state  state;
+
+       void __iomem            *regs;
+       struct clk              *clk;
+       struct device           *dev;
+       struct resource         *irq;
+       struct resource         *ioarea;
+       struct i2c_adapter      adap;
+};
+
+/* default platform data to use if not supplied in the platform_device
+*/
+
+static struct s3c2410_platform_i2c s3c24xx_i2c_default_platform = {
+       .flags          = 0,
+       .slave_addr     = 0x10,
+       .bus_freq       = 100*1000,
+       .max_freq       = 400*1000,
+       .sda_delay      = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
+};
+
+/* s3c24xx_i2c_is2440()
+ *
+ * return true is this is an s3c2440
+*/
+
+static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
+{
+       struct platform_device *pdev = to_platform_device(i2c->dev);
+
+       return !strcmp(pdev->name, "s3c2440-i2c");
+}
+
+
+/* s3c24xx_i2c_get_platformdata
+ *
+ * get the platform data associated with the given device, or return
+ * the default if there is none
+*/
+
+static inline struct s3c2410_platform_i2c *s3c24xx_i2c_get_platformdata(struct device *dev)
+{
+       if (dev->platform_data != NULL)
+               return (struct s3c2410_platform_i2c *)dev->platform_data;
+
+       return &s3c24xx_i2c_default_platform;
+}
+
+/* s3c24xx_i2c_master_complete
+ *
+ * complete the message and wake up the caller, using the given return code,
+ * or zero to mean ok.
+*/
+
+static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
+{
+       dev_dbg(i2c->dev, "master_complete %d\n", ret);
+
+       i2c->msg_ptr = 0;
+       i2c->msg = NULL;
+       i2c->msg_idx ++;
+       i2c->msg_num = 0;
+       if (ret)
+               i2c->msg_idx = ret;
+
+       wake_up(&i2c->wait);
+}
+
+static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
+{
+       unsigned long tmp;
+       
+       tmp = readl(i2c->regs + S3C2410_IICCON);
+       writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+
+}
+
+static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
+{
+       unsigned long tmp;
+       
+       tmp = readl(i2c->regs + S3C2410_IICCON);
+       writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+
+}
+
+/* irq enable/disable functions */
+
+static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
+{
+       unsigned long tmp;
+       
+       tmp = readl(i2c->regs + S3C2410_IICCON);
+       writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
+{
+       unsigned long tmp;
+       
+       tmp = readl(i2c->regs + S3C2410_IICCON);
+       writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+
+/* s3c24xx_i2c_message_start
+ *
+ * put the start of a message onto the bus 
+*/
+
+static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, 
+                                     struct i2c_msg *msg)
+{
+       unsigned int addr = (msg->addr & 0x7f) << 1;
+       unsigned long stat;
+       unsigned long iiccon;
+
+       stat = 0;
+       stat |=  S3C2410_IICSTAT_TXRXEN;
+
+       if (msg->flags & I2C_M_RD) {
+               stat |= S3C2410_IICSTAT_MASTER_RX;
+               addr |= 1;
+       } else
+               stat |= S3C2410_IICSTAT_MASTER_TX;
+
+       // todo - check for wether ack wanted or not
+       s3c24xx_i2c_enable_ack(i2c);
+
+       iiccon = readl(i2c->regs + S3C2410_IICCON);
+       writel(stat, i2c->regs + S3C2410_IICSTAT);
+       
+       dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
+       writeb(addr, i2c->regs + S3C2410_IICDS);
+       
+       // delay a bit and reset iiccon before setting start (per samsung)
+       udelay(1);
+       dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
+       writel(iiccon, i2c->regs + S3C2410_IICCON);
+       
+       stat |=  S3C2410_IICSTAT_START;
+       writel(stat, i2c->regs + S3C2410_IICSTAT);
+}
+
+static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
+{
+       unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+       dev_dbg(i2c->dev, "STOP\n");
+
+       /* stop the transfer */
+       iicstat &= ~ S3C2410_IICSTAT_START;
+       writel(iicstat, i2c->regs + S3C2410_IICSTAT);
+       
+       i2c->state = STATE_STOP;
+       
+       s3c24xx_i2c_master_complete(i2c, ret);
+       s3c24xx_i2c_disable_irq(i2c);
+}
+
+/* helper functions to determine the current state in the set of
+ * messages we are sending */
+
+/* is_lastmsg()
+ *
+ * returns TRUE if the current message is the last in the set 
+*/
+
+static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
+{
+       return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+/* is_msglast
+ *
+ * returns TRUE if we this is the last byte in the current message
+*/
+
+static inline int is_msglast(struct s3c24xx_i2c *i2c)
+{
+       return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/* is_msgend
+ *
+ * returns TRUE if we reached the end of the current message
+*/
+
+static inline int is_msgend(struct s3c24xx_i2c *i2c)
+{
+       return i2c->msg_ptr >= i2c->msg->len;
+}
+
+/* i2s_s3c_irq_nextbyte
+ *
+ * process an interrupt and work out what to do
+ */
+
+static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
+{
+       unsigned long tmp;
+       unsigned char byte;
+       int ret = 0;
+
+       switch (i2c->state) {
+
+       case STATE_IDLE:
+               dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __FUNCTION__);
+               goto out;
+               break;
+
+       case STATE_STOP:
+               dev_err(i2c->dev, "%s: called in STATE_STOP\n", __FUNCTION__);
+               s3c24xx_i2c_disable_irq(i2c);           
+               goto out_ack;
+
+       case STATE_START:
+               /* last thing we did was send a start condition on the
+                * bus, or started a new i2c message
+                */
+               
+               if (iicstat  & S3C2410_IICSTAT_LASTBIT &&
+                   !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+                       /* ack was not received... */
+
+                       dev_err(i2c->dev, "ack was not received\n" );
+                       s3c24xx_i2c_stop(i2c, -EREMOTEIO);
+                       goto out_ack;
+               }
+
+               if (i2c->msg->flags & I2C_M_RD)
+                       i2c->state = STATE_READ;
+               else
+                       i2c->state = STATE_WRITE;
+
+               /* terminate the transfer if there is nothing to do
+                * (used by the i2c probe to find devices */
+
+               if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+                       s3c24xx_i2c_stop(i2c, 0);
+                       goto out_ack;
+               }
+
+               if (i2c->state == STATE_READ)
+                       goto prepare_read;
+
+               /* fall through to the write state, as we will need to 
+                * send a byte as well */
+
+       case STATE_WRITE:
+               /* we are writing data to the device... check for the
+                * end of the message, and if so, work out what to do
+                */
+
+       retry_write:
+               if (!is_msgend(i2c)) {
+                       byte = i2c->msg->buf[i2c->msg_ptr++];
+                       writeb(byte, i2c->regs + S3C2410_IICDS);
+                       
+               } else if (!is_lastmsg(i2c)) {
+                       /* we need to go to the next i2c message */
+
+                       dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+                       i2c->msg_ptr = 0;
+                       i2c->msg_idx ++;
+                       i2c->msg++;
+                       
+                       /* check to see if we need to do another message */
+                       if (i2c->msg->flags & I2C_M_NOSTART) {
+
+                               if (i2c->msg->flags & I2C_M_RD) {
+                                       /* cannot do this, the controller
+                                        * forces us to send a new START
+                                        * when we change direction */
+
+                                       s3c24xx_i2c_stop(i2c, -EINVAL);
+                               }
+
+                               goto retry_write;
+                       } else {
+                       
+                               /* send the new start */
+                               s3c24xx_i2c_message_start(i2c, i2c->msg);
+                               i2c->state = STATE_START;
+                       }
+
+               } else {
+                       /* send stop */
+
+                       s3c24xx_i2c_stop(i2c, 0);
+               }
+               break;
+
+       case STATE_READ:
+               /* we have a byte of data in the data register, do 
+                * something with it, and then work out wether we are
+                * going to do any more read/write
+                */
+
+               if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
+                   !(is_msglast(i2c) && is_lastmsg(i2c))) {
+
+                       if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+                               dev_dbg(i2c->dev, "READ: No Ack\n");
+
+                               s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+                               goto out_ack;
+                       }
+               }
+
+               byte = readb(i2c->regs + S3C2410_IICDS);
+               i2c->msg->buf[i2c->msg_ptr++] = byte;
+
+       prepare_read:
+               if (is_msglast(i2c)) {
+                       /* last byte of buffer */
+
+                       if (is_lastmsg(i2c))
+                               s3c24xx_i2c_disable_ack(i2c);
+                       
+               } else if (is_msgend(i2c)) {
+                       /* ok, we've read the entire buffer, see if there
+                        * is anything else we need to do */
+
+                       if (is_lastmsg(i2c)) {
+                               /* last message, send stop and complete */
+                               dev_dbg(i2c->dev, "READ: Send Stop\n");
+
+                               s3c24xx_i2c_stop(i2c, 0);
+                       } else {
+                               /* go to the next transfer */
+                               dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+                               i2c->msg_ptr = 0;
+                               i2c->msg_idx++;
+                               i2c->msg++;
+                       }
+               }
+
+               break;
+       }
+
+       /* acknowlegde the IRQ and get back on with the work */
+
+ out_ack:
+       tmp = readl(i2c->regs + S3C2410_IICCON);        
+       tmp &= ~S3C2410_IICCON_IRQPEND;
+       writel(tmp, i2c->regs + S3C2410_IICCON);
+ out:
+       return ret;
+}
+
+/* s3c24xx_i2c_irq
+ *
+ * top level IRQ servicing routine
+*/
+
+static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id,
+                                  struct pt_regs *regs)
+{
+       struct s3c24xx_i2c *i2c = dev_id;
+       unsigned long status;
+       unsigned long tmp;
+
+       status = readl(i2c->regs + S3C2410_IICSTAT);
+
+       if (status & S3C2410_IICSTAT_ARBITR) {
+               // deal with arbitration loss
+               dev_err(i2c->dev, "deal with arbitration loss\n");
+       }
+
+       if (i2c->state == STATE_IDLE) {
+               dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
+
+               tmp = readl(i2c->regs + S3C2410_IICCON);        
+               tmp &= ~S3C2410_IICCON_IRQPEND;
+               writel(tmp, i2c->regs +  S3C2410_IICCON);
+               goto out;
+       }
+       
+       /* pretty much this leaves us with the fact that we've
+        * transmitted or received whatever byte we last sent */
+
+       i2s_s3c_irq_nextbyte(i2c, status);
+
+ out:
+       return IRQ_HANDLED;
+}
+
+
+/* s3c24xx_i2c_set_master
+ *
+ * get the i2c bus for a master transaction
+*/
+
+static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
+{
+       unsigned long iicstat;
+       int timeout = 400;
+
+       while (timeout-- > 0) {
+               iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+               
+               if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
+                       return 0;
+
+               msleep(1);
+       }
+
+       dev_dbg(i2c->dev, "timeout: GPEDAT is %08x\n",
+               __raw_readl(S3C2410_GPEDAT));
+
+       return -ETIMEDOUT;
+}
+
+/* s3c24xx_i2c_doxfer
+ *
+ * this starts an i2c transfer
+*/
+
+static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], int num)
+{
+       unsigned long timeout;
+       int ret;
+
+       ret = s3c24xx_i2c_set_master(i2c);
+       if (ret != 0) {
+               dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       spin_lock_irq(&i2c->lock);
+
+       i2c->msg     = msgs;
+       i2c->msg_num = num;
+       i2c->msg_ptr = 0;
+       i2c->msg_idx = 0;
+       i2c->state   = STATE_START;
+
+       s3c24xx_i2c_enable_irq(i2c);
+       s3c24xx_i2c_message_start(i2c, msgs);
+       spin_unlock_irq(&i2c->lock);
+       
+       timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+       ret = i2c->msg_idx;
+
+       /* having these next two as dev_err() makes life very 
+        * noisy when doing an i2cdetect */
+
+       if (timeout == 0)
+               dev_dbg(i2c->dev, "timeout\n");
+       else if (ret != num)
+               dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+       /* ensure the stop has been through the bus */
+
+       msleep(1);
+
+ out:
+       return ret;
+}
+
+/* s3c24xx_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transfering across the i2c bus.
+*/
+
+static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
+                       struct i2c_msg msgs[], int num)
+{
+       struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
+       int retry;
+       int ret;
+
+       for (retry = 0; retry < adap->retries; retry++) {
+
+               ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
+
+               if (ret != -EAGAIN)
+                       return ret;
+
+               dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+               udelay(100);
+       }
+
+       return -EREMOTEIO;
+}
+
+/* i2c bus registration info */
+
+static struct i2c_algorithm s3c24xx_i2c_algorithm = {
+       .name                   = "S3C2410-I2C-Algorithm",
+       .master_xfer            = s3c24xx_i2c_xfer,
+};
+
+static struct s3c24xx_i2c s3c24xx_i2c = {
+       .lock   = SPIN_LOCK_UNLOCKED,
+       .wait   = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
+       .adap   = {
+               .name                   = "s3c2410-i2c",
+               .algo                   = &s3c24xx_i2c_algorithm,
+               .retries                = 2,
+       },
+};
+
+/* s3c24xx_i2c_calcdivisor
+ *
+ * return the divisor settings for a given frequency
+*/
+
+static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
+                                  unsigned int *div1, unsigned int *divs)
+{
+       unsigned int calc_divs = clkin / wanted;
+       unsigned int calc_div1;
+
+       if (calc_divs > (16*16))
+               calc_div1 = 512;
+       else
+               calc_div1 = 16;
+
+       calc_divs += calc_div1-1;
+       calc_divs /= calc_div1;
+
+       if (calc_divs == 0)
+               calc_divs = 1;
+       if (calc_divs > 17)
+               calc_divs = 17;
+
+       *divs = calc_divs;
+       *div1 = calc_div1;
+
+       return clkin / (calc_divs * calc_div1);
+}
+
+/* freq_acceptable
+ *
+ * test wether a frequency is within the acceptable range of error
+*/
+
+static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
+{
+       int diff = freq - wanted;
+
+       return (diff >= -2 && diff <= 2);
+}
+
+/* s3c24xx_i2c_getdivisor
+ *
+ * work out a divisor for the user requested frequency setting,
+ * either by the requested frequency, or scanning the acceptable
+ * range of frequencies until something is found
+*/
+
+static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c,
+                                 struct s3c2410_platform_i2c *pdata,
+                                 unsigned long *iicon,
+                                 unsigned int *got)
+{
+       unsigned long clkin = clk_get_rate(i2c->clk);
+       
+       unsigned int divs, div1;
+       int freq;
+       int start, end;
+
+       clkin /= 1000;          /* clkin now in KHz */
+     
+       dev_dbg(i2c->dev,  "pdata %p, freq %lu %lu..%lu\n",
+                pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq);
+
+       if (pdata->bus_freq != 0) {
+               freq = s3c24xx_i2c_calcdivisor(clkin, pdata->bus_freq/1000,
+                                              &div1, &divs);
+               if (freq_acceptable(freq, pdata->bus_freq/1000))
+                       goto found;
+       }
+
+       /* ok, we may have to search for something suitable... */
+
+       start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq;
+       end = pdata->min_freq;
+
+       start /= 1000;
+       end /= 1000;
+
+       /* search loop... */
+
+       for (; start > end; start--) {
+               freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs);
+               if (freq_acceptable(freq, start))
+                       goto found;
+       }
+
+       /* cannot find frequency spec */
+
+       return -EINVAL;
+
+ found:
+       *got = freq;
+       *iicon |= (divs-1);
+       *iicon |= (div1 == 512) ? S3C2410_IICCON_TXDIV_512 : 0;
+       return 0;
+}
+
+/* s3c24xx_i2c_init
+ *
+ * initialise the controller, set the IO lines and frequency 
+*/
+
+static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
+{
+       unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
+       struct s3c2410_platform_i2c *pdata;
+       unsigned int freq;
+
+       /* get the plafrom data */
+
+       pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent);
+
+       /* inititalise the gpio */
+
+       s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
+       s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);
+
+       /* write slave address */
+       
+       writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
+
+       dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
+
+       /* we need to work out the divisors for the clock... */
+
+       if (s3c24xx_i2c_getdivisor(i2c, pdata, &iicon, &freq) != 0) {
+               dev_err(i2c->dev, "cannot meet bus frequency required\n");
+               return -EINVAL;
+       }
+
+       /* todo - check that the i2c lines aren't being dragged anywhere */
+
+       dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
+       dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
+       
+       writel(iicon, i2c->regs + S3C2410_IICCON);
+
+       /* check for s3c2440 i2c controller  */
+
+       if (s3c24xx_i2c_is2440(i2c)) {
+               dev_dbg(i2c->dev, "S3C2440_IICLC=%08x\n", pdata->sda_delay);
+
+               writel(pdata->sda_delay, i2c->regs + S3C2440_IICLC);
+       }
+
+       return 0;
+}
+
+static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
+{
+       if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
+               clk_disable(i2c->clk);
+               clk_unuse(i2c->clk);
+               clk_put(i2c->clk);
+               i2c->clk = NULL;
+       }
+
+       if (i2c->regs != NULL) {
+               iounmap(i2c->regs);
+               i2c->regs = NULL;
+       }
+
+       if (i2c->ioarea != NULL) {
+               release_resource(i2c->ioarea);
+               kfree(i2c->ioarea);
+               i2c->ioarea = NULL;
+       }
+}
+
+/* s3c24xx_i2c_probe
+ *
+ * called by the bus driver when a suitable device is found
+*/
+
+static int s3c24xx_i2c_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
+       struct resource *res;
+       int ret;
+
+       /* find the clock and enable it */
+
+       i2c->dev = dev;
+       i2c->clk = clk_get(dev, "i2c");
+       if (IS_ERR(i2c->clk)) {
+               dev_err(dev, "cannot get clock\n");
+               ret = -ENOENT;
+               goto out;
+       }
+
+       dev_dbg(dev, "clock source %p\n", i2c->clk);
+
+       clk_use(i2c->clk);
+       clk_enable(i2c->clk);
+
+       /* map the registers */
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "cannot find IO resource\n");
+               ret = -ENOENT;
+               goto out;
+       }
+
+       i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
+                                        pdev->name);
+
+       if (i2c->ioarea == NULL) {
+               dev_err(dev, "cannot request IO\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       i2c->regs = ioremap(res->start, (res->end-res->start)+1);
+
+       if (i2c->regs == NULL) {
+               dev_err(dev, "cannot map IO\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       dev_dbg(dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
+
+       /* setup info block for the i2c core */
+
+       i2c->adap.algo_data = i2c;
+       i2c->adap.dev.parent = dev;
+
+       /* initialise the i2c controller */
+
+       ret = s3c24xx_i2c_init(i2c);
+       if (ret != 0)
+               goto out;
+
+       /* find the IRQ for this unit (note, this relies on the init call to
+        * ensure no current IRQs pending 
+        */
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "cannot find IRQ\n");
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ret = request_irq(res->start, s3c24xx_i2c_irq, SA_INTERRUPT,
+                         pdev->name, i2c);
+
+       if (ret != 0) {
+               dev_err(dev, "cannot claim IRQ\n");
+               goto out;
+       }
+
+       i2c->irq = res;
+               
+       dev_dbg(dev, "irq resource %p (%ld)\n", res, res->start);
+
+       ret = i2c_add_adapter(&i2c->adap);
+       if (ret < 0) {
+               dev_err(dev, "failed to add bus to i2c core\n");
+               goto out;
+       }
+
+       dev_set_drvdata(dev, i2c);
+
+       dev_info(dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
+
+ out:
+       if (ret < 0)
+               s3c24xx_i2c_free(i2c);
+
+       return ret;
+}
+
+/* s3c24xx_i2c_remove
+ *
+ * called when device is removed from the bus
+*/
+
+static int s3c24xx_i2c_remove(struct device *dev)
+{
+       struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
+       
+       if (i2c != NULL) {
+               s3c24xx_i2c_free(i2c);
+               dev_set_drvdata(dev, NULL);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c24xx_i2c_resume(struct device *dev, u32 level)
+{
+       struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
+       
+       if (i2c != NULL && level == RESUME_ENABLE) {
+               dev_dbg(dev, "resume: level %d\n", level);
+               s3c24xx_i2c_init(i2c);
+       }
+
+       return 0;
+}
+
+#else
+#define s3c24xx_i2c_resume NULL
+#endif
+
+/* device driver for platform bus bits */
+
+static struct device_driver s3c2410_i2c_driver = {
+       .name           = "s3c2410-i2c",
+       .bus            = &platform_bus_type,
+       .probe          = s3c24xx_i2c_probe,
+       .remove         = s3c24xx_i2c_remove,
+       .resume         = s3c24xx_i2c_resume,
+};
+
+static struct device_driver s3c2440_i2c_driver = {
+       .name           = "s3c2440-i2c",
+       .bus            = &platform_bus_type,
+       .probe          = s3c24xx_i2c_probe,
+       .remove         = s3c24xx_i2c_remove,
+       .resume         = s3c24xx_i2c_resume,
+};
+
+static int __init i2c_adap_s3c_init(void)
+{
+       int ret;
+
+       ret = driver_register(&s3c2410_i2c_driver);
+       if (ret == 0)
+               ret = driver_register(&s3c2440_i2c_driver); 
+
+       return ret;
+}
+
+static void __exit i2c_adap_s3c_exit(void)
+{
+       driver_unregister(&s3c2410_i2c_driver);
+       driver_unregister(&s3c2440_i2c_driver);
+}
+
+module_init(i2c_adap_s3c_init);
+module_exit(i2c_adap_s3c_exit);
+
+MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
new file mode 100644 (file)
index 0000000..fec0bff
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+    i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+
+    Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define DEBUG 1
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+
+static u8  stub_bytes[256];
+static u16 stub_words[256];
+
+/* Return -1 on error. */
+static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
+       char read_write, u8 command, int size, union i2c_smbus_data * data)
+{
+       s32 ret;
+
+       switch (size) {
+
+       case I2C_SMBUS_QUICK:
+               dev_dbg(&adap->dev, "smbus quick - addr 0x%02x\n", addr);
+               ret = 0;
+               break;
+
+       case I2C_SMBUS_BYTE_DATA:
+               if (read_write == I2C_SMBUS_WRITE) {
+                       stub_bytes[command] = data->byte;
+                       dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+                                       "wrote 0x%02x at 0x%02x.\n",
+                                       addr, data->byte, command);
+               } else {
+                       data->byte = stub_bytes[command];
+                       dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+                                       "read  0x%02x at 0x%02x.\n",
+                                       addr, data->byte, command);
+               }
+
+               ret = 0;
+               break;
+
+       case I2C_SMBUS_WORD_DATA:
+               if (read_write == I2C_SMBUS_WRITE) {
+                       stub_words[command] = data->word;
+                       dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
+                                       "wrote 0x%04x at 0x%02x.\n",
+                                       addr, data->word, command);
+               } else {
+                       data->word = stub_words[command];
+                       dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
+                                       "read  0x%04x at 0x%02x.\n",
+                                       addr, data->word, command);
+               }
+
+               ret = 0;
+               break;
+
+       default:
+               dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
+               ret = -1;
+               break;
+       } /* switch (size) */
+
+       return ret;
+}
+
+static u32 stub_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE_DATA |
+               I2C_FUNC_SMBUS_WORD_DATA;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+       .name           = "Non-I2C SMBus adapter",
+       .id             = I2C_ALGO_SMBUS,
+       .functionality  = stub_func,
+       .smbus_xfer     = stub_xfer,
+};
+
+static struct i2c_adapter stub_adapter = {
+       .owner          = THIS_MODULE,
+       .class          = I2C_CLASS_HWMON,
+       .algo           = &smbus_algorithm,
+       .name           = "SMBus stub driver",
+};
+
+static int __init i2c_stub_init(void)
+{
+       printk(KERN_INFO "i2c-stub loaded\n");
+       return i2c_add_adapter(&stub_adapter);
+}
+
+static void __exit i2c_stub_exit(void)
+{
+       i2c_del_adapter(&stub_adapter);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("I2C stub driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_stub_init);
+module_exit(i2c_stub_exit);
+
diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c
new file mode 100644 (file)
index 0000000..e2d13fa
--- /dev/null
@@ -0,0 +1,1779 @@
+/*
+    adm1026.c - Part of lm_sensors, Linux kernel modules for hardware
+            monitoring
+    Copyright (C) 2002, 2003  Philip Pokorny <ppokorny@penguincomputing.com>
+    Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com>
+
+    Chip details at:
+
+    <http://www.analog.com/UploadedFiles/Data_Sheets/779263102ADM1026_a.pdf>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(adm1026);
+
+static int gpio_input[17]  = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+                               -1, -1, -1, -1, -1, -1, -1, -1 }; 
+static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+                               -1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+                               -1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1,
+                               -1, -1, -1, -1, -1, -1, -1, -1 };
+static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+module_param_array(gpio_input,int,NULL,0);
+MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs");
+module_param_array(gpio_output,int,NULL,0);
+MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as "
+       "outputs");
+module_param_array(gpio_inverted,int,NULL,0);
+MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as "
+       "inverted");
+module_param_array(gpio_normal,int,NULL,0);
+MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as "
+       "normal/non-inverted");
+module_param_array(gpio_fan,int,NULL,0);
+MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs");
+
+/* Many ADM1026 constants specified below */
+
+/* The ADM1026 registers */
+#define ADM1026_REG_CONFIG1  0x00
+#define CFG1_MONITOR     0x01
+#define CFG1_INT_ENABLE  0x02
+#define CFG1_INT_CLEAR   0x04
+#define CFG1_AIN8_9      0x08
+#define CFG1_THERM_HOT   0x10
+#define CFG1_DAC_AFC     0x20
+#define CFG1_PWM_AFC     0x40
+#define CFG1_RESET       0x80
+#define ADM1026_REG_CONFIG2  0x01
+/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */
+#define ADM1026_REG_CONFIG3  0x07
+#define CFG3_GPIO16_ENABLE  0x01
+#define CFG3_CI_CLEAR  0x02
+#define CFG3_VREF_250  0x04
+#define CFG3_GPIO16_DIR  0x40
+#define CFG3_GPIO16_POL  0x80
+#define ADM1026_REG_E2CONFIG  0x13
+#define E2CFG_READ  0x01
+#define E2CFG_WRITE  0x02
+#define E2CFG_ERASE  0x04
+#define E2CFG_ROM  0x08
+#define E2CFG_CLK_EXT  0x80
+
+/* There are 10 general analog inputs and 7 dedicated inputs
+ * They are:
+ *    0 - 9  =  AIN0 - AIN9
+ *       10  =  Vbat
+ *       11  =  3.3V Standby
+ *       12  =  3.3V Main
+ *       13  =  +5V
+ *       14  =  Vccp (CPU core voltage)
+ *       15  =  +12V
+ *       16  =  -12V
+ */
+static u16 ADM1026_REG_IN[] = {
+               0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+               0x36, 0x37, 0x27, 0x29, 0x26, 0x2a,
+               0x2b, 0x2c, 0x2d, 0x2e, 0x2f
+       };
+static u16 ADM1026_REG_IN_MIN[] = {
+               0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d,
+               0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a,
+               0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+       };
+static u16 ADM1026_REG_IN_MAX[] = {
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
+               0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42,
+               0x43, 0x44, 0x45, 0x46, 0x47
+       };
+
+/* Temperatures are:
+ *    0 - Internal
+ *    1 - External 1
+ *    2 - External 2
+ */
+static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 };
+static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 };
+static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 };
+static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 };
+static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f };
+static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };
+
+#define ADM1026_REG_FAN(nr) (0x38 + (nr))
+#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr))
+#define ADM1026_REG_FAN_DIV_0_3 0x02
+#define ADM1026_REG_FAN_DIV_4_7 0x03
+
+#define ADM1026_REG_DAC  0x04
+#define ADM1026_REG_PWM  0x05
+
+#define ADM1026_REG_GPIO_CFG_0_3 0x08
+#define ADM1026_REG_GPIO_CFG_4_7 0x09
+#define ADM1026_REG_GPIO_CFG_8_11 0x0a
+#define ADM1026_REG_GPIO_CFG_12_15 0x0b
+/* CFG_16 in REG_CFG3 */
+#define ADM1026_REG_GPIO_STATUS_0_7 0x24
+#define ADM1026_REG_GPIO_STATUS_8_15 0x25
+/* STATUS_16 in REG_STATUS4 */
+#define ADM1026_REG_GPIO_MASK_0_7 0x1c
+#define ADM1026_REG_GPIO_MASK_8_15 0x1d
+/* MASK_16 in REG_MASK4 */
+
+#define ADM1026_REG_COMPANY 0x16
+#define ADM1026_REG_VERSTEP 0x17
+/* These are the recognized values for the above regs */
+#define ADM1026_COMPANY_ANALOG_DEV 0x41
+#define ADM1026_VERSTEP_GENERIC 0x40
+#define ADM1026_VERSTEP_ADM1026 0x44
+
+#define ADM1026_REG_MASK1 0x18
+#define ADM1026_REG_MASK2 0x19
+#define ADM1026_REG_MASK3 0x1a
+#define ADM1026_REG_MASK4 0x1b
+
+#define ADM1026_REG_STATUS1 0x20
+#define ADM1026_REG_STATUS2 0x21
+#define ADM1026_REG_STATUS3 0x22
+#define ADM1026_REG_STATUS4 0x23
+
+#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6
+#define ADM1026_FAN_CONTROL_TEMP_RANGE 20
+#define ADM1026_PWM_MAX 255
+
+/* Conversions. Rounding and limit checking is only done on the TO_REG 
+ * variants. Note that you should be a bit careful with which arguments
+ * these macros are called: arguments may be evaluated more than once.
+ */
+
+/* IN are scaled acording to built-in resistors.  These are the
+ *   voltages corresponding to 3/4 of full scale (192 or 0xc0)
+ *   NOTE: The -12V input needs an additional factor to account
+ *      for the Vref pullup resistor.
+ *      NEG12_OFFSET = SCALE * Vref / V-192 - Vref
+ *                   = 13875 * 2.50 / 1.875 - 2500
+ *                   = 16000
+ *
+ * The values in this table are based on Table II, page 15 of the
+ *    datasheet.
+ */
+static int adm1026_scaling[] = {  /* .001 Volts */
+               2250, 2250, 2250, 2250, 2250, 2250, 
+               1875, 1875, 1875, 1875, 3000, 3330, 
+               3330, 4995, 2250, 12000, 13875
+       };
+#define NEG12_OFFSET  16000
+#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))
+#define INS_TO_REG(n,val)  (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\
+       0,255))
+#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n]))
+
+/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses
+ *   and we assume a 2 pulse-per-rev fan tach signal
+ *      22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000
+ */
+#define FAN_TO_REG(val,div)  ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\
+       (div)),1,254)) 
+#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\
+       (div)))
+#define DIV_FROM_REG(val) (1<<(val))
+#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0)
+
+/* Temperature is reported in 1 degC increments */
+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\
+       -127,127))
+#define TEMP_FROM_REG(val) ((val) * 1000)
+#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\
+       -127,127))
+#define OFFSET_FROM_REG(val) ((val) * 1000)
+
+#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
+#define PWM_FROM_REG(val) (val)
+
+#define PWM_MIN_TO_REG(val) ((val) & 0xf0)
+#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4))
+
+/* Analog output is a voltage, and scaled to millivolts.  The datasheet 
+ *   indicates that the DAC could be used to drive the fans, but in our 
+ *   example board (Arima HDAMA) it isn't connected to the fans at all.
+ */
+#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) 
+#define DAC_FROM_REG(val) (((val)*2500)/255)
+
+/* Typically used with systems using a v9.1 VRM spec ? */
+#define ADM1026_INIT_VRM  91
+
+/* Chip sampling rates
+ *
+ * Some sensors are not updated more frequently than once per second
+ *    so it doesn't make sense to read them more often than that.
+ *    We cache the results and return the saved data if the driver
+ *    is called again before a second has elapsed.
+ *
+ * Also, there is significant configuration data for this chip
+ *    So, we keep the config data up to date in the cache
+ *    when it is written and only sample it once every 5 *minutes*
+ */
+#define ADM1026_DATA_INTERVAL  (1 * HZ)
+#define ADM1026_CONFIG_INTERVAL  (5 * 60 * HZ)
+
+/* We allow for multiple chips in a single system.
+ *
+ * For each registered ADM1026, we need to keep state information
+ * at client->data. The adm1026_data structure is dynamically
+ * allocated, when a new client structure is allocated. */
+
+struct pwm_data {
+       u8 pwm;
+       u8 enable;
+       u8 auto_pwm_min;
+};
+
+struct adm1026_data {
+       struct i2c_client client;
+       struct semaphore lock;
+       enum chips type;
+
+       struct semaphore update_lock;
+       int valid;              /* !=0 if following fields are valid */
+       unsigned long last_reading;     /* In jiffies */
+       unsigned long last_config;      /* In jiffies */
+
+       u8 in[17];              /* Register value */
+       u8 in_max[17];          /* Register value */
+       u8 in_min[17];          /* Register value */
+       s8 temp[3];             /* Register value */
+       s8 temp_min[3];         /* Register value */
+       s8 temp_max[3];         /* Register value */
+       s8 temp_tmin[3];        /* Register value */
+       s8 temp_crit[3];        /* Register value */
+       s8 temp_offset[3];      /* Register value */
+       u8 fan[8];              /* Register value */
+       u8 fan_min[8];          /* Register value */
+       u8 fan_div[8];          /* Decoded value */
+       struct pwm_data pwm1;   /* Pwm control values */
+       int vid;                /* Decoded value */
+       u8 vrm;                 /* VRM version */
+       u8 analog_out;          /* Register value (DAC) */
+       long alarms;            /* Register encoding, combined */
+       long alarm_mask;        /* Register encoding, combined */
+       long gpio;              /* Register encoding, combined */
+       long gpio_mask;         /* Register encoding, combined */
+       u8 gpio_config[17];     /* Decoded value */
+       u8 config1;             /* Register value */
+       u8 config2;             /* Register value */
+       u8 config3;             /* Register value */
+};
+
+static int adm1026_attach_adapter(struct i2c_adapter *adapter);
+static int adm1026_detect(struct i2c_adapter *adapter, int address,
+       int kind);
+static int adm1026_detach_client(struct i2c_client *client);
+static int adm1026_read_value(struct i2c_client *client, u8 register);
+static int adm1026_write_value(struct i2c_client *client, u8 register,
+       int value); 
+static void adm1026_print_gpio(struct i2c_client *client);
+static void adm1026_fixup_gpio(struct i2c_client *client); 
+static struct adm1026_data *adm1026_update_device(struct device *dev);
+static void adm1026_init_client(struct i2c_client *client);
+
+
+static struct i2c_driver adm1026_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "adm1026",
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = adm1026_attach_adapter,
+       .detach_client  = adm1026_detach_client,
+};
+
+static int adm1026_id;
+
+int adm1026_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON)) {
+               return 0;
+       }
+       return i2c_detect(adapter, &addr_data, adm1026_detect);
+}
+
+int adm1026_detach_client(struct i2c_client *client)
+{
+       i2c_detach_client(client);
+       kfree(client);
+       return 0;
+}
+
+int adm1026_read_value(struct i2c_client *client, u8 reg)
+{
+       int res;
+
+       if (reg < 0x80) {
+               /* "RAM" locations */
+               res = i2c_smbus_read_byte_data(client, reg) & 0xff;
+       } else {
+               /* EEPROM, do nothing */
+               res = 0;
+       }
+       return res;
+}
+
+int adm1026_write_value(struct i2c_client *client, u8 reg, int value)
+{
+       int res;
+
+       if (reg < 0x80) {
+               /* "RAM" locations */
+               res = i2c_smbus_write_byte_data(client, reg, value);
+       } else {
+               /* EEPROM, do nothing */
+               res = 0;
+       }
+       return res;
+}
+
+void adm1026_init_client(struct i2c_client *client)
+{
+       int value, i;
+       struct adm1026_data *data = i2c_get_clientdata(client);
+
+        dev_dbg(&client->dev,"(%d): Initializing device\n", client->id);
+       /* Read chip config */
+       data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
+       data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
+       data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
+
+       /* Inform user of chip config */
+       dev_dbg(&client->dev, "(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n",
+               client->id, data->config1);
+       if ((data->config1 & CFG1_MONITOR) == 0) {
+               dev_dbg(&client->dev, "(%d): Monitoring not currently "
+                       "enabled.\n", client->id);
+       }
+       if (data->config1 & CFG1_INT_ENABLE) {
+               dev_dbg(&client->dev, "(%d): SMBALERT interrupts are "
+                       "enabled.\n", client->id);
+       }
+       if (data->config1 & CFG1_AIN8_9) {
+               dev_dbg(&client->dev, "(%d): in8 and in9 enabled. "
+                       "temp3 disabled.\n", client->id);
+       } else {
+               dev_dbg(&client->dev, "(%d): temp3 enabled.  in8 and "
+                       "in9 disabled.\n", client->id);
+       }
+       if (data->config1 & CFG1_THERM_HOT) {
+               dev_dbg(&client->dev, "(%d): Automatic THERM, PWM, "
+                       "and temp limits enabled.\n", client->id);
+       }
+
+       value = data->config3;
+       if (data->config3 & CFG3_GPIO16_ENABLE) {
+               dev_dbg(&client->dev, "(%d): GPIO16 enabled.  THERM"
+                       "pin disabled.\n", client->id);
+       } else {
+               dev_dbg(&client->dev, "(%d): THERM pin enabled.  "
+                       "GPIO16 disabled.\n", client->id);
+       }
+       if (data->config3 & CFG3_VREF_250) {
+               dev_dbg(&client->dev, "(%d): Vref is 2.50 Volts.\n",
+                       client->id);
+       } else {
+               dev_dbg(&client->dev, "(%d): Vref is 1.82 Volts.\n",
+                       client->id);
+       }
+       /* Read and pick apart the existing GPIO configuration */
+       value = 0;
+       for (i = 0;i <= 15;++i) {
+               if ((i & 0x03) == 0) {
+                       value = adm1026_read_value(client,
+                                       ADM1026_REG_GPIO_CFG_0_3 + i/4);
+               }
+               data->gpio_config[i] = value & 0x03;
+               value >>= 2;
+       }
+       data->gpio_config[16] = (data->config3 >> 6) & 0x03;
+
+       /* ... and then print it */
+       adm1026_print_gpio(client);
+
+       /* If the user asks us to reprogram the GPIO config, then
+        *   do it now.  But only if this is the first ADM1026.
+        */
+       if (client->id == 0
+           && (gpio_input[0] != -1 || gpio_output[0] != -1
+               || gpio_inverted[0] != -1 || gpio_normal[0] != -1
+               || gpio_fan[0] != -1)) {
+               adm1026_fixup_gpio(client);
+       }
+
+       /* WE INTENTIONALLY make no changes to the limits,
+        *   offsets, pwms, fans and zones.  If they were
+        *   configured, we don't want to mess with them.
+        *   If they weren't, the default is 100% PWM, no
+        *   control and will suffice until 'sensors -s'
+        *   can be run by the user.  We DO set the default 
+        *   value for pwm1.auto_pwm_min to its maximum
+        *   so that enabling automatic pwm fan control
+        *   without first setting a value for pwm1.auto_pwm_min 
+        *   will not result in potentially dangerous fan speed decrease.
+        */
+       data->pwm1.auto_pwm_min=255;
+       /* Start monitoring */
+       value = adm1026_read_value(client, ADM1026_REG_CONFIG1);
+       /* Set MONITOR, clear interrupt acknowledge and s/w reset */
+       value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET);
+       dev_dbg(&client->dev, "(%d): Setting CONFIG to: 0x%02x\n",
+               client->id, value);
+       data->config1 = value;
+       adm1026_write_value(client, ADM1026_REG_CONFIG1, value);
+}
+
+void adm1026_print_gpio(struct i2c_client *client)
+{
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int  i;
+
+       dev_dbg(&client->dev, "(%d): GPIO config is:",
+                           client->id);
+       for (i = 0;i <= 7;++i) {
+               if (data->config2 & (1 << i)) {
+                       dev_dbg(&client->dev, "\t(%d): %sGP%s%d\n", client->id,
+                               data->gpio_config[i] & 0x02 ? "" : "!",
+                               data->gpio_config[i] & 0x01 ? "OUT" : "IN",
+                               i);
+               } else {
+                       dev_dbg(&client->dev, "\t(%d): FAN%d\n",
+                               client->id, i);
+               }
+       }
+       for (i = 8;i <= 15;++i) {
+               dev_dbg(&client->dev, "\t(%d): %sGP%s%d\n", client->id,
+                       data->gpio_config[i] & 0x02 ? "" : "!",
+                       data->gpio_config[i] & 0x01 ? "OUT" : "IN",
+                       i);
+       }
+       if (data->config3 & CFG3_GPIO16_ENABLE) {
+               dev_dbg(&client->dev, "\t(%d): %sGP%s16\n", client->id,
+                       data->gpio_config[16] & 0x02 ? "" : "!",
+                       data->gpio_config[16] & 0x01 ? "OUT" : "IN");
+       } else {
+               /* GPIO16 is THERM  */
+               dev_dbg(&client->dev, "\t(%d): THERM\n", client->id);
+       }
+}
+
+void adm1026_fixup_gpio(struct i2c_client *client)
+{
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int  i;
+       int  value;
+
+       /* Make the changes requested. */
+       /* We may need to unlock/stop monitoring or soft-reset the
+        *    chip before we can make changes.  This hasn't been
+        *    tested much.  FIXME
+        */
+
+       /* Make outputs */
+       for (i = 0;i <= 16;++i) {
+               if (gpio_output[i] >= 0 && gpio_output[i] <= 16) {
+                       data->gpio_config[gpio_output[i]] |= 0x01;
+               }
+               /* if GPIO0-7 is output, it isn't a FAN tach */
+               if (gpio_output[i] >= 0 && gpio_output[i] <= 7) {
+                       data->config2 |= 1 << gpio_output[i];
+               }
+       }
+
+       /* Input overrides output */
+       for (i = 0;i <= 16;++i) {
+               if (gpio_input[i] >= 0 && gpio_input[i] <= 16) {
+                       data->gpio_config[gpio_input[i]] &= ~ 0x01;
+               }
+               /* if GPIO0-7 is input, it isn't a FAN tach */
+               if (gpio_input[i] >= 0 && gpio_input[i] <= 7) {
+                       data->config2 |= 1 << gpio_input[i];
+               }
+       }
+
+       /* Inverted  */
+       for (i = 0;i <= 16;++i) {
+               if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) {
+                       data->gpio_config[gpio_inverted[i]] &= ~ 0x02;
+               }
+       }
+
+       /* Normal overrides inverted  */
+       for (i = 0;i <= 16;++i) {
+               if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) {
+                       data->gpio_config[gpio_normal[i]] |= 0x02;
+               }
+       }
+
+       /* Fan overrides input and output */
+       for (i = 0;i <= 7;++i) {
+               if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) {
+                       data->config2 &= ~(1 << gpio_fan[i]);
+               }
+       }
+
+       /* Write new configs to registers */
+       adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2);
+       data->config3 = (data->config3 & 0x3f)
+                       | ((data->gpio_config[16] & 0x03) << 6);
+       adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3);
+       for (i = 15, value = 0;i >= 0;--i) {
+               value <<= 2;
+               value |= data->gpio_config[i] & 0x03;
+               if ((i & 0x03) == 0) {
+                       adm1026_write_value(client,
+                                       ADM1026_REG_GPIO_CFG_0_3 + i/4,
+                                       value);
+                       value = 0;
+               }
+       }
+
+       /* Print the new config */
+       adm1026_print_gpio(client);
+}
+
+
+static struct adm1026_data *adm1026_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int i;
+       long value, alarms, gpio;
+
+       down(&data->update_lock);
+       if (!data->valid
+           || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL)) {
+               /* Things that change quickly */
+               dev_dbg(&client->dev,"(%d): Reading sensor values\n", 
+                       client->id);
+               for (i = 0;i <= 16;++i) {
+                       data->in[i] =
+                           adm1026_read_value(client, ADM1026_REG_IN[i]);
+               }
+
+               for (i = 0;i <= 7;++i) {
+                       data->fan[i] =
+                           adm1026_read_value(client, ADM1026_REG_FAN(i));
+               }
+
+               for (i = 0;i <= 2;++i) {
+                       /* NOTE: temp[] is s8 and we assume 2's complement
+                        *   "conversion" in the assignment   */
+                       data->temp[i] =
+                           adm1026_read_value(client, ADM1026_REG_TEMP[i]);
+               }
+
+               data->pwm1.pwm = adm1026_read_value(client, 
+                       ADM1026_REG_PWM);
+               data->analog_out = adm1026_read_value(client, 
+                       ADM1026_REG_DAC);
+               /* GPIO16 is MSbit of alarms, move it to gpio */
+               alarms = adm1026_read_value(client, ADM1026_REG_STATUS4);
+               gpio = alarms & 0x80 ? 0x0100 : 0;  /* GPIO16 */
+               alarms &= 0x7f;
+               alarms <<= 8;
+               alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3);
+               alarms <<= 8;
+               alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2);
+               alarms <<= 8;
+               alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1);
+               data->alarms = alarms;
+
+               /* Read the GPIO values */
+               gpio |= adm1026_read_value(client, 
+                       ADM1026_REG_GPIO_STATUS_8_15);
+               gpio <<= 8;
+               gpio |= adm1026_read_value(client, 
+                       ADM1026_REG_GPIO_STATUS_0_7);
+               data->gpio = gpio;
+
+               data->last_reading = jiffies;
+       };  /* last_reading */
+
+       if (!data->valid || (jiffies - data->last_config > 
+               ADM1026_CONFIG_INTERVAL)) {
+               /* Things that don't change often */
+               dev_dbg(&client->dev, "(%d): Reading config values\n", 
+                       client->id);
+               for (i = 0;i <= 16;++i) {
+                       data->in_min[i] = adm1026_read_value(client, 
+                               ADM1026_REG_IN_MIN[i]);
+                       data->in_max[i] = adm1026_read_value(client, 
+                               ADM1026_REG_IN_MAX[i]);
+               }
+
+               value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3)
+                       | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7)
+                       << 8);
+               for (i = 0;i <= 7;++i) {
+                       data->fan_min[i] = adm1026_read_value(client, 
+                               ADM1026_REG_FAN_MIN(i));
+                       data->fan_div[i] = DIV_FROM_REG(value & 0x03);
+                       value >>= 2;
+               }
+
+               for (i = 0; i <= 2; ++i) {
+                       /* NOTE: temp_xxx[] are s8 and we assume 2's 
+                        *    complement "conversion" in the assignment
+                        */
+                       data->temp_min[i] = adm1026_read_value(client, 
+                               ADM1026_REG_TEMP_MIN[i]);
+                       data->temp_max[i] = adm1026_read_value(client, 
+                               ADM1026_REG_TEMP_MAX[i]);
+                       data->temp_tmin[i] = adm1026_read_value(client, 
+                               ADM1026_REG_TEMP_TMIN[i]);
+                       data->temp_crit[i] = adm1026_read_value(client, 
+                               ADM1026_REG_TEMP_THERM[i]);
+                       data->temp_offset[i] = adm1026_read_value(client, 
+                               ADM1026_REG_TEMP_OFFSET[i]);
+               }
+
+               /* Read the STATUS/alarm masks */
+               alarms  = adm1026_read_value(client, ADM1026_REG_MASK4);
+               gpio    = alarms & 0x80 ? 0x0100 : 0;  /* GPIO16 */
+               alarms  = (alarms & 0x7f) << 8;
+               alarms |= adm1026_read_value(client, ADM1026_REG_MASK3);
+               alarms <<= 8;
+               alarms |= adm1026_read_value(client, ADM1026_REG_MASK2);
+               alarms <<= 8;
+               alarms |= adm1026_read_value(client, ADM1026_REG_MASK1);
+               data->alarm_mask = alarms;
+
+               /* Read the GPIO values */
+               gpio |= adm1026_read_value(client, 
+                       ADM1026_REG_GPIO_MASK_8_15);
+               gpio <<= 8;
+               gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7);
+               data->gpio_mask = gpio;
+
+               /* Read various values from CONFIG1 */
+               data->config1 = adm1026_read_value(client, 
+                       ADM1026_REG_CONFIG1);
+               if (data->config1 & CFG1_PWM_AFC) {
+                       data->pwm1.enable = 2;
+                       data->pwm1.auto_pwm_min = 
+                               PWM_MIN_FROM_REG(data->pwm1.pwm);
+               }
+               /* Read the GPIO config */
+               data->config2 = adm1026_read_value(client, 
+                       ADM1026_REG_CONFIG2);
+               data->config3 = adm1026_read_value(client, 
+                       ADM1026_REG_CONFIG3);
+               data->gpio_config[16] = (data->config3 >> 6) & 0x03;
+
+               value = 0;
+               for (i = 0;i <= 15;++i) {
+                       if ((i & 0x03) == 0) {
+                               value = adm1026_read_value(client,
+                                           ADM1026_REG_GPIO_CFG_0_3 + i/4);
+                       }
+                       data->gpio_config[i] = value & 0x03;
+                       value >>= 2;
+               }
+
+               data->last_config = jiffies;
+       };  /* last_config */
+
+       dev_dbg(&client->dev, "(%d): Setting VID from GPIO11-15.\n", 
+               client->id);
+       data->vid = (data->gpio >> 11) & 0x1f;
+       data->valid = 1;
+       up(&data->update_lock);
+       return data;
+}
+
+static ssize_t show_in(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr]));
+}
+static ssize_t show_in_min(struct device *dev, char *buf, int nr) 
+{
+       struct adm1026_data *data = adm1026_update_device(dev); 
+       return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]));
+}
+static ssize_t set_in_min(struct device *dev, const char *buf, 
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->in_min[nr] = INS_TO_REG(nr, val);
+       adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]);
+       up(&data->update_lock);
+       return count; 
+}
+static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]));
+}
+static ssize_t set_in_max(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->in_max[nr] = INS_TO_REG(nr, val);
+       adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]);
+       up(&data->update_lock);
+       return count;
+}
+
+#define in_reg(offset)                                                    \
+static ssize_t show_in##offset (struct device *dev, char *buf)            \
+{                                                                         \
+       return show_in(dev, buf, offset);                                 \
+}                                                                         \
+static ssize_t show_in##offset##_min (struct device *dev, char *buf)      \
+{                                                                         \
+       return show_in_min(dev, buf, offset);                             \
+}                                                                         \
+static ssize_t set_in##offset##_min (struct device *dev,                  \
+       const char *buf, size_t count)                                    \
+{                                                                         \
+       return set_in_min(dev, buf, count, offset);                       \
+}                                                                         \
+static ssize_t show_in##offset##_max (struct device *dev, char *buf)      \
+{                                                                         \
+       return show_in_max(dev, buf, offset);                             \
+}                                                                         \
+static ssize_t set_in##offset##_max (struct device *dev,                  \
+       const char *buf, size_t count)                                    \
+{                                                                         \
+       return set_in_max(dev, buf, count, offset);                       \
+}                                                                         \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);   \
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,                   \
+               show_in##offset##_min, set_in##offset##_min);             \
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,                   \
+               show_in##offset##_max, set_in##offset##_max);
+
+
+in_reg(0);
+in_reg(1);
+in_reg(2);
+in_reg(3);
+in_reg(4);
+in_reg(5);
+in_reg(6);
+in_reg(7);
+in_reg(8);
+in_reg(9);
+in_reg(10);
+in_reg(11);
+in_reg(12);
+in_reg(13);
+in_reg(14);
+in_reg(15);
+
+static ssize_t show_in16(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) -
+               NEG12_OFFSET);
+}
+static ssize_t show_in16_min(struct device *dev, char *buf) 
+{
+       struct adm1026_data *data = adm1026_update_device(dev); 
+       return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16])
+               - NEG12_OFFSET);
+}
+static ssize_t set_in16_min(struct device *dev, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
+       adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]);
+       up(&data->update_lock);
+       return count; 
+}
+static ssize_t show_in16_max(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16])
+                       - NEG12_OFFSET);
+}
+static ssize_t set_in16_max(struct device *dev, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET);
+       adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]);
+       up(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL);
+static DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min);
+static DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max);
+
+
+
+
+/* Now add fan read/write functions */
+
+static ssize_t show_fan(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
+               data->fan_div[nr]));
+}
+static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
+               data->fan_div[nr]));
+}
+static ssize_t set_fan_min(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]);
+       adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr),
+               data->fan_min[nr]);
+       up(&data->update_lock);
+       return count;
+}
+
+#define fan_offset(offset)                                                  \
+static ssize_t show_fan_##offset (struct device *dev, char *buf)            \
+{                                                                           \
+       return show_fan(dev, buf, offset - 1);                              \
+}                                                                           \
+static ssize_t show_fan_##offset##_min (struct device *dev, char *buf)      \
+{                                                                           \
+       return show_fan_min(dev, buf, offset - 1);                          \
+}                                                                           \
+static ssize_t set_fan_##offset##_min (struct device *dev,                  \
+       const char *buf, size_t count)                                      \
+{                                                                           \
+       return set_fan_min(dev, buf, count, offset - 1);                    \
+}                                                                           \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);  \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,                    \
+               show_fan_##offset##_min, set_fan_##offset##_min);
+
+fan_offset(1);
+fan_offset(2);
+fan_offset(3);
+fan_offset(4);
+fan_offset(5);
+fan_offset(6);
+fan_offset(7);
+fan_offset(8);
+
+/* Adjust fan_min to account for new fan divisor */
+static void fixup_fan_min(struct device *dev, int fan, int old_div)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int    new_min;
+       int    new_div = data->fan_div[fan];
+
+       /* 0 and 0xff are special.  Don't adjust them */
+       if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) {
+               return;
+       }
+
+       new_min = data->fan_min[fan] * old_div / new_div;
+       new_min = SENSORS_LIMIT(new_min, 1, 254);
+       data->fan_min[fan] = new_min;
+       adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min);
+}
+
+/* Now add fan_div read/write functions */
+static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", data->fan_div[nr]);
+}
+static ssize_t set_fan_div(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int    val,orig_div,new_div,shift;
+
+       val = simple_strtol(buf, NULL, 10);
+       new_div = DIV_TO_REG(val); 
+       if (new_div == 0) {
+               return -EINVAL;
+       }
+       down(&data->update_lock);
+       orig_div = data->fan_div[nr];
+       data->fan_div[nr] = DIV_FROM_REG(new_div);
+
+       if (nr < 4) { /* 0 <= nr < 4 */
+               shift = 2 * nr;
+               adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
+                       ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) |
+                       (new_div << shift)));
+       } else { /* 3 < nr < 8 */
+               shift = 2 * (nr - 4);
+               adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
+                       ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) |
+                       (new_div << shift)));
+       }
+
+       if (data->fan_div[nr] != orig_div) {
+               fixup_fan_min(dev,nr,orig_div);
+       }
+       up(&data->update_lock);
+       return count;
+}
+
+#define fan_offset_div(offset)                                          \
+static ssize_t show_fan_##offset##_div (struct device *dev, char *buf)  \
+{                                                                       \
+       return show_fan_div(dev, buf, offset - 1);                      \
+}                                                                       \
+static ssize_t set_fan_##offset##_div (struct device *dev,              \
+       const char *buf, size_t count)                                  \
+{                                                                       \
+       return set_fan_div(dev, buf, count, offset - 1);                \
+}                                                                       \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,                \
+               show_fan_##offset##_div, set_fan_##offset##_div);
+
+fan_offset_div(1);
+fan_offset_div(2);
+fan_offset_div(3);
+fan_offset_div(4);
+fan_offset_div(5);
+fan_offset_div(6);
+fan_offset_div(7);
+fan_offset_div(8);
+
+/* Temps */
+static ssize_t show_temp(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]));
+}
+static ssize_t set_temp_min(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->temp_min[nr] = TEMP_TO_REG(val);
+       adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr],
+               data->temp_min[nr]);
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]));
+}
+static ssize_t set_temp_max(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->temp_max[nr] = TEMP_TO_REG(val);
+       adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr],
+               data->temp_max[nr]);
+       up(&data->update_lock);
+       return count;
+}
+#define temp_reg(offset)                                                      \
+static ssize_t show_temp_##offset (struct device *dev, char *buf)             \
+{                                                                             \
+       return show_temp(dev, buf, offset - 1);                               \
+}                                                                             \
+static ssize_t show_temp_##offset##_min (struct device *dev, char *buf)       \
+{                                                                             \
+       return show_temp_min(dev, buf, offset - 1);                           \
+}                                                                             \
+static ssize_t show_temp_##offset##_max (struct device *dev, char *buf)       \
+{                                                                             \
+       return show_temp_max(dev, buf, offset - 1);                           \
+}                                                                             \
+static ssize_t set_temp_##offset##_min (struct device *dev,                   \
+       const char *buf, size_t count)                                        \
+{                                                                             \
+       return set_temp_min(dev, buf, count, offset - 1);                     \
+}                                                                             \
+static ssize_t set_temp_##offset##_max (struct device *dev,                   \
+       const char *buf, size_t count)                                        \
+{                                                                             \
+       return set_temp_max(dev, buf, count, offset - 1);                     \
+}                                                                             \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);  \
+static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,                     \
+               show_temp_##offset##_min, set_temp_##offset##_min);           \
+static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,                     \
+               show_temp_##offset##_max, set_temp_##offset##_max);
+
+
+temp_reg(1);
+temp_reg(2);
+temp_reg(3);
+
+static ssize_t show_temp_offset(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr]));
+}
+static ssize_t set_temp_offset(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->temp_offset[nr] = TEMP_TO_REG(val);
+       adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr],
+               data->temp_offset[nr]);
+       up(&data->update_lock);
+       return count;
+}
+
+#define temp_offset_reg(offset)                                             \
+static ssize_t show_temp_##offset##_offset (struct device *dev, char *buf)  \
+{                                                                           \
+       return show_temp_offset(dev, buf, offset - 1);                      \
+}                                                                           \
+static ssize_t set_temp_##offset##_offset (struct device *dev,              \
+       const char *buf, size_t count)                                      \
+{                                                                           \
+       return set_temp_offset(dev, buf, count, offset - 1);                \
+}                                                                           \
+static DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR,                \
+               show_temp_##offset##_offset, set_temp_##offset##_offset);
+
+temp_offset_reg(1);
+temp_offset_reg(2);
+temp_offset_reg(3);
+
+static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, char *buf,
+               int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(
+               ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr]));
+}
+static ssize_t show_temp_auto_point2_temp(struct device *dev, char *buf,
+               int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] +
+               ADM1026_FAN_CONTROL_TEMP_RANGE));
+}
+static ssize_t show_temp_auto_point1_temp(struct device *dev, char *buf,
+               int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr]));
+}
+static ssize_t set_temp_auto_point1_temp(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->temp_tmin[nr] = TEMP_TO_REG(val);
+       adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr],
+               data->temp_tmin[nr]);
+       up(&data->update_lock);
+       return count;
+}
+
+#define temp_auto_point(offset)                                             \
+static ssize_t show_temp##offset##_auto_point1_temp (struct device *dev,    \
+       char *buf)                                                          \
+{                                                                           \
+       return show_temp_auto_point1_temp(dev, buf, offset - 1);            \
+}                                                                           \
+static ssize_t set_temp##offset##_auto_point1_temp (struct device *dev,     \
+       const char *buf, size_t count)                                      \
+{                                                                           \
+       return set_temp_auto_point1_temp(dev, buf, count, offset - 1);      \
+}                                                                           \
+static ssize_t show_temp##offset##_auto_point1_temp_hyst (struct device     \
+       *dev, char *buf)                                                    \
+{                                                                           \
+       return show_temp_auto_point1_temp_hyst(dev, buf, offset - 1);       \
+}                                                                           \
+static ssize_t show_temp##offset##_auto_point2_temp (struct device *dev,    \
+        char *buf)                                                         \
+{                                                                           \
+       return show_temp_auto_point2_temp(dev, buf, offset - 1);            \
+}                                                                           \
+static DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR,      \
+               show_temp##offset##_auto_point1_temp,                       \
+               set_temp##offset##_auto_point1_temp);                       \
+static DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO,           \
+               show_temp##offset##_auto_point1_temp_hyst, NULL);           \
+static DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO,                \
+               show_temp##offset##_auto_point2_temp, NULL);
+
+temp_auto_point(1);
+temp_auto_point(2);
+temp_auto_point(3);
+
+static ssize_t show_temp_crit_enable(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4);
+}
+static ssize_t set_temp_crit_enable(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       val = simple_strtol(buf, NULL, 10);
+       if ((val == 1) || (val==0)) {
+               down(&data->update_lock);
+               data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4);
+               adm1026_write_value(client, ADM1026_REG_CONFIG1, 
+                       data->config1);
+               up(&data->update_lock);
+       }
+       return count;
+}
+
+static DEVICE_ATTR(temp1_crit_enable, S_IRUGO | S_IWUSR, 
+       show_temp_crit_enable, set_temp_crit_enable);
+
+static DEVICE_ATTR(temp2_crit_enable, S_IRUGO | S_IWUSR, 
+       show_temp_crit_enable, set_temp_crit_enable);
+
+static DEVICE_ATTR(temp3_crit_enable, S_IRUGO | S_IWUSR, 
+       show_temp_crit_enable, set_temp_crit_enable);
+
+
+static ssize_t show_temp_crit(struct device *dev, char *buf, int nr)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
+}
+static ssize_t set_temp_crit(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->temp_crit[nr] = TEMP_TO_REG(val);
+       adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr],
+               data->temp_crit[nr]);
+       up(&data->update_lock);
+       return count;
+}
+
+#define temp_crit_reg(offset)                                             \
+static ssize_t show_temp_##offset##_crit (struct device *dev, char *buf)  \
+{                                                                         \
+       return show_temp_crit(dev, buf, offset - 1);                      \
+}                                                                         \
+static ssize_t set_temp_##offset##_crit (struct device *dev,              \
+       const char *buf, size_t count)                                    \
+{                                                                         \
+       return set_temp_crit(dev, buf, count, offset - 1);                \
+}                                                                         \
+static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR,                \
+               show_temp_##offset##_crit, set_temp_##offset##_crit);
+
+temp_crit_reg(1);
+temp_crit_reg(2);
+temp_crit_reg(3);
+
+static ssize_t show_analog_out_reg(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out));
+}
+static ssize_t set_analog_out_reg(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->analog_out = DAC_TO_REG(val);
+       adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out);
+       up(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, 
+       set_analog_out_reg);
+
+static ssize_t show_vid_reg(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm));
+}
+
+static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL);
+
+static ssize_t show_vrm_reg(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", data->vrm);
+}
+static ssize_t store_vrm_reg(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+
+       data->vrm = simple_strtol(buf, NULL, 10);
+       return count;
+}
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
+static ssize_t show_alarms_reg(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf, "%ld\n", (long) (data->alarms));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
+static ssize_t show_alarm_mask(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%ld\n", data->alarm_mask);
+}
+static ssize_t set_alarm_mask(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+       unsigned long mask;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->alarm_mask = val & 0x7fffffff;
+       mask = data->alarm_mask
+               | (data->gpio_mask & 0x10000 ? 0x80000000 : 0);
+       adm1026_write_value(client, ADM1026_REG_MASK1,
+               mask & 0xff);
+       mask >>= 8;
+       adm1026_write_value(client, ADM1026_REG_MASK2,
+               mask & 0xff);
+       mask >>= 8;
+       adm1026_write_value(client, ADM1026_REG_MASK3,
+               mask & 0xff);
+       mask >>= 8;
+       adm1026_write_value(client, ADM1026_REG_MASK4,
+               mask & 0xff);
+       up(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask,
+       set_alarm_mask);
+
+
+static ssize_t show_gpio(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%ld\n", data->gpio);
+}
+static ssize_t set_gpio(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+       long   gpio;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->gpio = val & 0x1ffff;
+       gpio = data->gpio;
+       adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff);
+       gpio >>= 8;
+       adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff);
+       gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f);
+       adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff);
+       up(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio);
+
+
+static ssize_t show_gpio_mask(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%ld\n", data->gpio_mask);
+}
+static ssize_t set_gpio_mask(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+       long   mask;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->gpio_mask = val & 0x1ffff;
+       mask = data->gpio_mask;
+       adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff);
+       mask >>= 8;
+       adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff);
+       mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f);
+       adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff);
+       up(&data->update_lock);
+       return count;
+}
+
+static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask);
+
+static ssize_t show_pwm_reg(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm));
+}
+static ssize_t set_pwm_reg(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       if (data->pwm1.enable == 1) {
+               down(&data->update_lock);
+               val = simple_strtol(buf, NULL, 10);
+               data->pwm1.pwm = PWM_TO_REG(val);
+               adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
+               up(&data->update_lock);
+       }
+       return count;
+}
+static ssize_t show_auto_pwm_min(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min);
+}
+static ssize_t set_auto_pwm_min(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+
+       down(&data->update_lock);
+       val = simple_strtol(buf, NULL, 10);
+       data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255);
+       if (data->pwm1.enable == 2) { /* apply immediately */
+               data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
+                       PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); 
+               adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm);
+       }
+       up(&data->update_lock);
+       return count;
+}
+static ssize_t show_auto_pwm_max(struct device *dev, char *buf)
+{
+       return sprintf(buf,"%d\n", ADM1026_PWM_MAX);
+}
+static ssize_t show_pwm_enable(struct device *dev, char *buf)
+{
+       struct adm1026_data *data = adm1026_update_device(dev);
+       return sprintf(buf,"%d\n", data->pwm1.enable);
+}
+static ssize_t set_pwm_enable(struct device *dev, const char *buf,
+               size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adm1026_data *data = i2c_get_clientdata(client);
+       int     val;
+       int     old_enable;
+
+       val = simple_strtol(buf, NULL, 10);
+       if ((val >= 0) && (val < 3)) {
+               down(&data->update_lock);
+               old_enable = data->pwm1.enable;
+               data->pwm1.enable = val;
+               data->config1 = (data->config1 & ~CFG1_PWM_AFC)
+                               | ((val == 2) ? CFG1_PWM_AFC : 0);
+               adm1026_write_value(client, ADM1026_REG_CONFIG1,
+                       data->config1);
+               if (val == 2) {  /* apply pwm1_auto_pwm_min to pwm1 */
+                       data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) |
+                               PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); 
+                       adm1026_write_value(client, ADM1026_REG_PWM, 
+                               data->pwm1.pwm);
+               } else if (!((old_enable == 1) && (val == 1))) {
+                       /* set pwm to safe value */
+                       data->pwm1.pwm = 255;
+                       adm1026_write_value(client, ADM1026_REG_PWM, 
+                               data->pwm1.pwm);
+               }
+               up(&data->update_lock);
+       }
+       return count;
+}
+
+/* enable PWM fan control */
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); 
+static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); 
+static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); 
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, 
+       set_pwm_enable);
+static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, 
+       set_pwm_enable);
+static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, 
+       set_pwm_enable);
+static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, 
+       show_auto_pwm_min, set_auto_pwm_min);
+static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, 
+       show_auto_pwm_min, set_auto_pwm_min);
+static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, 
+       show_auto_pwm_min, set_auto_pwm_min);
+
+static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+
+int adm1026_detect(struct i2c_adapter *adapter, int address,
+               int kind)
+{
+       int company, verstep;
+       struct i2c_client *new_client;
+       struct adm1026_data *data;
+       int err = 0;
+       const char *type_name = "";
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               /* We need to be able to do byte I/O */
+               goto exit;
+       };
+
+       /* OK. For now, we presume we have a valid client. We now create the
+          client structure, even though we cannot fill it completely yet.
+          But it allows us to access adm1026_{read,write}_value. */
+
+       if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       memset(data, 0, sizeof(struct adm1026_data));
+
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &adm1026_driver;
+       new_client->flags = 0;
+
+       /* Now, we do the remaining detection. */
+
+       company = adm1026_read_value(new_client, ADM1026_REG_COMPANY);
+       verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP);
+
+       dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with"
+               " COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+               i2c_adapter_id(new_client->adapter), new_client->addr,
+               company, verstep);
+
+       /* If auto-detecting, Determine the chip type. */
+       if (kind <= 0) {
+               dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x "
+                       "...\n", i2c_adapter_id(adapter), address);
+               if (company == ADM1026_COMPANY_ANALOG_DEV
+                   && verstep == ADM1026_VERSTEP_ADM1026) {
+                       kind = adm1026;
+               } else if (company == ADM1026_COMPANY_ANALOG_DEV
+                       && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
+                       dev_err(&adapter->dev, ": Unrecognized stepping "
+                               "0x%02x. Defaulting to ADM1026.\n", verstep);
+                       kind = adm1026;
+               } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
+                       dev_err(&adapter->dev, ": Found version/stepping "
+                               "0x%02x. Assuming generic ADM1026.\n",
+                               verstep);
+                       kind = any_chip;
+               } else {
+                       dev_dbg(&new_client->dev, ": Autodetection "
+                               "failed\n");
+                       /* Not an ADM1026 ... */
+                       if (kind == 0)  { /* User used force=x,y */
+                               dev_err(&adapter->dev, "Generic ADM1026 not "
+                                       "found at %d,0x%02x.  Try "
+                                       "force_adm1026.\n",
+                                       i2c_adapter_id(adapter), address);
+                       }
+                       err = 0;
+                       goto exitfree;
+               }
+       }
+
+       /* Fill in the chip specific driver values */
+       switch (kind) {
+       case any_chip :
+               type_name = "adm1026";
+               break;
+       case adm1026 :
+               type_name = "adm1026";
+               break;
+       default :
+               dev_err(&adapter->dev, ": Internal error, invalid "
+                       "kind (%d)!", kind);
+               err = -EFAULT;
+               goto exitfree;
+       }
+       strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
+
+       /* Fill in the remaining client fields */
+       new_client->id = adm1026_id++;
+       data->type = kind;
+       data->valid = 0;
+       init_MUTEX(&data->update_lock);
+
+       dev_dbg(&new_client->dev, "(%d): Assigning ID %d to %s at %d,0x%02x\n",
+               new_client->id, new_client->id, new_client->name,
+               i2c_adapter_id(new_client->adapter),
+               new_client->addr);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(new_client)))
+               goto exitfree;
+
+       /* Set the VRM version */
+       data->vrm = i2c_which_vrm();
+
+       /* Initialize the ADM1026 chip */
+       adm1026_init_client(new_client);
+
+       /* Register sysfs hooks */
+       device_create_file(&new_client->dev, &dev_attr_in0_input);
+       device_create_file(&new_client->dev, &dev_attr_in0_max);
+       device_create_file(&new_client->dev, &dev_attr_in0_min);
+       device_create_file(&new_client->dev, &dev_attr_in1_input);
+       device_create_file(&new_client->dev, &dev_attr_in1_max);
+       device_create_file(&new_client->dev, &dev_attr_in1_min);
+       device_create_file(&new_client->dev, &dev_attr_in2_input);
+       device_create_file(&new_client->dev, &dev_attr_in2_max);
+       device_create_file(&new_client->dev, &dev_attr_in2_min);
+       device_create_file(&new_client->dev, &dev_attr_in3_input);
+       device_create_file(&new_client->dev, &dev_attr_in3_max);
+       device_create_file(&new_client->dev, &dev_attr_in3_min);
+       device_create_file(&new_client->dev, &dev_attr_in4_input);
+       device_create_file(&new_client->dev, &dev_attr_in4_max);
+       device_create_file(&new_client->dev, &dev_attr_in4_min);
+       device_create_file(&new_client->dev, &dev_attr_in5_input);
+       device_create_file(&new_client->dev, &dev_attr_in5_max);
+       device_create_file(&new_client->dev, &dev_attr_in5_min);
+       device_create_file(&new_client->dev, &dev_attr_in6_input);
+       device_create_file(&new_client->dev, &dev_attr_in6_max);
+       device_create_file(&new_client->dev, &dev_attr_in6_min);
+       device_create_file(&new_client->dev, &dev_attr_in7_input);
+       device_create_file(&new_client->dev, &dev_attr_in7_max);
+       device_create_file(&new_client->dev, &dev_attr_in7_min);
+       device_create_file(&new_client->dev, &dev_attr_in8_input);
+       device_create_file(&new_client->dev, &dev_attr_in8_max);
+       device_create_file(&new_client->dev, &dev_attr_in8_min);
+       device_create_file(&new_client->dev, &dev_attr_in9_input);
+       device_create_file(&new_client->dev, &dev_attr_in9_max);
+       device_create_file(&new_client->dev, &dev_attr_in9_min);
+       device_create_file(&new_client->dev, &dev_attr_in10_input);
+       device_create_file(&new_client->dev, &dev_attr_in10_max);
+       device_create_file(&new_client->dev, &dev_attr_in10_min);
+       device_create_file(&new_client->dev, &dev_attr_in11_input);
+       device_create_file(&new_client->dev, &dev_attr_in11_max);
+       device_create_file(&new_client->dev, &dev_attr_in11_min);
+       device_create_file(&new_client->dev, &dev_attr_in12_input);
+       device_create_file(&new_client->dev, &dev_attr_in12_max);
+       device_create_file(&new_client->dev, &dev_attr_in12_min);
+       device_create_file(&new_client->dev, &dev_attr_in13_input);
+       device_create_file(&new_client->dev, &dev_attr_in13_max);
+       device_create_file(&new_client->dev, &dev_attr_in13_min);
+       device_create_file(&new_client->dev, &dev_attr_in14_input);
+       device_create_file(&new_client->dev, &dev_attr_in14_max);
+       device_create_file(&new_client->dev, &dev_attr_in14_min);
+       device_create_file(&new_client->dev, &dev_attr_in15_input);
+       device_create_file(&new_client->dev, &dev_attr_in15_max);
+       device_create_file(&new_client->dev, &dev_attr_in15_min);
+       device_create_file(&new_client->dev, &dev_attr_in16_input);
+       device_create_file(&new_client->dev, &dev_attr_in16_max);
+       device_create_file(&new_client->dev, &dev_attr_in16_min);
+       device_create_file(&new_client->dev, &dev_attr_fan1_input);
+       device_create_file(&new_client->dev, &dev_attr_fan1_div);
+       device_create_file(&new_client->dev, &dev_attr_fan1_min);
+       device_create_file(&new_client->dev, &dev_attr_fan2_input);
+       device_create_file(&new_client->dev, &dev_attr_fan2_div);
+       device_create_file(&new_client->dev, &dev_attr_fan2_min);
+       device_create_file(&new_client->dev, &dev_attr_fan3_input);
+       device_create_file(&new_client->dev, &dev_attr_fan3_div);
+       device_create_file(&new_client->dev, &dev_attr_fan3_min);
+       device_create_file(&new_client->dev, &dev_attr_fan4_input);
+       device_create_file(&new_client->dev, &dev_attr_fan4_div);
+       device_create_file(&new_client->dev, &dev_attr_fan4_min);
+       device_create_file(&new_client->dev, &dev_attr_fan5_input);
+       device_create_file(&new_client->dev, &dev_attr_fan5_div);
+       device_create_file(&new_client->dev, &dev_attr_fan5_min);
+       device_create_file(&new_client->dev, &dev_attr_fan6_input);
+       device_create_file(&new_client->dev, &dev_attr_fan6_div);
+       device_create_file(&new_client->dev, &dev_attr_fan6_min);
+       device_create_file(&new_client->dev, &dev_attr_fan7_input);
+       device_create_file(&new_client->dev, &dev_attr_fan7_div);
+       device_create_file(&new_client->dev, &dev_attr_fan7_min);
+       device_create_file(&new_client->dev, &dev_attr_fan8_input);
+       device_create_file(&new_client->dev, &dev_attr_fan8_div);
+       device_create_file(&new_client->dev, &dev_attr_fan8_min);
+       device_create_file(&new_client->dev, &dev_attr_temp1_input);
+       device_create_file(&new_client->dev, &dev_attr_temp1_max);
+       device_create_file(&new_client->dev, &dev_attr_temp1_min);
+       device_create_file(&new_client->dev, &dev_attr_temp2_input);
+       device_create_file(&new_client->dev, &dev_attr_temp2_max);
+       device_create_file(&new_client->dev, &dev_attr_temp2_min);
+       device_create_file(&new_client->dev, &dev_attr_temp3_input);
+       device_create_file(&new_client->dev, &dev_attr_temp3_max);
+       device_create_file(&new_client->dev, &dev_attr_temp3_min);
+       device_create_file(&new_client->dev, &dev_attr_temp1_offset);
+       device_create_file(&new_client->dev, &dev_attr_temp2_offset);
+       device_create_file(&new_client->dev, &dev_attr_temp3_offset);
+       device_create_file(&new_client->dev, 
+               &dev_attr_temp1_auto_point1_temp);
+       device_create_file(&new_client->dev, 
+               &dev_attr_temp2_auto_point1_temp);
+       device_create_file(&new_client->dev, 
+               &dev_attr_temp3_auto_point1_temp);
+       device_create_file(&new_client->dev,
+               &dev_attr_temp1_auto_point1_temp_hyst);
+       device_create_file(&new_client->dev,
+               &dev_attr_temp2_auto_point1_temp_hyst);
+       device_create_file(&new_client->dev,
+               &dev_attr_temp3_auto_point1_temp_hyst);
+       device_create_file(&new_client->dev, 
+               &dev_attr_temp1_auto_point2_temp);
+       device_create_file(&new_client->dev, 
+               &dev_attr_temp2_auto_point2_temp);
+       device_create_file(&new_client->dev, 
+               &dev_attr_temp3_auto_point2_temp);
+       device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+       device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+       device_create_file(&new_client->dev, &dev_attr_temp3_crit);
+       device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
+       device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
+       device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
+       device_create_file(&new_client->dev, &dev_attr_vid);
+       device_create_file(&new_client->dev, &dev_attr_vrm);
+       device_create_file(&new_client->dev, &dev_attr_alarms);
+       device_create_file(&new_client->dev, &dev_attr_alarm_mask);
+       device_create_file(&new_client->dev, &dev_attr_gpio);
+       device_create_file(&new_client->dev, &dev_attr_gpio_mask);
+       device_create_file(&new_client->dev, &dev_attr_pwm1);
+       device_create_file(&new_client->dev, &dev_attr_pwm2);
+       device_create_file(&new_client->dev, &dev_attr_pwm3);
+       device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+       device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
+       device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
+       device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm);
+       device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm);
+       device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm);
+       device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm);
+       device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm);
+       device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm);
+       device_create_file(&new_client->dev, &dev_attr_analog_out);
+       return 0;
+
+       /* Error out and cleanup code */
+exitfree:
+       kfree(new_client);
+exit:
+       return err;
+}
+static int __init sm_adm1026_init(void)
+{
+       return i2c_add_driver(&adm1026_driver);
+}
+
+static void  __exit sm_adm1026_exit(void)
+{
+       i2c_del_driver(&adm1026_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, "
+              "Justin Thiessen <jthiessen@penguincomputing.com>");
+MODULE_DESCRIPTION("ADM1026 driver");
+
+module_init(sm_adm1026_init);
+module_exit(sm_adm1026_exit);
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
new file mode 100644 (file)
index 0000000..11d0df3
--- /dev/null
@@ -0,0 +1,1660 @@
+/*
+ * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#undef DEBUG
+#undef VERBOSE
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb.h>
+#include <linux/usb_otg.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <asm/irq.h>
+#include <asm/arch/usb.h>
+
+
+#ifndef        DEBUG
+#undef VERBOSE
+#endif
+
+
+#define        DRIVER_VERSION  "24 August 2004"
+#define        DRIVER_NAME     (isp1301_driver.name)
+
+MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
+MODULE_LICENSE("GPL");
+
+struct isp1301 {
+       struct otg_transceiver  otg;
+       struct i2c_client       client;
+       void                    (*i2c_release)(struct device *dev);
+
+       int                     irq;
+
+       u32                     last_otg_ctrl;
+       unsigned                working:1;
+
+       struct timer_list       timer;
+
+       /* use keventd context to change the state for us */
+       struct work_struct      work;
+       
+       unsigned long           todo;
+#              define WORK_UPDATE_ISP  0       /* update ISP from OTG */
+#              define WORK_UPDATE_OTG  1       /* update OTG from ISP */
+#              define WORK_HOST_RESUME 4       /* resume host */
+#              define WORK_TIMER       6       /* timer fired */
+#              define WORK_STOP        7       /* don't resubmit */
+};
+
+
+/* bits in OTG_CTRL_REG */
+
+#define        OTG_XCEIV_OUTPUTS \
+       (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+#define        OTG_XCEIV_INPUTS \
+       (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+#define        OTG_CTRL_BITS \
+       (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
+       /* and OTG_PULLUP is sometimes written */
+
+#define        OTG_CTRL_MASK   (OTG_DRIVER_SEL| \
+       OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
+       OTG_CTRL_BITS)
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_MACH_OMAP_H2
+
+/* board-specific PM hooks */
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/mach-types.h>
+
+
+#if    defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
+
+#include <asm/arch/tps65010.h>
+
+#else
+
+static inline int tps65010_set_vbus_draw(unsigned mA)
+{
+       pr_debug("tps65010: draw %d mA (STUB)\n", mA);
+       return 0;
+}
+
+#endif
+
+static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
+{
+       int status = tps65010_set_vbus_draw(mA);
+       if (status < 0)
+               pr_debug("  VBUS %d mA error %d\n", mA, status);
+}
+
+static void enable_vbus_source(struct isp1301 *isp)
+{
+       /* this board won't supply more than 8mA vbus power.
+        * some boards can switch a 100ma "unit load" (or more).
+        */
+}
+
+
+/* products will deliver OTG messages with LEDs, GUI, etc */
+static inline void notresponding(struct isp1301 *isp)
+{
+       printk(KERN_NOTICE "OTG device not responding.\n");
+}
+
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* only two addresses possible */
+#define        ISP_BASE                0x2c
+static unsigned short normal_i2c[] = {
+       ISP_BASE, ISP_BASE + 1,
+       I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver isp1301_driver;
+
+/* smbus apis are used for portability */
+
+static inline u8
+isp1301_get_u8(struct isp1301 *isp, u8 reg)
+{
+       return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+}
+
+static inline int
+isp1301_get_u16(struct isp1301 *isp, u8 reg)
+{
+       return i2c_smbus_read_word_data(&isp->client, reg);
+}
+
+static inline int
+isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+       return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+}
+
+static inline int
+isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+       return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* identification */
+#define        ISP1301_VENDOR_ID               0x00    /* u16 read */
+#define        ISP1301_PRODUCT_ID              0x02    /* u16 read */
+#define        ISP1301_BCD_DEVICE              0x14    /* u16 read */
+
+#define        I2C_VENDOR_ID_PHILIPS           0x04cc
+#define        I2C_PRODUCT_ID_PHILIPS_1301     0x1301
+
+/* operational registers */
+#define        ISP1301_MODE_CONTROL_1          0x04    /* u8 read, set, +1 clear */
+#      define  MC1_SPEED_REG           (1 << 0)
+#      define  MC1_SUSPEND_REG         (1 << 1)
+#      define  MC1_DAT_SE0             (1 << 2)
+#      define  MC1_TRANSPARENT         (1 << 3)
+#      define  MC1_BDIS_ACON_EN        (1 << 4)
+#      define  MC1_OE_INT_EN           (1 << 5)
+#      define  MC1_UART_EN             (1 << 6)
+#      define  MC1_MASK                0x7f
+#define        ISP1301_MODE_CONTROL_2          0x12    /* u8 read, set, +1 clear */
+#      define  MC2_GLOBAL_PWR_DN       (1 << 0)
+#      define  MC2_SPD_SUSP_CTRL       (1 << 1)
+#      define  MC2_BI_DI               (1 << 2)
+#      define  MC2_TRANSP_BDIR0        (1 << 3)
+#      define  MC2_TRANSP_BDIR1        (1 << 4)
+#      define  MC2_AUDIO_EN            (1 << 5)
+#      define  MC2_PSW_EN              (1 << 6)
+#      define  MC2_EN2V7               (1 << 7)
+#define        ISP1301_OTG_CONTROL_1           0x06    /* u8 read, set, +1 clear */
+#      define  OTG1_DP_PULLUP          (1 << 0)
+#      define  OTG1_DM_PULLUP          (1 << 1)
+#      define  OTG1_DP_PULLDOWN        (1 << 2)
+#      define  OTG1_DM_PULLDOWN        (1 << 3)
+#      define  OTG1_ID_PULLDOWN        (1 << 4)
+#      define  OTG1_VBUS_DRV           (1 << 5)
+#      define  OTG1_VBUS_DISCHRG       (1 << 6)
+#      define  OTG1_VBUS_CHRG          (1 << 7)
+#define        ISP1301_OTG_STATUS              0x10    /* u8 readonly */
+#      define  OTG_B_SESS_END          (1 << 6)
+#      define  OTG_B_SESS_VLD          (1 << 7)
+
+#define        ISP1301_INTERRUPT_SOURCE        0x08    /* u8 read */
+#define        ISP1301_INTERRUPT_LATCH         0x0A    /* u8 read, set, +1 clear */
+
+#define        ISP1301_INTERRUPT_FALLING       0x0C    /* u8 read, set, +1 clear */
+#define        ISP1301_INTERRUPT_RISING        0x0E    /* u8 read, set, +1 clear */
+
+/* same bitfields in all interrupt registers */
+#      define  INTR_VBUS_VLD           (1 << 0)
+#      define  INTR_SESS_VLD           (1 << 1)
+#      define  INTR_DP_HI              (1 << 2)
+#      define  INTR_ID_GND             (1 << 3)
+#      define  INTR_DM_HI              (1 << 4)
+#      define  INTR_ID_FLOAT           (1 << 5)
+#      define  INTR_BDIS_ACON          (1 << 6)
+#      define  INTR_CR_INT             (1 << 7)
+
+/*-------------------------------------------------------------------------*/
+
+static const char *state_string(enum usb_otg_state state)
+{
+       switch (state) {
+       case OTG_STATE_A_IDLE:          return "a_idle";
+       case OTG_STATE_A_WAIT_VRISE:    return "a_wait_vrise";
+       case OTG_STATE_A_WAIT_BCON:     return "a_wait_bcon";
+       case OTG_STATE_A_HOST:          return "a_host";
+       case OTG_STATE_A_SUSPEND:       return "a_suspend";
+       case OTG_STATE_A_PERIPHERAL:    return "a_peripheral";
+       case OTG_STATE_A_WAIT_VFALL:    return "a_wait_vfall";
+       case OTG_STATE_A_VBUS_ERR:      return "a_vbus_err";
+       case OTG_STATE_B_IDLE:          return "b_idle";
+       case OTG_STATE_B_SRP_INIT:      return "b_srp_init";
+       case OTG_STATE_B_PERIPHERAL:    return "b_peripheral";
+       case OTG_STATE_B_WAIT_ACON:     return "b_wait_acon";
+       case OTG_STATE_B_HOST:          return "b_host";
+       default:                        return "UNDEFINED";
+       }
+}
+
+static inline const char *state_name(struct isp1301 *isp)
+{
+       return state_string(isp->otg.state);
+}
+
+#ifdef VERBOSE
+#define        dev_vdbg                        dev_dbg
+#else
+#define        dev_vdbg(dev, fmt, arg...)      do{}while(0)
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* NOTE:  some of this ISP1301 setup is specific to H2 boards;
+ * not everything is guarded by board-specific checks, or even using
+ * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI.
+ *
+ * ALSO:  this currently doesn't use ISP1301 low-power modes
+ * while OTG is running.
+ */
+
+static void power_down(struct isp1301 *isp)
+{
+       isp->otg.state = OTG_STATE_UNDEFINED;
+
+       // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG);
+
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN);
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+}
+
+static void power_up(struct isp1301 *isp)
+{
+       // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG);
+       
+       /* do this only when cpu is driving transceiver,
+        * so host won't see a low speed device...
+        */
+       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+}
+
+#define        NO_HOST_SUSPEND
+
+static int host_suspend(struct isp1301 *isp)
+{
+#ifdef NO_HOST_SUSPEND
+       return 0;
+#else
+       struct device   *dev;
+
+       if (!isp->otg.host)
+               return -ENODEV;
+
+       /* Currently ASSUMES only the OTG port matters;
+        * other ports could be active...
+        */
+       dev = isp->otg.host->controller;
+       return dev->driver->suspend(dev, 3, 0);
+#endif
+}
+
+static int host_resume(struct isp1301 *isp)
+{
+#ifdef NO_HOST_SUSPEND
+       return 0;
+#else
+       struct device   *dev;
+
+       if (!isp->otg.host)
+               return -ENODEV;
+
+       dev = isp->otg.host->controller;
+       return dev->driver->resume(dev, 0);
+#endif
+}
+
+static int gadget_suspend(struct isp1301 *isp)
+{
+       isp->otg.gadget->b_hnp_enable = 0;
+       isp->otg.gadget->a_hnp_support = 0;
+       isp->otg.gadget->a_alt_hnp_support = 0;
+       return usb_gadget_vbus_disconnect(isp->otg.gadget);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define        TIMER_MINUTES   10
+#define        TIMER_JIFFIES   (TIMER_MINUTES * 60 * HZ)
+
+/* Almost all our I2C messaging comes from a work queue's task context.
+ * NOTE: guaranteeing certain response times might mean we shouldn't
+ * share keventd's work queue; a realtime task might be safest.
+ */
+void
+isp1301_defer_work(struct isp1301 *isp, int work)
+{
+       int status;
+
+       if (isp && !test_and_set_bit(work, &isp->todo)) {
+               (void) get_device(&isp->client.dev);
+               status = schedule_work(&isp->work);
+               if (!status && !isp->working)
+                       dev_vdbg(&isp->client.dev,
+                               "work item %d may be lost\n", work);
+       }
+}
+
+/* called from irq handlers */
+static void a_idle(struct isp1301 *isp, const char *tag)
+{
+       if (isp->otg.state == OTG_STATE_A_IDLE)
+               return;
+
+       isp->otg.default_a = 1;
+       if (isp->otg.host) {
+               isp->otg.host->is_b_host = 0;
+               host_suspend(isp);
+       }
+       if (isp->otg.gadget) {
+               isp->otg.gadget->is_a_peripheral = 1;
+               gadget_suspend(isp);
+       }
+       isp->otg.state = OTG_STATE_A_IDLE;
+       isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;
+       pr_debug("  --> %s/%s\n", state_name(isp), tag);
+}
+
+/* called from irq handlers */
+static void b_idle(struct isp1301 *isp, const char *tag)
+{
+       if (isp->otg.state == OTG_STATE_B_IDLE)
+               return;
+
+       isp->otg.default_a = 0;
+       if (isp->otg.host) {
+               isp->otg.host->is_b_host = 1;
+               host_suspend(isp);
+       }
+       if (isp->otg.gadget) {
+               isp->otg.gadget->is_a_peripheral = 0;
+               gadget_suspend(isp);
+       }
+       isp->otg.state = OTG_STATE_B_IDLE;
+       isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;
+       pr_debug("  --> %s/%s\n", state_name(isp), tag);
+}
+
+static void
+dump_regs(struct isp1301 *isp, const char *label)
+{
+#ifdef DEBUG
+       u8      ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1);
+       u8      status = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
+       u8      src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+
+       pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n",
+               OTG_CTRL_REG, label, state_name(isp),
+               ctrl, status, src);
+       /* mode control and irq enables don't change much */
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_OTG
+
+/*
+ * The OMAP OTG controller handles most of the OTG state transitions.
+ *
+ * We translate isp1301 outputs (mostly voltage comparator status) into
+ * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state
+ * flags into isp1301 inputs ... and infer state transitions.
+ */
+
+#ifdef VERBOSE
+
+static void check_state(struct isp1301 *isp, const char *tag)
+{
+       enum usb_otg_state      state = OTG_STATE_UNDEFINED;
+       u8                      fsm = OTG_TEST_REG & 0x0ff;
+       unsigned                extra = 0;
+
+       switch (fsm) {
+
+       /* default-b */
+       case 0x0:
+               state = OTG_STATE_B_IDLE;
+               break;
+       case 0x3:
+       case 0x7:
+               extra = 1;
+       case 0x1:
+               state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case 0x11:
+               state = OTG_STATE_B_SRP_INIT;
+               break;
+
+       /* extra dual-role default-b states */
+       case 0x12:
+       case 0x13:
+       case 0x16:
+               extra = 1;
+       case 0x17:
+               state = OTG_STATE_B_WAIT_ACON;
+               break;
+       case 0x34:
+               state = OTG_STATE_B_HOST;
+               break;
+
+       /* default-a */
+       case 0x36:
+               state = OTG_STATE_A_IDLE;
+               break;
+       case 0x3c:
+               state = OTG_STATE_A_WAIT_VFALL;
+               break;
+       case 0x7d:
+               state = OTG_STATE_A_VBUS_ERR;
+               break;
+       case 0x9e:
+       case 0x9f:
+               extra = 1;
+       case 0x89:
+               state = OTG_STATE_A_PERIPHERAL;
+               break;
+       case 0xb7:
+               state = OTG_STATE_A_WAIT_VRISE;
+               break;
+       case 0xb8:
+               state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case 0xb9:
+               state = OTG_STATE_A_HOST;
+               break;
+       case 0xba:
+               state = OTG_STATE_A_SUSPEND;
+               break;
+       default:
+               break;
+       }
+       if (isp->otg.state == state && !extra)
+               return;
+       pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
+               state_string(state), fsm, state_name(isp), OTG_CTRL_REG);
+}
+
+#else
+
+static inline void check_state(struct isp1301 *isp, const char *tag) { }
+
+#endif
+
+/* outputs from ISP1301_INTERRUPT_SOURCE */
+static void update_otg1(struct isp1301 *isp, u8 int_src)
+{
+       u32     otg_ctrl;
+
+       otg_ctrl = OTG_CTRL_REG
+                       & OTG_CTRL_MASK
+                       & ~OTG_XCEIV_INPUTS
+                       & ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD);
+       if (int_src & INTR_SESS_VLD)
+               otg_ctrl |= OTG_ASESSVLD;
+       else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) {
+               a_idle(isp, "vfall");
+               otg_ctrl &= ~OTG_CTRL_BITS;
+       }
+       if (int_src & INTR_VBUS_VLD)
+               otg_ctrl |= OTG_VBUSVLD;
+       if (int_src & INTR_ID_GND) {            /* default-A */
+               if (isp->otg.state == OTG_STATE_B_IDLE
+                               || isp->otg.state == OTG_STATE_UNDEFINED) {
+                       a_idle(isp, "init");
+                       return;
+               }
+       } else {                                /* default-B */
+               otg_ctrl |= OTG_ID;
+               if (isp->otg.state == OTG_STATE_A_IDLE
+                               || isp->otg.state == OTG_STATE_UNDEFINED) {
+                       b_idle(isp, "init");
+                       return;
+               }
+       }
+       OTG_CTRL_REG = otg_ctrl;
+}
+
+/* outputs from ISP1301_OTG_STATUS */
+static void update_otg2(struct isp1301 *isp, u8 otg_status)
+{
+       u32     otg_ctrl;
+
+       otg_ctrl = OTG_CTRL_REG
+                       & OTG_CTRL_MASK
+                       & ~OTG_XCEIV_INPUTS
+                       & ~(OTG_BSESSVLD|OTG_BSESSEND);
+       if (otg_status & OTG_B_SESS_VLD)
+               otg_ctrl |= OTG_BSESSVLD;
+       else if (otg_status & OTG_B_SESS_END)
+               otg_ctrl |= OTG_BSESSEND;
+       OTG_CTRL_REG = otg_ctrl;
+}
+
+/* inputs going to ISP1301 */
+static void otg_update_isp(struct isp1301 *isp)
+{
+       u32     otg_ctrl, otg_change;
+       u8      set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP;
+
+       otg_ctrl = OTG_CTRL_REG;
+       otg_change = otg_ctrl ^ isp->last_otg_ctrl;
+       isp->last_otg_ctrl = otg_ctrl;
+       otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;
+
+       switch (isp->otg.state) {
+       case OTG_STATE_B_IDLE:
+       case OTG_STATE_B_PERIPHERAL:
+       case OTG_STATE_B_SRP_INIT:
+               if (!(otg_ctrl & OTG_PULLUP)) {
+                       // if (otg_ctrl & OTG_B_HNPEN) {
+                       if (isp->otg.gadget->b_hnp_enable) {
+                               isp->otg.state = OTG_STATE_B_WAIT_ACON;
+                               pr_debug("  --> b_wait_acon\n");
+                       }
+                       goto pulldown;
+               }
+pullup:
+               set |= OTG1_DP_PULLUP;
+               clr |= OTG1_DP_PULLDOWN;
+               break;
+       case OTG_STATE_A_SUSPEND:
+       case OTG_STATE_A_PERIPHERAL:
+               if (otg_ctrl & OTG_PULLUP)
+                       goto pullup;
+               /* FALLTHROUGH */
+       // case OTG_STATE_B_WAIT_ACON:
+       default:
+pulldown:
+               set |= OTG1_DP_PULLDOWN;
+               clr |= OTG1_DP_PULLUP;
+               break;
+       }
+
+#      define toggle(OTG,ISP) do { \
+               if (otg_ctrl & OTG) set |= ISP; \
+               else clr |= ISP; \
+               } while (0)
+
+       if (!(isp->otg.host))
+               otg_ctrl &= ~OTG_DRV_VBUS;
+
+       switch (isp->otg.state) {
+       case OTG_STATE_A_SUSPEND:
+               if (otg_ctrl & OTG_DRV_VBUS) {
+                       set |= OTG1_VBUS_DRV;
+                       break;
+               }
+               /* HNP failed for some reason (A_AIDL_BDIS timeout) */
+               notresponding(isp);
+
+               /* FALLTHROUGH */
+       case OTG_STATE_A_VBUS_ERR:
+               isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+               pr_debug("  --> a_wait_vfall\n");
+               /* FALLTHROUGH */
+       case OTG_STATE_A_WAIT_VFALL:
+               /* FIXME usbcore thinks port power is still on ... */
+               clr |= OTG1_VBUS_DRV;
+               break;
+       case OTG_STATE_A_IDLE:
+               if (otg_ctrl & OTG_DRV_VBUS) {
+                       isp->otg.state = OTG_STATE_A_WAIT_VRISE;
+                       pr_debug("  --> a_wait_vrise\n");
+               }
+               /* FALLTHROUGH */
+       default:
+               toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV);
+       }
+
+       toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG);
+       toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG);
+
+#      undef toggle
+
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set);
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr);
+
+       /* HNP switch to host or peripheral; and SRP */
+       if (otg_change & OTG_PULLUP) {
+               switch (isp->otg.state) {
+               case OTG_STATE_B_IDLE:
+                       if (clr & OTG1_DP_PULLUP)
+                               break;
+                       isp->otg.state = OTG_STATE_B_PERIPHERAL;
+                       pr_debug("  --> b_peripheral\n");
+                       break;
+               case OTG_STATE_A_SUSPEND:
+                       if (clr & OTG1_DP_PULLUP)
+                               break;
+                       isp->otg.state = OTG_STATE_A_PERIPHERAL;
+                       pr_debug("  --> a_peripheral\n");
+                       break;
+               default:
+                       break;
+               }
+               OTG_CTRL_REG |= OTG_PULLUP;
+       }
+
+       check_state(isp, __FUNCTION__);
+       dump_regs(isp, "otg->isp1301");
+}
+
+static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs)
+{
+       u16             otg_irq = OTG_IRQ_SRC_REG;
+       u32             otg_ctrl;
+       int             ret = IRQ_NONE;
+       struct isp1301  *isp = _isp;
+
+       /* update ISP1301 transciever from OTG controller */
+       if (otg_irq & OPRT_CHG) {
+               OTG_IRQ_SRC_REG = OPRT_CHG;
+               isp1301_defer_work(isp, WORK_UPDATE_ISP);
+               ret = IRQ_HANDLED;
+
+       /* SRP to become b_peripheral failed */
+       } else if (otg_irq & B_SRP_TMROUT) {
+               pr_debug("otg: B_SRP_TIMEOUT, %06x\n", OTG_CTRL_REG);
+               notresponding(isp);
+
+               /* gadget drivers that care should monitor all kinds of
+                * remote wakeup (SRP, normal) using their own timer
+                * to give "check cable and A-device" messages.
+                */
+               if (isp->otg.state == OTG_STATE_B_SRP_INIT)
+                       b_idle(isp, "srp_timeout");
+
+               OTG_IRQ_SRC_REG = B_SRP_TMROUT;
+               ret = IRQ_HANDLED;
+
+       /* HNP to become b_host failed */
+       } else if (otg_irq & B_HNP_FAIL) {
+               pr_debug("otg: %s B_HNP_FAIL, %06x\n",
+                               state_name(isp), OTG_CTRL_REG);
+               notresponding(isp);
+
+               otg_ctrl = OTG_CTRL_REG;
+               otg_ctrl |= OTG_BUSDROP;
+               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+               OTG_CTRL_REG = otg_ctrl;
+
+               /* subset of b_peripheral()... */
+               isp->otg.state = OTG_STATE_B_PERIPHERAL;
+               pr_debug("  --> b_peripheral\n");
+
+               OTG_IRQ_SRC_REG = B_HNP_FAIL;
+               ret = IRQ_HANDLED;
+
+       /* detect SRP from B-device ... */
+       } else if (otg_irq & A_SRP_DETECT) {
+               pr_debug("otg: %s SRP_DETECT, %06x\n",
+                               state_name(isp), OTG_CTRL_REG);
+
+               isp1301_defer_work(isp, WORK_UPDATE_OTG);
+               switch (isp->otg.state) {
+               case OTG_STATE_A_IDLE:
+                       if (!isp->otg.host)
+                               break;
+                       isp1301_defer_work(isp, WORK_HOST_RESUME);
+                       otg_ctrl = OTG_CTRL_REG;
+                       otg_ctrl |= OTG_A_BUSREQ;
+                       otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
+                                       & ~OTG_XCEIV_INPUTS
+                                       & OTG_CTRL_MASK;
+                       OTG_CTRL_REG = otg_ctrl;
+                       break;
+               default:
+                       break;
+               }
+
+               OTG_IRQ_SRC_REG = A_SRP_DETECT;
+               ret = IRQ_HANDLED;
+
+       /* timer expired:  T(a_wait_bcon) and maybe T(a_wait_vrise)
+        * we don't track them separately
+        */
+       } else if (otg_irq & A_REQ_TMROUT) {
+               otg_ctrl = OTG_CTRL_REG;
+               pr_info("otg: BCON_TMOUT from %s, %06x\n",
+                               state_name(isp), otg_ctrl);
+               notresponding(isp);
+
+               otg_ctrl |= OTG_BUSDROP;
+               otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+               OTG_CTRL_REG = otg_ctrl;
+               isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+
+               OTG_IRQ_SRC_REG = A_REQ_TMROUT;
+               ret = IRQ_HANDLED;
+
+       /* A-supplied voltage fell too low; overcurrent */
+       } else if (otg_irq & A_VBUS_ERR) {
+               otg_ctrl = OTG_CTRL_REG;
+               printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n",
+                       state_name(isp), otg_irq, otg_ctrl);
+
+               otg_ctrl |= OTG_BUSDROP;
+               otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+               OTG_CTRL_REG = otg_ctrl;
+               isp->otg.state = OTG_STATE_A_VBUS_ERR;
+
+               OTG_IRQ_SRC_REG = A_VBUS_ERR;
+               ret = IRQ_HANDLED;
+
+       /* switch driver; the transciever code activates it,
+        * ungating the udc clock or resuming OHCI.
+        */
+       } else if (otg_irq & DRIVER_SWITCH) {
+               int     kick = 0;
+
+               otg_ctrl = OTG_CTRL_REG;
+               printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n",
+                               state_name(isp),
+                               (otg_ctrl & OTG_DRIVER_SEL)
+                                       ? "gadget" : "host",
+                               otg_ctrl);
+               isp1301_defer_work(isp, WORK_UPDATE_ISP);
+
+               /* role is peripheral */
+               if (otg_ctrl & OTG_DRIVER_SEL) {
+                       switch (isp->otg.state) {
+                       case OTG_STATE_A_IDLE:
+                               b_idle(isp, __FUNCTION__);
+                               break;
+                       default:
+                               break;
+                       }
+                       isp1301_defer_work(isp, WORK_UPDATE_ISP);
+
+               /* role is host */
+               } else {
+                       if (!(otg_ctrl & OTG_ID)) {
+                               otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+                               OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ;
+                       }
+
+                       if (isp->otg.host) {
+                               switch (isp->otg.state) {
+                               case OTG_STATE_B_WAIT_ACON:
+                                       isp->otg.state = OTG_STATE_B_HOST;
+                                       pr_debug("  --> b_host\n");
+                                       kick = 1;
+                                       break;
+                               case OTG_STATE_A_WAIT_BCON:
+                                       isp->otg.state = OTG_STATE_A_HOST;
+                                       pr_debug("  --> a_host\n");
+                                       break;
+                               case OTG_STATE_A_PERIPHERAL:
+                                       isp->otg.state = OTG_STATE_A_WAIT_BCON;
+                                       pr_debug("  --> a_wait_bcon\n");
+                                       break;
+                               default:
+                                       break;
+                               }
+                               isp1301_defer_work(isp, WORK_HOST_RESUME);
+                       }
+               }
+
+               OTG_IRQ_SRC_REG = DRIVER_SWITCH;
+               ret = IRQ_HANDLED;
+
+               if (kick)
+                       usb_bus_start_enum(isp->otg.host,
+                                               isp->otg.host->otg_port);
+       }
+
+       check_state(isp, __FUNCTION__);
+       return ret;
+}
+
+static struct platform_device *otg_dev;
+
+static int otg_init(struct isp1301 *isp)
+{
+       if (!otg_dev)
+               return -ENODEV;
+
+       dump_regs(isp, __FUNCTION__);
+       /* some of these values are board-specific... */
+       OTG_SYSCON_2_REG |= OTG_EN
+               /* for B-device: */
+               | SRP_GPDATA            /* 9msec Bdev D+ pulse */
+               | SRP_GPDVBUS           /* discharge after VBUS pulse */
+               // | (3 << 24)          /* 2msec VBUS pulse */
+               /* for A-device: */
+               | (0 << 20)             /* 200ms nominal A_WAIT_VRISE timer */
+               | SRP_DPW               /* detect 167+ns SRP pulses */
+               | SRP_DATA | SRP_VBUS   /* accept both kinds of SRP pulse */
+               ;
+
+       update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
+       update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
+
+       check_state(isp, __FUNCTION__);
+       pr_debug("otg: %s, %s %06x\n",
+                       state_name(isp), __FUNCTION__, OTG_CTRL_REG);
+
+       OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG
+                       | B_SRP_TMROUT | B_HNP_FAIL
+                       | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT;
+       OTG_SYSCON_2_REG |= OTG_EN;
+
+       return 0;
+}
+
+static int otg_probe(struct device *dev)
+{
+       // struct omap_usb_config *config = dev->platform_data;
+
+       otg_dev = to_platform_device(dev);
+       return 0;
+}
+
+static int otg_remove(struct device *dev)
+{
+       otg_dev = 0;
+       return 0;
+}
+
+struct device_driver omap_otg_driver = {
+       .name           = "omap_otg",
+       .bus            = &platform_bus_type,
+       .probe          = otg_probe,
+       .remove         = otg_remove,   
+};
+
+static int otg_bind(struct isp1301 *isp)
+{
+       int     status;
+
+       if (otg_dev)
+               return -EBUSY;
+
+       status = driver_register(&omap_otg_driver);
+       if (status < 0)
+               return status;
+
+       if (otg_dev)
+               status = request_irq(otg_dev->resource[1].start, omap_otg_irq,
+                               SA_INTERRUPT, DRIVER_NAME, isp);
+       else
+               status = -ENODEV;
+
+       if (status < 0)
+               driver_unregister(&omap_otg_driver);
+       return status;
+}
+
+static void otg_unbind(struct isp1301 *isp)
+{
+       if (!otg_dev)
+               return;
+       free_irq(otg_dev->resource[1].start, isp);
+}
+
+#else
+
+/* OTG controller isn't clocked */
+
+#endif /* CONFIG_USB_OTG */
+
+/*-------------------------------------------------------------------------*/
+
+static void b_peripheral(struct isp1301 *isp)
+{
+       enable_vbus_draw(isp, 8);
+       OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;
+       usb_gadget_vbus_connect(isp->otg.gadget);
+
+#ifdef CONFIG_USB_OTG
+       otg_update_isp(isp);
+#else
+       /* UDC driver just set OTG_BSESSVLD */
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);
+       isp->otg.state = OTG_STATE_B_PERIPHERAL;
+       pr_debug("  --> b_peripheral\n");
+       dump_regs(isp, "2periph");
+#endif
+}
+
+static int isp_update_otg(struct isp1301 *isp, u8 stat)
+{
+       u8                      isp_stat, isp_bstat;
+       enum usb_otg_state      state = isp->otg.state;
+
+       if (stat & INTR_BDIS_ACON)
+               pr_debug("OTG:  BDIS_ACON, %s\n", state_name(isp));
+
+       /* start certain state transitions right away */
+       isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+       if (isp_stat & INTR_ID_GND) {
+               if (isp->otg.default_a) {
+                       switch (state) {
+                       case OTG_STATE_B_IDLE:
+                               a_idle(isp, "idle");
+                               /* FALLTHROUGH */
+                       case OTG_STATE_A_IDLE:
+                               enable_vbus_source(isp);
+                               /* FALLTHROUGH */
+                       case OTG_STATE_A_WAIT_VRISE:
+                               /* we skip over OTG_STATE_A_WAIT_BCON, since
+                                * the HC will transition to A_HOST (or
+                                * A_SUSPEND!) without our noticing except
+                                * when HNP is used.
+                                */
+                               if (isp_stat & INTR_VBUS_VLD)
+                                       isp->otg.state = OTG_STATE_A_HOST;
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+                               if (!(isp_stat & INTR_SESS_VLD))
+                                       a_idle(isp, "vfell");
+                               break;
+                       default:
+                               if (!(isp_stat & INTR_VBUS_VLD))
+                                       isp->otg.state = OTG_STATE_A_VBUS_ERR;
+                               break;
+                       }
+                       isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
+               } else {
+                       switch (state) {
+                       case OTG_STATE_B_PERIPHERAL:
+                       case OTG_STATE_B_HOST:
+                       case OTG_STATE_B_WAIT_ACON:
+                               usb_gadget_vbus_disconnect(isp->otg.gadget);
+                               break;
+                       default:
+                               break;
+                       }
+                       if (state != OTG_STATE_A_IDLE)
+                               a_idle(isp, "id");
+                       if (isp->otg.host && state == OTG_STATE_A_IDLE)
+                               isp1301_defer_work(isp, WORK_HOST_RESUME);
+                       isp_bstat = 0;
+               }
+       } else {
+               /* if user unplugged mini-A end of cable,
+                * don't bypass A_WAIT_VFALL.
+                */
+               if (isp->otg.default_a) {
+                       switch (state) {
+                       default:
+                               isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+                               state = OTG_STATE_A_IDLE;
+                               /* khubd may take a while to notice and
+                                * handle this disconnect, so don't go
+                                * to B_IDLE quite yet.
+                                */
+                               break;
+                       case OTG_STATE_A_IDLE:
+                               host_suspend(isp);
+                               isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,
+                                               MC1_BDIS_ACON_EN);
+                               isp->otg.state = OTG_STATE_B_IDLE;
+                               OTG_CTRL_REG &= OTG_CTRL_REG & OTG_CTRL_MASK
+                                               & ~OTG_CTRL_BITS;
+                               break;
+                       case OTG_STATE_B_IDLE:
+                               break;
+                       }
+               }
+               isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
+
+               switch (isp->otg.state) {
+               case OTG_STATE_B_PERIPHERAL:
+               case OTG_STATE_B_WAIT_ACON:
+               case OTG_STATE_B_HOST:
+                       if (likely(isp_bstat & OTG_B_SESS_VLD))
+                               break;
+                       enable_vbus_draw(isp, 0);
+#ifndef        CONFIG_USB_OTG
+                       /* UDC driver will clear OTG_BSESSVLD */
+                       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
+                                               OTG1_DP_PULLDOWN);
+                       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
+                                               OTG1_DP_PULLUP);
+                       dump_regs(isp, __FUNCTION__);
+#endif
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_SRP_INIT:
+                       b_idle(isp, __FUNCTION__);
+                       OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_IDLE:
+                       if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) {
+#ifdef CONFIG_USB_OTG
+                               update_otg1(isp, isp_stat);
+                               update_otg2(isp, isp_bstat);
+#endif
+                               b_peripheral(isp);
+                       } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD)))
+                               isp_bstat |= OTG_B_SESS_END;
+                       break;
+               case OTG_STATE_A_WAIT_VFALL:
+                       break;
+               default:
+                       pr_debug("otg: unsupported b-device %s\n",
+                               state_name(isp));
+                       break;
+               }
+       }
+
+       if (state != isp->otg.state)
+               pr_debug("  isp, %s -> %s\n",
+                               state_string(state), state_name(isp));
+
+#ifdef CONFIG_USB_OTG
+       /* update the OTG controller state to match the isp1301; may
+        * trigger OPRT_CHG irqs for changes going to the isp1301.
+        */
+       update_otg1(isp, isp_stat);
+       update_otg2(isp, isp_bstat);
+       check_state(isp, __FUNCTION__);
+#endif
+
+       dump_regs(isp, "isp1301->otg");
+}
+
+/*-------------------------------------------------------------------------*/
+
+static u8 isp1301_clear_latch(struct isp1301 *isp)
+{
+       u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch);
+       return latch;
+}
+
+static void
+isp1301_work(void *data)
+{
+       struct isp1301  *isp = data;
+       int             stop;
+
+       /* implicit lock:  we're the only task using this device */
+       isp->working = 1;
+       do {
+               stop = test_bit(WORK_STOP, &isp->todo);
+
+#ifdef CONFIG_USB_OTG
+               /* transfer state from otg engine to isp1301 */
+               if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
+                       otg_update_isp(isp);
+                       put_device(&isp->client.dev);
+               }
+#endif
+               /* transfer state from isp1301 to otg engine */
+               if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) {
+                       u8              stat = isp1301_clear_latch(isp);
+
+                       isp_update_otg(isp, stat);
+                       put_device(&isp->client.dev);
+               }
+
+               if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
+                       u32     otg_ctrl;
+
+                       /*
+                        * skip A_WAIT_VRISE; hc transitions invisibly
+                        * skip A_WAIT_BCON; same.
+                        */
+                       switch (isp->otg.state) {
+                       case OTG_STATE_A_WAIT_BCON:
+                       case OTG_STATE_A_WAIT_VRISE:
+                               isp->otg.state = OTG_STATE_A_HOST;
+                               pr_debug("  --> a_host\n");
+                               otg_ctrl = OTG_CTRL_REG;
+                               otg_ctrl |= OTG_A_BUSREQ;
+                               otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
+                                               & OTG_CTRL_MASK;
+                               OTG_CTRL_REG = otg_ctrl;
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+                               isp->otg.state = OTG_STATE_B_HOST;
+                               pr_debug("  --> b_host (acon)\n");
+                               break;
+                       case OTG_STATE_B_HOST:
+                       case OTG_STATE_B_IDLE:
+                       case OTG_STATE_A_IDLE:
+                               break;
+                       default:
+                               pr_debug("  host resume in %s\n",
+                                               state_name(isp));
+                       }
+                       host_resume(isp);
+                       // mdelay(10);
+                       put_device(&isp->client.dev);
+               }
+
+               if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
+#ifdef VERBOSE
+                       dump_regs(isp, "timer");
+                       if (!stop)
+                               mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
+#endif
+                       put_device(&isp->client.dev);
+               }
+
+               if (isp->todo)
+                       dev_vdbg(&isp->client.dev,
+                               "work done, todo = 0x%lx\n",
+                               isp->todo);
+               if (stop) {
+                       dev_dbg(&isp->client.dev, "stop\n");
+                       break;
+               }
+       } while (isp->todo);
+       isp->working = 0;
+}
+
+static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs)
+{
+       isp1301_defer_work(isp, WORK_UPDATE_OTG);
+       return IRQ_HANDLED;
+}
+
+static void isp1301_timer(unsigned long _isp)
+{
+       isp1301_defer_work((void *)_isp, WORK_TIMER);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void isp1301_release(struct device *dev)
+{
+       struct isp1301  *isp;
+
+       isp = container_of(dev, struct isp1301, client.dev);
+
+       /* ugly -- i2c hijacks our memory hook to wait_for_completion() */
+       if (isp->i2c_release)
+               isp->i2c_release(dev);
+       kfree (isp);
+}
+
+static struct isp1301 *the_transceiver;
+
+static int isp1301_detach_client(struct i2c_client *i2c)
+{
+       struct isp1301  *isp;
+
+       isp = container_of(i2c, struct isp1301, client);
+
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+       free_irq(isp->irq, isp);
+#ifdef CONFIG_USB_OTG
+       otg_unbind(isp);
+#endif
+       if (machine_is_omap_h2())
+               omap_free_gpio(2);
+
+       isp->timer.data = 0;
+       set_bit(WORK_STOP, &isp->todo);
+       del_timer_sync(&isp->timer);
+       flush_scheduled_work();
+
+       put_device(&i2c->dev);
+       the_transceiver = 0;
+
+       return i2c_detach_client(i2c);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* NOTE:  three modes are possible here, only one of which
+ * will be standards-conformant on any given system:
+ *
+ *  - OTG mode (dual-role), required if there's a Mini-AB connector
+ *  - HOST mode, for when there's one or more A (host) connectors
+ *  - DEVICE mode, for when there's a B/Mini-B (device) connector
+ *
+ * As a rule, you won't have an isp1301 chip unless it's there to
+ * support the OTG mode.  Other modes help testing USB controllers 
+ * in isolation from (full) OTG support, or maybe so later board
+ * revisions can help to support those feature.
+ */
+
+#ifdef CONFIG_USB_OTG
+
+static int isp1301_otg_enable(struct isp1301 *isp)
+{
+       power_up(isp);
+       otg_init(isp);
+
+       /* NOTE:  since we don't change this, this provides
+        * a few more interrupts than are strictly needed.
+        */
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
+               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
+               INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+
+       dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+
+       return 0;
+}
+
+#endif
+
+/* add or disable the host device+driver */
+static int
+isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+{
+       struct isp1301  *isp = container_of(otg, struct isp1301, otg);
+
+       if (!otg || isp != the_transceiver)
+               return -ENODEV;
+
+       if (!host) {
+               OTG_IRQ_EN_REG = 0;
+               power_down(isp);
+               isp->otg.host = 0;
+               return 0;
+       }
+
+#ifdef CONFIG_USB_OTG
+       isp->otg.host = host;
+       dev_dbg(&isp->client.dev, "registered host\n");
+       host_suspend(isp);
+       if (isp->otg.gadget)
+               return isp1301_otg_enable(isp);
+       return 0;
+
+#elif  !defined(CONFIG_USB_GADGET_OMAP)
+       // FIXME update its refcount
+       isp->otg.host = host;
+
+       power_up(isp);
+
+       if (machine_is_omap_h2())
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+
+       dev_info(&isp->client.dev, "A-Host sessions ok\n");
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
+               INTR_ID_GND);
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
+               INTR_ID_GND);
+
+       /* If this has a Mini-AB connector, this mode is highly
+        * nonstandard ... but can be handy for testing, especially with
+        * the Mini-A end of an OTG cable.  (Or something nonstandard
+        * like MiniB-to-StandardB, maybe built with a gender mender.)
+        */
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
+
+       dump_regs(isp, __FUNCTION__);
+
+       return 0;
+
+#else
+       dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+       return -EINVAL;
+#endif
+
+}
+
+static int
+isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
+{
+       struct isp1301  *isp = container_of(otg, struct isp1301, otg);
+
+       if (!otg || isp != the_transceiver)
+               return -ENODEV;
+
+       if (!gadget) {
+               OTG_IRQ_EN_REG = 0;
+               if (!isp->otg.default_a)
+                       enable_vbus_draw(isp, 0);
+               usb_gadget_vbus_disconnect(isp->otg.gadget);
+               isp->otg.gadget = 0;
+               power_down(isp);
+               return 0;
+       }
+
+#ifdef CONFIG_USB_OTG
+       isp->otg.gadget = gadget;
+       dev_dbg(&isp->client.dev, "registered gadget\n");
+       /* gadget driver may be suspended until vbus_connect () */
+       if (isp->otg.host)
+               return isp1301_otg_enable(isp);
+       return 0;
+
+#elif  !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE)
+       isp->otg.gadget = gadget;
+       // FIXME update its refcount
+
+       OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK
+                               & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS))
+                       | OTG_ID;
+       power_up(isp);
+       isp->otg.state = OTG_STATE_B_IDLE;
+
+       if (machine_is_omap_h2())
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
+               INTR_SESS_VLD);
+       isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
+               INTR_VBUS_VLD);
+       dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+       dump_regs(isp, __FUNCTION__);
+
+       /* If this has a Mini-AB connector, this mode is highly
+        * nonstandard ... but can be handy for testing, so long
+        * as you don't plug a Mini-A cable into the jack.
+        */
+       if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD)
+               b_peripheral(isp);
+
+       return 0;
+
+#else
+       dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+       return -EINVAL;
+#endif
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int
+isp1301_set_power(struct otg_transceiver *dev, unsigned mA)
+{
+       if (!the_transceiver)
+               return -ENODEV;
+       if (dev->state == OTG_STATE_B_PERIPHERAL)
+               enable_vbus_draw(the_transceiver, mA);
+       return 0;
+}
+
+static int
+isp1301_start_srp(struct otg_transceiver *dev)
+{
+       struct isp1301  *isp = container_of(dev, struct isp1301, otg);
+       u32             otg_ctrl;
+
+       if (!dev || isp != the_transceiver
+                       || isp->otg.state != OTG_STATE_B_IDLE)
+               return -ENODEV;
+
+       otg_ctrl = OTG_CTRL_REG;
+       if (!(otg_ctrl & OTG_BSESSEND))
+               return -EINVAL;
+
+       otg_ctrl |= OTG_B_BUSREQ;
+       otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
+       OTG_CTRL_REG = otg_ctrl;
+       isp->otg.state = OTG_STATE_B_SRP_INIT;
+
+       pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG);
+#ifdef CONFIG_USB_OTG
+       check_state(isp, __FUNCTION__);
+#endif
+       return 0;
+}
+
+static int
+isp1301_start_hnp(struct otg_transceiver *dev)
+{
+#ifdef CONFIG_USB_OTG
+       struct isp1301  *isp = container_of(dev, struct isp1301, otg);
+
+       if (!dev || isp != the_transceiver)
+               return -ENODEV;
+       if (isp->otg.default_a && (isp->otg.host == NULL
+                       || !isp->otg.host->b_hnp_enable))
+               return -ENOTCONN;
+       if (!isp->otg.default_a && (isp->otg.gadget == NULL
+                       || !isp->otg.gadget->b_hnp_enable))
+               return -ENOTCONN;
+
+       /* We want hardware to manage most HNP protocol timings.
+        * So do this part as early as possible...
+        */
+       switch (isp->otg.state) {
+       case OTG_STATE_B_HOST:
+               isp->otg.state = OTG_STATE_B_PERIPHERAL;
+               /* caller will suspend next */
+               break;
+       case OTG_STATE_A_HOST:
+#if 0
+               /* autoconnect mode avoids irq latency bugs */
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
+                               MC1_BDIS_ACON_EN);
+#endif
+               /* caller must suspend then clear A_BUSREQ */
+               usb_gadget_vbus_connect(isp->otg.gadget);
+               OTG_CTRL_REG |= OTG_A_SETB_HNPEN;
+
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               /* initiated by B-Host suspend */
+               break;
+       default:
+               return -EILSEQ;
+       }
+       pr_debug("otg: HNP %s, %06x ...\n",
+               state_name(isp), OTG_CTRL_REG);
+       check_state(isp, __FUNCTION__);
+       return 0;
+#else
+       /* srp-only */
+       return -EINVAL;
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* no error returns, they'd just make bus scanning stop */
+static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+{
+       int                     status;
+       struct isp1301          *isp;
+       struct i2c_client       *i2c;
+
+       if (the_transceiver)
+               return 0;
+
+       isp = kmalloc(sizeof *isp, GFP_KERNEL);
+       if (!isp)
+               return 0;
+
+       memset(isp, 0, sizeof *isp);
+
+       INIT_WORK(&isp->work, isp1301_work, isp);
+       init_timer(&isp->timer);
+       isp->timer.function = isp1301_timer;
+       isp->timer.data = (unsigned long) isp;
+
+       isp->irq = -1;
+       isp->client.addr = address;
+       i2c_set_clientdata(&isp->client, isp);
+       isp->client.adapter = bus;
+       isp->client.id = 1301;
+       isp->client.driver = &isp1301_driver;
+       strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
+       i2c = &isp->client;
+
+       /* if this is a true probe, verify the chip ... */
+       if (kind < 0) {
+               status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+               if (status != I2C_VENDOR_ID_PHILIPS) {
+                       dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
+                               address, status);
+                       goto fail1;
+               }
+               status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+               if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+                       dev_dbg(&bus->dev, "%d not isp1301, %d\n",
+                               address, status);
+                       goto fail1;
+               }
+       }
+
+       status = i2c_attach_client(i2c);
+       if (status < 0) {
+               dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
+                               DRIVER_NAME, address, status);
+fail1:
+               kfree(isp);
+               return 0;
+       }
+       isp->i2c_release = i2c->dev.release;
+       i2c->dev.release = isp1301_release;
+
+       /* initial development used chiprev 2.00 */
+       status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE);
+       dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
+               status >> 8, status & 0xff);
+
+       /* make like power-on reset */
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK);
+
+       isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI);
+       isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI);
+
+       isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
+                               OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+       isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
+                               ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+       isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+
+#ifdef CONFIG_USB_OTG
+       status = otg_bind(isp);
+       if (status < 0) {
+               dev_dbg(&i2c->dev, "can't bind OTG\n");
+               goto fail2;
+       }
+#endif
+
+       if (machine_is_omap_h2()) {
+               /* full speed signaling by default */
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
+                       MC1_SPEED_REG);
+               isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
+                       MC2_SPD_SUSP_CTRL);
+
+               /* IRQ wired at M14 */
+               omap_cfg_reg(M14_1510_GPIO2);
+               isp->irq = OMAP_GPIO_IRQ(2);
+               omap_request_gpio(2);
+               omap_set_gpio_direction(2, 1);
+               omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE);
+       }
+
+       status = request_irq(isp->irq, isp1301_irq,
+                       SA_SAMPLE_RANDOM, DRIVER_NAME, isp);
+       if (status < 0) {
+               dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
+                               isp->irq, status);
+#ifdef CONFIG_USB_OTG
+fail2:
+#endif
+               i2c_detach_client(i2c);
+               goto fail1;
+       }
+
+       isp->otg.dev = &isp->client.dev;
+       isp->otg.label = DRIVER_NAME;
+
+       isp->otg.set_host = isp1301_set_host,
+       isp->otg.set_peripheral = isp1301_set_peripheral,
+       isp->otg.set_power = isp1301_set_power,
+       isp->otg.start_srp = isp1301_start_srp,
+       isp->otg.start_hnp = isp1301_start_hnp,
+
+       enable_vbus_draw(isp, 0);
+       power_down(isp);
+       the_transceiver = isp;
+
+#ifdef CONFIG_USB_OTG
+       update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
+       update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
+#endif
+
+       dump_regs(isp, __FUNCTION__);
+
+#ifdef VERBOSE
+       mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
+       dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
+#endif
+
+       status = otg_set_transceiver(&isp->otg);
+       if (status < 0)
+               dev_err(&i2c->dev, "can't register transceiver, %d\n",
+                       status);
+
+       return 0;
+}
+
+static int isp1301_scan_bus(struct i2c_adapter *bus)
+{
+       if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
+                       | I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -EINVAL;
+       return i2c_probe(bus, &addr_data, isp1301_probe);
+}
+
+static struct i2c_driver isp1301_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "isp1301_omap",
+       .id             = 1301,         /* FIXME "official", i2c-ids.h */
+       .class          = I2C_CLASS_HWMON,
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = isp1301_scan_bus,
+       .detach_client  = isp1301_detach_client,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init isp_init(void)
+{
+       return i2c_add_driver(&isp1301_driver);
+}
+module_init(isp_init);
+
+static void __exit isp_exit(void)
+{
+       if (the_transceiver)
+               otg_set_transceiver(0);
+       i2c_del_driver(&isp1301_driver);
+}
+module_exit(isp_exit);
+
diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c
new file mode 100644 (file)
index 0000000..73b8e83
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * lm63.c - driver for the National Semiconductor LM63 temperature sensor
+ *          with integrated fan control
+ * Copyright (C) 2004  Jean Delvare <khali@linux-fr.org>
+ * Based on the lm90 driver.
+ *
+ * The LM63 is a sensor chip made by National Semiconductor. It measures
+ * two temperatures (its own and one external one) and the speed of one
+ * fan, those speed it can additionally control. Complete datasheet can be
+ * obtained from National's website at:
+ *   http://www.national.com/pf/LM/LM63.html
+ *
+ * The LM63 is basically an LM86 with fan speed monitoring and control
+ * capabilities added. It misses some of the LM86 features though:
+ *  - No low limit for local temperature.
+ *  - No critical limit for local temperature.
+ *  - Critical limit for remote temperature can be changed only once. We
+ *    will consider that the critical limit is read-only.
+ *
+ * The datasheet isn't very clear about what the tachometer reading is.
+ * I had a explanation from National Semiconductor though. The two lower
+ * bits of the read value have to be masked out. The value is still 16 bit
+ * in width.
+ *
+ * This 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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+
+/*
+ * Addresses to scan
+ * Address is fully defined internally and cannot be changed.
+ */
+
+static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/*
+ * Insmod parameters
+ */
+
+SENSORS_INSMOD_1(lm63);
+
+/*
+ * The LM63 registers
+ */
+
+#define LM63_REG_CONFIG1               0x03
+#define LM63_REG_CONFIG2               0xBF
+#define LM63_REG_CONFIG_FAN            0x4A
+
+#define LM63_REG_TACH_COUNT_MSB                0x47
+#define LM63_REG_TACH_COUNT_LSB                0x46
+#define LM63_REG_TACH_LIMIT_MSB                0x49
+#define LM63_REG_TACH_LIMIT_LSB                0x48
+
+#define LM63_REG_PWM_VALUE             0x4C
+#define LM63_REG_PWM_FREQ              0x4D
+
+#define LM63_REG_LOCAL_TEMP            0x00
+#define LM63_REG_LOCAL_HIGH            0x05
+
+#define LM63_REG_REMOTE_TEMP_MSB       0x01
+#define LM63_REG_REMOTE_TEMP_LSB       0x10
+#define LM63_REG_REMOTE_OFFSET_MSB     0x11
+#define LM63_REG_REMOTE_OFFSET_LSB     0x12
+#define LM63_REG_REMOTE_HIGH_MSB       0x07
+#define LM63_REG_REMOTE_HIGH_LSB       0x13
+#define LM63_REG_REMOTE_LOW_MSB                0x08
+#define LM63_REG_REMOTE_LOW_LSB                0x14
+#define LM63_REG_REMOTE_TCRIT          0x19
+#define LM63_REG_REMOTE_TCRIT_HYST     0x21
+
+#define LM63_REG_ALERT_STATUS          0x02
+#define LM63_REG_ALERT_MASK            0x16
+
+#define LM63_REG_MAN_ID                        0xFE
+#define LM63_REG_CHIP_ID               0xFF
+
+/*
+ * Conversions and various macros
+ * For tachometer counts, the LM63 uses 16-bit values.
+ * For local temperature and high limit, remote critical limit and hysteresis
+ * value, it uses signed 8-bit values with LSB = 1 degree Celcius.
+ * For remote temperature, low and high limits, it uses signed 11-bit values
+ * with LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
+ */
+
+#define FAN_FROM_REG(reg)      ((reg) == 0xFFFC || (reg) == 0 ? 0 : \
+                                5400000 / (reg))
+#define FAN_TO_REG(val)                ((val) <= 82 ? 0xFFFC : \
+                                (5400000 / (val)) & 0xFFFC)
+#define TEMP8_FROM_REG(reg)    ((reg) * 1000)
+#define TEMP8_TO_REG(val)      ((val) <= -128000 ? -128 : \
+                                (val) >= 127000 ? 127 : \
+                                (val) < 0 ? ((val) - 500) / 1000 : \
+                                ((val) + 500) / 1000)
+#define TEMP11_FROM_REG(reg)   ((reg) / 32 * 125)
+#define TEMP11_TO_REG(val)     ((val) <= -128000 ? 0x8000 : \
+                                (val) >= 127875 ? 0x7FE0 : \
+                                (val) < 0 ? ((val) - 62) / 125 * 32 : \
+                                ((val) + 62) / 125 * 32)
+#define HYST_TO_REG(val)       ((val) <= 0 ? 0 : \
+                                (val) >= 127000 ? 127 : \
+                                ((val) + 500) / 1000)
+
+/*
+ * Functions declaration
+ */
+
+static int lm63_attach_adapter(struct i2c_adapter *adapter);
+static int lm63_detach_client(struct i2c_client *client);
+
+static struct lm63_data *lm63_update_device(struct device *dev);
+
+static int lm63_detect(struct i2c_adapter *adapter, int address, int kind);
+static void lm63_init_client(struct i2c_client *client);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver lm63_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "lm63",
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = lm63_attach_adapter,
+       .detach_client  = lm63_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm63_data {
+       struct i2c_client client;
+       struct semaphore update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+
+       /* registers values */
+       u8 config, config_fan;
+       u16 fan1_input;
+       u16 fan1_low;
+       u8 pwm1_freq;
+       u8 pwm1_value;
+       s8 temp1_input;
+       s8 temp1_high;
+       s16 temp2_input;
+       s16 temp2_high;
+       s16 temp2_low;
+       s8 temp2_crit;
+       u8 temp2_crit_hyst;
+       u8 alarms;
+};
+
+/*
+ * Sysfs callback functions and files
+ */
+
+#define show_fan(value) \
+static ssize_t show_##value(struct device *dev, char *buf) \
+{ \
+       struct lm63_data *data = lm63_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \
+}
+show_fan(fan1_input);
+show_fan(fan1_low);
+
+static ssize_t set_fan1_low(struct device *dev, const char *buf,
+       size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long val = simple_strtoul(buf, NULL, 10);
+       data->fan1_low = FAN_TO_REG(val);
+       i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
+                                 data->fan1_low & 0xFF);
+       i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
+                                 data->fan1_low >> 8);
+       return count;
+}
+
+static ssize_t show_pwm1(struct device *dev, char *buf)
+{
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
+                      255 : (data->pwm1_value * 255 + data->pwm1_freq) /
+                      (2 * data->pwm1_freq));
+}
+
+static ssize_t set_pwm1(struct device *dev, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       
+       if (!(data->config_fan & 0x20)) /* register is read-only */
+               return -EPERM;
+
+       val = simple_strtoul(buf, NULL, 10);
+       data->pwm1_value = val <= 0 ? 0 :
+                          val >= 255 ? 2 * data->pwm1_freq :
+                          (val * data->pwm1_freq * 2 + 127) / 255;
+       i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
+       return count;
+}
+
+static ssize_t show_pwm1_enable(struct device *dev, char *buf)
+{
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
+}
+
+#define show_temp8(value) \
+static ssize_t show_##value(struct device *dev, char *buf) \
+{ \
+       struct lm63_data *data = lm63_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \
+}
+#define show_temp11(value) \
+static ssize_t show_##value(struct device *dev, char *buf) \
+{ \
+       struct lm63_data *data = lm63_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \
+}
+show_temp8(temp1_input);
+show_temp8(temp1_high);
+show_temp11(temp2_input);
+show_temp11(temp2_high);
+show_temp11(temp2_low);
+show_temp8(temp2_crit);
+
+#define set_temp8(value, reg) \
+static ssize_t set_##value(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm63_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->value = TEMP8_TO_REG(val); \
+       i2c_smbus_write_byte_data(client, reg, data->value); \
+       return count; \
+}
+#define set_temp11(value, reg_msb, reg_lsb) \
+static ssize_t set_##value(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct lm63_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->value = TEMP11_TO_REG(val); \
+       i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \
+       i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \
+       return count; \
+}
+set_temp8(temp1_high, LM63_REG_LOCAL_HIGH);
+set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB);
+set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB);
+
+/* Hysteresis register holds a relative value, while we want to present
+   an absolute to user-space */
+static ssize_t show_temp2_crit_hyst(struct device *dev, char *buf)
+{
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit)
+                      - TEMP8_FROM_REG(data->temp2_crit_hyst));
+}
+
+/* And now the other way around, user-space provides an absolute
+   hysteresis value and we have to store a relative one */
+static ssize_t set_temp2_crit_hyst(struct device *dev, const char *buf,
+       size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       int hyst = TEMP8_FROM_REG(data->temp2_crit) -
+                  simple_strtol(buf, NULL, 10);
+       i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
+                                 HYST_TO_REG(hyst));
+       return count;
+}
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%u\n", data->alarms);
+}
+
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL);
+static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low,
+       set_fan1_low);
+
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high,
+       set_temp1_high);
+
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL);
+static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low,
+       set_temp2_low);
+static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high,
+       set_temp2_high);
+static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL);
+static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
+       set_temp2_crit_hyst);
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+/*
+ * Real code
+ */
+
+static int lm63_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_detect(adapter, &addr_data, lm63_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *new_client;
+       struct lm63_data *data;
+       int err = 0;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               goto exit;
+
+       if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       memset(data, 0, sizeof(struct lm63_data));
+
+       /* The common I2C client data is placed right before the
+          LM63-specific data. */
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &lm63_driver;
+       new_client->flags = 0;
+
+       /* Default to an LM63 if forced */
+       if (kind == 0)
+               kind = lm63;
+
+       if (kind < 0) { /* must identify */
+               u8 man_id, chip_id, reg_config1, reg_config2;
+               u8 reg_alert_status, reg_alert_mask;
+
+               man_id = i2c_smbus_read_byte_data(new_client,
+                        LM63_REG_MAN_ID);
+               chip_id = i2c_smbus_read_byte_data(new_client,
+                         LM63_REG_CHIP_ID);
+               reg_config1 = i2c_smbus_read_byte_data(new_client,
+                             LM63_REG_CONFIG1);
+               reg_config2 = i2c_smbus_read_byte_data(new_client,
+                             LM63_REG_CONFIG2);
+               reg_alert_status = i2c_smbus_read_byte_data(new_client,
+                                  LM63_REG_ALERT_STATUS);
+               reg_alert_mask = i2c_smbus_read_byte_data(new_client,
+                                LM63_REG_ALERT_MASK);
+
+               if (man_id == 0x01 /* National Semiconductor */
+                && chip_id == 0x41 /* LM63 */
+                && (reg_config1 & 0x18) == 0x00
+                && (reg_config2 & 0xF8) == 0x00
+                && (reg_alert_status & 0x20) == 0x00
+                && (reg_alert_mask & 0xA4) == 0xA4) {
+                       kind = lm63;
+               } else { /* failed */
+                       dev_dbg(&adapter->dev, "Unsupported chip "
+                               "(man_id=0x%02X, chip_id=0x%02X).\n",
+                               man_id, chip_id);
+                       goto exit_free;
+               }
+       }
+
+       strlcpy(new_client->name, "lm63", I2C_NAME_SIZE);
+       data->valid = 0;
+       init_MUTEX(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(new_client)))
+               goto exit_free;
+
+       /* Initialize the LM63 chip */
+       lm63_init_client(new_client);
+
+       /* Register sysfs hooks */
+       if (data->config & 0x04) { /* tachometer enabled */
+               device_create_file(&new_client->dev, &dev_attr_fan1_input);
+               device_create_file(&new_client->dev, &dev_attr_fan1_min);
+       }
+       device_create_file(&new_client->dev, &dev_attr_pwm1);
+       device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+       device_create_file(&new_client->dev, &dev_attr_temp1_input);
+       device_create_file(&new_client->dev, &dev_attr_temp2_input);
+       device_create_file(&new_client->dev, &dev_attr_temp2_min);
+       device_create_file(&new_client->dev, &dev_attr_temp1_max);
+       device_create_file(&new_client->dev, &dev_attr_temp2_max);
+       device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+       device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
+       device_create_file(&new_client->dev, &dev_attr_alarms);
+
+       return 0;
+
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+/* Idealy we shouldn't have to initialize anything, since the BIOS
+   should have taken care of everything */
+static void lm63_init_client(struct i2c_client *client)
+{
+       struct lm63_data *data = i2c_get_clientdata(client);
+
+       data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+       data->config_fan = i2c_smbus_read_byte_data(client,
+                                                   LM63_REG_CONFIG_FAN);
+
+       /* Start converting if needed */
+       if (data->config & 0x40) { /* standby */
+               dev_dbg(&client->dev, "Switching to operational mode");
+               data->config &= 0xA7;
+               i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
+                                         data->config);
+       }
+
+       /* We may need pwm1_freq before ever updating the client data */
+       data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
+       if (data->pwm1_freq == 0)
+               data->pwm1_freq = 1;
+
+       /* Show some debug info about the LM63 configuration */
+       dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
+               (data->config & 0x04) ? "tachometer input" :
+               "alert output");
+       dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n",
+               (data->config_fan & 0x04) ? "1.4" : "360",
+               ((data->config_fan & 0x04) ? 700 : 180000) / data->pwm1_freq);
+       dev_dbg(&client->dev, "PWM output active %s, %s mode\n",
+               (data->config_fan & 0x10) ? "low" : "high",
+               (data->config_fan & 0x20) ? "manual" : "auto");
+}
+
+static int lm63_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       if ((err = i2c_detach_client(client))) {
+               dev_err(&client->dev, "Client deregistration failed, "
+                       "client not detached\n");
+               return err;
+       }
+
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static struct lm63_data *lm63_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+
+       down(&data->update_lock);
+
+       if ((jiffies - data->last_updated > HZ) ||
+           (jiffies < data->last_updated) ||
+           !data->valid) {
+               if (data->config & 0x04) { /* tachometer enabled  */
+                       /* order matters for fan1_input */
+                       data->fan1_input = i2c_smbus_read_byte_data(client,
+                                          LM63_REG_TACH_COUNT_LSB) & 0xFC;
+                       data->fan1_input |= i2c_smbus_read_byte_data(client,
+                                           LM63_REG_TACH_COUNT_MSB) << 8;
+                       data->fan1_low = (i2c_smbus_read_byte_data(client,
+                                         LM63_REG_TACH_LIMIT_LSB) & 0xFC)
+                                      | (i2c_smbus_read_byte_data(client,
+                                         LM63_REG_TACH_LIMIT_MSB) << 8);
+               }
+
+               data->pwm1_freq = i2c_smbus_read_byte_data(client,
+                                 LM63_REG_PWM_FREQ);
+               if (data->pwm1_freq == 0)
+                       data->pwm1_freq = 1;
+               data->pwm1_value = i2c_smbus_read_byte_data(client,
+                                  LM63_REG_PWM_VALUE);
+
+               data->temp1_input = i2c_smbus_read_byte_data(client,
+                                   LM63_REG_LOCAL_TEMP);
+               data->temp1_high = i2c_smbus_read_byte_data(client,
+                                  LM63_REG_LOCAL_HIGH);
+
+               /* order matters for temp2_input */
+               data->temp2_input = i2c_smbus_read_byte_data(client,
+                                   LM63_REG_REMOTE_TEMP_MSB) << 8;
+               data->temp2_input |= i2c_smbus_read_byte_data(client,
+                                    LM63_REG_REMOTE_TEMP_LSB);
+               data->temp2_high = (i2c_smbus_read_byte_data(client,
+                                  LM63_REG_REMOTE_HIGH_MSB) << 8)
+                                | i2c_smbus_read_byte_data(client,
+                                  LM63_REG_REMOTE_HIGH_LSB);
+               data->temp2_low = (i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_LOW_MSB) << 8)
+                               | i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_LOW_LSB);
+               data->temp2_crit = i2c_smbus_read_byte_data(client,
+                                  LM63_REG_REMOTE_TCRIT);
+               data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
+                                       LM63_REG_REMOTE_TCRIT_HYST);
+
+               data->alarms = i2c_smbus_read_byte_data(client,
+                              LM63_REG_ALERT_STATUS) & 0x7F;
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       up(&data->update_lock);
+
+       return data;
+}
+
+static int __init sensors_lm63_init(void)
+{
+       return i2c_add_driver(&lm63_driver);
+}
+
+static void __exit sensors_lm63_exit(void)
+{
+       i2c_del_driver(&lm63_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("LM63 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm63_init);
+module_exit(sensors_lm63_exit);
diff --git a/drivers/i2c/chips/lm87.c b/drivers/i2c/chips/lm87.c
new file mode 100644 (file)
index 0000000..7da39fe
--- /dev/null
@@ -0,0 +1,812 @@
+/*
+ * lm87.c
+ *
+ * Copyright (C) 2000       Frodo Looijaard <frodol@dds.nl>
+ *                          Philip Edelbrock <phil@netroedge.com>
+ *                          Stephen Rousset <stephen.rousset@rocketlogix.com>
+ *                          Dan Eaton <dan.eaton@rocketlogix.com>
+ * Copyright (C) 2004       Jean Delvare <khali@linux-fr.org>
+ *
+ * Original port to Linux 2.6 by Jeff Oliver.
+ *
+ * The LM87 is a sensor chip made by National Semiconductor. It monitors up
+ * to 8 voltages (including its own power source), up to three temperatures
+ * (its own plus up to two external ones) and up to two fans. The default
+ * configuration is 6 voltages, two temperatures and two fans (see below).
+ * Voltages are scaled internally with ratios such that the nominal value of
+ * each voltage correspond to a register value of 192 (which means a
+ * resolution of about 0.5% of the nominal value). Temperature values are
+ * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete
+ * datasheet can be obtained from National's website at:
+ *   http://www.national.com/pf/LM/LM87.html
+ *
+ * Some functions share pins, so not all functions are available at the same
+ * time. Which are depends on the hardware setup. This driver assumes that
+ * the BIOS configured the chip correctly. In that respect, it  differs from
+ * the original driver (from lm_sensors for Linux 2.4), which would force the
+ * LM87 to an arbitrary, compile-time chosen mode, regardless of the actual
+ * chipset wiring.
+ * For reference, here is the list of exclusive functions:
+ *  - in0+in5 (default) or temp3
+ *  - fan1 (default) or in6
+ *  - fan2 (default) or in7
+ *  - VID lines (default) or IRQ lines (not handled by this driver)
+ *
+ * The LM87 additionally features an analog output, supposedly usable to
+ * control the speed of a fan. All new chips use pulse width modulation
+ * instead. The LM87 is the only hardware monitoring chipset I know of
+ * which uses amplitude modulation. Be careful when using this feature.
+ *
+ * This 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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+
+/*
+ * Addresses to scan
+ * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e.
+ */
+
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+
+/*
+ * Insmod parameters
+ */
+
+SENSORS_INSMOD_1(lm87);
+
+/*
+ * The LM87 registers
+ */
+
+/* nr in 0..5 */
+#define LM87_REG_IN(nr)                        (0x20 + (nr))
+#define LM87_REG_IN_MAX(nr)            (0x2B + (nr) * 2)
+#define LM87_REG_IN_MIN(nr)            (0x2C + (nr) * 2)
+/* nr in 0..1 */
+#define LM87_REG_AIN(nr)               (0x28 + (nr))
+#define LM87_REG_AIN_MIN(nr)           (0x1A + (nr))
+#define LM87_REG_AIN_MAX(nr)           (0x3B + (nr))
+
+static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 };
+static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B };
+static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
+
+#define LM87_REG_TEMP_HW_INT_LOCK      0x13
+#define LM87_REG_TEMP_HW_EXT_LOCK      0x14
+#define LM87_REG_TEMP_HW_INT           0x17
+#define LM87_REG_TEMP_HW_EXT           0x18
+
+/* nr in 0..1 */
+#define LM87_REG_FAN(nr)               (0x28 + (nr))
+#define LM87_REG_FAN_MIN(nr)           (0x3B + (nr))
+#define LM87_REG_AOUT                  0x19
+
+#define LM87_REG_CONFIG                        0x40
+#define LM87_REG_CHANNEL_MODE          0x16
+#define LM87_REG_VID_FAN_DIV           0x47
+#define LM87_REG_VID4                  0x49
+
+#define LM87_REG_ALARMS1               0x41
+#define LM87_REG_ALARMS2               0x42
+
+#define LM87_REG_COMPANY_ID            0x3E
+#define LM87_REG_REVISION              0x3F
+
+/*
+ * Conversions and various macros
+ * The LM87 uses signed 8-bit values for temperatures.
+ */
+
+#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192)
+#define IN_TO_REG(val,scale)   ((val) <= 0 ? 0 : \
+                                (val) * 192 >= (scale) * 255 ? 255 : \
+                                ((val) * 192 + (scale)/2) / (scale))
+
+#define TEMP_FROM_REG(reg)     ((reg) * 1000)
+#define TEMP_TO_REG(val)       ((val) <= -127500 ? -128 : \
+                                (val) >= 126500 ? 127 : \
+                                (((val) < 0 ? (val)-500 : (val)+500) / 1000))
+
+#define FAN_FROM_REG(reg,div)  ((reg) == 255 || (reg) == 0 ? 0 : \
+                                1350000 + (reg)*(div) / 2) / ((reg)*(div))
+#define FAN_TO_REG(val,div)    ((val)*(div) * 255 <= 1350000 ? 255 : \
+                                (1350000 + (val)*(div) / 2) / ((val)*(div)))
+
+#define FAN_DIV_FROM_REG(reg)  (1 << (reg))
+
+/* analog out is 9.80mV/LSB */
+#define AOUT_FROM_REG(reg)     (((reg) * 98 + 5) / 10)
+#define AOUT_TO_REG(val)       ((val) <= 0 ? 0 : \
+                                (val) >= 2500 ? 255 : \
+                                ((val) * 10 + 49) / 98)
+
+/* nr in 0..1 */
+#define CHAN_NO_FAN(nr)                (1 << (nr))
+#define CHAN_TEMP3             (1 << 2)
+#define CHAN_VCC_5V            (1 << 3)
+#define CHAN_NO_VID            (1 << 8)
+
+/*
+ * Functions declaration
+ */
+
+static int lm87_attach_adapter(struct i2c_adapter *adapter);
+static int lm87_detect(struct i2c_adapter *adapter, int address, int kind);
+static void lm87_init_client(struct i2c_client *client);
+static int lm87_detach_client(struct i2c_client *client);
+static struct lm87_data *lm87_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver lm87_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "lm87",
+       .id             = I2C_DRIVERID_LM87,
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = lm87_attach_adapter,
+       .detach_client  = lm87_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm87_data {
+       struct i2c_client client;
+       struct semaphore update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* In jiffies */
+
+       u8 channel;             /* register value */
+
+       u8 in[8];               /* register value */
+       u8 in_max[8];           /* register value */
+       u8 in_min[8];           /* register value */
+       u16 in_scale[8];
+
+       s8 temp[3];             /* register value */
+       s8 temp_high[3];        /* register value */
+       s8 temp_low[3];         /* register value */
+       s8 temp_crit_int;       /* min of two register values */
+       s8 temp_crit_ext;       /* min of two register values */
+
+       u8 fan[2];              /* register value */
+       u8 fan_min[2];          /* register value */
+       u8 fan_div[2];          /* register value, shifted right */
+       u8 aout;                /* register value */
+
+       u16 alarms;             /* register values, combined */
+       u8 vid;                 /* register values, combined */
+       u8 vrm;
+};
+
+/*
+ * Internal variables
+ */
+
+static int lm87_id;
+
+/*
+ * Sysfs stuff
+ */
+
+static inline int lm87_read_value(struct i2c_client *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+#define show_in(offset) \
+static ssize_t show_in##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
+                      data->in_scale[offset])); \
+} \
+static ssize_t show_in##offset##_min(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
+                      data->in_scale[offset])); \
+} \
+static ssize_t show_in##offset##_max(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
+                      data->in_scale[offset])); \
+} \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+               show_in##offset##_input, NULL);
+show_in(0);
+show_in(1);
+show_in(2);
+show_in(3);
+show_in(4);
+show_in(5);
+show_in(6);
+show_in(7);
+
+static void set_in_min(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
+       lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) :
+                        LM87_REG_AIN_MIN(nr-6), data->in_min[nr]);
+}
+
+static void set_in_max(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
+       lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) :
+                        LM87_REG_AIN_MAX(nr-6), data->in_max[nr]);
+}
+
+#define set_in(offset) \
+static ssize_t set_in##offset##_min(struct device *dev, \
+               const char *buf, size_t count) \
+{ \
+       set_in_min(dev, buf, offset); \
+       return count; \
+} \
+static ssize_t set_in##offset##_max(struct device *dev, \
+               const char *buf, size_t count) \
+{ \
+       set_in_max(dev, buf, offset); \
+       return count; \
+} \
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+               show_in##offset##_min, set_in##offset##_min); \
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+               show_in##offset##_max, set_in##offset##_max);
+set_in(0);
+set_in(1);
+set_in(2);
+set_in(3);
+set_in(4);
+set_in(5);
+set_in(6);
+set_in(7);
+
+#define show_temp(offset) \
+static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
+} \
+static ssize_t show_temp##offset##_low(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \
+} \
+static ssize_t show_temp##offset##_high(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \
+}\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+               show_temp##offset##_input, NULL);
+show_temp(1);
+show_temp(2);
+show_temp(3);
+
+static void set_temp_low(struct device *dev, const char *buf, int nr)
+{
+    struct i2c_client *client = to_i2c_client(dev);
+    struct lm87_data *data = i2c_get_clientdata(client);
+    long val = simple_strtol(buf, NULL, 10);
+    data->temp_low[nr] = TEMP_TO_REG(val);
+    lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
+}
+
+static void set_temp_high(struct device *dev, const char *buf, int nr)
+{
+    struct i2c_client *client = to_i2c_client(dev);
+    struct lm87_data *data = i2c_get_clientdata(client);
+    long val = simple_strtol(buf, NULL, 10);
+    data->temp_high[nr] = TEMP_TO_REG(val);
+    lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
+}
+
+#define set_temp(offset) \
+static ssize_t set_temp##offset##_low(struct device *dev, \
+               const char *buf, size_t count) \
+{ \
+       set_temp_low(dev, buf, offset-1); \
+       return count; \
+} \
+static ssize_t set_temp##offset##_high(struct device *dev, \
+               const char *buf, size_t count) \
+{ \
+       set_temp_high(dev, buf, offset-1); \
+       return count; \
+} \
+static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+               show_temp##offset##_high, set_temp##offset##_high); \
+static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+               show_temp##offset##_low, set_temp##offset##_low);
+set_temp(1);
+set_temp(2);
+set_temp(3);
+
+static ssize_t show_temp_crit_int(struct device *dev, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int));
+}
+
+static ssize_t show_temp_crit_ext(struct device *dev, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext));
+}
+
+static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL);
+static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL);
+static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL);
+
+#define show_fan(offset) \
+static ssize_t show_fan##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \
+                      FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \
+} \
+static ssize_t show_fan##offset##_min(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \
+                      FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \
+} \
+static ssize_t show_fan##offset##_div(struct device *dev, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \
+} \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+               show_fan##offset##_input, NULL);
+show_fan(1);
+show_fan(2);
+
+static void set_fan_min(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       data->fan_min[nr] = FAN_TO_REG(val,
+                           FAN_DIV_FROM_REG(data->fan_div[nr]));
+       lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+   determined in part by the fan clock divider.  This follows the principle
+   of least suprise; the user doesn't expect the fan minimum to change just
+   because the divider changed. */
+static ssize_t set_fan_div(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       unsigned long min = FAN_FROM_REG(data->fan_min[nr],
+                           FAN_DIV_FROM_REG(data->fan_div[nr]));
+       u8 reg;
+
+       switch (val) {
+       case 1: data->fan_div[nr] = 0; break;
+       case 2: data->fan_div[nr] = 1; break;
+       case 4: data->fan_div[nr] = 2; break;
+       case 8: data->fan_div[nr] = 3; break;
+       default: return -EINVAL;
+       }
+
+       reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
+       switch (nr) {
+       case 0:
+           reg = (reg & 0xCF) | (data->fan_div[0] << 4);
+           break;
+       case 1:
+           reg = (reg & 0x3F) | (data->fan_div[1] << 6);
+           break;
+       }
+       lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg);
+
+       data->fan_min[nr] = FAN_TO_REG(min, val);
+       lm87_write_value(client, LM87_REG_FAN_MIN(nr),
+                        data->fan_min[nr]);
+       return count;
+}
+
+#define set_fan(offset) \
+static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \
+               size_t count) \
+{ \
+       set_fan_min(dev, buf, offset-1); \
+       return count; \
+} \
+static ssize_t set_fan##offset##_div(struct device *dev, const char *buf, \
+               size_t count) \
+{ \
+       return set_fan_div(dev, buf, count, offset-1); \
+} \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+               show_fan##offset##_min, set_fan##offset##_min); \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+               show_fan##offset##_div, set_fan##offset##_div);
+set_fan(1);
+set_fan(2);
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_vid(struct device *dev, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       data->vrm = simple_strtoul(buf, NULL, 10);
+       return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_aout(struct device *dev, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
+}
+static ssize_t set_aout(struct device *dev, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       data->aout = AOUT_TO_REG(val);
+       lm87_write_value(client, LM87_REG_AOUT, data->aout);
+       return count;
+}
+static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+
+/*
+ * Real code
+ */
+
+static int lm87_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_detect(adapter, &addr_data, lm87_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *new_client;
+       struct lm87_data *data;
+       int err = 0;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               goto exit;
+
+       if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       memset(data, 0, sizeof(struct lm87_data));
+
+       /* The common I2C client data is placed right before the
+          LM87-specific data. */
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &lm87_driver;
+       new_client->flags = 0;
+
+       /* Default to an LM87 if forced */
+       if (kind == 0)
+               kind = lm87;
+
+       /* Now, we do the remaining detection. */
+       if (kind < 0) {
+               u8 rev = lm87_read_value(new_client, LM87_REG_REVISION);
+
+               if (rev < 0x01 || rev > 0x08
+                || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)
+                || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) {
+                       dev_dbg(&adapter->dev,
+                               "LM87 detection failed at 0x%02x.\n",
+                               address);
+                       goto exit_free;
+               }
+       }
+
+       /* We can fill in the remaining client fields */
+       strlcpy(new_client->name, "lm87", I2C_NAME_SIZE);
+       new_client->id = lm87_id++;
+       data->valid = 0;
+       init_MUTEX(&data->update_lock);
+
+       /* Tell the I2C layer a new client has arrived */
+       if ((err = i2c_attach_client(new_client)))
+               goto exit_free;
+
+       /* Initialize the LM87 chip */
+       lm87_init_client(new_client);
+
+       data->in_scale[0] = 2500;
+       data->in_scale[1] = 2700;
+       data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300;
+       data->in_scale[3] = 5000;
+       data->in_scale[4] = 12000;
+       data->in_scale[5] = 2700;
+       data->in_scale[6] = 1875;
+       data->in_scale[7] = 1875;
+
+       /* Register sysfs hooks */
+       device_create_file(&new_client->dev, &dev_attr_in1_input);
+       device_create_file(&new_client->dev, &dev_attr_in1_min);
+       device_create_file(&new_client->dev, &dev_attr_in1_max);
+       device_create_file(&new_client->dev, &dev_attr_in2_input);
+       device_create_file(&new_client->dev, &dev_attr_in2_min);
+       device_create_file(&new_client->dev, &dev_attr_in2_max);
+       device_create_file(&new_client->dev, &dev_attr_in3_input);
+       device_create_file(&new_client->dev, &dev_attr_in3_min);
+       device_create_file(&new_client->dev, &dev_attr_in3_max);
+       device_create_file(&new_client->dev, &dev_attr_in4_input);
+       device_create_file(&new_client->dev, &dev_attr_in4_min);
+       device_create_file(&new_client->dev, &dev_attr_in4_max);
+
+       if (data->channel & CHAN_NO_FAN(0)) {
+               device_create_file(&new_client->dev, &dev_attr_in6_input);
+               device_create_file(&new_client->dev, &dev_attr_in6_min);
+               device_create_file(&new_client->dev, &dev_attr_in6_max);
+       } else {
+               device_create_file(&new_client->dev, &dev_attr_fan1_input);
+               device_create_file(&new_client->dev, &dev_attr_fan1_min);
+               device_create_file(&new_client->dev, &dev_attr_fan1_div);
+       }
+       if (data->channel & CHAN_NO_FAN(1)) {
+               device_create_file(&new_client->dev, &dev_attr_in7_input);
+               device_create_file(&new_client->dev, &dev_attr_in7_min);
+               device_create_file(&new_client->dev, &dev_attr_in7_max);
+       } else {
+               device_create_file(&new_client->dev, &dev_attr_fan2_input);
+               device_create_file(&new_client->dev, &dev_attr_fan2_min);
+               device_create_file(&new_client->dev, &dev_attr_fan2_div);
+       }
+
+       device_create_file(&new_client->dev, &dev_attr_temp1_input);
+       device_create_file(&new_client->dev, &dev_attr_temp1_max);
+       device_create_file(&new_client->dev, &dev_attr_temp1_min);
+       device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+       device_create_file(&new_client->dev, &dev_attr_temp2_input);
+       device_create_file(&new_client->dev, &dev_attr_temp2_max);
+       device_create_file(&new_client->dev, &dev_attr_temp2_min);
+       device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+
+       if (data->channel & CHAN_TEMP3) {
+               device_create_file(&new_client->dev, &dev_attr_temp3_input);
+               device_create_file(&new_client->dev, &dev_attr_temp3_max);
+               device_create_file(&new_client->dev, &dev_attr_temp3_min);
+               device_create_file(&new_client->dev, &dev_attr_temp3_crit);
+       } else {
+               device_create_file(&new_client->dev, &dev_attr_in0_input);
+               device_create_file(&new_client->dev, &dev_attr_in0_min);
+               device_create_file(&new_client->dev, &dev_attr_in0_max);
+               device_create_file(&new_client->dev, &dev_attr_in5_input);
+               device_create_file(&new_client->dev, &dev_attr_in5_min);
+               device_create_file(&new_client->dev, &dev_attr_in5_max);
+       }
+
+       if (!(data->channel & CHAN_NO_VID)) {
+               device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+               device_create_file(&new_client->dev, &dev_attr_vrm);
+       }
+
+       device_create_file(&new_client->dev, &dev_attr_alarms);
+       device_create_file(&new_client->dev, &dev_attr_aout_output);
+
+       return 0;
+
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static void lm87_init_client(struct i2c_client *client)
+{
+       struct lm87_data *data = i2c_get_clientdata(client);
+       u8 config;
+
+       data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
+       data->vrm = i2c_which_vrm();
+
+       config = lm87_read_value(client, LM87_REG_CONFIG);
+       if (!(config & 0x01)) {
+               int i;
+
+               /* Limits are left uninitialized after power-up */
+               for (i = 1; i < 6; i++) {
+                       lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00);
+                       lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF);
+               }
+               for (i = 0; i < 2; i++) {
+                       lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F);
+                       lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00);
+                       lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00);
+                       lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF);
+               }
+               if (data->channel & CHAN_TEMP3) {
+                       lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F);
+                       lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00);
+               } else {
+                       lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00);
+                       lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF);
+               }
+       }
+       if ((config & 0x81) != 0x01) {
+               /* Start monitoring */
+               lm87_write_value(client, LM87_REG_CONFIG,
+                                (config & 0xF7) | 0x01);
+       }
+}
+
+static int lm87_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       if ((err = i2c_detach_client(client))) {
+               dev_err(&client->dev, "Client deregistration failed, "
+                       "client not detached.\n");
+               return err;
+       }
+
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static struct lm87_data *lm87_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+
+       down(&data->update_lock);
+
+       if (jiffies - data->last_updated > HZ
+         || jiffies < data->last_updated
+         || !data->valid) {
+               int i, j;
+
+               dev_dbg(&client->dev, "Updating data.\n");
+
+               i = (data->channel & CHAN_TEMP3) ? 1 : 0;
+               j = (data->channel & CHAN_TEMP3) ? 5 : 6;
+               for (; i < j; i++) {
+                       data->in[i] = lm87_read_value(client,
+                                     LM87_REG_IN(i));
+                       data->in_min[i] = lm87_read_value(client,
+                                         LM87_REG_IN_MIN(i));
+                       data->in_max[i] = lm87_read_value(client,
+                                         LM87_REG_IN_MAX(i));
+               }
+
+               for (i = 0; i < 2; i++) {
+                       if (data->channel & CHAN_NO_FAN(i)) {
+                               data->in[6+i] = lm87_read_value(client,
+                                               LM87_REG_AIN(i));
+                               data->in_max[6+i] = lm87_read_value(client,
+                                                   LM87_REG_AIN_MAX(i));
+                               data->in_min[6+i] = lm87_read_value(client,
+                                                   LM87_REG_AIN_MIN(i));
+
+                       } else {
+                               data->fan[i] = lm87_read_value(client,
+                                              LM87_REG_FAN(i));
+                               data->fan_min[i] = lm87_read_value(client,
+                                                  LM87_REG_FAN_MIN(i));
+                       }
+               }
+
+               j = (data->channel & CHAN_TEMP3) ? 3 : 2;
+               for (i = 0 ; i < j; i++) {
+                       data->temp[i] = lm87_read_value(client,
+                                       LM87_REG_TEMP[i]);
+                       data->temp_high[i] = lm87_read_value(client,
+                                            LM87_REG_TEMP_HIGH[i]);
+                       data->temp_low[i] = lm87_read_value(client,
+                                           LM87_REG_TEMP_LOW[i]);
+               }
+
+               i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK);
+               j = lm87_read_value(client, LM87_REG_TEMP_HW_INT);
+               data->temp_crit_int = min(i, j);
+
+               i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK);
+               j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT);
+               data->temp_crit_ext = min(i, j);
+
+               i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
+               data->fan_div[0] = (i >> 4) & 0x03;
+               data->fan_div[1] = (i >> 6) & 0x03;
+               data->vid = (i & 0x0F)
+                         | (lm87_read_value(client, LM87_REG_VID4) & 0x01)
+                            << 4;
+
+               data->alarms = lm87_read_value(client, LM87_REG_ALARMS1)
+                            | (lm87_read_value(client, LM87_REG_ALARMS2)
+                               << 8);
+               data->aout = lm87_read_value(client, LM87_REG_AOUT);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       up(&data->update_lock);
+
+       return data;
+}
+
+static int __init sensors_lm87_init(void)
+{
+       return i2c_add_driver(&lm87_driver);
+}
+
+static void __exit sensors_lm87_exit(void)
+{
+       i2c_del_driver(&lm87_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org> and others");
+MODULE_DESCRIPTION("LM87 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm87_init);
+module_exit(sensors_lm87_exit);
diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c
new file mode 100644 (file)
index 0000000..3b1c020
--- /dev/null
@@ -0,0 +1,1298 @@
+/*
+ *  pc87360.c - Part of lm_sensors, Linux kernel modules
+ *              for hardware monitoring
+ *  Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ *
+ *  Copied from smsc47m1.c:
+ *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@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
+ *  (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.
+ *
+ *  Supports the following chips:
+ *
+ *  Chip        #vin    #fan    #pwm    #temp   devid
+ *  PC87360     -       2       2       -       0xE1
+ *  PC87363     -       2       2       -       0xE8
+ *  PC87364     -       3       3       -       0xE4
+ *  PC87365     11      3       3       2       0xE5
+ *  PC87366     11      3       3       3-4     0xE9
+ *
+ *  This driver assumes that no more than one chip is present, and one of
+ *  the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F).
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/i2c-vid.h>
+#include <asm/io.h>
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
+static struct i2c_force_data forces[] = {{ NULL }};
+static u8 devid;
+static unsigned int extra_isa[3];
+static u8 confreg[4];
+
+enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
+static struct i2c_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_isa             = normal_isa,
+       .forces                 = forces,
+};
+
+static int init = 1;
+module_param(init, int, 0);
+MODULE_PARM_DESC(init,
+ "Chip initialization level:\n"
+ " 0: None\n"
+ "*1: Forcibly enable internal voltage and temperature channels, except in9\n"
+ " 2: Forcibly enable all voltage and temperature channels, except in9\n"
+ " 3: Forcibly enable all voltage and temperature channels, including in9");
+
+/*
+ * Super-I/O registers and operations
+ */
+
+#define DEV    0x07    /* Register: Logical device select */
+#define DEVID  0x20    /* Register: Device ID */
+#define ACT    0x30    /* Register: Device activation */
+#define BASE   0x60    /* Register: Base address */
+
+#define FSCM   0x09    /* Logical device: fans */
+#define VLM    0x0d    /* Logical device: voltages */
+#define TMS    0x0e    /* Logical device: temperatures */
+static const u8 logdev[3] = { FSCM, VLM, TMS };
+
+#define LD_FAN         0
+#define LD_IN          1
+#define LD_TEMP                2
+
+static inline void superio_outb(int sioaddr, int reg, int val)
+{
+       outb(reg, sioaddr);
+       outb(val, sioaddr+1);
+}
+
+static inline int superio_inb(int sioaddr, int reg)
+{
+       outb(reg, sioaddr);
+       return inb(sioaddr+1);
+}
+
+static inline void superio_exit(int sioaddr)
+{
+       outb(0x02, sioaddr);
+       outb(0x02, sioaddr+1);
+}
+
+/*
+ * Logical devices
+ */
+
+#define PC87360_EXTENT         0x10
+#define PC87365_REG_BANK       0x09
+#define NO_BANK                        0xff
+
+/*
+ * Fan registers and conversions
+ */
+
+/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */
+#define PC87360_REG_PRESCALE(nr)       (0x00 + 2 * (nr))
+#define PC87360_REG_PWM(nr)            (0x01 + 2 * (nr))
+#define PC87360_REG_FAN_MIN(nr)                (0x06 + 3 * (nr))
+#define PC87360_REG_FAN(nr)            (0x07 + 3 * (nr))
+#define PC87360_REG_FAN_STATUS(nr)     (0x08 + 3 * (nr))
+
+#define FAN_FROM_REG(val,div)          ((val) == 0 ? 0: \
+                                        480000 / ((val)*(div)))
+#define FAN_TO_REG(val,div)            ((val) <= 100 ? 0 : \
+                                        480000 / ((val)*(div)))
+#define FAN_DIV_FROM_REG(val)          (1 << ((val >> 5) & 0x03))
+#define FAN_STATUS_FROM_REG(val)       ((val) & 0x07)
+
+#define FAN_CONFIG_MONITOR(val,nr)     (((val) >> (2 + nr * 3)) & 1)
+#define FAN_CONFIG_CONTROL(val,nr)     (((val) >> (3 + nr * 3)) & 1)
+#define FAN_CONFIG_INVERT(val,nr)      (((val) >> (4 + nr * 3)) & 1)
+
+#define PWM_FROM_REG(val,inv)          ((inv) ? 255 - (val) : (val))
+static inline u8 PWM_TO_REG(int val, int inv)
+{
+       if (inv)
+               val = 255 - val;
+       if (val < 0)
+               return 0;
+       if (val > 255)
+               return 255;
+       return val;
+}
+
+/*
+ * Voltage registers and conversions
+ */
+
+#define PC87365_REG_IN_CONVRATE                0x07
+#define PC87365_REG_IN_CONFIG          0x08
+#define PC87365_REG_IN                 0x0B
+#define PC87365_REG_IN_MIN             0x0D
+#define PC87365_REG_IN_MAX             0x0C
+#define PC87365_REG_IN_STATUS          0x0A
+#define PC87365_REG_IN_ALARMS1         0x00
+#define PC87365_REG_IN_ALARMS2         0x01
+#define PC87365_REG_VID                        0x06
+
+#define IN_FROM_REG(val,ref)           (((val) * (ref) + 128) / 256)
+#define IN_TO_REG(val,ref)             ((val) < 0 ? 0 : \
+                                        (val)*256 >= (ref)*255 ? 255: \
+                                        ((val) * 256 + (ref)/2) / (ref))
+
+/*
+ * Temperature registers and conversions
+ */
+
+#define PC87365_REG_TEMP_CONFIG                0x08
+#define PC87365_REG_TEMP               0x0B
+#define PC87365_REG_TEMP_MIN           0x0D
+#define PC87365_REG_TEMP_MAX           0x0C
+#define PC87365_REG_TEMP_CRIT          0x0E
+#define PC87365_REG_TEMP_STATUS                0x0A
+#define PC87365_REG_TEMP_ALARMS                0x00
+
+#define TEMP_FROM_REG(val)             ((val) * 1000)
+#define TEMP_TO_REG(val)               ((val) < -55000 ? -55 : \
+                                        (val) > 127000 ? 127 : \
+                                        (val) < 0 ? ((val) - 500) / 1000 : \
+                                        ((val) + 500) / 1000)
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct pc87360_data {
+       struct i2c_client client;
+       struct semaphore lock;
+       struct semaphore update_lock;
+       char valid;             /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       int address[3];
+
+       u8 fannr, innr, tempnr;
+
+       u8 fan[3];              /* Register value */
+       u8 fan_min[3];          /* Register value */
+       u8 fan_status[3];       /* Register value */
+       u8 pwm[3];              /* Register value */
+       u16 fan_conf;           /* Configuration register values, combined */
+
+       u16 in_vref;            /* 1 mV/bit */
+       u8 in[14];              /* Register value */
+       u8 in_min[14];          /* Register value */
+       u8 in_max[14];          /* Register value */
+       u8 in_crit[3];          /* Register value */
+       u8 in_status[14];       /* Register value */
+       u16 in_alarms;          /* Register values, combined, masked */
+       u8 vid_conf;            /* Configuration register value */
+       u8 vrm;
+       u8 vid;                 /* Register value */
+
+       s8 temp[3];             /* Register value */
+       s8 temp_min[3];         /* Register value */
+       s8 temp_max[3];         /* Register value */
+       s8 temp_crit[3];        /* Register value */
+       u8 temp_status[3];      /* Register value */
+       u8 temp_alarms;         /* Register value, masked */
+};
+
+/*
+ * Functions declaration
+ */
+
+static int pc87360_attach_adapter(struct i2c_adapter *adapter);
+static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pc87360_detach_client(struct i2c_client *client);
+
+static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
+                             u8 reg);
+static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
+                               u8 reg, u8 value);
+static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
+static struct pc87360_data *pc87360_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver pc87360_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "pc87360",
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = pc87360_attach_adapter,
+       .detach_client  = pc87360_detach_client,
+};
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t set_fan_min(struct device *dev, const char *buf,
+       size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       long fan_min = simple_strtol(buf, NULL, 10);
+
+       fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr]));
+
+       /* If it wouldn't fit, change clock divisor */
+       while (fan_min > 255
+           && (data->fan_status[nr] & 0x60) != 0x60) {
+               fan_min >>= 1;
+               data->fan[nr] >>= 1;
+               data->fan_status[nr] += 0x20;
+       }
+       data->fan_min[nr] = fan_min > 255 ? 255 : fan_min;
+       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr),
+                           data->fan_min[nr]);
+
+       /* Write new divider, preserve alarm bits */
+       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr),
+                           data->fan_status[nr] & 0xF9);
+
+       return count;
+}
+
+#define show_and_set_fan(offset) \
+static ssize_t show_fan##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \
+                      FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
+} \
+static ssize_t show_fan##offset##_min(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \
+                      FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \
+} \
+static ssize_t show_fan##offset##_div(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", \
+                      FAN_DIV_FROM_REG(data->fan_status[offset-1])); \
+} \
+static ssize_t show_fan##offset##_status(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", \
+                      FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \
+} \
+static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       return set_fan_min(dev, buf, count, offset-1); \
+} \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+       show_fan##offset##_input, NULL); \
+static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \
+       show_fan##offset##_min, set_fan##offset##_min); \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
+       show_fan##offset##_div, NULL); \
+static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \
+       show_fan##offset##_status, NULL);
+show_and_set_fan(1)
+show_and_set_fan(2)
+show_and_set_fan(3)
+
+#define show_and_set_pwm(offset) \
+static ssize_t show_pwm##offset(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", \
+                      PWM_FROM_REG(data->pwm[offset-1], \
+                                   FAN_CONFIG_INVERT(data->fan_conf, \
+                                                     offset-1))); \
+} \
+static ssize_t set_pwm##offset(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->pwm[offset-1] = PWM_TO_REG(val, \
+                             FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \
+       pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \
+                           data->pwm[offset-1]); \
+       return count; \
+} \
+static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
+       show_pwm##offset, set_pwm##offset);
+show_and_set_pwm(1)
+show_and_set_pwm(2)
+show_and_set_pwm(3)
+
+#define show_and_set_in(offset) \
+static ssize_t show_in##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
+                      data->in_vref)); \
+} \
+static ssize_t show_in##offset##_min(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
+                      data->in_vref)); \
+} \
+static ssize_t show_in##offset##_max(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
+                      data->in_vref)); \
+} \
+static ssize_t show_in##offset##_status(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", data->in_status[offset]); \
+} \
+static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_min[offset] = IN_TO_REG(val, data->in_vref); \
+       pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \
+                           data->in_min[offset]); \
+       return count; \
+} \
+static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_max[offset] = IN_TO_REG(val, \
+                              data->in_vref); \
+       pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \
+                           data->in_max[offset]); \
+       return count; \
+} \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+       show_in##offset##_input, NULL); \
+static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \
+       show_in##offset##_min, set_in##offset##_min); \
+static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \
+       show_in##offset##_max, set_in##offset##_max); \
+static DEVICE_ATTR(in##offset##_status, S_IRUGO, \
+       show_in##offset##_status, NULL);
+show_and_set_in(0)
+show_and_set_in(1)
+show_and_set_in(2)
+show_and_set_in(3)
+show_and_set_in(4)
+show_and_set_in(5)
+show_and_set_in(6)
+show_and_set_in(7)
+show_and_set_in(8)
+show_and_set_in(9)
+show_and_set_in(10)
+
+#define show_and_set_therm(offset) \
+static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \
+                      data->in_vref)); \
+} \
+static ssize_t show_temp##offset##_min(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \
+                      data->in_vref)); \
+} \
+static ssize_t show_temp##offset##_max(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \
+                      data->in_vref)); \
+} \
+static ssize_t show_temp##offset##_crit(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \
+                      data->in_vref)); \
+} \
+static ssize_t show_temp##offset##_status(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%u\n", data->in_status[offset+7]); \
+} \
+static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \
+       pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \
+                           data->in_min[offset+7]); \
+       return count; \
+} \
+static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \
+       pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \
+                           data->in_max[offset+7]); \
+       return count; \
+} \
+static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \
+       pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \
+                           data->in_crit[offset-4]); \
+       return count; \
+} \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+       show_temp##offset##_input, NULL); \
+static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+       show_temp##offset##_min, set_temp##offset##_min); \
+static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+       show_temp##offset##_max, set_temp##offset##_max); \
+static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+       show_temp##offset##_crit, set_temp##offset##_crit); \
+static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+       show_temp##offset##_status, NULL);
+show_and_set_therm(4)
+show_and_set_therm(5)
+show_and_set_therm(6)
+
+static ssize_t show_vid(struct device *dev, char *buf)
+{
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, char *buf)
+{
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       data->vrm = simple_strtoul(buf, NULL, 10);
+       return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_in_alarms(struct device *dev, char *buf)
+{
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", data->in_alarms);
+}
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+
+#define show_and_set_temp(offset) \
+static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
+} \
+static ssize_t show_temp##offset##_min(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \
+} \
+static ssize_t show_temp##offset##_max(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \
+}\
+static ssize_t show_temp##offset##_crit(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \
+}\
+static ssize_t show_temp##offset##_status(struct device *dev, char *buf) \
+{ \
+       struct pc87360_data *data = pc87360_update_device(dev); \
+       return sprintf(buf, "%d\n", data->temp_status[offset-1]); \
+}\
+static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->temp_min[offset-1] = TEMP_TO_REG(val); \
+       pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \
+                           data->temp_min[offset-1]); \
+       return count; \
+} \
+static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->temp_max[offset-1] = TEMP_TO_REG(val); \
+       pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \
+                           data->temp_max[offset-1]); \
+       return count; \
+} \
+static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \
+       size_t count) \
+{ \
+       struct i2c_client *client = to_i2c_client(dev); \
+       struct pc87360_data *data = i2c_get_clientdata(client); \
+       long val = simple_strtol(buf, NULL, 10); \
+       data->temp_crit[offset-1] = TEMP_TO_REG(val); \
+       pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \
+                           data->temp_crit[offset-1]); \
+       return count; \
+} \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+       show_temp##offset##_input, NULL); \
+static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \
+       show_temp##offset##_min, set_temp##offset##_min); \
+static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \
+       show_temp##offset##_max, set_temp##offset##_max); \
+static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \
+       show_temp##offset##_crit, set_temp##offset##_crit); \
+static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \
+       show_temp##offset##_status, NULL);
+show_and_set_temp(1)
+show_and_set_temp(2)
+show_and_set_temp(3)
+
+static ssize_t show_temp_alarms(struct device *dev, char *buf)
+{
+       struct pc87360_data *data = pc87360_update_device(dev);
+       return sprintf(buf, "%u\n", data->temp_alarms);
+}
+static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
+
+/*
+ * Device detection, registration and update
+ */
+
+static int pc87360_attach_adapter(struct i2c_adapter *adapter)
+{
+       return i2c_detect(adapter, &addr_data, pc87360_detect);
+}
+
+static int pc87360_find(int sioaddr, u8 *devid, int *address)
+{
+       u16 val;
+       int i;
+       int nrdev; /* logical device count */
+
+       /* No superio_enter */
+
+       /* Identify device */
+       val = superio_inb(sioaddr, DEVID);
+       switch (val) {
+       case 0xE1: /* PC87360 */
+       case 0xE8: /* PC87363 */
+       case 0xE4: /* PC87364 */
+               nrdev = 1;
+               break;
+       case 0xE5: /* PC87365 */
+       case 0xE9: /* PC87366 */
+               nrdev = 3;
+               break;
+       default:
+               superio_exit(sioaddr);
+               return -ENODEV;
+       }
+       /* Remember the device id */
+       *devid = val;
+
+       for (i = 0; i < nrdev; i++) {
+               /* select logical device */
+               superio_outb(sioaddr, DEV, logdev[i]);
+
+               val = superio_inb(sioaddr, ACT);
+               if (!(val & 0x01)) {
+                       printk(KERN_INFO "pc87360: Device 0x%02x not "
+                              "activated\n", logdev[i]);
+                       continue;
+               }
+
+               val = (superio_inb(sioaddr, BASE) << 8)
+                   | superio_inb(sioaddr, BASE + 1);
+               if (!val) {
+                       printk(KERN_INFO "pc87360: Base address not set for "
+                              "device 0x%02x\n", logdev[i]);
+                       continue;
+               }
+
+               address[i] = val;
+
+               if (i==0) { /* Fans */
+                       confreg[0] = superio_inb(sioaddr, 0xF0);
+                       confreg[1] = superio_inb(sioaddr, 0xF1);
+
+#ifdef DEBUG
+                       printk(KERN_DEBUG "pc87360: Fan 1: mon=%d "
+                              "ctrl=%d inv=%d\n", (confreg[0]>>2)&1,
+                              (confreg[0]>>3)&1, (confreg[0]>>4)&1);
+                       printk(KERN_DEBUG "pc87360: Fan 2: mon=%d "
+                              "ctrl=%d inv=%d\n", (confreg[0]>>5)&1,
+                              (confreg[0]>>6)&1, (confreg[0]>>7)&1);
+                       printk(KERN_DEBUG "pc87360: Fan 3: mon=%d "
+                              "ctrl=%d inv=%d\n", confreg[1]&1,
+                              (confreg[1]>>1)&1, (confreg[1]>>2)&1);
+#endif
+               } else if (i==1) { /* Voltages */
+                       /* Are we using thermistors? */
+                       if (*devid == 0xE9) { /* PC87366 */
+                               /* These registers are not logical-device
+                                  specific, just that we won't need them if
+                                  we don't use the VLM device */
+                               confreg[2] = superio_inb(sioaddr, 0x2B);
+                               confreg[3] = superio_inb(sioaddr, 0x25);
+
+                               if (confreg[2] & 0x40) {
+                                       printk(KERN_INFO "pc87360: Using "
+                                              "thermistors for temperature "
+                                              "monitoring\n");
+                               }
+                               if (confreg[3] & 0xE0) {
+                                       printk(KERN_INFO "pc87360: VID "
+                                              "inputs routed (mode %u)\n",
+                                              confreg[3] >> 5);
+                               }
+                       }
+               }
+       }
+
+       superio_exit(sioaddr);
+       return 0;
+}
+
+/* We don't really care about the address.
+   Read from extra_isa instead. */
+int pc87360_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       int i;
+       struct i2c_client *new_client;
+       struct pc87360_data *data;
+       int err = 0;
+       const char *name = "pc87360";
+       int use_thermistors = 0;
+
+       if (!i2c_is_isa_adapter(adapter))
+               return -ENODEV;
+
+       if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
+               return -ENOMEM;
+       memset(data, 0x00, sizeof(struct pc87360_data));
+
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       init_MUTEX(&data->lock);
+       new_client->adapter = adapter;
+       new_client->driver = &pc87360_driver;
+       new_client->flags = 0;
+
+       data->fannr = 2;
+       data->innr = 0;
+       data->tempnr = 0;
+
+       switch (devid) {
+       case 0xe8:
+               name = "pc87363";
+               break;
+       case 0xe4:
+               name = "pc87364";
+               data->fannr = 3;
+               break;
+       case 0xe5:
+               name = "pc87365";
+               data->fannr = extra_isa[0] ? 3 : 0;
+               data->innr = extra_isa[1] ? 11 : 0;
+               data->tempnr = extra_isa[2] ? 2 : 0;
+               break;
+       case 0xe9:
+               name = "pc87366";
+               data->fannr = extra_isa[0] ? 3 : 0;
+               data->innr = extra_isa[1] ? 14 : 0;
+               data->tempnr = extra_isa[2] ? 3 : 0;
+               break;
+       }
+
+       strcpy(new_client->name, name);
+       data->valid = 0;
+       init_MUTEX(&data->update_lock);
+
+       for (i = 0; i < 3; i++) {
+               if (((data->address[i] = extra_isa[i]))
+                && !request_region(extra_isa[i], PC87360_EXTENT, "pc87360")) {
+                       dev_err(&new_client->dev, "Region 0x%x-0x%x already "
+                               "in use!\n", extra_isa[i],
+                               extra_isa[i]+PC87360_EXTENT-1);
+                       for (i--; i >= 0; i--)
+                               release_region(extra_isa[i], PC87360_EXTENT);
+                       err = -EBUSY;
+                       goto ERROR1;
+               }
+       }
+
+       /* Retrieve the fans configuration from Super-I/O space */
+       if (data->fannr)
+               data->fan_conf = confreg[0] | (confreg[1] << 8);
+
+       if ((err = i2c_attach_client(new_client)))
+               goto ERROR2;
+
+       /* Use the correct reference voltage
+          Unless both the VLM and the TMS logical devices agree to
+          use an external Vref, the internal one is used. */
+       if (data->innr) {
+               i = pc87360_read_value(data, LD_IN, NO_BANK,
+                                      PC87365_REG_IN_CONFIG);
+               if (data->tempnr) {
+                       i &= pc87360_read_value(data, LD_TEMP, NO_BANK,
+                                               PC87365_REG_TEMP_CONFIG);
+               }
+               data->in_vref = (i&0x02) ? 3025 : 2966;
+               dev_dbg(&new_client->dev, "Using %s reference voltage\n",
+                       (i&0x02) ? "external" : "internal");
+
+               data->vid_conf = confreg[3];
+               data->vrm = 90;
+       }
+
+       /* Fan clock dividers may be needed before any data is read */
+       for (i = 0; i < data->fannr; i++) {
+               data->fan_status[i] = pc87360_read_value(data, LD_FAN,
+                                     NO_BANK, PC87360_REG_FAN_STATUS(i));
+       }
+
+       if (init > 0) {
+               if (devid == 0xe9 && data->address[1]) /* PC87366 */
+                       use_thermistors = confreg[2] & 0x40;
+
+               pc87360_init_client(new_client, use_thermistors);
+       }
+
+       /* Register sysfs hooks */
+       if (data->innr) {
+               device_create_file(&new_client->dev, &dev_attr_in0_input);
+               device_create_file(&new_client->dev, &dev_attr_in1_input);
+               device_create_file(&new_client->dev, &dev_attr_in2_input);
+               device_create_file(&new_client->dev, &dev_attr_in3_input);
+               device_create_file(&new_client->dev, &dev_attr_in4_input);
+               device_create_file(&new_client->dev, &dev_attr_in5_input);
+               device_create_file(&new_client->dev, &dev_attr_in6_input);
+               device_create_file(&new_client->dev, &dev_attr_in7_input);
+               device_create_file(&new_client->dev, &dev_attr_in8_input);
+               device_create_file(&new_client->dev, &dev_attr_in9_input);
+               device_create_file(&new_client->dev, &dev_attr_in10_input);
+               device_create_file(&new_client->dev, &dev_attr_in0_min);
+               device_create_file(&new_client->dev, &dev_attr_in1_min);
+               device_create_file(&new_client->dev, &dev_attr_in2_min);
+               device_create_file(&new_client->dev, &dev_attr_in3_min);
+               device_create_file(&new_client->dev, &dev_attr_in4_min);
+               device_create_file(&new_client->dev, &dev_attr_in5_min);
+               device_create_file(&new_client->dev, &dev_attr_in6_min);
+               device_create_file(&new_client->dev, &dev_attr_in7_min);
+               device_create_file(&new_client->dev, &dev_attr_in8_min);
+               device_create_file(&new_client->dev, &dev_attr_in9_min);
+               device_create_file(&new_client->dev, &dev_attr_in10_min);
+               device_create_file(&new_client->dev, &dev_attr_in0_max);
+               device_create_file(&new_client->dev, &dev_attr_in1_max);
+               device_create_file(&new_client->dev, &dev_attr_in2_max);
+               device_create_file(&new_client->dev, &dev_attr_in3_max);
+               device_create_file(&new_client->dev, &dev_attr_in4_max);
+               device_create_file(&new_client->dev, &dev_attr_in5_max);
+               device_create_file(&new_client->dev, &dev_attr_in6_max);
+               device_create_file(&new_client->dev, &dev_attr_in7_max);
+               device_create_file(&new_client->dev, &dev_attr_in8_max);
+               device_create_file(&new_client->dev, &dev_attr_in9_max);
+               device_create_file(&new_client->dev, &dev_attr_in10_max);
+               device_create_file(&new_client->dev, &dev_attr_in0_status);
+               device_create_file(&new_client->dev, &dev_attr_in1_status);
+               device_create_file(&new_client->dev, &dev_attr_in2_status);
+               device_create_file(&new_client->dev, &dev_attr_in3_status);
+               device_create_file(&new_client->dev, &dev_attr_in4_status);
+               device_create_file(&new_client->dev, &dev_attr_in5_status);
+               device_create_file(&new_client->dev, &dev_attr_in6_status);
+               device_create_file(&new_client->dev, &dev_attr_in7_status);
+               device_create_file(&new_client->dev, &dev_attr_in8_status);
+               device_create_file(&new_client->dev, &dev_attr_in9_status);
+               device_create_file(&new_client->dev, &dev_attr_in10_status);
+
+               device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
+               device_create_file(&new_client->dev, &dev_attr_vrm);
+               device_create_file(&new_client->dev, &dev_attr_alarms_in);
+       }
+
+       if (data->tempnr) {
+               device_create_file(&new_client->dev, &dev_attr_temp1_input);
+               device_create_file(&new_client->dev, &dev_attr_temp2_input);
+               device_create_file(&new_client->dev, &dev_attr_temp1_min);
+               device_create_file(&new_client->dev, &dev_attr_temp2_min);
+               device_create_file(&new_client->dev, &dev_attr_temp1_max);
+               device_create_file(&new_client->dev, &dev_attr_temp2_max);
+               device_create_file(&new_client->dev, &dev_attr_temp1_crit);
+               device_create_file(&new_client->dev, &dev_attr_temp2_crit);
+               device_create_file(&new_client->dev, &dev_attr_temp1_status);
+               device_create_file(&new_client->dev, &dev_attr_temp2_status);
+
+               device_create_file(&new_client->dev, &dev_attr_alarms_temp);
+       }
+       if (data->tempnr == 3) {
+               device_create_file(&new_client->dev, &dev_attr_temp3_input);
+               device_create_file(&new_client->dev, &dev_attr_temp3_min);
+               device_create_file(&new_client->dev, &dev_attr_temp3_max);
+               device_create_file(&new_client->dev, &dev_attr_temp3_crit);
+               device_create_file(&new_client->dev, &dev_attr_temp3_status);
+       }
+       if (data->innr == 14) {
+               device_create_file(&new_client->dev, &dev_attr_temp4_input);
+               device_create_file(&new_client->dev, &dev_attr_temp5_input);
+               device_create_file(&new_client->dev, &dev_attr_temp6_input);
+               device_create_file(&new_client->dev, &dev_attr_temp4_min);
+               device_create_file(&new_client->dev, &dev_attr_temp5_min);
+               device_create_file(&new_client->dev, &dev_attr_temp6_min);
+               device_create_file(&new_client->dev, &dev_attr_temp4_max);
+               device_create_file(&new_client->dev, &dev_attr_temp5_max);
+               device_create_file(&new_client->dev, &dev_attr_temp6_max);
+               device_create_file(&new_client->dev, &dev_attr_temp4_crit);
+               device_create_file(&new_client->dev, &dev_attr_temp5_crit);
+               device_create_file(&new_client->dev, &dev_attr_temp6_crit);
+               device_create_file(&new_client->dev, &dev_attr_temp4_status);
+               device_create_file(&new_client->dev, &dev_attr_temp5_status);
+               device_create_file(&new_client->dev, &dev_attr_temp6_status);
+       }
+
+       if (data->fannr) {
+               device_create_file(&new_client->dev, &dev_attr_fan1_input);
+               device_create_file(&new_client->dev, &dev_attr_fan2_input);
+               device_create_file(&new_client->dev, &dev_attr_fan1_min);
+               device_create_file(&new_client->dev, &dev_attr_fan2_min);
+               device_create_file(&new_client->dev, &dev_attr_fan1_div);
+               device_create_file(&new_client->dev, &dev_attr_fan2_div);
+               device_create_file(&new_client->dev, &dev_attr_fan1_status);
+               device_create_file(&new_client->dev, &dev_attr_fan2_status);
+
+               if (FAN_CONFIG_CONTROL(data->fan_conf, 0))
+                       device_create_file(&new_client->dev, &dev_attr_pwm1);
+               if (FAN_CONFIG_CONTROL(data->fan_conf, 1))
+                       device_create_file(&new_client->dev, &dev_attr_pwm2);
+       }
+       if (data->fannr == 3) {
+               device_create_file(&new_client->dev, &dev_attr_fan3_input);
+               device_create_file(&new_client->dev, &dev_attr_fan3_min);
+               device_create_file(&new_client->dev, &dev_attr_fan3_div);
+               device_create_file(&new_client->dev, &dev_attr_fan3_status);
+
+               if (FAN_CONFIG_CONTROL(data->fan_conf, 2))
+                       device_create_file(&new_client->dev, &dev_attr_pwm3);
+       }
+
+       return 0;
+
+ERROR2:
+       for (i = 0; i < 3; i++) {
+               if (data->address[i]) {
+                       release_region(data->address[i], PC87360_EXTENT);
+               }
+       }
+ERROR1:
+       kfree(data);
+       return err;
+}
+
+static int pc87360_detach_client(struct i2c_client *client)
+{
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       int i;
+
+       if ((i = i2c_detach_client(client))) {
+               dev_err(&client->dev, "Client deregistration failed, "
+                       "client not detached.\n");
+               return i;
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (data->address[i]) {
+                       release_region(data->address[i], PC87360_EXTENT);
+               }
+       }
+       kfree(data);
+
+       return 0;
+}
+
+/* ldi is the logical device index
+   bank is for voltages and temperatures only */
+static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
+                             u8 reg)
+{
+       int res;
+
+       down(&(data->lock));
+       if (bank != NO_BANK)
+               outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
+       res = inb_p(data->address[ldi] + reg);
+       up(&(data->lock));
+
+       return res;
+}
+
+static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
+                               u8 reg, u8 value)
+{
+       down(&(data->lock));
+       if (bank != NO_BANK)
+               outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
+       outb_p(value, data->address[ldi] + reg);
+       up(&(data->lock));
+}
+
+static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
+{
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       int i, nr;
+       const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
+       const u8 init_temp[3] = { 2, 2, 1 };
+       u8 reg;
+
+       if (init >= 2 && data->innr) {
+               reg = pc87360_read_value(data, LD_IN, NO_BANK,
+                                        PC87365_REG_IN_CONVRATE);
+               dev_info(&client->dev, "VLM conversion set to"
+                        "1s period, 160us delay\n");
+               pc87360_write_value(data, LD_IN, NO_BANK,
+                                   PC87365_REG_IN_CONVRATE,
+                                   (reg & 0xC0) | 0x11);
+       }
+
+       nr = data->innr < 11 ? data->innr : 11;
+       for (i=0; i<nr; i++) {
+               if (init >= init_in[i]) {
+                       /* Forcibly enable voltage channel */
+                       reg = pc87360_read_value(data, LD_IN, i,
+                                                PC87365_REG_IN_STATUS);
+                       if (!(reg & 0x01)) {
+                               dev_dbg(&client->dev, "Forcibly "
+                                       "enabling in%d\n", i);
+                               pc87360_write_value(data, LD_IN, i,
+                                                   PC87365_REG_IN_STATUS,
+                                                   (reg & 0x68) | 0x87);
+                       }
+               }
+       }
+
+       /* We can't blindly trust the Super-I/O space configuration bit,
+          most BIOS won't set it properly */
+       for (i=11; i<data->innr; i++) {
+               reg = pc87360_read_value(data, LD_IN, i,
+                                        PC87365_REG_TEMP_STATUS);
+               use_thermistors = use_thermistors || (reg & 0x01);
+       }
+
+       i = use_thermistors ? 2 : 0;
+       for (; i<data->tempnr; i++) {
+               if (init >= init_temp[i]) {
+                       /* Forcibly enable temperature channel */
+                       reg = pc87360_read_value(data, LD_TEMP, i,
+                                                PC87365_REG_TEMP_STATUS);
+                       if (!(reg & 0x01)) {
+                               dev_dbg(&client->dev, "Forcibly "
+                                       "enabling temp%d\n", i+1);
+                               pc87360_write_value(data, LD_TEMP, i,
+                                                   PC87365_REG_TEMP_STATUS,
+                                                   0xCF);
+                       }
+               }
+       }
+
+       if (use_thermistors) {
+               for (i=11; i<data->innr; i++) {
+                       if (init >= init_in[i]) {
+                               /* The pin may already be used by thermal
+                                  diodes */
+                               reg = pc87360_read_value(data, LD_TEMP,
+                                     (i-11)/2, PC87365_REG_TEMP_STATUS);
+                               if (reg & 0x01) {
+                                       dev_dbg(&client->dev, "Skipping "
+                                               "temp%d, pin already in use "
+                                               "by temp%d\n", i-7, (i-11)/2);
+                                       continue;
+                               }
+
+                               /* Forcibly enable thermistor channel */
+                               reg = pc87360_read_value(data, LD_IN, i,
+                                                        PC87365_REG_IN_STATUS);
+                               if (!(reg & 0x01)) {
+                                       dev_dbg(&client->dev, "Forcibly "
+                                               "enabling temp%d\n", i-7);
+                                       pc87360_write_value(data, LD_IN, i,
+                                               PC87365_REG_TEMP_STATUS,
+                                               (reg & 0x60) | 0x8F);
+                               }
+                       }
+               }
+       }
+
+       if (data->innr) {
+               reg = pc87360_read_value(data, LD_IN, NO_BANK,
+                                        PC87365_REG_IN_CONFIG);
+               if (reg & 0x01) {
+                       dev_dbg(&client->dev, "Forcibly "
+                               "enabling monitoring (VLM)\n");
+                       pc87360_write_value(data, LD_IN, NO_BANK,
+                                           PC87365_REG_IN_CONFIG,
+                                           reg & 0xFE);
+               }
+       }
+
+       if (data->tempnr) {
+               reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
+                                        PC87365_REG_TEMP_CONFIG);
+               if (reg & 0x01) {
+                       dev_dbg(&client->dev, "Forcibly enabling "
+                               "monitoring (TMS)\n");
+                       pc87360_write_value(data, LD_TEMP, NO_BANK,
+                                           PC87365_REG_TEMP_CONFIG,
+                                           reg & 0xFE);
+               }
+
+               if (init >= 2) {
+                       /* Chip config as documented by National Semi. */
+                       pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);
+                       /* We voluntarily omit the bank here, in case the
+                          sequence itself matters. It shouldn't be a problem,
+                          since nobody else is supposed to access the
+                          device at that point. */
+                       pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);
+                       pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);
+                       pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);
+                       pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05);
+               }
+       }
+}
+
+static void pc87360_autodiv(struct i2c_client *client, int nr)
+{
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       u8 old_min = data->fan_min[nr];
+
+       /* Increase clock divider if needed and possible */
+       if ((data->fan_status[nr] & 0x04) /* overflow flag */
+        || (data->fan[nr] >= 224)) { /* next to overflow */
+               if ((data->fan_status[nr] & 0x60) != 0x60) {
+                       data->fan_status[nr] += 0x20;
+                       data->fan_min[nr] >>= 1;
+                       data->fan[nr] >>= 1;
+                       dev_dbg(&client->dev, "Increasing "
+                               "clock divider to %d for fan %d\n",
+                               FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);
+               }
+       } else {
+               /* Decrease clock divider if possible */
+               while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */
+                && data->fan[nr] < 85 /* bad accuracy */
+                && (data->fan_status[nr] & 0x60) != 0x00) {
+                       data->fan_status[nr] -= 0x20;
+                       data->fan_min[nr] <<= 1;
+                       data->fan[nr] <<= 1;
+                       dev_dbg(&client->dev, "Decreasing "
+                               "clock divider to %d for fan %d\n",
+                               FAN_DIV_FROM_REG(data->fan_status[nr]),
+                               nr+1);
+               }
+       }
+
+       /* Write new fan min if it changed */
+       if (old_min != data->fan_min[nr]) {
+               pc87360_write_value(data, LD_FAN, NO_BANK,
+                                   PC87360_REG_FAN_MIN(nr),
+                                   data->fan_min[nr]);
+       }
+}
+
+static struct pc87360_data *pc87360_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pc87360_data *data = i2c_get_clientdata(client);
+       u8 i;
+
+       down(&data->update_lock);
+
+       if ((jiffies - data->last_updated > HZ * 2)
+        || (jiffies < data->last_updated) || !data->valid) {
+               dev_dbg(&client->dev, "Data update\n");
+
+               /* Fans */
+               for (i = 0; i < data->fannr; i++) {
+                       if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
+                               data->fan_status[i] =
+                                       pc87360_read_value(data, LD_FAN,
+                                       NO_BANK, PC87360_REG_FAN_STATUS(i));
+                               data->fan[i] = pc87360_read_value(data, LD_FAN,
+                                              NO_BANK, PC87360_REG_FAN(i));
+                               data->fan_min[i] = pc87360_read_value(data,
+                                                  LD_FAN, NO_BANK,
+                                                  PC87360_REG_FAN_MIN(i));
+                               /* Change clock divider if needed */
+                               pc87360_autodiv(client, i);
+                               /* Clear bits and write new divider */
+                               pc87360_write_value(data, LD_FAN, NO_BANK,
+                                                   PC87360_REG_FAN_STATUS(i),
+                                                   data->fan_status[i]);
+                       }
+                       if (FAN_CONFIG_CONTROL(data->fan_conf, i))
+                               data->pwm[i] = pc87360_read_value(data, LD_FAN,
+                                              NO_BANK, PC87360_REG_PWM(i));
+               }
+
+               /* Voltages */
+               for (i = 0; i < data->innr; i++) {
+                       data->in_status[i] = pc87360_read_value(data, LD_IN, i,
+                                            PC87365_REG_IN_STATUS);
+                       /* Clear bits */
+                       pc87360_write_value(data, LD_IN, i,
+                                           PC87365_REG_IN_STATUS,
+                                           data->in_status[i]);
+                       if ((data->in_status[i] & 0x81) == 0x81) {
+                               data->in[i] = pc87360_read_value(data, LD_IN,
+                                             i, PC87365_REG_IN);
+                       }
+                       if (data->in_status[i] & 0x01) {
+                               data->in_min[i] = pc87360_read_value(data,
+                                                 LD_IN, i,
+                                                 PC87365_REG_IN_MIN);
+                               data->in_max[i] = pc87360_read_value(data,
+                                                 LD_IN, i,
+                                                 PC87365_REG_IN_MAX);
+                               if (i >= 11)
+                                       data->in_crit[i-11] =
+                                               pc87360_read_value(data, LD_IN,
+                                               i, PC87365_REG_TEMP_CRIT);
+                       }
+               }
+               if (data->innr) {
+                       data->in_alarms = pc87360_read_value(data, LD_IN,
+                                         NO_BANK, PC87365_REG_IN_ALARMS1)
+                                       | ((pc87360_read_value(data, LD_IN,
+                                           NO_BANK, PC87365_REG_IN_ALARMS2)
+                                           & 0x07) << 8);
+                       data->vid = (data->vid_conf & 0xE0) ?
+                                   pc87360_read_value(data, LD_IN,
+                                   NO_BANK, PC87365_REG_VID) : 0x1F;
+               }
+
+               /* Temperatures */
+               for (i = 0; i < data->tempnr; i++) {
+                       data->temp_status[i] = pc87360_read_value(data,
+                                              LD_TEMP, i,
+                                              PC87365_REG_TEMP_STATUS);
+                       /* Clear bits */
+                       pc87360_write_value(data, LD_TEMP, i,
+                                           PC87365_REG_TEMP_STATUS,
+                                           data->temp_status[i]);
+                       if ((data->temp_status[i] & 0x81) == 0x81) {
+                               data->temp[i] = pc87360_read_value(data,
+                                               LD_TEMP, i,
+                                               PC87365_REG_TEMP);
+                       }
+                       if (data->temp_status[i] & 0x01) {
+                               data->temp_min[i] = pc87360_read_value(data,
+                                                   LD_TEMP, i,
+                                                   PC87365_REG_TEMP_MIN);
+                               data->temp_max[i] = pc87360_read_value(data,
+                                                   LD_TEMP, i,
+                                                   PC87365_REG_TEMP_MAX);
+                               data->temp_crit[i] = pc87360_read_value(data,
+                                                    LD_TEMP, i,
+                                                    PC87365_REG_TEMP_CRIT);
+                       }
+               }
+               if (data->tempnr) {
+                       data->temp_alarms = pc87360_read_value(data, LD_TEMP,
+                                           NO_BANK, PC87365_REG_TEMP_ALARMS)
+                                           & 0x3F;
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       up(&data->update_lock);
+
+       return data;
+}
+
+static int __init pc87360_init(void)
+{
+       int i;
+
+       if (pc87360_find(0x2e, &devid, extra_isa)
+        && pc87360_find(0x4e, &devid, extra_isa)) {
+               printk(KERN_WARNING "pc87360: PC8736x not detected, "
+                      "module not inserted.\n");
+               return -ENODEV;
+       }
+
+       /* Arbitrarily pick one of the addresses */
+       for (i = 0; i < 3; i++) {
+               if (extra_isa[i] != 0x0000) {
+                       normal_isa[0] = extra_isa[i];
+                       break;
+               }
+       }
+
+       if (normal_isa[0] == 0x0000) {
+               printk(KERN_WARNING "pc87360: No active logical device, "
+                      "module not inserted.\n");
+               return -ENODEV;
+       }
+
+       return i2c_add_driver(&pc87360_driver);
+}
+
+static void __exit pc87360_exit(void)
+{
+       i2c_del_driver(&pc87360_driver);
+}
+
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("PC8736x hardware monitor");
+MODULE_LICENSE("GPL");
+
+module_init(pc87360_init);
+module_exit(pc87360_exit);
diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c
new file mode 100644 (file)
index 0000000..078c65f
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+    smsc47m1.c - Part of lm_sensors, Linux kernel modules
+                 for hardware monitoring
+
+    Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x
+    Super-I/O chips.
+
+    Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+    Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
+                        and Jean Delvare
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+/* Address is autodetected, there is no default value */
+static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END };
+static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
+static struct i2c_force_data forces[] = {{NULL}};
+
+enum chips { any_chip, smsc47m1 };
+static struct i2c_address_data addr_data = {
+       .normal_i2c             = normal_i2c,
+       .normal_i2c_range       = normal_i2c_range,
+       .normal_isa             = normal_isa,
+       .normal_isa_range       = normal_isa_range,
+       .probe                  = normal_i2c,           /* cheat */
+       .probe_range            = normal_i2c_range,     /* cheat */
+       .ignore                 = normal_i2c,           /* cheat */
+       .ignore_range           = normal_i2c_range,     /* cheat */
+       .forces                 = forces,
+};
+
+/* Super-I/0 registers and commands */
+
+#define        REG     0x2e    /* The register to read/write */
+#define        VAL     0x2f    /* The value to read/write */
+
+static inline void
+superio_outb(int reg, int val)
+{
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+static inline int
+superio_inb(int reg)
+{
+       outb(reg, REG);
+       return inb(VAL);
+}
+
+/* logical device for fans is 0x0A */
+#define superio_select() superio_outb(0x07, 0x0A)
+
+static inline void
+superio_enter(void)
+{
+       outb(0x55, REG);
+}
+
+static inline void
+superio_exit(void)
+{
+       outb(0xAA, REG);
+}
+
+#define SUPERIO_REG_ACT                0x30
+#define SUPERIO_REG_BASE       0x60
+#define SUPERIO_REG_DEVID      0x20
+
+/* Logical device registers */
+
+#define SMSC_EXTENT            0x80
+
+/* nr is 0 or 1 in the macros below */
+#define SMSC47M1_REG_ALARM             0x04
+#define SMSC47M1_REG_TPIN(nr)          (0x34 - (nr))
+#define SMSC47M1_REG_PPIN(nr)          (0x36 - (nr))
+#define SMSC47M1_REG_PWM(nr)           (0x56 + (nr))
+#define SMSC47M1_REG_FANDIV            0x58
+#define SMSC47M1_REG_FAN(nr)           (0x59 + (nr))
+#define SMSC47M1_REG_FAN_PRELOAD(nr)   (0x5B + (nr))
+
+#define MIN_FROM_REG(reg,div)          ((reg)>=192 ? 0 : \
+                                        983040/((192-(reg))*(div)))
+#define FAN_FROM_REG(reg,div,preload)  ((reg)<=(preload) || (reg)==255 ? 0 : \
+                                        983040/(((reg)-(preload))*(div)))
+#define DIV_FROM_REG(reg)              (1 << (reg))
+#define PWM_FROM_REG(reg)              (((reg) & 0x7E) << 1)
+#define PWM_EN_FROM_REG(reg)           ((~(reg)) & 0x01)
+#define PWM_TO_REG(reg)                        (((reg) >> 1) & 0x7E)
+
+struct smsc47m1_data {
+       struct i2c_client client;
+       struct semaphore lock;
+       int sysctl_id;
+
+       struct semaphore update_lock;
+       unsigned long last_updated;     /* In jiffies */
+
+       u8 fan[2];              /* Register value */
+       u8 fan_preload[2];      /* Register value */
+       u8 fan_div[2];          /* Register encoding, shifted right */
+       u8 alarms;              /* Register encoding */
+       u8 pwm[2];              /* Register value (bit 7 is enable) */
+};
+
+
+static int smsc47m1_attach_adapter(struct i2c_adapter *adapter);
+static int smsc47m1_find(int *address);
+static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind);
+static int smsc47m1_detach_client(struct i2c_client *client);
+
+static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
+static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value);
+
+static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
+               int init);
+
+
+static int smsc47m1_id;
+
+static struct i2c_driver smsc47m1_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "smsc47m1",
+       .id             = I2C_DRIVERID_SMSC47M1,
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = smsc47m1_attach_adapter,
+       .detach_client  = smsc47m1_detach_client,
+};
+
+/* nr is 0 or 1 in the callback functions below */
+
+static ssize_t get_fan(struct device *dev, char *buf, int nr)
+{
+       struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+       /* This chip (stupidly) stops monitoring fan speed if PWM is
+          enabled and duty cycle is 0%. This is fine if the monitoring
+          and control concern the same fan, but troublesome if they are
+          not (which could as well happen). */
+       int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 :
+                 FAN_FROM_REG(data->fan[nr],
+                              DIV_FROM_REG(data->fan_div[nr]),
+                              data->fan_preload[nr]);
+       return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t get_fan_min(struct device *dev, char *buf, int nr)
+{
+       struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+       int rpm = MIN_FROM_REG(data->fan_preload[nr],
+                              DIV_FROM_REG(data->fan_div[nr]));
+       return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
+{
+       struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+       return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+}
+
+static ssize_t get_fan_pwm(struct device *dev, char *buf, int nr)
+{
+       struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+       return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
+}
+
+static ssize_t get_fan_pwm_en(struct device *dev, char *buf, int nr)
+{
+       struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+       return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr]));
+}
+
+static ssize_t get_alarms(struct device *dev, char *buf)
+{
+       struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+       return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t set_fan_min(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct smsc47m1_data *data = i2c_get_clientdata(client);
+
+       long rpmdiv = simple_strtol(buf, NULL, 10)
+                   * DIV_FROM_REG(data->fan_div[nr]);
+
+       if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040)
+               return -EINVAL;
+
+       data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
+       smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
+                            data->fan_preload[nr]);
+
+       return count;
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+   determined in part by the fan clock divider.  This follows the principle
+   of least suprise; the user doesn't expect the fan minimum to change just
+   because the divider changed. */
+static ssize_t set_fan_div(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct smsc47m1_data *data = i2c_get_clientdata(client);
+
+       long new_div = simple_strtol(buf, NULL, 10), tmp;
+       u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
+
+       if (new_div == old_div) /* No change */
+               return count;
+       switch (new_div) {
+       case 1: data->fan_div[nr] = 0; break;
+       case 2: data->fan_div[nr] = 1; break;
+       case 4: data->fan_div[nr] = 2; break;
+       case 8: data->fan_div[nr] = 3; break;
+       default: return -EINVAL;
+       }
+
+       tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F;
+       tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6);
+       smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp);
+
+       /* Preserve fan min */
+       tmp = 192 - (old_div * (192 - data->fan_preload[nr])
+                    + new_div / 2) / new_div;
+       data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
+       smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
+                            data->fan_preload[nr]);
+
+       return count;
+}
+
+static ssize_t set_fan_pwm(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct smsc47m1_data *data = i2c_get_clientdata(client);
+
+       long val = simple_strtol(buf, NULL, 10);
+
+       if (val < 0 || val > 255)
+               return -EINVAL;
+
+       data->pwm[nr] &= 0x81; /* Preserve additional bits */
+       data->pwm[nr] |= PWM_TO_REG(val);
+
+       smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
+                            data->pwm[nr]);
+       return count;
+}
+
+static ssize_t set_fan_pwm_en(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct smsc47m1_data *data = i2c_get_clientdata(client);
+
+       long val = simple_strtol(buf, NULL, 10);
+       
+       if (val != 0 && val != 1)
+               return -EINVAL;
+
+       data->pwm[nr] &= 0xFE; /* preserve the other bits */
+       data->pwm[nr] |= !val;
+
+       smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
+                            data->pwm[nr]);
+
+       return count;
+}
+
+#define fan_present(offset)                                            \
+static ssize_t get_fan##offset (struct device *dev, char *buf)         \
+{                                                                      \
+       return get_fan(dev, buf, 0x##offset - 1);                       \
+}                                                                      \
+static ssize_t get_fan##offset##_min (struct device *dev, char *buf)   \
+{                                                                      \
+       return get_fan_min(dev, buf, 0x##offset - 1);                   \
+}                                                                      \
+static ssize_t set_fan##offset##_min (struct device *dev,              \
+               const char *buf, size_t count)                          \
+{                                                                      \
+       return set_fan_min(dev, buf, count, 0x##offset - 1);            \
+}                                                                      \
+static ssize_t get_fan##offset##_div (struct device *dev, char *buf)   \
+{                                                                      \
+       return get_fan_div(dev, buf, 0x##offset - 1);                   \
+}                                                                      \
+static ssize_t set_fan##offset##_div (struct device *dev,              \
+               const char *buf, size_t count)                          \
+{                                                                      \
+       return set_fan_div(dev, buf, count, 0x##offset - 1);            \
+}                                                                      \
+static ssize_t get_fan##offset##_pwm (struct device *dev, char *buf)   \
+{                                                                      \
+       return get_fan_pwm(dev, buf, 0x##offset - 1);                   \
+}                                                                      \
+static ssize_t set_fan##offset##_pwm (struct device *dev,              \
+               const char *buf, size_t count)                          \
+{                                                                      \
+       return set_fan_pwm(dev, buf, count, 0x##offset - 1);            \
+}                                                                      \
+static ssize_t get_fan##offset##_pwm_en (struct device *dev, char *buf)        \
+{                                                                      \
+       return get_fan_pwm_en(dev, buf, 0x##offset - 1);                \
+}                                                                      \
+static ssize_t set_fan##offset##_pwm_en (struct device *dev,           \
+               const char *buf, size_t count)                          \
+{                                                                      \
+       return set_fan_pwm_en(dev, buf, count, 0x##offset - 1);         \
+}                                                                      \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset,      \
+               NULL);                                                  \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,               \
+               get_fan##offset##_min, set_fan##offset##_min);          \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,               \
+               get_fan##offset##_div, set_fan##offset##_div);          \
+static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR,               \
+               get_fan##offset##_pwm, set_fan##offset##_pwm);          \
+static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR,                \
+               get_fan##offset##_pwm_en, set_fan##offset##_pwm_en);
+
+fan_present(1);
+fan_present(2);
+
+static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+
+static int smsc47m1_attach_adapter(struct i2c_adapter *adapter)
+{
+       if (!(adapter->class & I2C_CLASS_HWMON))
+               return 0;
+       return i2c_detect(adapter, &addr_data, smsc47m1_detect);
+}
+
+static int smsc47m1_find(int *address)
+{
+       u8 val;
+
+       superio_enter();
+       val = superio_inb(SUPERIO_REG_DEVID);
+
+       /*
+        * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
+        * 0x5F) and LPC47B27x (device id 0x51) have fan control.
+        * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
+        * can do much more besides (device id 0x60, unsupported).
+        */
+       if (val == 0x51)
+               printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n");
+       else if (val == 0x59)
+               printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n");
+       else if (val == 0x5F)
+               printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n");
+       else {
+               superio_exit();
+               return -ENODEV;
+       }
+
+       superio_select();
+       *address = (superio_inb(SUPERIO_REG_BASE) << 8)
+                |  superio_inb(SUPERIO_REG_BASE + 1);
+       val = superio_inb(SUPERIO_REG_ACT);
+       if (*address == 0 || (val & 0x01) == 0) {
+               printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
+               superio_exit();
+               return -ENODEV;
+       }
+
+       superio_exit();
+       return 0;
+}
+
+static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *new_client;
+       struct smsc47m1_data *data;
+       int err = 0;
+
+       if (!i2c_is_isa_adapter(adapter)) {
+               return 0;
+       }
+
+       if (!request_region(address, SMSC_EXTENT, "smsc47m1")) {
+               dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
+               return -EBUSY;
+       }
+
+       if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {
+               err = -ENOMEM;
+               goto error_release;
+       }
+       memset(data, 0x00, sizeof(struct smsc47m1_data));
+
+       new_client = &data->client;
+       i2c_set_clientdata(new_client, data);
+       new_client->addr = address;
+       init_MUTEX(&data->lock);
+       new_client->adapter = adapter;
+       new_client->driver = &smsc47m1_driver;
+       new_client->flags = 0;
+
+       strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
+
+       new_client->id = smsc47m1_id++;
+       init_MUTEX(&data->update_lock);
+
+       if ((err = i2c_attach_client(new_client)))
+               goto error_free;
+
+       /* Some values (fan min, clock dividers, pwm registers) may be
+          needed before any update is triggered, so we better read them
+          at least once here. We don't usually do it that way, but in
+          this particular case, manually reading 5 registers out of 8
+          doesn't make much sense and we're better using the existing
+          function. */
+       smsc47m1_update_device(&new_client->dev, 1);
+
+       if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
+           == 0x05) {
+               device_create_file(&new_client->dev, &dev_attr_fan1_input);
+               device_create_file(&new_client->dev, &dev_attr_fan1_min);
+               device_create_file(&new_client->dev, &dev_attr_fan1_div);
+       } else
+               dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
+                       "skipping\n");
+
+       if ((smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)
+           == 0x05) {
+               device_create_file(&new_client->dev, &dev_attr_fan2_input);
+               device_create_file(&new_client->dev, &dev_attr_fan2_min);
+               device_create_file(&new_client->dev, &dev_attr_fan2_div);
+       } else
+               dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
+                       "skipping\n");
+
+       if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
+           == 0x04) {
+               device_create_file(&new_client->dev, &dev_attr_fan1_pwm);
+               device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable);
+       } else
+               dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
+                       "skipping\n");
+       if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
+           == 0x04) {
+               device_create_file(&new_client->dev, &dev_attr_fan2_pwm);
+               device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable);
+       } else
+               dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
+                       "skipping\n");
+
+       device_create_file(&new_client->dev, &dev_attr_alarms);
+
+       return 0;
+
+error_free:
+       kfree(new_client);
+error_release:
+       release_region(address, SMSC_EXTENT);
+       return err;
+}
+
+static int smsc47m1_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       if ((err = i2c_detach_client(client))) {
+               dev_err(&client->dev, "Client deregistration failed, "
+                       "client not detached.\n");
+               return err;
+       }
+
+       release_region(client->addr, SMSC_EXTENT);
+       kfree(i2c_get_clientdata(client));
+
+       return 0;
+}
+
+static int smsc47m1_read_value(struct i2c_client *client, u8 reg)
+{
+       int res;
+
+       down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       res = inb_p(client->addr + reg);
+       up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       return res;
+}
+
+static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+       down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+       outb_p(value, client->addr + reg);
+       up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
+}
+
+static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
+               int init)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct smsc47m1_data *data = i2c_get_clientdata(client);
+
+       down(&data->update_lock);
+
+       if ((jiffies - data->last_updated > HZ + HZ / 2) ||
+           (jiffies < data->last_updated) || init) {
+               int i;
+
+               for (i = 0; i < 2; i++) {
+                       data->fan[i] = smsc47m1_read_value(client,
+                                      SMSC47M1_REG_FAN(i));
+                       data->fan_preload[i] = smsc47m1_read_value(client,
+                                              SMSC47M1_REG_FAN_PRELOAD(i));
+                       data->pwm[i] = smsc47m1_read_value(client,
+                                      SMSC47M1_REG_PWM(i));
+               }
+
+               i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
+               data->fan_div[0] = (i >> 4) & 0x03;
+               data->fan_div[1] = i >> 6;
+
+               data->alarms = smsc47m1_read_value(client,
+                              SMSC47M1_REG_ALARM) >> 6;
+               /* Clear alarms if needed */
+               if (data->alarms)
+                       smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);
+
+               data->last_updated = jiffies;
+       }
+
+       up(&data->update_lock);
+       return data;
+}
+
+static int __init sm_smsc47m1_init(void)
+{
+       if (smsc47m1_find(normal_isa)) {
+               return -ENODEV;
+       }
+
+       return i2c_add_driver(&smsc47m1_driver);
+}
+
+static void __exit sm_smsc47m1_exit(void)
+{
+       i2c_del_driver(&smsc47m1_driver);
+}
+
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");
+MODULE_LICENSE("GPL");
+
+module_init(sm_smsc47m1_init);
+module_exit(sm_smsc47m1_exit);
diff --git a/drivers/i2c/i2c-sensor-detect.c b/drivers/i2c/i2c-sensor-detect.c
new file mode 100644 (file)
index 0000000..70e82f2
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+    i2c-sensor-detect.c - Part of lm_sensors, Linux kernel modules for hardware
+                         monitoring
+    Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl> and
+    Mark D. Studebaker <mdsxyz123@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
+    (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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <asm/uaccess.h>
+
+
+/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */
+int i2c_detect(struct i2c_adapter *adapter,
+              struct i2c_address_data *address_data,
+              int (*found_proc) (struct i2c_adapter *, int, int))
+{
+       int addr, i, found, j, err;
+       struct i2c_force_data *this_force;
+       int is_isa = i2c_is_isa_adapter(adapter);
+       int adapter_id =
+           is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter);
+
+       /* Forget it if we can't probe using SMBUS_QUICK */
+       if ((!is_isa) &&
+           !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK))
+               return -1;
+
+       for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) {
+               if (!is_isa && i2c_check_addr(adapter, addr))
+                       continue;
+
+               /* If it is in one of the force entries, we don't do any
+                  detection at all */
+               found = 0;
+               for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) {
+                       for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) {
+                               if ( ((adapter_id == this_force->force[j]) ||
+                                     ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) &&
+                                     (addr == this_force->force[j + 1]) ) {
+                                       dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr);
+                                       if ((err = found_proc(adapter, addr, this_force->kind)))
+                                               return err;
+                                       found = 1;
+                               }
+                       }
+               }
+               if (found)
+                       continue;
+
+               /* If this address is in one of the ignores, we can forget about it
+                  right now */
+               for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) {
+                       if ( ((adapter_id == address_data->ignore[i]) ||
+                             ((address_data->ignore[i] == ANY_I2C_BUS) &&
+                              !is_isa)) &&
+                             (addr == address_data->ignore[i + 1])) {
+                               dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr);
+                               found = 1;
+                       }
+               }
+               for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) {
+                       if ( ((adapter_id == address_data->ignore_range[i]) ||
+                             ((address_data-> ignore_range[i] == ANY_I2C_BUS) & 
+                              !is_isa)) &&
+                            (addr >= address_data->ignore_range[i + 1]) &&
+                            (addr <= address_data->ignore_range[i + 2])) {
+                               dev_dbg(&adapter->dev,  "found ignore_range parameter for adapter %d, addr %04x\n", adapter_id, addr);
+                               found = 1;
+                       }
+               }
+               if (found)
+                       continue;
+
+               /* Now, we will do a detection, but only if it is in the normal or 
+                  probe entries */
+               if (is_isa) {
+                       for (i = 0; !found && (address_data->normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) {
+                               if (addr == address_data->normal_isa[i]) {
+                                       dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr);
+                                       found = 1;
+                               }
+                       }
+                       for (i = 0; !found && (address_data->normal_isa_range[i] != I2C_CLIENT_ISA_END); i += 3) {
+                               if ((addr >= address_data->normal_isa_range[i]) &&
+                                   (addr <= address_data->normal_isa_range[i + 1]) &&
+                                   ((addr - address_data->normal_isa_range[i]) % address_data->normal_isa_range[i + 2] == 0)) {
+                                       dev_dbg(&adapter->dev, "found normal isa_range entry for adapter %d, addr %04x", adapter_id, addr);
+                                       found = 1;
+                               }
+                       }
+               } else {
+                       for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) {
+                               if (addr == address_data->normal_i2c[i]) {
+                                       found = 1;
+                                       dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x", adapter_id, addr);
+                               }
+                       }
+                       for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) {
+                               if ((addr >= address_data->normal_i2c_range[i]) &&
+                                   (addr <= address_data->normal_i2c_range[i + 1])) {
+                                       dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, addr %04x\n", adapter_id, addr);
+                                       found = 1;
+                               }
+                       }
+               }
+
+               for (i = 0;
+                    !found && (address_data->probe[i] != I2C_CLIENT_END);
+                    i += 2) {
+                       if (((adapter_id == address_data->probe[i]) ||
+                            ((address_data->
+                              probe[i] == ANY_I2C_BUS) && !is_isa))
+                           && (addr == address_data->probe[i + 1])) {
+                               dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr);
+                               found = 1;
+                       }
+               }
+               for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) {
+                       if ( ((adapter_id == address_data->probe_range[i]) ||
+                             ((address_data->probe_range[i] == ANY_I2C_BUS) && !is_isa)) &&
+                            (addr >= address_data->probe_range[i + 1]) &&
+                            (addr <= address_data->probe_range[i + 2])) {
+                               found = 1;
+                               dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, addr %04x\n", adapter_id, addr);
+                       }
+               }
+               if (!found)
+                       continue;
+
+               /* OK, so we really should examine this address. First check
+                  whether there is some client here at all! */
+               if (is_isa ||
+                   (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0))
+                       if ((err = found_proc(adapter, addr, -1)))
+                               return err;
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(i2c_detect);
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+             "Rudolf Marek <r.marek@sh.cvut.cz>");
+
+MODULE_DESCRIPTION("i2c-sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-sensor-vid.c b/drivers/i2c/i2c-sensor-vid.c
new file mode 100644 (file)
index 0000000..017dcc5
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+    i2c-sensor-vid.c -  Part of lm_sensors, Linux kernel modules for hardware
+                       monitoring
+
+    Copyright (c) 2004 Rudolf Marek <r.marek@sh.cvut.cz>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+struct vrm_model {
+       u8 vendor;
+       u8 eff_family;
+       u8 eff_model;
+       int vrm_type;
+};
+
+#define ANY 0xFF
+
+#ifdef CONFIG_X86
+
+static struct vrm_model vrm_models[] = {
+       {X86_VENDOR_AMD, 0x6, ANY, 90},         /* Athlon Duron etc */
+       {X86_VENDOR_AMD, 0xF, 0x4, 90},         /* Athlon 64 */
+       {X86_VENDOR_AMD, 0xF, 0x5, 24},         /* Opteron */
+       {X86_VENDOR_INTEL, 0x6, 0x9, 85},       /* 0.13um too */
+       {X86_VENDOR_INTEL, 0x6, 0xB, 85},       /* 0xB Tualatin */
+       {X86_VENDOR_INTEL, 0x6, ANY, 82},       /* any P6 */
+       {X86_VENDOR_INTEL, 0x7, ANY, 0},        /* Itanium */
+       {X86_VENDOR_INTEL, 0xF, 0x3, 100},      /* P4 Prescott */
+       {X86_VENDOR_INTEL, 0xF, ANY, 90},       /* P4 before Prescott */
+       {X86_VENDOR_INTEL, 0x10,ANY, 0},        /* Itanium 2 */
+       {X86_VENDOR_UNKNOWN, ANY, ANY, 0}       /* stop here */
+       };
+
+static int find_vrm(u8 eff_family, u8 eff_model, u8 vendor)
+{
+       int i = 0;
+
+       while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) {
+               if (vrm_models[i].vendor==vendor)
+                       if ((vrm_models[i].eff_family==eff_family)&& \
+                       ((vrm_models[i].eff_model==eff_model)|| \
+                       (vrm_models[i].eff_model==ANY)))
+                               return vrm_models[i].vrm_type;
+               i++;
+       }
+
+       return 0;
+}
+
+int i2c_which_vrm(void)
+{
+       struct cpuinfo_x86 *c = cpu_data;
+       u32 eax;
+       u8 eff_family, eff_model;
+       int vrm_ret;
+
+       if (c->x86 < 6) return 0;       /* any CPU with familly lower than 6
+                                       dont have VID and/or CPUID */
+       eax = cpuid_eax(1);
+       eff_family = ((eax & 0x00000F00)>>8);
+       eff_model  = ((eax & 0x000000F0)>>4);
+       if (eff_family == 0xF) {        /* use extended model & family */
+               eff_family += ((eax & 0x00F00000)>>20);
+               eff_model += ((eax & 0x000F0000)>>16)<<4;
+       }
+       vrm_ret = find_vrm(eff_family,eff_model,c->x86_vendor);
+       if (vrm_ret == 0)
+               printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your"
+               " x86 CPU\n");
+       return vrm_ret;
+}
+
+/* and now something completely different for Non-x86 world*/
+#else
+int i2c_which_vrm(void)
+{
+       printk(KERN_INFO "i2c-sensor.o: Unknown VRM version of your CPU\n");
+       return 0;
+}
+#endif
+
+EXPORT_SYMBOL(i2c_which_vrm);
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
new file mode 100644 (file)
index 0000000..9d474e5
--- /dev/null
@@ -0,0 +1,71 @@
+/* linux/drivers/ide/arm/bast-ide.c
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *  Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/arch/map.h>
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-irq.h>
+
+/* list of registered interfaces */
+static ide_hwif_t *ifs[2];
+
+static int __init
+bastide_register(unsigned int base, unsigned int aux, int irq,
+                ide_hwif_t **hwif)
+{
+       hw_regs_t hw;
+       int i;
+
+       memset(&hw, 0, sizeof(hw));
+
+       base += BAST_IDE_CS;
+       aux  += BAST_IDE_CS;
+
+       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+               hw.io_ports[i] = (unsigned long)base;
+               base += 0x20;
+       }
+
+       hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
+       hw.irq = irq;
+
+       ide_register_hw(&hw, hwif);
+
+       return 0;
+}
+
+static int __init bastide_init(void)
+{
+       /* we can treat the VR1000 and the BAST the same */
+
+       if (!(machine_is_bast() || machine_is_vr1000()))
+               return 0;
+
+       printk("BAST: IDE driver, (c) 2003-2004 Simtec Electronics\n");
+
+       bastide_register(BAST_VA_IDEPRI, BAST_VA_IDEPRIAUX, IRQ_IDE0, &ifs[0]);
+       bastide_register(BAST_VA_IDESEC, BAST_VA_IDESECAUX, IRQ_IDE1, &ifs[1]);
+       return 0;
+}
+
+module_init(bastide_init);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simtec BAST / Thorcom VR1000 IDE driver");
diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
new file mode 100644 (file)
index 0000000..fdc2943
--- /dev/null
@@ -0,0 +1,3 @@
+EXTRA_CFLAGS                           += -Idrivers/ide
+
+obj-$(CONFIG_ETRAX_ARCH_V10)           += ide-v10.o
diff --git a/drivers/ide/cris/ide-v10.c b/drivers/ide/cris/ide-v10.c
new file mode 100644 (file)
index 0000000..4631b4a
--- /dev/null
@@ -0,0 +1,859 @@
+/* $Id: ide.c,v 1.4 2004/10/12 07:55:48 starvik Exp $
+ *
+ * Etrax specific IDE functions, like init and PIO-mode setting etc.
+ * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
+ * Copyright (c) 2000-2004 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen        (initial version)
+ *             Mikael Starvik     (pio setup stuff, Linux 2.6 port)
+ */
+
+/* Regarding DMA:
+ *
+ * There are two forms of DMA - "DMA handshaking" between the interface and the drive,
+ * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
+ * something built-in in the Etrax. However only some drives support the DMA-mode handshaking
+ * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
+ * device can't do DMA handshaking for some stupid reason. We don't need to do that.
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+#include <asm/dma.h>
+
+/* number of Etrax DMA descriptors */
+#define MAX_DMA_DESCRS 64
+
+/* number of times to retry busy-flags when reading/writing IDE-registers
+ * this can't be too high because a hung harddisk might cause the watchdog
+ * to trigger (sometimes INB and OUTB are called with irq's disabled)
+ */
+
+#define IDE_REGISTER_TIMEOUT 300
+
+static int e100_read_command = 0;
+
+#define LOWDB(x)
+#define D(x)
+
+static int e100_ide_build_dmatable (ide_drive_t *drive);
+static ide_startstop_t etrax_dma_intr (ide_drive_t *drive);
+
+void
+etrax100_ide_outw(unsigned short data, unsigned long reg) {
+       int timeleft;
+       LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
+
+       /* note the lack of handling any timeouts. we stop waiting, but we don't
+        * really notify anybody.
+        */
+
+       timeleft = IDE_REGISTER_TIMEOUT;
+       /* wait for busy flag */
+       while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+               timeleft--;
+
+       /*
+        * Fall through at a timeout, so the ongoing command will be
+        * aborted by the write below, which is expected to be a dummy
+        * command to the command register.  This happens when a faulty
+        * drive times out on a command.  See comment on timeout in
+        * INB.
+        */
+       if(!timeleft)
+               printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
+
+       *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
+
+       timeleft = IDE_REGISTER_TIMEOUT;
+       /* wait for transmitter ready */
+       while(timeleft && !(*R_ATA_STATUS_DATA &
+                           IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
+               timeleft--;
+}
+
+void
+etrax100_ide_outb(unsigned char data, unsigned long reg)
+{
+       etrax100_ide_outw(data, reg);
+}
+
+void
+etrax100_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
+{
+       etrax100_ide_outw(addr, port);
+}
+
+unsigned short
+etrax100_ide_inw(unsigned long reg) {
+       int status;
+       int timeleft;
+
+       timeleft = IDE_REGISTER_TIMEOUT;
+       /* wait for busy flag */
+       while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+               timeleft--;
+
+       if(!timeleft) {
+               /*
+                * If we're asked to read the status register, like for
+                * example when a command does not complete for an
+                * extended time, but the ATA interface is stuck in a
+                * busy state at the *ETRAX* ATA interface level (as has
+                * happened repeatedly with at least one bad disk), then
+                * the best thing to do is to pretend that we read
+                * "busy" in the status register, so the IDE driver will
+                * time-out, abort the ongoing command and perform a
+                * reset sequence.  Note that the subsequent OUT_BYTE
+                * call will also timeout on busy, but as long as the
+                * write is still performed, everything will be fine.
+                */
+               if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr))
+                   == IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET))
+                       return BUSY_STAT;
+               else
+                       /* For other rare cases we assume 0 is good enough.  */
+                       return 0;
+       }
+
+       *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
+
+       timeleft = IDE_REGISTER_TIMEOUT;
+       /* wait for available */
+       while(timeleft && !((status = *R_ATA_STATUS_DATA) &
+                           IO_MASK(R_ATA_STATUS_DATA, dav)))
+               timeleft--;
+
+       if(!timeleft)
+               return 0;
+
+       LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
+
+        return (unsigned short)status;
+}
+
+unsigned char
+etrax100_ide_inb(unsigned long reg)
+{
+       return (unsigned char)etrax100_ide_inw(reg);
+}
+
+/* PIO timing (in R_ATA_CONFIG)
+ *
+ *                        _____________________________
+ * ADDRESS :     ________/
+ *
+ *                            _______________
+ * DIOR    :     ____________/               \__________
+ *
+ *                               _______________
+ * DATA    :     XXXXXXXXXXXXXXXX_______________XXXXXXXX
+ *
+ *
+ * DIOR is unbuffered while address and data is buffered.
+ * This creates two problems:
+ * 1. The DIOR pulse is to early (because it is unbuffered)
+ * 2. The rise time of DIOR is long
+ *
+ * There are at least three different plausible solutions
+ * 1. Use a pad capable of larger currents in Etrax
+ * 2. Use an external buffer
+ * 3. Make the strobe pulse longer
+ *
+ * Some of the strobe timings below are modified to compensate
+ * for this. This implies a slight performance decrease.
+ *
+ * THIS SHOULD NEVER BE CHANGED!
+ *
+ * TODO: Is this true for the latest LX boards still ?
+ */
+
+#define ATA_DMA2_STROBE  4
+#define ATA_DMA2_HOLD    0
+#define ATA_DMA1_STROBE  4
+#define ATA_DMA1_HOLD    1
+#define ATA_DMA0_STROBE 12
+#define ATA_DMA0_HOLD    9
+#define ATA_PIO4_SETUP   1
+#define ATA_PIO4_STROBE  5
+#define ATA_PIO4_HOLD    0
+#define ATA_PIO3_SETUP   1
+#define ATA_PIO3_STROBE  5
+#define ATA_PIO3_HOLD    1
+#define ATA_PIO2_SETUP   1
+#define ATA_PIO2_STROBE  6
+#define ATA_PIO2_HOLD    2
+#define ATA_PIO1_SETUP   2
+#define ATA_PIO1_STROBE 11
+#define ATA_PIO1_HOLD    4
+#define ATA_PIO0_SETUP   4
+#define ATA_PIO0_STROBE 19
+#define ATA_PIO0_HOLD    4
+
+static int e100_dma_check (ide_drive_t *drive);
+static void e100_dma_start(ide_drive_t *drive);
+static int e100_dma_end (ide_drive_t *drive);
+static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int);
+static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int);
+static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
+static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
+static int e100_dma_off (ide_drive_t *drive);
+
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mword2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+
+const char *good_dma_drives[] = {"Micropolis 2112A",
+                                "CONNER CTMA 4000",
+                                "CONNER CTT8000-A",
+                                NULL};
+
+static void tune_e100_ide(ide_drive_t *drive, byte pio)
+{
+       pio = 4;
+       /* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
+
+       /* set pio mode! */
+
+       switch(pio) {
+               case 0:
+                       *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO0_SETUP ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO0_HOLD ) );
+                       break;
+               case 1:
+                       *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO1_SETUP ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO1_HOLD ) );
+                       break;
+               case 2:
+                       *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO2_SETUP ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO2_HOLD ) );
+                       break;
+               case 3:
+                       *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO3_SETUP ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO3_HOLD ) );
+                       break;
+               case 4:
+                       *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO4_SETUP ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+                                         IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
+                       break;
+       }
+}
+
+static int e100_dma_setup(ide_drive_t *drive)
+{
+       struct request *rq = drive->hwif->hwgroup->rq;
+
+       if (rq_data_dir(rq)) {
+               e100_read_command = 0;
+
+               RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+               WAIT_DMA(ATA_TX_DMA_NBR);
+       } else {
+               e100_read_command = 1;
+
+               RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+               WAIT_DMA(ATA_RX_DMA_NBR);
+       }
+
+       /* set up the Etrax DMA descriptors */
+       if (e100_ide_build_dmatable(drive)) {
+               ide_map_sg(drive, rq);
+               return 1;
+       }
+
+       return 0;
+}
+
+static void e100_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+       /* set the irq handler which will finish the request when DMA is done */
+       ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+       /* issue cmd to drive */
+       etrax100_ide_outb(command, IDE_COMMAND_REG);
+}
+
+void __init
+init_e100_ide (void)
+{
+       volatile unsigned int dummy;
+       int h;
+
+       printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
+
+       /* first fill in some stuff in the ide_hwifs fields */
+
+       for(h = 0; h < MAX_HWIFS; h++) {
+               ide_hwif_t *hwif = &ide_hwifs[h];
+               hwif->mmio = 2;
+               hwif->chipset = ide_etrax100;
+               hwif->tuneproc = &tune_e100_ide;
+                hwif->ata_input_data = &e100_ide_input_data;
+                hwif->ata_output_data = &e100_ide_output_data;
+                hwif->atapi_input_bytes = &e100_atapi_input_bytes;
+                hwif->atapi_output_bytes = &e100_atapi_output_bytes;
+                hwif->ide_dma_check = &e100_dma_check;
+                hwif->ide_dma_end = &e100_dma_end;
+               hwif->dma_setup = &e100_dma_setup;
+               hwif->dma_exec_cmd = &e100_dma_exec_cmd;
+               hwif->dma_start = &e100_dma_start;
+               hwif->OUTB = &etrax100_ide_outb;
+               hwif->OUTW = &etrax100_ide_outw;
+               hwif->OUTBSYNC = &etrax100_ide_outbsync;
+               hwif->INB = &etrax100_ide_inb;
+               hwif->INW = &etrax100_ide_inw;
+               hwif->ide_dma_off_quietly = &e100_dma_off;
+       }
+
+       /* actually reset and configure the etrax100 ide/ata interface */
+
+       *R_ATA_CTRL_DATA = 0;
+       *R_ATA_TRANSFER_CNT = 0;
+       *R_ATA_CONFIG = 0;
+
+       genconfig_shadow = (genconfig_shadow &
+                           ~IO_MASK(R_GEN_CONFIG, dma2) &
+                           ~IO_MASK(R_GEN_CONFIG, dma3) &
+                           ~IO_MASK(R_GEN_CONFIG, ata)) |
+               ( IO_STATE( R_GEN_CONFIG, dma3, ata    ) |
+                 IO_STATE( R_GEN_CONFIG, dma2, ata    ) |
+                 IO_STATE( R_GEN_CONFIG, ata,  select ) );
+
+       *R_GEN_CONFIG = genconfig_shadow;
+
+        /* pull the chosen /reset-line low */
+
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+        REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+        REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+        REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_PB7_RESET
+       port_pb_dir_shadow = port_pb_dir_shadow |
+               IO_STATE(R_PORT_PB_DIR, dir7, output);
+       *R_PORT_PB_DIR = port_pb_dir_shadow;
+       REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
+#endif
+
+       /* wait some */
+
+       udelay(25);
+
+       /* de-assert bus-reset */
+
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+       REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+       REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1);
+#endif
+
+       /* make a dummy read to set the ata controller in a proper state */
+       dummy = *R_ATA_STATUS_DATA;
+
+       *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable,     1 ) |
+                         IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+                         IO_FIELD( R_ATA_CONFIG, dma_hold,   ATA_DMA2_HOLD ) |
+                         IO_FIELD( R_ATA_CONFIG, pio_setup,  ATA_PIO4_SETUP ) |
+                         IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+                         IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
+
+       *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw,   read) |
+                            IO_FIELD( R_ATA_CTRL_DATA, addr, 1   ) );
+
+       while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
+
+       *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
+                            IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
+                            IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
+                            IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
+
+       printk("ide: waiting %d seconds for drives to regain consciousness\n",
+              CONFIG_ETRAX_IDE_DELAY);
+
+       h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
+       while(time_before(jiffies, h)) /* nothing */ ;
+
+       /* reset the dma channels we will use */
+
+       RESET_DMA(ATA_TX_DMA_NBR);
+       RESET_DMA(ATA_RX_DMA_NBR);
+       WAIT_DMA(ATA_TX_DMA_NBR);
+       WAIT_DMA(ATA_RX_DMA_NBR);
+
+}
+
+static int e100_dma_off (ide_drive_t *drive)
+{
+       return 0;
+}
+
+static etrax_dma_descr mydescr;
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+static void
+e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+       unsigned long data_reg = IDE_DATA_REG;
+
+       D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+                data_reg, buffer, bytecount));
+
+       if(bytecount & 1) {
+               printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
+               bytecount++; /* to round off */
+       }
+
+       /* make sure the DMA channel is available */
+       RESET_DMA(ATA_RX_DMA_NBR);
+       WAIT_DMA(ATA_RX_DMA_NBR);
+
+       /* setup DMA descriptor */
+
+       mydescr.sw_len = bytecount;
+       mydescr.ctrl   = d_eol;
+       mydescr.buf    = virt_to_phys(buffer);
+
+       /* start the dma channel */
+
+       *R_DMA_CH3_FIRST = virt_to_phys(&mydescr);
+       *R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+       /* initiate a multi word dma read using PIO handshaking */
+
+       *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
+
+       *R_ATA_CTRL_DATA = data_reg |
+               IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+               IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
+               IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+               IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+               IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+       /* wait for completion */
+
+       LED_DISK_READ(1);
+       WAIT_DMA(ATA_RX_DMA_NBR);
+       LED_DISK_READ(0);
+
+#if 0
+        /* old polled transfer code
+        * this should be moved into a new function that can do polled
+        * transfers if DMA is not available
+        */
+
+        /* initiate a multi word read */
+
+        *R_ATA_TRANSFER_CNT = wcount << 1;
+
+        *R_ATA_CTRL_DATA = data_reg |
+                IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
+                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+        /* svinto has a latency until the busy bit actually is set */
+
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+        nop(); nop();
+
+        /* unit should be busy during multi transfer */
+        while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
+                while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
+                        status = *R_ATA_STATUS_DATA;
+                *ptr++ = (unsigned short)(status & 0xffff);
+        }
+#endif
+}
+
+static void
+e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+       unsigned long data_reg = IDE_DATA_REG;
+
+       D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+                data_reg, buffer, bytecount));
+
+       if(bytecount & 1) {
+               printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
+               bytecount++;
+       }
+
+       /* make sure the DMA channel is available */
+       RESET_DMA(ATA_TX_DMA_NBR);
+       WAIT_DMA(ATA_TX_DMA_NBR);
+
+       /* setup DMA descriptor */
+
+       mydescr.sw_len = bytecount;
+       mydescr.ctrl   = d_eol;
+       mydescr.buf    = virt_to_phys(buffer);
+
+       /* start the dma channel */
+
+       *R_DMA_CH2_FIRST = virt_to_phys(&mydescr);
+       *R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+       /* initiate a multi word dma write using PIO handshaking */
+
+       *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
+
+       *R_ATA_CTRL_DATA = data_reg |
+               IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+               IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
+               IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+               IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+               IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+       /* wait for completion */
+
+       LED_DISK_WRITE(1);
+       WAIT_DMA(ATA_TX_DMA_NBR);
+       LED_DISK_WRITE(0);
+
+#if 0
+        /* old polled write code - see comment in input_bytes */
+
+       /* wait for busy flag */
+        while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+        /* initiate a multi word write */
+
+        *R_ATA_TRANSFER_CNT = bytecount >> 1;
+
+        ctrl = data_reg |
+                IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+                IO_STATE(R_ATA_CTRL_DATA, src_dst,  register) |
+                IO_STATE(R_ATA_CTRL_DATA, handsh,   pio) |
+                IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+        LED_DISK_WRITE(1);
+
+        /* Etrax will set busy = 1 until the multi pio transfer has finished
+         * and tr_rdy = 1 after each successful word transfer.
+         * When the last byte has been transferred Etrax will first set tr_tdy = 1
+         * and then busy = 0 (not in the same cycle). If we read busy before it
+         * has been set to 0 we will think that we should transfer more bytes
+         * and then tr_rdy would be 0 forever. This is solved by checking busy
+         * in the inner loop.
+         */
+
+        do {
+                *R_ATA_CTRL_DATA = ctrl | *ptr++;
+                while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
+                      (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
+        } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+        LED_DISK_WRITE(0);
+#endif
+
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+static void
+e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+       e100_atapi_input_bytes(drive, buffer, wcount << 2);
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+static void
+e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+       e100_atapi_output_bytes(drive, buffer, wcount << 2);
+}
+
+/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
+static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
+static unsigned int ata_tot_size;
+
+/*
+ * e100_ide_build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ */
+static int e100_ide_build_dmatable (ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       struct scatterlist* sg;
+       struct request *rq  = HWGROUP(drive)->rq;
+       unsigned long size, addr;
+       unsigned int count = 0;
+       int i = 0;
+
+       sg = hwif->sg_table;
+
+       ata_tot_size = 0;
+
+       ide_map_sg(drive, rq);
+
+       i = hwif->sg_nents;
+
+       while(i) {
+               /*
+                * Determine addr and size of next buffer area.  We assume that
+                * individual virtual buffers are always composed linearly in
+                * physical memory.  For example, we assume that any 8kB buffer
+                * is always composed of two adjacent physical 4kB pages rather
+                * than two possibly non-adjacent physical 4kB pages.
+                */
+               /* group sequential buffers into one large buffer */
+               addr = page_to_phys(sg->page) + sg->offset;
+               size = sg_dma_len(sg);
+               while (sg++, --i) {
+                       if ((addr + size) != page_to_phys(sg->page) + sg->offset)
+                               break;
+                       size += sg_dma_len(sg);
+               }
+
+               /* did we run out of descriptors? */
+
+               if(count >= MAX_DMA_DESCRS) {
+                       printk("%s: too few DMA descriptors\n", drive->name);
+                       return 1;
+               }
+
+               /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
+                  than 65536 words per transfer, so in that case we need to either
+                  1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
+                     the descriptors, or
+                  2) simply do the request here, and get dma_intr to only ide_end_request on
+                     those blocks that were actually set-up for transfer.
+               */
+
+               if(ata_tot_size + size > 131072) {
+                       printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
+                       return 1;
+               }
+
+               /* If size > 65536 it has to be splitted into new descriptors. Since we don't handle
+                   size > 131072 only one split is necessary */
+
+               if(size > 65536) {
+                       /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+                        ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
+                        ata_descrs[count].ctrl = 0;
+                        ata_descrs[count].buf = addr;
+                        ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+                        count++;
+                        ata_tot_size += 65536;
+                        /* size and addr should refere to not handled data */
+                        size -= 65536;
+                        addr += 65536;
+                }
+               /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+                if(size == 65536) {
+                       ata_descrs[count].sw_len = 0;  /* 0 means 65536, this is a 16-bit field */
+                } else {
+                       ata_descrs[count].sw_len = size;
+                }
+               ata_descrs[count].ctrl = 0;
+               ata_descrs[count].buf = addr;
+               ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+               count++;
+               ata_tot_size += size;
+       }
+
+       if (count) {
+               /* set the end-of-list flag on the last descriptor */
+               ata_descrs[count - 1].ctrl |= d_eol;
+               /* return and say all is ok */
+               return 0;
+       }
+
+       printk("%s: empty DMA table?\n", drive->name);
+       return 1;       /* let the PIO routines handle this weirdness */
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+        const char **list;
+        struct hd_driveid *id = drive->id;
+
+        if (id && (id->capability & 1)) {
+                /* Enable DMA on any drive that supports mword2 DMA */
+                if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
+                        drive->using_dma = 1;
+                        return 0;               /* DMA enabled */
+                }
+
+                /* Consult the list of known "good" drives */
+                list = good_dma_drives;
+                while (*list) {
+                        if (!strcmp(*list++,id->model)) {
+                                drive->using_dma = 1;
+                                return 0;       /* DMA enabled */
+                        }
+                }
+        }
+        return 1;       /* DMA not enabled */
+}
+
+/*
+ * etrax_dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
+{
+       int i, dma_stat;
+       byte stat;
+
+       LED_DISK_READ(0);
+       LED_DISK_WRITE(0);
+
+       dma_stat = HWIF(drive)->ide_dma_end(drive);
+       stat = HWIF(drive)->INB(IDE_STATUS_REG);                /* get drive status */
+       if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+               if (!dma_stat) {
+                       struct request *rq;
+                       rq = HWGROUP(drive)->rq;
+                       for (i = rq->nr_sectors; i > 0;) {
+                               i -= rq->current_nr_sectors;
+                               DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
+                       }
+                       return ide_stopped;
+               }
+               printk("%s: bad DMA status\n", drive->name);
+       }
+       return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+/*
+ * Functions below initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA.  All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ */
+
+static int e100_dma_check(ide_drive_t *drive)
+{
+       return config_drive_for_dma (drive);
+}
+
+static int e100_dma_end(ide_drive_t *drive)
+{
+       /* TODO: check if something went wrong with the DMA */
+       return 0;
+}
+
+static void e100_dma_start(ide_drive_t *drive)
+{
+       if (e100_read_command) {
+               /* begin DMA */
+
+               /* need to do this before RX DMA due to a chip bug
+                * it is enough to just flush the part of the cache that
+                * corresponds to the buffers we start, but since HD transfers
+                * usually are more than 8 kB, it is easier to optimize for the
+                * normal case and just flush the entire cache. its the only
+                * way to be sure! (OB movie quote)
+                */
+               flush_etrax_cache();
+               *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
+               *R_DMA_CH3_CMD   = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+               /* initiate a multi word dma read using DMA handshaking */
+
+               *R_ATA_TRANSFER_CNT =
+                       IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
+
+               *R_ATA_CTRL_DATA =
+                       IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
+                       IO_STATE(R_ATA_CTRL_DATA, rw,       read) |
+                       IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma)  |
+                       IO_STATE(R_ATA_CTRL_DATA, handsh,   dma)  |
+                       IO_STATE(R_ATA_CTRL_DATA, multi,    on)   |
+                       IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+               LED_DISK_READ(1);
+
+               D(printk("dma read of %d bytes.\n", ata_tot_size));
+
+       } else {
+               /* writing */
+               /* begin DMA */
+
+               *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
+               *R_DMA_CH2_CMD   = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+               /* initiate a multi word dma write using DMA handshaking */
+
+               *R_ATA_TRANSFER_CNT =
+                       IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
+
+               *R_ATA_CTRL_DATA =
+                       IO_FIELD(R_ATA_CTRL_DATA, data,     IDE_DATA_REG) |
+                       IO_STATE(R_ATA_CTRL_DATA, rw,       write) |
+                       IO_STATE(R_ATA_CTRL_DATA, src_dst,  dma) |
+                       IO_STATE(R_ATA_CTRL_DATA, handsh,   dma) |
+                       IO_STATE(R_ATA_CTRL_DATA, multi,    on) |
+                       IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+               LED_DISK_WRITE(1);
+
+               D(printk("dma write of %d bytes.\n", ata_tot_size));
+       }
+}
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
new file mode 100644 (file)
index 0000000..f424fdf
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Raw serio device providing access to a raw byte stream from underlying
+ * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
+ *
+ * Copyright (c) 2004 Dmitry Torokhov
+ *
+ * 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/slab.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/device.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+#define DRIVER_DESC    "Raw serio driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define SERIO_RAW_QUEUE_LEN    64
+struct serio_raw {
+       unsigned char queue[SERIO_RAW_QUEUE_LEN];
+       unsigned int tail, head;
+
+       char name[16];
+       unsigned int refcnt;
+       struct serio *serio;
+       struct miscdevice dev;
+       wait_queue_head_t wait;
+       struct list_head list;
+       struct list_head node;
+};
+
+struct serio_raw_list {
+       struct fasync_struct *fasync;
+       struct serio_raw *serio_raw;
+       struct list_head node;
+};
+
+static DECLARE_MUTEX(serio_raw_sem);
+static LIST_HEAD(serio_raw_list);
+static unsigned int serio_raw_no;
+
+/*********************************************************************
+ *             Interface with userspace (file operations)            *
+ *********************************************************************/
+
+static int serio_raw_fasync(int fd, struct file *file, int on)
+{
+       struct serio_raw_list *list = file->private_data;
+       int retval;
+
+       retval = fasync_helper(fd, file, on, &list->fasync);
+       return retval < 0 ? retval : 0;
+}
+
+static struct serio_raw *serio_raw_locate(int minor)
+{
+       struct serio_raw *serio_raw;
+
+       list_for_each_entry(serio_raw, &serio_raw_list, node) {
+               if (serio_raw->dev.minor == minor)
+                       return serio_raw;
+       }
+
+       return NULL;
+}
+
+static int serio_raw_open(struct inode *inode, struct file *file)
+{
+       struct serio_raw *serio_raw;
+       struct serio_raw_list *list;
+       int retval = 0;
+
+       retval = down_interruptible(&serio_raw_sem);
+       if (retval)
+               return retval;
+
+       if (!(serio_raw = serio_raw_locate(iminor(inode)))) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       if (!serio_raw->serio) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       memset(list, 0, sizeof(struct serio_raw_list));
+       list->serio_raw = serio_raw;
+       file->private_data = list;
+
+       serio_raw->refcnt++;
+       list_add_tail(&list->node, &serio_raw->list);
+
+out:
+       up(&serio_raw_sem);
+       return retval;
+}
+
+static int serio_raw_cleanup(struct serio_raw *serio_raw)
+{
+       if (--serio_raw->refcnt == 0) {
+               misc_deregister(&serio_raw->dev);
+               list_del_init(&serio_raw->node);
+               kfree(serio_raw);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int serio_raw_release(struct inode *inode, struct file *file)
+{
+       struct serio_raw_list *list = file->private_data;
+       struct serio_raw *serio_raw = list->serio_raw;
+
+       down(&serio_raw_sem);
+
+       serio_raw_fasync(-1, file, 0);
+       serio_raw_cleanup(serio_raw);
+
+       up(&serio_raw_sem);
+       return 0;
+}
+
+static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
+{
+       unsigned long flags;
+       int empty;
+
+       spin_lock_irqsave(&serio_raw->serio->lock, flags);
+
+       empty = serio_raw->head == serio_raw->tail;
+       if (!empty) {
+               *c = serio_raw->queue[serio_raw->tail];
+               serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
+       }
+
+       spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
+
+       return !empty;
+}
+
+static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+       struct serio_raw_list *list = file->private_data;
+       struct serio_raw *serio_raw = list->serio_raw;
+       char c;
+       ssize_t retval = 0;
+
+       if (!serio_raw->serio)
+               return -ENODEV;
+
+       if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
+               return -EAGAIN;
+
+       retval = wait_event_interruptible(list->serio_raw->wait,
+                                         serio_raw->head != serio_raw->tail || !serio_raw->serio);
+       if (retval)
+               return retval;
+
+       if (!serio_raw->serio)
+               return -ENODEV;
+
+       while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
+               if (put_user(c, buffer++))
+                       return -EFAULT;
+               retval++;
+       }
+
+       return retval;
+}
+
+static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+       struct serio_raw_list *list = file->private_data;
+       ssize_t written = 0;
+       int retval;
+       unsigned char c;
+
+       retval = down_interruptible(&serio_raw_sem);
+       if (retval)
+               return retval;
+
+       if (!list->serio_raw->serio) {
+               retval = -ENODEV;
+               goto out;
+       }
+
+       if (count > 32)
+               count = 32;
+
+       while (count--) {
+               if (get_user(c, buffer++)) {
+                       retval = -EFAULT;
+                       goto out;
+               }
+               if (serio_write(list->serio_raw->serio, c)) {
+                       retval = -EIO;
+                       goto out;
+               }
+               written++;
+       };
+
+out:
+       up(&serio_raw_sem);
+       return written;
+}
+
+static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
+{
+       struct serio_raw_list *list = file->private_data;
+
+       poll_wait(file, &list->serio_raw->wait, wait);
+
+       if (list->serio_raw->head != list->serio_raw->tail)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+struct file_operations serio_raw_fops = {
+       .owner =        THIS_MODULE,
+       .open =         serio_raw_open,
+       .release =      serio_raw_release,
+       .read =         serio_raw_read,
+       .write =        serio_raw_write,
+       .poll =         serio_raw_poll,
+       .fasync =       serio_raw_fasync,
+};
+
+
+/*********************************************************************
+ *                   Interface with serio port                      *
+ *********************************************************************/
+
+static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
+                                       unsigned int dfl, struct pt_regs *regs)
+{
+       struct serio_raw *serio_raw = serio->private;
+       struct serio_raw_list *list;
+       unsigned int head = serio_raw->head;
+
+       /* we are holding serio->lock here so we are prootected */
+       serio_raw->queue[head] = data;
+       head = (head + 1) % SERIO_RAW_QUEUE_LEN;
+       if (likely(head != serio_raw->tail)) {
+               serio_raw->head = head;
+               list_for_each_entry(list, &serio_raw->list, node)
+                       kill_fasync(&list->fasync, SIGIO, POLL_IN);
+               wake_up_interruptible(&serio_raw->wait);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void serio_raw_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct serio_raw *serio_raw;
+       int err;
+
+       if ((serio->type & SERIO_TYPE) != SERIO_8042)
+               return;
+
+       if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
+               printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
+               return;
+       }
+
+       down(&serio_raw_sem);
+
+       memset(serio_raw, 0, sizeof(struct serio_raw));
+       snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
+       serio_raw->refcnt = 1;
+       serio_raw->serio = serio;
+       INIT_LIST_HEAD(&serio_raw->list);
+       init_waitqueue_head(&serio_raw->wait);
+
+       serio->private = serio_raw;
+       if (serio_open(serio, drv))
+               goto out_free;
+
+       list_add_tail(&serio_raw->node, &serio_raw_list);
+
+       serio_raw->dev.minor = PSMOUSE_MINOR;
+       serio_raw->dev.name = serio_raw->name;
+       serio_raw->dev.fops = &serio_raw_fops;
+
+       err = misc_register(&serio_raw->dev);
+       if (err) {
+               serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
+               err = misc_register(&serio_raw->dev);
+       }
+
+       if (err) {
+               printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
+                       serio->phys);
+               goto out_close;
+       }
+
+       printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
+               serio->phys, serio_raw->name, serio_raw->dev.minor);
+       goto out;
+
+out_close:
+       serio_close(serio);
+       list_del_init(&serio_raw->node);
+out_free:
+       serio->private = NULL;
+       kfree(serio_raw);
+out:
+       up(&serio_raw_sem);
+}
+
+static int serio_raw_reconnect(struct serio *serio)
+{
+       struct serio_raw *serio_raw = serio->private;
+       struct serio_driver *drv = serio->drv;
+
+       if (!drv || !serio_raw) {
+               printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
+               return -1;
+       }
+
+       /*
+        * Nothing needs to be done here, we just need this method to
+        * keep the same device.
+        */
+       return 0;
+}
+
+static void serio_raw_disconnect(struct serio *serio)
+{
+       struct serio_raw *serio_raw;
+
+       down(&serio_raw_sem);
+
+       serio_raw = serio->private;
+
+       serio_close(serio);
+       serio->private = NULL;
+
+       serio_raw->serio = NULL;
+       if (!serio_raw_cleanup(serio_raw))
+               wake_up_interruptible(&serio_raw->wait);
+
+       up(&serio_raw_sem);
+}
+
+static struct serio_driver serio_raw_drv = {
+       .driver         = {
+               .name   = "serio_raw",
+       },
+       .description    = DRIVER_DESC,
+       .interrupt      = serio_raw_interrupt,
+       .connect        = serio_raw_connect,
+       .reconnect      = serio_raw_reconnect,
+       .disconnect     = serio_raw_disconnect,
+       .manual_bind    = 1,
+};
+
+int __init serio_raw_init(void)
+{
+       serio_register_driver(&serio_raw_drv);
+       return 0;
+}
+
+void __exit serio_raw_exit(void)
+{
+       serio_unregister_driver(&serio_raw_drv);
+}
+
+module_init(serio_raw_init);
+module_exit(serio_raw_exit);
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
new file mode 100644 (file)
index 0000000..0248f8e
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * faulty.c : Multiple Devices driver for Linux
+ *
+ * Copyright (C) 2004 Neil Brown
+ *
+ * fautly-device-simulator personality for md
+ *
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * The "faulty" personality causes some requests to fail.
+ *
+ * Possible failure modes are:
+ *   reads fail "randomly" but succeed on retry
+ *   writes fail "randomly" but succeed on retry
+ *   reads for some address fail and then persist until a write
+ *   reads for some address fail and then persist irrespective of write
+ *   writes for some address fail and persist
+ *   all writes fail
+ *
+ * Different modes can be active at a time, but only
+ * one can be set at array creation.  Others can be added later.
+ * A mode can be one-shot or recurrent with the recurrance being
+ * once in every N requests.
+ * The bottom 5 bits of the "layout" indicate the mode.  The
+ * remainder indicate a period, or 0 for one-shot.
+ *
+ * There is an implementation limit on the number of concurrently
+ * persisting-faulty blocks. When a new fault is requested that would
+ * exceed the limit, it is ignored.
+ * All current faults can be clear using a layout of "0".
+ *
+ * Requests are always sent to the device.  If they are to fail,
+ * we clone the bio and insert a new b_end_io into the chain.
+ */
+
+#define        WriteTransient  0
+#define        ReadTransient   1
+#define        WritePersistent 2
+#define        ReadPersistent  3
+#define        WriteAll        4 /* doesn't go to device */
+#define        ReadFixable     5
+#define        Modes   6
+
+#define        ClearErrors     31
+#define        ClearFaults     30
+
+#define AllPersist     100 /* internal use only */
+#define        NoPersist       101
+
+#define        ModeMask        0x1f
+#define        ModeShift       5
+
+#define MaxFault       50
+#include <linux/raid/md.h>
+
+
+static int faulty_fail(struct bio *bio, unsigned int bytes_done, int error)
+{
+       struct bio *b = bio->bi_private;
+
+       b->bi_size = bio->bi_size;
+       b->bi_sector = bio->bi_sector;
+
+       if (bio->bi_size == 0)
+               bio_put(bio);
+
+       clear_bit(BIO_UPTODATE, &b->bi_flags);
+       return (b->bi_end_io)(b, bytes_done, -EIO);
+}
+
+typedef struct faulty_conf {
+       int period[Modes];
+       atomic_t counters[Modes];
+       sector_t faults[MaxFault];
+       int     modes[MaxFault];
+       int nfaults;
+       mdk_rdev_t *rdev;
+} conf_t;
+
+static int check_mode(conf_t *conf, int mode)
+{
+       if (conf->period[mode] == 0 &&
+           atomic_read(&conf->counters[mode]) <= 0)
+               return 0; /* no failure, no decrement */
+
+
+       if (atomic_dec_and_test(&conf->counters[mode])) {
+               if (conf->period[mode])
+                       atomic_set(&conf->counters[mode], conf->period[mode]);
+               return 1;
+       }
+       return 0;
+}
+
+static int check_sector(conf_t *conf, sector_t start, sector_t end, int dir)
+{
+       /* If we find a ReadFixable sector, we fix it ... */
+       int i;
+       for (i=0; i<conf->nfaults; i++)
+               if (conf->faults[i] >= start &&
+                   conf->faults[i] < end) {
+                       /* found it ... */
+                       switch (conf->modes[i] * 2 + dir) {
+                       case WritePersistent*2+WRITE: return 1;
+                       case ReadPersistent*2+READ: return 1;
+                       case ReadFixable*2+READ: return 1;
+                       case ReadFixable*2+WRITE:
+                               conf->modes[i] = NoPersist;
+                               return 0;
+                       case AllPersist*2+READ:
+                       case AllPersist*2+WRITE: return 1;
+                       default:
+                               return 0;
+                       }
+               }
+       return 0;
+}
+
+static void add_sector(conf_t *conf, sector_t start, int mode)
+{
+       int i;
+       int n = conf->nfaults;
+       for (i=0; i<conf->nfaults; i++)
+               if (conf->faults[i] == start) {
+                       switch(mode) {
+                       case NoPersist: conf->modes[i] = mode; return;
+                       case WritePersistent:
+                               if (conf->modes[i] == ReadPersistent ||
+                                   conf->modes[i] == ReadFixable)
+                                       conf->modes[i] = AllPersist;
+                               else
+                                       conf->modes[i] = WritePersistent;
+                               return;
+                       case ReadPersistent:
+                               if (conf->modes[i] == WritePersistent)
+                                       conf->modes[i] = AllPersist;
+                               else
+                                       conf->modes[i] = ReadPersistent;
+                               return;
+                       case ReadFixable:
+                               if (conf->modes[i] == WritePersistent ||
+                                   conf->modes[i] == ReadPersistent)
+                                       conf->modes[i] = AllPersist;
+                               else
+                                       conf->modes[i] = ReadFixable;
+                               return;
+                       }
+               } else if (conf->modes[i] == NoPersist)
+                       n = i;
+
+       if (n >= MaxFault)
+               return;
+       conf->faults[n] = start;
+       conf->modes[n] = mode;
+       if (conf->nfaults == n)
+               conf->nfaults = n+1;
+}
+
+static int make_request(request_queue_t *q, struct bio *bio)
+{
+       mddev_t *mddev = q->queuedata;
+       conf_t *conf = (conf_t*)mddev->private;
+       int failit = 0;
+
+       if (bio->bi_rw & 1) {
+               /* write request */
+               if (atomic_read(&conf->counters[WriteAll])) {
+                       /* special case - don't decrement, don't generic_make_request,
+                        * just fail immediately
+                        */
+                       bio_endio(bio, bio->bi_size, -EIO);
+                       return 0;
+               }
+
+               if (check_sector(conf, bio->bi_sector, bio->bi_sector+(bio->bi_size>>9),
+                                WRITE))
+                       failit = 1;
+               if (check_mode(conf, WritePersistent)) {
+                       add_sector(conf, bio->bi_sector, WritePersistent);
+                       failit = 1;
+               }
+               if (check_mode(conf, WriteTransient))
+                       failit = 1;
+       } else {
+               /* read request */
+               if (check_sector(conf, bio->bi_sector, bio->bi_sector + (bio->bi_size>>9),
+                                READ))
+                       failit = 1;
+               if (check_mode(conf, ReadTransient))
+                       failit = 1;
+               if (check_mode(conf, ReadPersistent)) {
+                       add_sector(conf, bio->bi_sector, ReadPersistent);
+                       failit = 1;
+               }
+               if (check_mode(conf, ReadFixable)) {
+                       add_sector(conf, bio->bi_sector, ReadFixable);
+                       failit = 1;
+               }
+       }
+       if (failit) {
+               struct bio *b = bio_clone(bio, GFP_NOIO);
+               b->bi_bdev = conf->rdev->bdev;
+               b->bi_private = bio;
+               b->bi_end_io = faulty_fail;
+               generic_make_request(b);
+               return 0;
+       } else {
+               bio->bi_bdev = conf->rdev->bdev;
+               return 1;
+       }
+}
+
+static void status(struct seq_file *seq, mddev_t *mddev)
+{
+       conf_t *conf = (conf_t*)mddev->private;
+       int n;
+
+       if ((n=atomic_read(&conf->counters[WriteTransient])) != 0)
+               seq_printf(seq, " WriteTransient=%d(%d)",
+                          n, conf->period[WriteTransient]);
+
+       if ((n=atomic_read(&conf->counters[ReadTransient])) != 0)
+               seq_printf(seq, " ReadTransient=%d(%d)",
+                          n, conf->period[ReadTransient]);
+
+       if ((n=atomic_read(&conf->counters[WritePersistent])) != 0)
+               seq_printf(seq, " WritePersistent=%d(%d)",
+                          n, conf->period[WritePersistent]);
+
+       if ((n=atomic_read(&conf->counters[ReadPersistent])) != 0)
+               seq_printf(seq, " ReadPersistent=%d(%d)",
+                          n, conf->period[ReadPersistent]);
+
+
+       if ((n=atomic_read(&conf->counters[ReadFixable])) != 0)
+               seq_printf(seq, " ReadFixable=%d(%d)",
+                          n, conf->period[ReadFixable]);
+
+       if ((n=atomic_read(&conf->counters[WriteAll])) != 0)
+               seq_printf(seq, " WriteAll");
+
+       seq_printf(seq, " nfaults=%d", conf->nfaults);
+}
+
+
+static int reconfig(mddev_t *mddev, int layout, int chunk_size)
+{
+       int mode = layout & ModeMask;
+       int count = layout >> ModeShift;
+       conf_t *conf = mddev->private;
+
+       if (chunk_size != -1)
+               return -EINVAL;
+
+       /* new layout */
+       if (mode == ClearFaults)
+               conf->nfaults = 0;
+       else if (mode == ClearErrors) {
+               int i;
+               for (i=0 ; i < Modes ; i++) {
+                       conf->period[i] = 0;
+                       atomic_set(&conf->counters[i], 0);
+               }
+       } else if (mode < Modes) {
+               conf->period[mode] = count;
+               if (!count) count++;
+               atomic_set(&conf->counters[mode], count);
+       } else
+               return -EINVAL;
+       mddev->layout = -1; /* makes sure further changes come through */
+       return 0;
+}
+
+static int run(mddev_t *mddev)
+{
+       mdk_rdev_t *rdev;
+       struct list_head *tmp;
+       int i;
+
+       conf_t *conf = kmalloc(sizeof(*conf), GFP_KERNEL);
+
+       for (i=0; i<Modes; i++) {
+               atomic_set(&conf->counters[i], 0);
+               conf->period[i] = 0;
+       }
+       conf->nfaults = 0;
+
+       ITERATE_RDEV(mddev, rdev, tmp)
+               conf->rdev = rdev;
+
+       mddev->array_size = mddev->size;
+       mddev->private = conf;
+
+       reconfig(mddev, mddev->layout, -1);
+
+       return 0;
+}
+
+static int stop(mddev_t *mddev)
+{
+       conf_t *conf = (conf_t *)mddev->private;
+
+       kfree(conf);
+       mddev->private = NULL;
+       return 0;
+}
+
+static mdk_personality_t faulty_personality =
+{
+       .name           = "faulty",
+       .owner          = THIS_MODULE,
+       .make_request   = make_request,
+       .run            = run,
+       .stop           = stop,
+       .status         = status,
+       .reconfig       = reconfig,
+};
+
+static int __init raid_init(void)
+{
+       return register_md_personality(FAULTY, &faulty_personality);
+}
+
+static void raid_exit(void)
+{
+       unregister_md_personality(FAULTY);
+}
+
+module_init(raid_init);
+module_exit(raid_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("md-personality-10"); /* faulty */
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
new file mode 100644 (file)
index 0000000..6c3fde9
--- /dev/null
@@ -0,0 +1,1780 @@
+/*
+ * raid10.c : Multiple Devices driver for Linux
+ *
+ * Copyright (C) 2000-2004 Neil Brown
+ *
+ * RAID-10 support for md.
+ *
+ * Base on code in raid1.c.  See raid1.c for futher copyright 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/raid/raid10.h>
+
+/*
+ * RAID10 provides a combination of RAID0 and RAID1 functionality.
+ * The layout of data is defined by
+ *    chunk_size
+ *    raid_disks
+ *    near_copies (stored in low byte of layout)
+ *    far_copies (stored in second byte of layout)
+ *
+ * The data to be stored is divided into chunks using chunksize.
+ * Each device is divided into far_copies sections.
+ * In each section, chunks are laid out in a style similar to raid0, but
+ * near_copies copies of each chunk is stored (each on a different drive).
+ * The starting device for each section is offset near_copies from the starting
+ * device of the previous section.
+ * Thus there are (near_copies*far_copies) of each chunk, and each is on a different
+ * drive.
+ * near_copies and far_copies must be at least one, and there product is at most
+ * raid_disks.
+ */
+
+/*
+ * Number of guaranteed r10bios in case of extreme VM load:
+ */
+#define        NR_RAID10_BIOS 256
+
+static void unplug_slaves(mddev_t *mddev);
+
+static void * r10bio_pool_alloc(int gfp_flags, void *data)
+{
+       conf_t *conf = data;
+       r10bio_t *r10_bio;
+       int size = offsetof(struct r10bio_s, devs[conf->copies]);
+
+       /* allocate a r10bio with room for raid_disks entries in the bios array */
+       r10_bio = kmalloc(size, gfp_flags);
+       if (r10_bio)
+               memset(r10_bio, 0, size);
+       else
+               unplug_slaves(conf->mddev);
+
+       return r10_bio;
+}
+
+static void r10bio_pool_free(void *r10_bio, void *data)
+{
+       kfree(r10_bio);
+}
+
+#define RESYNC_BLOCK_SIZE (64*1024)
+//#define RESYNC_BLOCK_SIZE PAGE_SIZE
+#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
+#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
+#define RESYNC_WINDOW (2048*1024)
+
+/*
+ * When performing a resync, we need to read and compare, so
+ * we need as many pages are there are copies.
+ * When performing a recovery, we need 2 bios, one for read,
+ * one for write (we recover only one drive per r10buf)
+ *
+ */
+static void * r10buf_pool_alloc(int gfp_flags, void *data)
+{
+       conf_t *conf = data;
+       struct page *page;
+       r10bio_t *r10_bio;
+       struct bio *bio;
+       int i, j;
+       int nalloc;
+
+       r10_bio = r10bio_pool_alloc(gfp_flags, conf);
+       if (!r10_bio) {
+               unplug_slaves(conf->mddev);
+               return NULL;
+       }
+
+       if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
+               nalloc = conf->copies; /* resync */
+       else
+               nalloc = 2; /* recovery */
+
+       /*
+        * Allocate bios.
+        */
+       for (j = nalloc ; j-- ; ) {
+               bio = bio_alloc(gfp_flags, RESYNC_PAGES);
+               if (!bio)
+                       goto out_free_bio;
+               r10_bio->devs[j].bio = bio;
+       }
+       /*
+        * Allocate RESYNC_PAGES data pages and attach them
+        * where needed.
+        */
+       for (j = 0 ; j < nalloc; j++) {
+               bio = r10_bio->devs[j].bio;
+               for (i = 0; i < RESYNC_PAGES; i++) {
+                       page = alloc_page(gfp_flags);
+                       if (unlikely(!page))
+                               goto out_free_pages;
+
+                       bio->bi_io_vec[i].bv_page = page;
+               }
+       }
+
+       return r10_bio;
+
+out_free_pages:
+       for ( ; i > 0 ; i--)
+               __free_page(bio->bi_io_vec[i-1].bv_page);
+       while (j--)
+               for (i = 0; i < RESYNC_PAGES ; i++)
+                       __free_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
+       j = -1;
+out_free_bio:
+       while ( ++j < nalloc )
+               bio_put(r10_bio->devs[j].bio);
+       r10bio_pool_free(r10_bio, conf);
+       return NULL;
+}
+
+static void r10buf_pool_free(void *__r10_bio, void *data)
+{
+       int i;
+       conf_t *conf = data;
+       r10bio_t *r10bio = __r10_bio;
+       int j;
+
+       for (j=0; j < conf->copies; j++) {
+               struct bio *bio = r10bio->devs[j].bio;
+               if (bio) {
+                       for (i = 0; i < RESYNC_PAGES; i++) {
+                               __free_page(bio->bi_io_vec[i].bv_page);
+                               bio->bi_io_vec[i].bv_page = NULL;
+                       }
+                       bio_put(bio);
+               }
+       }
+       r10bio_pool_free(r10bio, conf);
+}
+
+static void put_all_bios(conf_t *conf, r10bio_t *r10_bio)
+{
+       int i;
+
+       for (i = 0; i < conf->copies; i++) {
+               struct bio **bio = & r10_bio->devs[i].bio;
+               if (*bio)
+                       bio_put(*bio);
+               *bio = NULL;
+       }
+}
+
+static inline void free_r10bio(r10bio_t *r10_bio)
+{
+       unsigned long flags;
+
+       conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+       /*
+        * Wake up any possible resync thread that waits for the device
+        * to go idle.
+        */
+       spin_lock_irqsave(&conf->resync_lock, flags);
+       if (!--conf->nr_pending) {
+               wake_up(&conf->wait_idle);
+               wake_up(&conf->wait_resume);
+       }
+       spin_unlock_irqrestore(&conf->resync_lock, flags);
+
+       put_all_bios(conf, r10_bio);
+       mempool_free(r10_bio, conf->r10bio_pool);
+}
+
+static inline void put_buf(r10bio_t *r10_bio)
+{
+       conf_t *conf = mddev_to_conf(r10_bio->mddev);
+       unsigned long flags;
+
+       mempool_free(r10_bio, conf->r10buf_pool);
+
+       spin_lock_irqsave(&conf->resync_lock, flags);
+       if (!conf->barrier)
+               BUG();
+       --conf->barrier;
+       wake_up(&conf->wait_resume);
+       wake_up(&conf->wait_idle);
+
+       if (!--conf->nr_pending) {
+               wake_up(&conf->wait_idle);
+               wake_up(&conf->wait_resume);
+       }
+       spin_unlock_irqrestore(&conf->resync_lock, flags);
+}
+
+static void reschedule_retry(r10bio_t *r10_bio)
+{
+       unsigned long flags;
+       mddev_t *mddev = r10_bio->mddev;
+       conf_t *conf = mddev_to_conf(mddev);
+
+       spin_lock_irqsave(&conf->device_lock, flags);
+       list_add(&r10_bio->retry_list, &conf->retry_list);
+       spin_unlock_irqrestore(&conf->device_lock, flags);
+
+       md_wakeup_thread(mddev->thread);
+}
+
+/*
+ * raid_end_bio_io() is called when we have finished servicing a mirrored
+ * operation and are ready to return a success/failure code to the buffer
+ * cache layer.
+ */
+static void raid_end_bio_io(r10bio_t *r10_bio)
+{
+       struct bio *bio = r10_bio->master_bio;
+
+       bio_endio(bio, bio->bi_size,
+               test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO);
+       free_r10bio(r10_bio);
+}
+
+/*
+ * Update disk head position estimator based on IRQ completion info.
+ */
+static inline void update_head_pos(int slot, r10bio_t *r10_bio)
+{
+       conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+       conf->mirrors[r10_bio->devs[slot].devnum].head_position =
+               r10_bio->devs[slot].addr + (r10_bio->sectors);
+}
+
+static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+{
+       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+       int slot, dev;
+       conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+       if (bio->bi_size)
+               return 1;
+
+       slot = r10_bio->read_slot;
+       dev = r10_bio->devs[slot].devnum;
+       /*
+        * this branch is our 'one mirror IO has finished' event handler:
+        */
+       if (!uptodate)
+               md_error(r10_bio->mddev, conf->mirrors[dev].rdev);
+       else
+               /*
+                * Set R10BIO_Uptodate in our master bio, so that
+                * we will return a good error code to the higher
+                * levels even if IO on some other mirrored buffer fails.
+                *
+                * The 'master' represents the composite IO operation to
+                * user-side. So if something waits for IO, then it will
+                * wait for the 'master' bio.
+                */
+               set_bit(R10BIO_Uptodate, &r10_bio->state);
+
+       update_head_pos(slot, r10_bio);
+
+       /*
+        * we have only one bio on the read side
+        */
+       if (uptodate)
+               raid_end_bio_io(r10_bio);
+       else {
+               /*
+                * oops, read error:
+                */
+               char b[BDEVNAME_SIZE];
+               if (printk_ratelimit())
+                       printk(KERN_ERR "raid10: %s: rescheduling sector %llu\n",
+                              bdevname(conf->mirrors[dev].rdev->bdev,b), (unsigned long long)r10_bio->sector);
+               reschedule_retry(r10_bio);
+       }
+
+       rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
+       return 0;
+}
+
+static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+{
+       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+       int slot, dev;
+       conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+       if (bio->bi_size)
+               return 1;
+
+       for (slot = 0; slot < conf->copies; slot++)
+               if (r10_bio->devs[slot].bio == bio)
+                       break;
+       dev = r10_bio->devs[slot].devnum;
+
+       /*
+        * this branch is our 'one mirror IO has finished' event handler:
+        */
+       if (!uptodate)
+               md_error(r10_bio->mddev, conf->mirrors[dev].rdev);
+       else
+               /*
+                * Set R10BIO_Uptodate in our master bio, so that
+                * we will return a good error code for to the higher
+                * levels even if IO on some other mirrored buffer fails.
+                *
+                * The 'master' represents the composite IO operation to
+                * user-side. So if something waits for IO, then it will
+                * wait for the 'master' bio.
+                */
+               set_bit(R10BIO_Uptodate, &r10_bio->state);
+
+       update_head_pos(slot, r10_bio);
+
+       /*
+        *
+        * Let's see if all mirrored write operations have finished
+        * already.
+        */
+       if (atomic_dec_and_test(&r10_bio->remaining)) {
+               md_write_end(r10_bio->mddev);
+               raid_end_bio_io(r10_bio);
+       }
+
+       rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
+       return 0;
+}
+
+
+/*
+ * RAID10 layout manager
+ * Aswell as the chunksize and raid_disks count, there are two
+ * parameters: near_copies and far_copies.
+ * near_copies * far_copies must be <= raid_disks.
+ * Normally one of these will be 1.
+ * If both are 1, we get raid0.
+ * If near_copies == raid_disks, we get raid1.
+ *
+ * Chunks are layed out in raid0 style with near_copies copies of the
+ * first chunk, followed by near_copies copies of the next chunk and
+ * so on.
+ * If far_copies > 1, then after 1/far_copies of the array has been assigned
+ * as described above, we start again with a device offset of near_copies.
+ * So we effectively have another copy of the whole array further down all
+ * the drives, but with blocks on different drives.
+ * With this layout, and block is never stored twice on the one device.
+ *
+ * raid10_find_phys finds the sector offset of a given virtual sector
+ * on each device that it is on. If a block isn't on a device,
+ * that entry in the array is set to MaxSector.
+ *
+ * raid10_find_virt does the reverse mapping, from a device and a
+ * sector offset to a virtual address
+ */
+
+static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio)
+{
+       int n,f;
+       sector_t sector;
+       sector_t chunk;
+       sector_t stripe;
+       int dev;
+
+       int slot = 0;
+
+       /* now calculate first sector/dev */
+       chunk = r10bio->sector >> conf->chunk_shift;
+       sector = r10bio->sector & conf->chunk_mask;
+
+       chunk *= conf->near_copies;
+       stripe = chunk;
+       dev = sector_div(stripe, conf->raid_disks);
+
+       sector += stripe << conf->chunk_shift;
+
+       /* and calculate all the others */
+       for (n=0; n < conf->near_copies; n++) {
+               int d = dev;
+               sector_t s = sector;
+               r10bio->devs[slot].addr = sector;
+               r10bio->devs[slot].devnum = d;
+               slot++;
+
+               for (f = 1; f < conf->far_copies; f++) {
+                       d += conf->near_copies;
+                       if (d >= conf->raid_disks)
+                               d -= conf->raid_disks;
+                       s += conf->stride;
+                       r10bio->devs[slot].devnum = d;
+                       r10bio->devs[slot].addr = s;
+                       slot++;
+               }
+               dev++;
+               if (dev >= conf->raid_disks) {
+                       dev = 0;
+                       sector += (conf->chunk_mask + 1);
+               }
+       }
+       BUG_ON(slot != conf->copies);
+}
+
+static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
+{
+       sector_t offset, chunk, vchunk;
+
+       while (sector > conf->stride) {
+               sector -= conf->stride;
+               if (dev < conf->near_copies)
+                       dev += conf->raid_disks - conf->near_copies;
+               else
+                       dev -= conf->near_copies;
+       }
+
+       offset = sector & conf->chunk_mask;
+       chunk = sector >> conf->chunk_shift;
+       vchunk = chunk * conf->raid_disks + dev;
+       sector_div(vchunk, conf->near_copies);
+       return (vchunk << conf->chunk_shift) + offset;
+}
+
+/**
+ *     raid10_mergeable_bvec -- tell bio layer if a two requests can be merged
+ *     @q: request queue
+ *     @bio: the buffer head that's been built up so far
+ *     @biovec: the request that could be merged to it.
+ *
+ *     Return amount of bytes we can accept at this offset
+ *      If near_copies == raid_disk, there are no striping issues,
+ *      but in that case, the function isn't called at all.
+ */
+static int raid10_mergeable_bvec(request_queue_t *q, struct bio *bio,
+                               struct bio_vec *bio_vec)
+{
+       mddev_t *mddev = q->queuedata;
+       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       int max;
+       unsigned int chunk_sectors = mddev->chunk_size >> 9;
+       unsigned int bio_sectors = bio->bi_size >> 9;
+
+       max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
+       if (max < 0) max = 0; /* bio_add cannot handle a negative return */
+       if (max <= bio_vec->bv_len && bio_sectors == 0)
+               return bio_vec->bv_len;
+       else
+               return max;
+}
+
+/*
+ * This routine returns the disk from which the requested read should
+ * be done. There is a per-array 'next expected sequential IO' sector
+ * number - if this matches on the next IO then we use the last disk.
+ * There is also a per-disk 'last know head position' sector that is
+ * maintained from IRQ contexts, both the normal and the resync IO
+ * completion handlers update this position correctly. If there is no
+ * perfect sequential match then we pick the disk whose head is closest.
+ *
+ * If there are 2 mirrors in the same 2 devices, performance degrades
+ * because position is mirror, not device based.
+ *
+ * The rdev for the device selected will have nr_pending incremented.
+ */
+
+/*
+ * FIXME: possibly should rethink readbalancing and do it differently
+ * depending on near_copies / far_copies geometry.
+ */
+static int read_balance(conf_t *conf, r10bio_t *r10_bio)
+{
+       const unsigned long this_sector = r10_bio->sector;
+       int disk, slot, nslot;
+       const int sectors = r10_bio->sectors;
+       sector_t new_distance, current_distance;
+
+       raid10_find_phys(conf, r10_bio);
+       spin_lock_irq(&conf->device_lock);
+       /*
+        * Check if we can balance. We can balance on the whole
+        * device if no resync is going on, or below the resync window.
+        * We take the first readable disk when above the resync window.
+        */
+       if (conf->mddev->recovery_cp < MaxSector
+           && (this_sector + sectors >= conf->next_resync)) {
+               /* make sure that disk is operational */
+               slot = 0;
+               disk = r10_bio->devs[slot].devnum;
+
+               while (!conf->mirrors[disk].rdev ||
+                      !conf->mirrors[disk].rdev->in_sync) {
+                       slot++;
+                       if (slot == conf->copies) {
+                               slot = 0;
+                               disk = -1;
+                               break;
+                       }
+                       disk = r10_bio->devs[slot].devnum;
+               }
+               goto rb_out;
+       }
+
+
+       /* make sure the disk is operational */
+       slot = 0;
+       disk = r10_bio->devs[slot].devnum;
+       while (!conf->mirrors[disk].rdev ||
+              !conf->mirrors[disk].rdev->in_sync) {
+               slot ++;
+               if (slot == conf->copies) {
+                       disk = -1;
+                       goto rb_out;
+               }
+               disk = r10_bio->devs[slot].devnum;
+       }
+
+
+       current_distance = abs(this_sector - conf->mirrors[disk].head_position);
+
+       /* Find the disk whose head is closest */
+
+       for (nslot = slot; nslot < conf->copies; nslot++) {
+               int ndisk = r10_bio->devs[nslot].devnum;
+
+
+               if (!conf->mirrors[ndisk].rdev ||
+                   !conf->mirrors[ndisk].rdev->in_sync)
+                       continue;
+
+               if (!atomic_read(&conf->mirrors[ndisk].rdev->nr_pending)) {
+                       disk = ndisk;
+                       slot = nslot;
+                       break;
+               }
+               new_distance = abs(r10_bio->devs[nslot].addr -
+                                  conf->mirrors[ndisk].head_position);
+               if (new_distance < current_distance) {
+                       current_distance = new_distance;
+                       disk = ndisk;
+                       slot = nslot;
+               }
+       }
+
+rb_out:
+       r10_bio->read_slot = slot;
+/*     conf->next_seq_sect = this_sector + sectors;*/
+
+       if (disk >= 0 && conf->mirrors[disk].rdev)
+               atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+       spin_unlock_irq(&conf->device_lock);
+
+       return disk;
+}
+
+static void unplug_slaves(mddev_t *mddev)
+{
+       conf_t *conf = mddev_to_conf(mddev);
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&conf->device_lock, flags);
+       for (i=0; i<mddev->raid_disks; i++) {
+               mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+               if (rdev && atomic_read(&rdev->nr_pending)) {
+                       request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+
+                       atomic_inc(&rdev->nr_pending);
+                       spin_unlock_irqrestore(&conf->device_lock, flags);
+
+                       if (r_queue->unplug_fn)
+                               r_queue->unplug_fn(r_queue);
+
+                       spin_lock_irqsave(&conf->device_lock, flags);
+                       atomic_dec(&rdev->nr_pending);
+               }
+       }
+       spin_unlock_irqrestore(&conf->device_lock, flags);
+}
+static void raid10_unplug(request_queue_t *q)
+{
+       unplug_slaves(q->queuedata);
+}
+
+static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
+                            sector_t *error_sector)
+{
+       mddev_t *mddev = q->queuedata;
+       conf_t *conf = mddev_to_conf(mddev);
+       unsigned long flags;
+       int i, ret = 0;
+
+       spin_lock_irqsave(&conf->device_lock, flags);
+       for (i=0; i<mddev->raid_disks; i++) {
+               mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+               if (rdev && !rdev->faulty) {
+                       struct block_device *bdev = rdev->bdev;
+                       request_queue_t *r_queue = bdev_get_queue(bdev);
+
+                       if (r_queue->issue_flush_fn) {
+                               ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+                               if (ret)
+                                       break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&conf->device_lock, flags);
+       return ret;
+}
+
+/*
+ * Throttle resync depth, so that we can both get proper overlapping of
+ * requests, but are still able to handle normal requests quickly.
+ */
+#define RESYNC_DEPTH 32
+
+static void device_barrier(conf_t *conf, sector_t sect)
+{
+       spin_lock_irq(&conf->resync_lock);
+       wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume),
+                           conf->resync_lock, unplug_slaves(conf->mddev));
+
+       if (!conf->barrier++) {
+               wait_event_lock_irq(conf->wait_idle, !conf->nr_pending,
+                                   conf->resync_lock, unplug_slaves(conf->mddev));
+               if (conf->nr_pending)
+                       BUG();
+       }
+       wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH,
+                           conf->resync_lock, unplug_slaves(conf->mddev));
+       conf->next_resync = sect;
+       spin_unlock_irq(&conf->resync_lock);
+}
+
+static int make_request(request_queue_t *q, struct bio * bio)
+{
+       mddev_t *mddev = q->queuedata;
+       conf_t *conf = mddev_to_conf(mddev);
+       mirror_info_t *mirror;
+       r10bio_t *r10_bio;
+       struct bio *read_bio;
+       int i;
+       int chunk_sects = conf->chunk_mask + 1;
+
+       /* If this request crosses a chunk boundary, we need to
+        * split it.  This will only happen for 1 PAGE (or less) requests.
+        */
+       if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9)
+                     > chunk_sects &&
+                   conf->near_copies < conf->raid_disks)) {
+               struct bio_pair *bp;
+               /* Sanity check -- queue functions should prevent this happening */
+               if (bio->bi_vcnt != 1 ||
+                   bio->bi_idx != 0)
+                       goto bad_map;
+               /* This is a one page bio that upper layers
+                * refuse to split for us, so we need to split it.
+                */
+               bp = bio_split(bio, bio_split_pool,
+                              chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
+               if (make_request(q, &bp->bio1))
+                       generic_make_request(&bp->bio1);
+               if (make_request(q, &bp->bio2))
+                       generic_make_request(&bp->bio2);
+
+               bio_pair_release(bp);
+               return 0;
+       bad_map:
+               printk("raid10_make_request bug: can't convert block across chunks"
+                      " or bigger than %dk %llu %d\n", chunk_sects/2,
+                      (unsigned long long)bio->bi_sector, bio->bi_size >> 10);
+
+               bio_io_error(bio, bio->bi_size);
+               return 0;
+       }
+
+       /*
+        * Register the new request and wait if the reconstruction
+        * thread has put up a bar for new requests.
+        * Continue immediately if no resync is active currently.
+        */
+       spin_lock_irq(&conf->resync_lock);
+       wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock, );
+       conf->nr_pending++;
+       spin_unlock_irq(&conf->resync_lock);
+
+       if (bio_data_dir(bio)==WRITE) {
+               disk_stat_inc(mddev->gendisk, writes);
+               disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio));
+       } else {
+               disk_stat_inc(mddev->gendisk, reads);
+               disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio));
+       }
+
+       r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+       r10_bio->master_bio = bio;
+       r10_bio->sectors = bio->bi_size >> 9;
+
+       r10_bio->mddev = mddev;
+       r10_bio->sector = bio->bi_sector;
+
+       if (bio_data_dir(bio) == READ) {
+               /*
+                * read balancing logic:
+                */
+               int disk = read_balance(conf, r10_bio);
+               int slot = r10_bio->read_slot;
+               if (disk < 0) {
+                       raid_end_bio_io(r10_bio);
+                       return 0;
+               }
+               mirror = conf->mirrors + disk;
+
+               read_bio = bio_clone(bio, GFP_NOIO);
+
+               r10_bio->devs[slot].bio = read_bio;
+
+               read_bio->bi_sector = r10_bio->devs[slot].addr +
+                       mirror->rdev->data_offset;
+               read_bio->bi_bdev = mirror->rdev->bdev;
+               read_bio->bi_end_io = raid10_end_read_request;
+               read_bio->bi_rw = READ;
+               read_bio->bi_private = r10_bio;
+
+               generic_make_request(read_bio);
+               return 0;
+       }
+
+       /*
+        * WRITE:
+        */
+       /* first select target devices under spinlock and
+        * inc refcount on their rdev.  Record them by setting
+        * bios[x] to bio
+        */
+       raid10_find_phys(conf, r10_bio);
+       spin_lock_irq(&conf->device_lock);
+       for (i = 0;  i < conf->copies; i++) {
+               int d = r10_bio->devs[i].devnum;
+               if (conf->mirrors[d].rdev &&
+                   !conf->mirrors[d].rdev->faulty) {
+                       atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+                       r10_bio->devs[i].bio = bio;
+               } else
+                       r10_bio->devs[i].bio = NULL;
+       }
+       spin_unlock_irq(&conf->device_lock);
+
+       atomic_set(&r10_bio->remaining, 1);
+       md_write_start(mddev);
+       for (i = 0; i < conf->copies; i++) {
+               struct bio *mbio;
+               int d = r10_bio->devs[i].devnum;
+               if (!r10_bio->devs[i].bio)
+                       continue;
+
+               mbio = bio_clone(bio, GFP_NOIO);
+               r10_bio->devs[i].bio = mbio;
+
+               mbio->bi_sector = r10_bio->devs[i].addr+
+                       conf->mirrors[d].rdev->data_offset;
+               mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
+               mbio->bi_end_io = raid10_end_write_request;
+               mbio->bi_rw = WRITE;
+               mbio->bi_private = r10_bio;
+
+               atomic_inc(&r10_bio->remaining);
+               generic_make_request(mbio);
+       }
+
+       if (atomic_dec_and_test(&r10_bio->remaining)) {
+               md_write_end(mddev);
+               raid_end_bio_io(r10_bio);
+       }
+
+       return 0;
+}
+
+static void status(struct seq_file *seq, mddev_t *mddev)
+{
+       conf_t *conf = mddev_to_conf(mddev);
+       int i;
+
+       if (conf->near_copies < conf->raid_disks)
+               seq_printf(seq, " %dK chunks", mddev->chunk_size/1024);
+       if (conf->near_copies > 1)
+               seq_printf(seq, " %d near-copies", conf->near_copies);
+       if (conf->far_copies > 1)
+               seq_printf(seq, " %d far-copies", conf->far_copies);
+
+       seq_printf(seq, " [%d/%d] [", conf->raid_disks,
+                                               conf->working_disks);
+       for (i = 0; i < conf->raid_disks; i++)
+               seq_printf(seq, "%s",
+                             conf->mirrors[i].rdev &&
+                             conf->mirrors[i].rdev->in_sync ? "U" : "_");
+       seq_printf(seq, "]");
+}
+
+static void error(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       char b[BDEVNAME_SIZE];
+       conf_t *conf = mddev_to_conf(mddev);
+
+       /*
+        * If it is not operational, then we have already marked it as dead
+        * else if it is the last working disks, ignore the error, let the
+        * next level up know.
+        * else mark the drive as failed
+        */
+       if (rdev->in_sync
+           && conf->working_disks == 1)
+               /*
+                * Don't fail the drive, just return an IO error.
+                * The test should really be more sophisticated than
+                * "working_disks == 1", but it isn't critical, and
+                * can wait until we do more sophisticated "is the drive
+                * really dead" tests...
+                */
+               return;
+       if (rdev->in_sync) {
+               mddev->degraded++;
+               conf->working_disks--;
+               /*
+                * if recovery is running, make sure it aborts.
+                */
+               set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+       }
+       rdev->in_sync = 0;
+       rdev->faulty = 1;
+       mddev->sb_dirty = 1;
+       printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
+               "       Operation continuing on %d devices\n",
+               bdevname(rdev->bdev,b), conf->working_disks);
+}
+
+static void print_conf(conf_t *conf)
+{
+       int i;
+       mirror_info_t *tmp;
+
+       printk("RAID10 conf printout:\n");
+       if (!conf) {
+               printk("(!conf)\n");
+               return;
+       }
+       printk(" --- wd:%d rd:%d\n", conf->working_disks,
+               conf->raid_disks);
+
+       for (i = 0; i < conf->raid_disks; i++) {
+               char b[BDEVNAME_SIZE];
+               tmp = conf->mirrors + i;
+               if (tmp->rdev)
+                       printk(" disk %d, wo:%d, o:%d, dev:%s\n",
+                               i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+                               bdevname(tmp->rdev->bdev,b));
+       }
+}
+
+static void close_sync(conf_t *conf)
+{
+       spin_lock_irq(&conf->resync_lock);
+       wait_event_lock_irq(conf->wait_resume, !conf->barrier,
+                           conf->resync_lock,  unplug_slaves(conf->mddev));
+       spin_unlock_irq(&conf->resync_lock);
+
+       if (conf->barrier) BUG();
+       if (waitqueue_active(&conf->wait_idle)) BUG();
+
+       mempool_destroy(conf->r10buf_pool);
+       conf->r10buf_pool = NULL;
+}
+
+static int raid10_spare_active(mddev_t *mddev)
+{
+       int i;
+       conf_t *conf = mddev->private;
+       mirror_info_t *tmp;
+
+       spin_lock_irq(&conf->device_lock);
+       /*
+        * Find all non-in_sync disks within the RAID10 configuration
+        * and mark them in_sync
+        */
+       for (i = 0; i < conf->raid_disks; i++) {
+               tmp = conf->mirrors + i;
+               if (tmp->rdev
+                   && !tmp->rdev->faulty
+                   && !tmp->rdev->in_sync) {
+                       conf->working_disks++;
+                       mddev->degraded--;
+                       tmp->rdev->in_sync = 1;
+               }
+       }
+       spin_unlock_irq(&conf->device_lock);
+
+       print_conf(conf);
+       return 0;
+}
+
+
+static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       conf_t *conf = mddev->private;
+       int found = 0;
+       int mirror;
+       mirror_info_t *p;
+
+       if (mddev->recovery_cp < MaxSector)
+               /* only hot-add to in-sync arrays, as recovery is
+                * very different from resync
+                */
+               return 0;
+       spin_lock_irq(&conf->device_lock);
+       for (mirror=0; mirror < mddev->raid_disks; mirror++)
+               if ( !(p=conf->mirrors+mirror)->rdev) {
+                       p->rdev = rdev;
+
+                       blk_queue_stack_limits(mddev->queue,
+                                              rdev->bdev->bd_disk->queue);
+                       /* as we don't honour merge_bvec_fn, we must never risk
+                        * violating it, so limit ->max_sector to one PAGE, as
+                        * a one page request is never in violation.
+                        */
+                       if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
+                           mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                               mddev->queue->max_sectors = (PAGE_SIZE>>9);
+
+                       p->head_position = 0;
+                       rdev->raid_disk = mirror;
+                       found = 1;
+                       break;
+               }
+       spin_unlock_irq(&conf->device_lock);
+
+       print_conf(conf);
+       return found;
+}
+
+static int raid10_remove_disk(mddev_t *mddev, int number)
+{
+       conf_t *conf = mddev->private;
+       int err = 1;
+       mirror_info_t *p = conf->mirrors+ number;
+
+       print_conf(conf);
+       spin_lock_irq(&conf->device_lock);
+       if (p->rdev) {
+               if (p->rdev->in_sync ||
+                   atomic_read(&p->rdev->nr_pending)) {
+                       err = -EBUSY;
+                       goto abort;
+               }
+               p->rdev = NULL;
+               err = 0;
+       }
+       if (err)
+               MD_BUG();
+abort:
+       spin_unlock_irq(&conf->device_lock);
+
+       print_conf(conf);
+       return err;
+}
+
+
+static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+{
+       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+       conf_t *conf = mddev_to_conf(r10_bio->mddev);
+       int i,d;
+
+       if (bio->bi_size)
+               return 1;
+
+       for (i=0; i<conf->copies; i++)
+               if (r10_bio->devs[i].bio == bio)
+                       break;
+       if (i == conf->copies)
+               BUG();
+       update_head_pos(i, r10_bio);
+       d = r10_bio->devs[i].devnum;
+       if (!uptodate)
+               md_error(r10_bio->mddev,
+                        conf->mirrors[d].rdev);
+
+       /* for reconstruct, we always reschedule after a read.
+        * for resync, only after all reads
+        */
+       if (test_bit(R10BIO_IsRecover, &r10_bio->state) ||
+           atomic_dec_and_test(&r10_bio->remaining)) {
+               /* we have read all the blocks,
+                * do the comparison in process context in raid10d
+                */
+               reschedule_retry(r10_bio);
+       }
+       rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
+       return 0;
+}
+
+static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+{
+       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+       mddev_t *mddev = r10_bio->mddev;
+       conf_t *conf = mddev_to_conf(mddev);
+       int i,d;
+
+       if (bio->bi_size)
+               return 1;
+
+       for (i = 0; i < conf->copies; i++)
+               if (r10_bio->devs[i].bio == bio)
+                       break;
+       d = r10_bio->devs[i].devnum;
+
+       if (!uptodate)
+               md_error(mddev, conf->mirrors[d].rdev);
+       update_head_pos(i, r10_bio);
+
+       while (atomic_dec_and_test(&r10_bio->remaining)) {
+               if (r10_bio->master_bio == NULL) {
+                       /* the primary of several recovery bios */
+                       md_done_sync(mddev, r10_bio->sectors, 1);
+                       put_buf(r10_bio);
+                       break;
+               } else {
+                       r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio;
+                       put_buf(r10_bio);
+                       r10_bio = r10_bio2;
+               }
+       }
+       rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+       return 0;
+}
+
+/*
+ * Note: sync and recover and handled very differently for raid10
+ * This code is for resync.
+ * For resync, we read through virtual addresses and read all blocks.
+ * If there is any error, we schedule a write.  The lowest numbered
+ * drive is authoritative.
+ * However requests come for physical address, so we need to map.
+ * For every physical address there are raid_disks/copies virtual addresses,
+ * which is always are least one, but is not necessarly an integer.
+ * This means that a physical address can span multiple chunks, so we may
+ * have to submit multiple io requests for a single sync request.
+ */
+/*
+ * We check if all blocks are in-sync and only write to blocks that
+ * aren't in sync
+ */
+static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio)
+{
+       conf_t *conf = mddev_to_conf(mddev);
+       int i, first;
+       struct bio *tbio, *fbio;
+
+       atomic_set(&r10_bio->remaining, 1);
+
+       /* find the first device with a block */
+       for (i=0; i<conf->copies; i++)
+               if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags))
+                       break;
+
+       if (i == conf->copies)
+               goto done;
+
+       first = i;
+       fbio = r10_bio->devs[i].bio;
+
+       /* now find blocks with errors */
+       for (i=first+1 ; i < conf->copies ; i++) {
+               int vcnt, j, d;
+
+               if (!test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags))
+                       continue;
+               /* We know that the bi_io_vec layout is the same for
+                * both 'first' and 'i', so we just compare them.
+                * All vec entries are PAGE_SIZE;
+                */
+               tbio = r10_bio->devs[i].bio;
+               vcnt = r10_bio->sectors >> (PAGE_SHIFT-9);
+               for (j = 0; j < vcnt; j++)
+                       if (memcmp(page_address(fbio->bi_io_vec[j].bv_page),
+                                  page_address(tbio->bi_io_vec[j].bv_page),
+                                  PAGE_SIZE))
+                               break;
+               if (j == vcnt)
+                       continue;
+               /* Ok, we need to write this bio
+                * First we need to fixup bv_offset, bv_len and
+                * bi_vecs, as the read request might have corrupted these
+                */
+               tbio->bi_vcnt = vcnt;
+               tbio->bi_size = r10_bio->sectors << 9;
+               tbio->bi_idx = 0;
+               tbio->bi_phys_segments = 0;
+               tbio->bi_hw_segments = 0;
+               tbio->bi_hw_front_size = 0;
+               tbio->bi_hw_back_size = 0;
+               tbio->bi_flags &= ~(BIO_POOL_MASK - 1);
+               tbio->bi_flags |= 1 << BIO_UPTODATE;
+               tbio->bi_next = NULL;
+               tbio->bi_rw = WRITE;
+               tbio->bi_private = r10_bio;
+               tbio->bi_sector = r10_bio->devs[i].addr;
+
+               for (j=0; j < vcnt ; j++) {
+                       tbio->bi_io_vec[j].bv_offset = 0;
+                       tbio->bi_io_vec[j].bv_len = PAGE_SIZE;
+
+                       memcpy(page_address(tbio->bi_io_vec[j].bv_page),
+                              page_address(fbio->bi_io_vec[j].bv_page),
+                              PAGE_SIZE);
+               }
+               tbio->bi_end_io = end_sync_write;
+
+               d = r10_bio->devs[i].devnum;
+               atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+               atomic_inc(&r10_bio->remaining);
+               md_sync_acct(conf->mirrors[d].rdev->bdev, tbio->bi_size >> 9);
+
+               generic_make_request(tbio);
+       }
+
+done:
+       if (atomic_dec_and_test(&r10_bio->remaining)) {
+               md_done_sync(mddev, r10_bio->sectors, 1);
+               put_buf(r10_bio);
+       }
+}
+
+/*
+ * Now for the recovery code.
+ * Recovery happens across physical sectors.
+ * We recover all non-is_sync drives by finding the virtual address of
+ * each, and then choose a working drive that also has that virt address.
+ * There is a separate r10_bio for each non-in_sync drive.
+ * Only the first two slots are in use. The first for reading,
+ * The second for writing.
+ *
+ */
+
+static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
+{
+       conf_t *conf = mddev_to_conf(mddev);
+       int i, d;
+       struct bio *bio, *wbio;
+
+
+       /* move the pages across to the second bio
+        * and submit the write request
+        */
+       bio = r10_bio->devs[0].bio;
+       wbio = r10_bio->devs[1].bio;
+       for (i=0; i < wbio->bi_vcnt; i++) {
+               struct page *p = bio->bi_io_vec[i].bv_page;
+               bio->bi_io_vec[i].bv_page = wbio->bi_io_vec[i].bv_page;
+               wbio->bi_io_vec[i].bv_page = p;
+       }
+       d = r10_bio->devs[1].devnum;
+
+       atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+       md_sync_acct(conf->mirrors[d].rdev->bdev, wbio->bi_size >> 9);
+       generic_make_request(wbio);
+}
+
+
+/*
+ * This is a kernel thread which:
+ *
+ *     1.      Retries failed read operations on working mirrors.
+ *     2.      Updates the raid superblock when problems encounter.
+ *     3.      Performs writes following reads for array syncronising.
+ */
+
+static void raid10d(mddev_t *mddev)
+{
+       r10bio_t *r10_bio;
+       struct bio *bio;
+       unsigned long flags;
+       conf_t *conf = mddev_to_conf(mddev);
+       struct list_head *head = &conf->retry_list;
+       int unplug=0;
+       mdk_rdev_t *rdev;
+
+       md_check_recovery(mddev);
+       md_handle_safemode(mddev);
+
+       for (;;) {
+               char b[BDEVNAME_SIZE];
+               spin_lock_irqsave(&conf->device_lock, flags);
+               if (list_empty(head))
+                       break;
+               r10_bio = list_entry(head->prev, r10bio_t, retry_list);
+               list_del(head->prev);
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+
+               mddev = r10_bio->mddev;
+               conf = mddev_to_conf(mddev);
+               if (test_bit(R10BIO_IsSync, &r10_bio->state)) {
+                       sync_request_write(mddev, r10_bio);
+                       unplug = 1;
+               } else  if (test_bit(R10BIO_IsRecover, &r10_bio->state)) {
+                       recovery_request_write(mddev, r10_bio);
+                       unplug = 1;
+               } else {
+                       int mirror;
+                       bio = r10_bio->devs[r10_bio->read_slot].bio;
+                       r10_bio->devs[r10_bio->read_slot].bio = NULL;
+                       mirror = read_balance(conf, r10_bio);
+                       r10_bio->devs[r10_bio->read_slot].bio = bio;
+                       if (mirror == -1) {
+                               printk(KERN_ALERT "raid10: %s: unrecoverable I/O"
+                                      " read error for block %llu\n",
+                                      bdevname(bio->bi_bdev,b),
+                                      (unsigned long long)r10_bio->sector);
+                               raid_end_bio_io(r10_bio);
+                       } else {
+                               rdev = conf->mirrors[mirror].rdev;
+                               if (printk_ratelimit())
+                                       printk(KERN_ERR "raid10: %s: redirecting sector %llu to"
+                                              " another mirror\n",
+                                              bdevname(rdev->bdev,b),
+                                              (unsigned long long)r10_bio->sector);
+                               bio->bi_bdev = rdev->bdev;
+                               bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr
+                                       + rdev->data_offset;
+                               bio->bi_next = NULL;
+                               bio->bi_flags &= (1<<BIO_CLONED);
+                               bio->bi_flags |= 1 << BIO_UPTODATE;
+                               bio->bi_idx = 0;
+                               bio->bi_size = r10_bio->sectors << 9;
+                               bio->bi_rw = READ;
+                               unplug = 1;
+                               generic_make_request(bio);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&conf->device_lock, flags);
+       if (unplug)
+               unplug_slaves(mddev);
+}
+
+
+static int init_resync(conf_t *conf)
+{
+       int buffs;
+
+       buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
+       if (conf->r10buf_pool)
+               BUG();
+       conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
+       if (!conf->r10buf_pool)
+               return -ENOMEM;
+       conf->next_resync = 0;
+       return 0;
+}
+
+/*
+ * perform a "sync" on one "block"
+ *
+ * We need to make sure that no normal I/O request - particularly write
+ * requests - conflict with active sync requests.
+ *
+ * This is achieved by tracking pending requests and a 'barrier' concept
+ * that can be installed to exclude normal IO requests.
+ *
+ * Resync and recovery are handled very differently.
+ * We differentiate by looking at MD_RECOVERY_SYNC in mddev->recovery.
+ *
+ * For resync, we iterate over virtual addresses, read all copies,
+ * and update if there are differences.  If only one copy is live,
+ * skip it.
+ * For recovery, we iterate over physical addresses, read a good
+ * value for each non-in_sync drive, and over-write.
+ *
+ * So, for recovery we may have several outstanding complex requests for a
+ * given address, one for each out-of-sync device.  We model this by allocating
+ * a number of r10_bio structures, one for each out-of-sync device.
+ * As we setup these structures, we collect all bio's together into a list
+ * which we then process collectively to add pages, and then process again
+ * to pass to generic_make_request.
+ *
+ * The r10_bio structures are linked using a borrowed master_bio pointer.
+ * This link is counted in ->remaining.  When the r10_bio that points to NULL
+ * has its remaining count decremented to 0, the whole complex operation
+ * is complete.
+ *
+ */
+
+static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
+{
+       conf_t *conf = mddev_to_conf(mddev);
+       r10bio_t *r10_bio;
+       struct bio *biolist = NULL, *bio;
+       sector_t max_sector, nr_sectors;
+       int disk;
+       int i;
+
+       sector_t sectors_skipped = 0;
+       int chunks_skipped = 0;
+
+       if (!conf->r10buf_pool)
+               if (init_resync(conf))
+                       return -ENOMEM;
+
+ skipped:
+       max_sector = mddev->size << 1;
+       if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+               max_sector = mddev->resync_max_sectors;
+       if (sector_nr >= max_sector) {
+               close_sync(conf);
+               return sectors_skipped;
+       }
+       if (chunks_skipped >= conf->raid_disks) {
+               /* if there has been nothing to do on any drive,
+                * then there is nothing to do at all..
+                */
+               sector_t sec = max_sector - sector_nr;
+               md_done_sync(mddev, sec, 1);
+               return sec + sectors_skipped;
+       }
+
+       /* make sure whole request will fit in a chunk - if chunks
+        * are meaningful
+        */
+       if (conf->near_copies < conf->raid_disks &&
+           max_sector > (sector_nr | conf->chunk_mask))
+               max_sector = (sector_nr | conf->chunk_mask) + 1;
+       /*
+        * If there is non-resync activity waiting for us then
+        * put in a delay to throttle resync.
+        */
+       if (!go_faster && waitqueue_active(&conf->wait_resume))
+               schedule_timeout(HZ);
+       device_barrier(conf, sector_nr + RESYNC_SECTORS);
+
+       /* Again, very different code for resync and recovery.
+        * Both must result in an r10bio with a list of bios that
+        * have bi_end_io, bi_sector, bi_bdev set,
+        * and bi_private set to the r10bio.
+        * For recovery, we may actually create several r10bios
+        * with 2 bios in each, that correspond to the bios in the main one.
+        * In this case, the subordinate r10bios link back through a
+        * borrowed master_bio pointer, and the counter in the master
+        * includes a ref from each subordinate.
+        */
+       /* First, we decide what to do and set ->bi_end_io
+        * To end_sync_read if we want to read, and
+        * end_sync_write if we will want to write.
+        */
+
+       if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+               /* recovery... the complicated one */
+               int i, j, k;
+               r10_bio = NULL;
+
+               for (i=0 ; i<conf->raid_disks; i++)
+                       if (conf->mirrors[i].rdev &&
+                           !conf->mirrors[i].rdev->in_sync) {
+                               /* want to reconstruct this device */
+                               r10bio_t *rb2 = r10_bio;
+
+                               r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+                               spin_lock_irq(&conf->resync_lock);
+                               conf->nr_pending++;
+                               if (rb2) conf->barrier++;
+                               spin_unlock_irq(&conf->resync_lock);
+                               atomic_set(&r10_bio->remaining, 0);
+
+                               r10_bio->master_bio = (struct bio*)rb2;
+                               if (rb2)
+                                       atomic_inc(&rb2->remaining);
+                               r10_bio->mddev = mddev;
+                               set_bit(R10BIO_IsRecover, &r10_bio->state);
+                               r10_bio->sector = raid10_find_virt(conf, sector_nr, i);
+                               raid10_find_phys(conf, r10_bio);
+                               for (j=0; j<conf->copies;j++) {
+                                       int d = r10_bio->devs[j].devnum;
+                                       if (conf->mirrors[d].rdev &&
+                                           conf->mirrors[d].rdev->in_sync) {
+                                               /* This is where we read from */
+                                               bio = r10_bio->devs[0].bio;
+                                               bio->bi_next = biolist;
+                                               biolist = bio;
+                                               bio->bi_private = r10_bio;
+                                               bio->bi_end_io = end_sync_read;
+                                               bio->bi_rw = 0;
+                                               bio->bi_sector = r10_bio->devs[j].addr +
+                                                       conf->mirrors[d].rdev->data_offset;
+                                               bio->bi_bdev = conf->mirrors[d].rdev->bdev;
+                                               atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+                                               atomic_inc(&r10_bio->remaining);
+                                               /* and we write to 'i' */
+
+                                               for (k=0; k<conf->copies; k++)
+                                                       if (r10_bio->devs[k].devnum == i)
+                                                               break;
+                                               bio = r10_bio->devs[1].bio;
+                                               bio->bi_next = biolist;
+                                               biolist = bio;
+                                               bio->bi_private = r10_bio;
+                                               bio->bi_end_io = end_sync_write;
+                                               bio->bi_rw = 1;
+                                               bio->bi_sector = r10_bio->devs[k].addr +
+                                                       conf->mirrors[i].rdev->data_offset;
+                                               bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+
+                                               r10_bio->devs[0].devnum = d;
+                                               r10_bio->devs[1].devnum = i;
+
+                                               break;
+                                       }
+                               }
+                               if (j == conf->copies) {
+                                       BUG();
+                               }
+                       }
+               if (biolist == NULL) {
+                       while (r10_bio) {
+                               r10bio_t *rb2 = r10_bio;
+                               r10_bio = (r10bio_t*) rb2->master_bio;
+                               rb2->master_bio = NULL;
+                               put_buf(rb2);
+                       }
+                       goto giveup;
+               }
+       } else {
+               /* resync. Schedule a read for every block at this virt offset */
+               int count = 0;
+               r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+
+               spin_lock_irq(&conf->resync_lock);
+               conf->nr_pending++;
+               spin_unlock_irq(&conf->resync_lock);
+
+               r10_bio->mddev = mddev;
+               atomic_set(&r10_bio->remaining, 0);
+
+               r10_bio->master_bio = NULL;
+               r10_bio->sector = sector_nr;
+               set_bit(R10BIO_IsSync, &r10_bio->state);
+               raid10_find_phys(conf, r10_bio);
+               r10_bio->sectors = (sector_nr | conf->chunk_mask) - sector_nr +1;
+               spin_lock_irq(&conf->device_lock);
+               for (i=0; i<conf->copies; i++) {
+                       int d = r10_bio->devs[i].devnum;
+                       bio = r10_bio->devs[i].bio;
+                       bio->bi_end_io = NULL;
+                       if (conf->mirrors[d].rdev == NULL ||
+                           conf->mirrors[d].rdev->faulty)
+                               continue;
+                       atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+                       atomic_inc(&r10_bio->remaining);
+                       bio->bi_next = biolist;
+                       biolist = bio;
+                       bio->bi_private = r10_bio;
+                       bio->bi_end_io = end_sync_read;
+                       bio->bi_rw = 0;
+                       bio->bi_sector = r10_bio->devs[i].addr +
+                               conf->mirrors[d].rdev->data_offset;
+                       bio->bi_bdev = conf->mirrors[d].rdev->bdev;
+                       count++;
+               }
+               spin_unlock_irq(&conf->device_lock);
+               if (count < 2) {
+                       for (i=0; i<conf->copies; i++) {
+                               int d = r10_bio->devs[i].devnum;
+                               if (r10_bio->devs[i].bio->bi_end_io)
+                                       atomic_dec(&conf->mirrors[d].rdev->nr_pending);
+                       }
+                       put_buf(r10_bio);
+                       goto giveup;
+               }
+       }
+
+       for (bio = biolist; bio ; bio=bio->bi_next) {
+
+               bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+               if (bio->bi_end_io)
+                       bio->bi_flags |= 1 << BIO_UPTODATE;
+               bio->bi_vcnt = 0;
+               bio->bi_idx = 0;
+               bio->bi_phys_segments = 0;
+               bio->bi_hw_segments = 0;
+               bio->bi_size = 0;
+       }
+
+       nr_sectors = 0;
+       do {
+               struct page *page;
+               int len = PAGE_SIZE;
+               disk = 0;
+               if (sector_nr + (len>>9) > max_sector)
+                       len = (max_sector - sector_nr) << 9;
+               if (len == 0)
+                       break;
+               for (bio= biolist ; bio ; bio=bio->bi_next) {
+                       page = bio->bi_io_vec[bio->bi_vcnt].bv_page;
+                       if (bio_add_page(bio, page, len, 0) == 0) {
+                               /* stop here */
+                               struct bio *bio2;
+                               bio->bi_io_vec[bio->bi_vcnt].bv_page = page;
+                               for (bio2 = biolist; bio2 && bio2 != bio; bio2 = bio2->bi_next) {
+                                       /* remove last page from this bio */
+                                       bio2->bi_vcnt--;
+                                       bio2->bi_size -= len;
+                                       bio2->bi_flags &= ~(1<< BIO_SEG_VALID);
+                               }
+                               goto bio_full;
+                       }
+                       disk = i;
+               }
+               nr_sectors += len>>9;
+               sector_nr += len>>9;
+       } while (biolist->bi_vcnt < RESYNC_PAGES);
+ bio_full:
+       r10_bio->sectors = nr_sectors;
+
+       while (biolist) {
+               bio = biolist;
+               biolist = biolist->bi_next;
+
+               bio->bi_next = NULL;
+               r10_bio = bio->bi_private;
+               r10_bio->sectors = nr_sectors;
+
+               if (bio->bi_end_io == end_sync_read) {
+                       md_sync_acct(bio->bi_bdev, nr_sectors);
+                       generic_make_request(bio);
+               }
+       }
+
+       return nr_sectors;
+ giveup:
+       /* There is nowhere to write, so all non-sync
+        * drives must be failed, so try the next chunk...
+        */
+       {
+       int sec = max_sector - sector_nr;
+       sectors_skipped += sec;
+       chunks_skipped ++;
+       sector_nr = max_sector;
+       md_done_sync(mddev, sec, 1);
+       goto skipped;
+       }
+}
+
+static int run(mddev_t *mddev)
+{
+       conf_t *conf;
+       int i, disk_idx;
+       mirror_info_t *disk;
+       mdk_rdev_t *rdev;
+       struct list_head *tmp;
+       int nc, fc;
+       sector_t stride, size;
+
+       if (mddev->level != 10) {
+               printk(KERN_ERR "raid10: %s: raid level not set correctly... (%d)\n",
+                      mdname(mddev), mddev->level);
+               goto out;
+       }
+       nc = mddev->layout & 255;
+       fc = (mddev->layout >> 8) & 255;
+       if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
+           (mddev->layout >> 16)) {
+               printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n",
+                      mdname(mddev), mddev->layout);
+               goto out;
+       }
+       /*
+        * copy the already verified devices into our private RAID10
+        * bookkeeping area. [whatever we allocate in run(),
+        * should be freed in stop()]
+        */
+       conf = kmalloc(sizeof(conf_t), GFP_KERNEL);
+       mddev->private = conf;
+       if (!conf) {
+               printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
+                       mdname(mddev));
+               goto out;
+       }
+       memset(conf, 0, sizeof(*conf));
+       conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+                                GFP_KERNEL);
+       if (!conf->mirrors) {
+               printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
+                      mdname(mddev));
+               goto out_free_conf;
+       }
+       memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks);
+
+       conf->near_copies = nc;
+       conf->far_copies = fc;
+       conf->copies = nc*fc;
+       conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
+       conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
+       stride = mddev->size >> (conf->chunk_shift-1);
+       sector_div(stride, fc);
+       conf->stride = stride << conf->chunk_shift;
+
+       conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
+                                               r10bio_pool_free, conf);
+       if (!conf->r10bio_pool) {
+               printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
+                       mdname(mddev));
+               goto out_free_conf;
+       }
+       mddev->queue->unplug_fn = raid10_unplug;
+
+       mddev->queue->issue_flush_fn = raid10_issue_flush;
+
+       ITERATE_RDEV(mddev, rdev, tmp) {
+               disk_idx = rdev->raid_disk;
+               if (disk_idx >= mddev->raid_disks
+                   || disk_idx < 0)
+                       continue;
+               disk = conf->mirrors + disk_idx;
+
+               disk->rdev = rdev;
+
+               blk_queue_stack_limits(mddev->queue,
+                                      rdev->bdev->bd_disk->queue);
+               /* as we don't honour merge_bvec_fn, we must never risk
+                * violating it, so limit ->max_sector to one PAGE, as
+                * a one page request is never in violation.
+                */
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
+                   mddev->queue->max_sectors > (PAGE_SIZE>>9))
+                       mddev->queue->max_sectors = (PAGE_SIZE>>9);
+
+               disk->head_position = 0;
+               if (!rdev->faulty && rdev->in_sync)
+                       conf->working_disks++;
+       }
+       conf->raid_disks = mddev->raid_disks;
+       conf->mddev = mddev;
+       conf->device_lock = SPIN_LOCK_UNLOCKED;
+       INIT_LIST_HEAD(&conf->retry_list);
+
+       conf->resync_lock = SPIN_LOCK_UNLOCKED;
+       init_waitqueue_head(&conf->wait_idle);
+       init_waitqueue_head(&conf->wait_resume);
+
+       if (!conf->working_disks) {
+               printk(KERN_ERR "raid10: no operational mirrors for %s\n",
+                       mdname(mddev));
+               goto out_free_conf;
+       }
+
+       mddev->degraded = 0;
+       for (i = 0; i < conf->raid_disks; i++) {
+
+               disk = conf->mirrors + i;
+
+               if (!disk->rdev) {
+                       disk->head_position = 0;
+                       mddev->degraded++;
+               }
+       }
+
+
+       mddev->thread = md_register_thread(raid10d, mddev, "%s_raid10");
+       if (!mddev->thread) {
+               printk(KERN_ERR
+                      "raid10: couldn't allocate thread for %s\n",
+                      mdname(mddev));
+               goto out_free_conf;
+       }
+
+       printk(KERN_INFO
+               "raid10: raid set %s active with %d out of %d devices\n",
+               mdname(mddev), mddev->raid_disks - mddev->degraded,
+               mddev->raid_disks);
+       /*
+        * Ok, everything is just fine now
+        */
+       size = conf->stride * conf->raid_disks;
+       sector_div(size, conf->near_copies);
+       mddev->array_size = size/2;
+       mddev->resync_max_sectors = size;
+
+       /* Calculate max read-ahead size.
+        * We need to readahead at least twice a whole stripe....
+        * maybe...
+        */
+       {
+               int stripe = conf->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE;
+               stripe /= conf->near_copies;
+               if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
+                       mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+       }
+
+       if (conf->near_copies < mddev->raid_disks)
+               blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
+       return 0;
+
+out_free_conf:
+       if (conf->r10bio_pool)
+               mempool_destroy(conf->r10bio_pool);
+       if (conf->mirrors)
+               kfree(conf->mirrors);
+       kfree(conf);
+       mddev->private = NULL;
+out:
+       return -EIO;
+}
+
+static int stop(mddev_t *mddev)
+{
+       conf_t *conf = mddev_to_conf(mddev);
+
+       md_unregister_thread(mddev->thread);
+       mddev->thread = NULL;
+       if (conf->r10bio_pool)
+               mempool_destroy(conf->r10bio_pool);
+       if (conf->mirrors)
+               kfree(conf->mirrors);
+       kfree(conf);
+       mddev->private = NULL;
+       return 0;
+}
+
+
+static mdk_personality_t raid10_personality =
+{
+       .name           = "raid10",
+       .owner          = THIS_MODULE,
+       .make_request   = make_request,
+       .run            = run,
+       .stop           = stop,
+       .status         = status,
+       .error_handler  = error,
+       .hot_add_disk   = raid10_add_disk,
+       .hot_remove_disk= raid10_remove_disk,
+       .spare_active   = raid10_spare_active,
+       .sync_request   = sync_request,
+};
+
+static int __init raid_init(void)
+{
+       return register_md_personality(RAID10, &raid10_personality);
+}
+
+static void raid_exit(void)
+{
+       unregister_md_personality(RAID10);
+}
+
+module_init(raid_init);
+module_exit(raid_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("md-personality-9"); /* RAID10 */
diff --git a/drivers/media/dvb/b2c2/b2c2-common.c b/drivers/media/dvb/b2c2/b2c2-common.c
new file mode 100644 (file)
index 0000000..cb42d44
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * b2c2-common.c - common methods for the B2C2/Technisat SkyStar2 PCI DVB card and
+ *                 for the B2C2/Technisat Sky/Cable/AirStar USB devices
+ *                 based on the FlexCopII/FlexCopIII by B2C2, Inc.
+ *
+ * Copyright (C) 2003  Vadim Catana, skystar@moldova.cc
+ *
+ * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
+ * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
+ *     Vincenzo Di Massa, hawk.it at tiscalinet.it
+ *
+ * Converted to Linux coding style
+ * Misc reorganization, polishing, restyling
+ *     Roberto Ragusa, r.ragusa at libero.it
+ *
+ * Added hardware filtering support,
+ *     Niklas Peinecke, peinecke at gdv.uni-hannover.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser 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 "stv0299.h"
+#include "mt352.h"
+#include "mt312.h"
+
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+       u8 aclk = 0;
+       u8 bclk = 0;
+
+       if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+       else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+       else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+       else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+       else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+       else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+       stv0299_writereg (fe, 0x13, aclk);
+       stv0299_writereg (fe, 0x14, bclk);
+       stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+       stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
+       stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
+
+       return 0;
+}
+
+static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+//     struct adapter* adapter = (struct adapter*) fe->dvb->priv;
+
+       div = params->frequency / 125;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = div & 0xff;
+       buf[2] = 0x84;  // 0xC4
+       buf[3] = 0x08;
+
+       if (params->frequency < 1500000) buf[3] |= 0x10;
+
+//     if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
+
+static u8 samsung_tbmu24112_inittab[] = {
+            0x01, 0x15,
+            0x02, 0x30,
+            0x03, 0x00,
+            0x04, 0x7D,
+            0x05, 0x35,
+            0x06, 0x02,
+            0x07, 0x00,
+            0x08, 0xC3,
+            0x0C, 0x00,
+            0x0D, 0x81,
+            0x0E, 0x23,
+            0x0F, 0x12,
+            0x10, 0x7E,
+            0x11, 0x84,
+            0x12, 0xB9,
+            0x13, 0x88,
+            0x14, 0x89,
+            0x15, 0xC9,
+            0x16, 0x00,
+            0x17, 0x5C,
+            0x18, 0x00,
+            0x19, 0x00,
+            0x1A, 0x00,
+            0x1C, 0x00,
+            0x1D, 0x00,
+            0x1E, 0x00,
+            0x1F, 0x3A,
+            0x20, 0x2E,
+            0x21, 0x80,
+            0x22, 0xFF,
+            0x23, 0xC1,
+            0x28, 0x00,
+            0x29, 0x1E,
+            0x2A, 0x14,
+            0x2B, 0x0F,
+            0x2C, 0x09,
+            0x2D, 0x05,
+            0x31, 0x1F,
+            0x32, 0x19,
+            0x33, 0xFE,
+            0x34, 0x93,
+            0xff, 0xff,
+};
+
+static struct stv0299_config samsung_tbmu24112_config = {
+       .demod_address = 0x68,
+       .inittab = samsung_tbmu24112_inittab,
+       .mclk = 88000000UL,
+       .invert = 0,
+       .enhanced_tuning = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0229_LOCKOUTPUT_LK,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
+       .pll_set = samsung_tbmu24112_pll_set,
+};
+
+
+
+
+
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+{
+       static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d };
+       static u8 mt352_reset [] = { 0x50, 0x80 };
+       static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+       static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+       static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+       mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+       udelay(2000);
+       mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+       mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+       mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+       mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+       return 0;
+}
+
+int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+       u32 div;
+       unsigned char bs = 0;
+
+       #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+       if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
+       if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
+       if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+
+       pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+       pllbuf[1] = div >> 8;
+       pllbuf[2] = div & 0xff;
+       pllbuf[3] = 0xcc;
+       pllbuf[4] = bs;
+
+       return 0;
+}
+
+static struct mt352_config samsung_tdtc9251dh0_config = {
+
+       .demod_address = 0x0f,
+       .demod_init = samsung_tdtc9251dh0_demod_init,
+       .pll_set = samsung_tdtc9251dh0_pll_set,
+};
+
+static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+//     struct adapter* adapter = (struct adapter*) fe->dvb->priv;
+
+       div = (params->frequency + (125/2)) / 125;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = (div >> 0) & 0xff;
+       buf[2] = 0x84 | ((div >> 10) & 0x60);
+       buf[3] = 0x80;
+
+       if (params->frequency < 1550000)
+               buf[3] |= 0x02;
+
+       //if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
+       return 0;
+}
+
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+
+       .demod_address = 0x0e,
+       .pll_set = skystar23_samsung_tbdu18132_pll_set,
+};
diff --git a/drivers/media/dvb/b2c2/b2c2-usb-core.c b/drivers/media/dvb/b2c2/b2c2-usb-core.c
new file mode 100644 (file)
index 0000000..d46c8c0
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2004 Patrick Boettcher <patrick.boettcher@desy.de>,
+ *                    Luca Bertagnolio <>,
+ *
+ * based on information provided by John Jurrius from BBTI, 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, version 2.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/version.h>
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+/* debug */
+#define dprintk(level,args...) \
+           do { if ((debug & level)) { printk(args); } } while (0)
+#define debug_dump(b,l) if (debug) {\
+       int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
+       for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
+       deb_xfer("\n");\
+}
+
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able)).");
+
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_ts(args...)   dprintk(0x02,args)
+#define deb_ctrl(args...) dprintk(0x04,args)
+
+/* Version information */
+#define DRIVER_VERSION "0.0"
+#define DRIVER_DESC "Driver for B2C2/Technisat Air/Cable/Sky-2-PC USB devices"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+/* transfer parameters */
+#define B2C2_USB_FRAMES_PER_ISO                4
+#define B2C2_USB_NUM_ISO_URB           4    /* TODO check out a good value */
+
+#define B2C2_USB_CTRL_PIPE_IN          usb_rcvctrlpipe(b2c2->udev,0)
+#define B2C2_USB_CTRL_PIPE_OUT         usb_sndctrlpipe(b2c2->udev,0)
+#define B2C2_USB_DATA_PIPE                     usb_rcvisocpipe(b2c2->udev,0x81)
+
+struct usb_b2c2_usb {
+       struct usb_device *udev;
+       struct usb_interface *uintf;
+
+       u8 *iso_buffer;
+       int buffer_size;
+       dma_addr_t iso_dma_handle;
+       struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
+};
+
+
+/*
+ * USB
+ * 10 90 34 12 78 56 04 00
+ * usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+ * 0x90,
+ * 0x10,
+ * 0x1234,
+ * 0x5678,
+ * buf,
+ * 4,
+ * 5*HZ);
+ *
+ * extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
+ * __u8 request,
+ * __u8 requesttype,
+ * __u16 value,
+ * __u16 index,
+ * void *data,
+ * __u16 size,
+ * int timeout);
+ *
+ */
+
+/* request types */
+typedef enum {
+       RTYPE_READ_DW         = (1 << 6),
+       RTYPE_WRITE_DW_1      = (3 << 6),
+       RTYPE_READ_V8_MEMORY  = (6 << 6),
+       RTYPE_WRITE_V8_MEMORY = (7 << 6),
+       RTYPE_WRITE_V8_FLASH  = (8 << 6),
+       RTYPE_GENERIC         = (9 << 6),
+} b2c2_usb_request_type_t;
+
+/* request */
+typedef enum {
+       B2C2_USB_WRITE_V8_MEM = 0x04,
+       B2C2_USB_READ_V8_MEM  = 0x05,
+       B2C2_USB_READ_REG     = 0x08,
+       B2C2_USB_WRITE_REG    = 0x0A,
+/*     B2C2_USB_WRITEREGLO   = 0x0A, */
+       B2C2_USB_WRITEREGHI   = 0x0B,
+       B2C2_USB_FLASH_BLOCK  = 0x10,
+       B2C2_USB_I2C_REQUEST  = 0x11,
+       B2C2_USB_UTILITY      = 0x12,
+} b2c2_usb_request_t;
+
+/* function definition for I2C_REQUEST */
+typedef enum {
+       USB_FUNC_I2C_WRITE       = 0x01,
+       USB_FUNC_I2C_MULTIWRITE  = 0x02,
+       USB_FUNC_I2C_READ        = 0x03,
+       USB_FUNC_I2C_REPEATWRITE = 0x04,
+       USB_FUNC_GET_DESCRIPTOR  = 0x05,
+       USB_FUNC_I2C_REPEATREAD  = 0x06,
+/* DKT 020208 - add this to support special case of DiSEqC */
+       USB_FUNC_I2C_CHECKWRITE  = 0x07,
+       USB_FUNC_I2C_CHECKRESULT = 0x08,
+} b2c2_usb_i2c_function_t;
+
+/*
+ * function definition for UTILITY request 0x12
+ * DKT 020304 - new utility function
+ */
+typedef enum {
+       UTILITY_SET_FILTER          = 0x01,
+       UTILITY_DATA_ENABLE         = 0x02,
+       UTILITY_FLEX_MULTIWRITE     = 0x03,
+       UTILITY_SET_BUFFER_SIZE     = 0x04,
+       UTILITY_FLEX_OPERATOR       = 0x05,
+       UTILITY_FLEX_RESET300_START = 0x06,
+       UTILITY_FLEX_RESET300_STOP  = 0x07,
+       UTILITY_FLEX_RESET300       = 0x08,
+       UTILITY_SET_ISO_SIZE        = 0x09,
+       UTILITY_DATA_RESET          = 0x0A,
+       UTILITY_GET_DATA_STATUS     = 0x10,
+       UTILITY_GET_V8_REG          = 0x11,
+/* DKT 020326 - add function for v1.14 */
+       UTILITY_SRAM_WRITE          = 0x12,
+       UTILITY_SRAM_READ           = 0x13,
+       UTILITY_SRAM_TESTFILL       = 0x14,
+       UTILITY_SRAM_TESTSET        = 0x15,
+       UTILITY_SRAM_TESTVERIFY     = 0x16,
+} b2c2_usb_utility_function_t;
+
+#define B2C2_WAIT_FOR_OPERATION_RW  1  // 1 s
+#define B2C2_WAIT_FOR_OPERATION_RDW 3  // 3 s
+#define B2C2_WAIT_FOR_OPERATION_WDW 1  // 1 s
+
+#define B2C2_WAIT_FOR_OPERATION_V8READ   3  // 3 s
+#define B2C2_WAIT_FOR_OPERATION_V8WRITE  3  // 3 s
+#define B2C2_WAIT_FOR_OPERATION_V8FLASH  3  // 3 s
+
+/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
+ * in the IBI address, to make the V8 code simpler.
+ * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
+ *                  in general: 0000 0HHH 000L LL00
+ * IBI ADDRESS FORMAT:                    RHHH BLLL
+ *
+ * where R is the read(1)/write(0) bit, B is the busy bit
+ * and HHH and LLL are the two sets of three bits from the PCI address.
+ */
+#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
+#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
+
+/*
+ * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register
+ * deal with DWORD or 4 bytes, that should be should from now on
+ */
+static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI)
+{
+       u32 val;
+       u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 0x0080;
+       int len = usb_control_msg(b2c2->udev,
+                       B2C2_USB_CTRL_PIPE_IN,
+                       B2C2_USB_READ_REG,
+                       RTYPE_READ_DW,
+                       wAddress,
+                       0,
+                       &val,
+                       sizeof(u32),
+                       B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+
+       if (len != sizeof(u32)) {
+               err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
+               return -EIO;
+       } else
+               return val;
+}
+
+/*
+ * DKT 020228 - from now on, we don't support anything older than firm 1.00
+ * I eliminated the write register as a 2 trip of writing hi word and lo word
+ * and force this to write only 4 bytes at a time.
+ * NOTE: this should work with all the firmware from 1.00 and newer
+ */
+static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val)
+{
+       u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI);
+       int len = usb_control_msg(b2c2->udev,
+                       B2C2_USB_CTRL_PIPE_OUT,
+                       B2C2_USB_WRITE_REG,
+                       RTYPE_WRITE_DW_1,
+                       wAddress,
+                       0,
+                       &val,
+                       sizeof(u32),
+                       B2C2_WAIT_FOR_OPERATION_RDW * HZ);
+
+       if (len != sizeof(u32)) {
+               err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
+               return -EIO;
+       } else
+               return 0;
+}
+
+/*
+ * DKT 010817 - add support for V8 memory read/write and flash update
+ */
+static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2,
+               b2c2_usb_request_t req, u8 page, u16 wAddress,
+               u16 buflen, u8 *pbBuffer)
+{
+       u8 dwRequestType;
+       u16 wIndex;
+       int nWaitTime,pipe,len;
+
+       wIndex = page << 8;
+
+       switch (req) {
+               case B2C2_USB_READ_V8_MEM:
+                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
+                       dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
+                       pipe = B2C2_USB_CTRL_PIPE_IN;
+               break;
+               case B2C2_USB_WRITE_V8_MEM:
+                       wIndex |= pbBuffer[0];
+                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
+                       dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
+                       pipe = B2C2_USB_CTRL_PIPE_OUT;
+               break;
+               case B2C2_USB_FLASH_BLOCK:
+                       nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
+                       dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
+                       pipe = B2C2_USB_CTRL_PIPE_OUT;
+               break;
+               default:
+                       deb_info("unsupported request for v8_mem_req %x.\n",req);
+               return -EINVAL;
+       }
+       len = usb_control_msg(b2c2->udev,pipe,
+                       req,
+                       dwRequestType,
+                       wAddress,
+                       wIndex,
+                       pbBuffer,
+                       buflen,
+                       nWaitTime * HZ);
+       return len == buflen ? 0 : -EIO;
+}
+
+static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2,
+               b2c2_usb_request_t req, b2c2_usb_i2c_function_t func,
+               u8 port, u8 chipaddr, u8 addr, u8 buflen, u8 *buf)
+{
+       u16 wValue, wIndex;
+       int nWaitTime,pipe,len;
+       u8 dwRequestType;
+
+       switch (func) {
+               case USB_FUNC_I2C_WRITE:
+               case USB_FUNC_I2C_MULTIWRITE:
+               case USB_FUNC_I2C_REPEATWRITE:
+               /* DKT 020208 - add this to support special case of DiSEqC */
+               case USB_FUNC_I2C_CHECKWRITE:
+                       pipe = B2C2_USB_CTRL_PIPE_OUT;
+                       nWaitTime = 2;
+                       dwRequestType = (u8) RTYPE_GENERIC;
+               break;
+               case USB_FUNC_I2C_READ:
+               case USB_FUNC_I2C_REPEATREAD:
+                       pipe = B2C2_USB_CTRL_PIPE_IN;
+                       nWaitTime = 2;
+                       dwRequestType = (u8) RTYPE_GENERIC;
+               break;
+               default:
+                       deb_info("unsupported function for i2c_req %x\n",func);
+                       return -EINVAL;
+       }
+       wValue = (func << 8 ) | port;
+       wIndex = (chipaddr << 8 ) | addr;
+
+       len = usb_control_msg(b2c2->udev,pipe,
+                       req,
+                       dwRequestType,
+                       addr,
+                       wIndex,
+                       buf,
+                       buflen,
+                       nWaitTime * HZ);
+       return len == buflen ? 0 : -EIO;
+}
+
+int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set,
+               b2c2_usb_utility_function_t func, u8 extra, u16 wIndex,
+               u16 buflen, u8 *pvBuffer)
+{
+       u16 wValue;
+       int nWaitTime = 2,
+               pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
+               len;
+
+       wValue = (func << 8) | extra;
+
+       len = usb_control_msg(b2c2->udev,pipe,
+                       B2C2_USB_UTILITY,
+                       (u8) RTYPE_GENERIC,
+                       wValue,
+                       wIndex,
+                       pvBuffer,
+                       buflen,
+                       nWaitTime * HZ);
+       return len == buflen ? 0 : -EIO;
+}
+
+
+
+static void b2c2_dumpfourreg(struct usb_b2c2_usb *b2c2, u16 offs)
+{
+       u32 r0,r1,r2,r3;
+       r0 = r1 = r2 = r3 = 0;
+       r0 = b2c2_usb_read_dw(b2c2,offs);
+       r1 = b2c2_usb_read_dw(b2c2,offs + 0x04);
+       r2 = b2c2_usb_read_dw(b2c2,offs + 0x08);
+       r3 = b2c2_usb_read_dw(b2c2,offs + 0x0c);
+       deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs,r0,r1,r2,r3);
+}
+
+static void b2c2_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+       struct usb_b2c2_usb *b2c2 = urb->context;
+       deb_ts("urb completed, bufsize: %d\n",urb->transfer_buffer_length);
+
+//     urb_submit_urb(urb,GFP_ATOMIC); enable for real action
+}
+
+static void b2c2_exit_usb(struct usb_b2c2_usb *b2c2)
+{
+       int i;
+       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+               if (b2c2->iso_urb[i] != NULL) { /* not sure about unlink_urb and iso-urbs TODO */
+                       deb_info("unlinking/killing urb no. %d\n",i);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
+                       usb_unlink_urb(b2c2->iso_urb[i]);
+#else
+                       usb_kill_urb(b2c2->iso_urb[i]);
+#endif
+                       usb_free_urb(b2c2->iso_urb[i]);
+               }
+
+       if (b2c2->iso_buffer != NULL)
+               pci_free_consistent(NULL,b2c2->buffer_size, b2c2->iso_buffer, b2c2->iso_dma_handle);
+
+}
+
+static int b2c2_init_usb(struct usb_b2c2_usb *b2c2)
+{
+       u16 frame_size = b2c2->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize;
+       int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
+       int buffer_offset = 0;
+
+       deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
+                       B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
+
+       b2c2->iso_buffer = pci_alloc_consistent(NULL,bufsize,&b2c2->iso_dma_handle);
+       if (b2c2->iso_buffer == NULL)
+               return -ENOMEM;
+       memset(b2c2->iso_buffer, 0, bufsize);
+       b2c2->buffer_size = bufsize;
+
+       /* creating iso urbs */
+       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
+               if (!(b2c2->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
+                       ret = -ENOMEM;
+                       goto urb_error;
+               }
+       /* initialising and submitting iso urbs */
+       for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
+               deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
+               int frame_offset = 0;
+               struct urb *urb = b2c2->iso_urb[i];
+
+               urb->dev = b2c2->udev;
+               urb->context = b2c2;
+               urb->complete = b2c2_urb_complete;
+               urb->pipe = B2C2_USB_DATA_PIPE;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->interval = 1;
+               urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
+               urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
+               urb->transfer_buffer = b2c2->iso_buffer + buffer_offset;
+
+               buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
+               for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
+                       deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
+                       urb->iso_frame_desc[j].offset = frame_offset;
+                       urb->iso_frame_desc[j].length = frame_size;
+                       frame_offset += frame_size;
+               }
+
+               if ((ret = usb_submit_urb(b2c2->iso_urb[i],GFP_ATOMIC))) {
+                       err("submitting urb %d failed with %d.",i,ret);
+                       goto urb_error;
+               }
+               deb_info("submitted urb no. %d.\n",i);
+       }
+
+       ret = 0;
+       goto success;
+urb_error:
+       b2c2_exit_usb(b2c2);
+success:
+       return ret;
+}
+
+static int b2c2_usb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_b2c2_usb *b2c2 = NULL;
+       int ret;
+
+       b2c2 = kmalloc(sizeof(struct usb_b2c2_usb),GFP_KERNEL);
+       if (b2c2 == NULL) {
+               err("no memory");
+               return -ENOMEM;
+       }
+       b2c2->udev = udev;
+       b2c2->uintf = intf;
+
+       /* use the alternate setting with the larges buffer */
+       usb_set_interface(udev,0,1);
+
+       if ((ret = b2c2_init_usb(b2c2)))
+               goto usb_init_error;
+
+       usb_set_intfdata(intf,b2c2);
+
+       switch (udev->speed) {
+               case USB_SPEED_LOW:
+                       err("cannot handle USB speed because it is to sLOW.");
+                       break;
+               case USB_SPEED_FULL:
+                       info("running at FULL speed.");
+                       break;
+               case USB_SPEED_HIGH:
+                       info("running at HIGH speed.");
+                       break;
+               case USB_SPEED_UNKNOWN: /* fall through */
+               default:
+                       err("cannot handle USB speed because it is unkown.");
+               break;
+       }
+
+       b2c2_dumpfourreg(b2c2,0x200);
+       b2c2_dumpfourreg(b2c2,0x300);
+       b2c2_dumpfourreg(b2c2,0x400);
+       b2c2_dumpfourreg(b2c2,0x700);
+
+
+       if (ret == 0)
+               info("%s successfully initialized and connected.",DRIVER_DESC);
+       else
+               info("%s error while loading driver (%d)",DRIVER_DESC,ret);
+
+       ret = 0;
+       goto success;
+
+usb_init_error:
+       kfree(b2c2);
+success:
+       return ret;
+}
+
+static void b2c2_usb_disconnect(struct usb_interface *intf)
+{
+       struct usb_b2c2_usb *b2c2 = usb_get_intfdata(intf);
+       usb_set_intfdata(intf,NULL);
+       if (b2c2 != NULL) {
+               b2c2_exit_usb(b2c2);
+               kfree(b2c2);
+       }
+       info("%s successfully deinitialized and disconnected.",DRIVER_DESC);
+
+}
+
+static struct usb_device_id b2c2_usb_table [] = {
+           { USB_DEVICE(0x0af7, 0x0101) }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver b2c2_usb_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "dvb_b2c2_usb",
+       .probe          = b2c2_usb_probe,
+       .disconnect = b2c2_usb_disconnect,
+       .id_table       = b2c2_usb_table,
+};
+
+/* module stuff */
+static int __init b2c2_usb_init(void)
+{
+       int result;
+       if ((result = usb_register(&b2c2_usb_driver))) {
+               err("usb_register failed. Error number %d",result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit b2c2_usb_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&b2c2_usb_driver);
+}
+
+module_init (b2c2_usb_init);
+module_exit (b2c2_usb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
new file mode 100644 (file)
index 0000000..62830d1
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+    Frontend-driver for TwinHan DST Frontend
+
+    Copyright (C) 2003 Jamie Honan
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "dst_priv.h"
+#include "dst.h"
+
+struct dst_state {
+
+       struct i2c_adapter* i2c;
+
+       struct bt878* bt;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct dst_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* private demodulator data */
+       u8 tx_tuna[10];
+       u8 rx_tuna[10];
+       u8 rxbuffer[10];
+       u8 diseq_flags;
+       u8 dst_type;
+       u32 type_flags;
+       u32 frequency;          /* intermediate frequency in kHz for QPSK */
+       fe_spectral_inversion_t inversion;
+       u32 symbol_rate;        /* symbol rate in Symbols per second */
+       fe_code_rate_t fec;
+       fe_sec_voltage_t voltage;
+       fe_sec_tone_mode_t tone;
+       u32 decode_freq;
+       u8 decode_lock;
+       u16 decode_strength;
+       u16 decode_snr;
+       unsigned long cur_jiff;
+       u8 k22;
+       fe_bandwidth_t bandwidth;
+};
+
+static unsigned int dst_verbose = 0;
+module_param(dst_verbose, int, 0644);
+MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
+static unsigned int dst_debug = 0;
+module_param(dst_debug, int, 0644);
+MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
+
+#define dprintk        if (dst_debug) printk
+
+#define DST_TYPE_IS_SAT                0
+#define DST_TYPE_IS_TERR       1
+#define DST_TYPE_IS_CABLE      2
+
+#define DST_TYPE_HAS_NEWTUNE   1
+#define DST_TYPE_HAS_TS204     2
+#define DST_TYPE_HAS_SYMDIV    4
+
+#define HAS_LOCK       1
+#define ATTEMPT_TUNE   2
+#define HAS_POWER      4
+
+static void dst_packsize(struct dst_state* state, int psize)
+{
+       union dst_gpio_packet bits;
+
+       bits.psize = psize;
+       bt878_device_control(state->bt, DST_IG_TS, &bits);
+}
+
+static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh)
+{
+       union dst_gpio_packet enb;
+       union dst_gpio_packet bits;
+       int err;
+
+       enb.enb.mask = mask;
+       enb.enb.enable = enbb;
+       if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
+               dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb);
+               return -EREMOTEIO;
+       }
+
+       /* because complete disabling means no output, no need to do output packet */
+       if (enbb == 0)
+               return 0;
+
+       bits.outp.mask = enbb;
+       bits.outp.highvals = outhigh;
+
+       if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
+               dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int dst_gpio_inb(struct dst_state *state, u8 * result)
+{
+       union dst_gpio_packet rd_packet;
+       int err;
+
+       *result = 0;
+
+       if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
+               dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err);
+               return -EREMOTEIO;
+       }
+
+       *result = (u8) rd_packet.rd.value;
+       return 0;
+}
+
+#define DST_I2C_ENABLE 1
+#define DST_8820       2
+
+static int dst_reset8820(struct dst_state *state)
+{
+       int retval;
+       /* pull 8820 gpio pin low, wait, high, wait, then low */
+       // dprintk ("%s: reset 8820\n", __FUNCTION__);
+       retval = dst_gpio_outb(state, DST_8820, DST_8820, 0);
+       if (retval < 0)
+               return retval;
+       msleep(10);
+       retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820);
+       if (retval < 0)
+               return retval;
+       /* wait for more feedback on what works here *
+          msleep(10);
+          retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
+          if (retval < 0)
+          return retval;
+        */
+       return 0;
+}
+
+static int dst_i2c_enable(struct dst_state *state)
+{
+       int retval;
+       /* pull I2C enable gpio pin low, wait */
+       // dprintk ("%s: i2c enable\n", __FUNCTION__);
+       retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0);
+       if (retval < 0)
+               return retval;
+       // dprintk ("%s: i2c enable delay\n", __FUNCTION__);
+       msleep(33);
+       return 0;
+}
+
+static int dst_i2c_disable(struct dst_state *state)
+{
+       int retval;
+       /* release I2C enable gpio pin, wait */
+       // dprintk ("%s: i2c disable\n", __FUNCTION__);
+       retval = dst_gpio_outb(state, ~0, 0, 0);
+       if (retval < 0)
+               return retval;
+       // dprintk ("%s: i2c disable delay\n", __FUNCTION__);
+       msleep(33);
+       return 0;
+}
+
+static int dst_wait_dst_ready(struct dst_state *state)
+{
+       u8 reply;
+       int retval;
+       int i;
+       for (i = 0; i < 200; i++) {
+               retval = dst_gpio_inb(state, &reply);
+               if (retval < 0)
+                       return retval;
+               if ((reply & DST_I2C_ENABLE) == 0) {
+                       dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
+                       return 1;
+               }
+               msleep(10);
+       }
+       dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
+       return 0;
+}
+
+static int write_dst(struct dst_state *state, u8 * data, u8 len)
+{
+       struct i2c_msg msg = {
+               .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len
+       };
+       int err;
+       int cnt;
+
+       if (dst_debug && dst_verbose) {
+               u8 i;
+               dprintk("%s writing", __FUNCTION__);
+               for (i = 0; i < len; i++) {
+                       dprintk(" 0x%02x", data[i]);
+               }
+               dprintk("\n");
+       }
+       msleep(30);
+       for (cnt = 0; cnt < 4; cnt++) {
+               if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+                       dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
+                       dst_i2c_disable(state);
+                       msleep(500);
+                       dst_i2c_enable(state);
+                       msleep(500);
+                       continue;
+               } else
+                       break;
+       }
+       if (cnt >= 4)
+               return -EREMOTEIO;
+       return 0;
+}
+
+static int read_dst(struct dst_state *state, u8 * ret, u8 len)
+{
+       struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len };
+       int err;
+       int cnt;
+
+       for (cnt = 0; cnt < 4; cnt++) {
+               if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+                       dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
+                       dst_i2c_disable(state);
+                       dst_i2c_enable(state);
+                       continue;
+               } else
+                       break;
+       }
+       if (cnt >= 4)
+               return -EREMOTEIO;
+       dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
+       if (dst_debug && dst_verbose) {
+               for (err = 1; err < len; err++)
+                       dprintk(" 0x%x", ret[err]);
+               if (err > 1)
+                       dprintk("\n");
+       }
+       return 0;
+}
+
+static int dst_set_freq(struct dst_state *state, u32 freq)
+{
+       u8 *val;
+
+       state->frequency = freq;
+
+       // dprintk("%s: set frequency %u\n", __FUNCTION__, freq);
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               freq = freq / 1000;
+               if (freq < 950 || freq > 2150)
+                       return -EINVAL;
+               val = &state->tx_tuna[0];
+               val[2] = (freq >> 8) & 0x7f;
+               val[3] = (u8) freq;
+               val[4] = 1;
+               val[8] &= ~4;
+               if (freq < 1531)
+                       val[8] |= 4;
+       } else if (state->dst_type == DST_TYPE_IS_TERR) {
+               freq = freq / 1000;
+               if (freq < 137000 || freq > 858000)
+                       return -EINVAL;
+               val = &state->tx_tuna[0];
+               val[2] = (freq >> 16) & 0xff;
+               val[3] = (freq >> 8) & 0xff;
+               val[4] = (u8) freq;
+               val[5] = 0;
+               switch (state->bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       val[6] = 6;
+                       break;
+
+               case BANDWIDTH_7_MHZ:
+               case BANDWIDTH_AUTO:
+                       val[6] = 7;
+                       break;
+
+               case BANDWIDTH_8_MHZ:
+                       val[6] = 8;
+                       break;
+               }
+
+               val[7] = 0;
+               val[8] = 0;
+       } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+               /* guess till will get one */
+               freq = freq / 1000;
+               val = &state->tx_tuna[0];
+               val[2] = (freq >> 16) & 0xff;
+               val[3] = (freq >> 8) & 0xff;
+               val[4] = (u8) freq;
+       } else
+               return -EINVAL;
+       return 0;
+}
+
+static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth)
+{
+       u8 *val;
+
+       state->bandwidth = bandwidth;
+
+       if (state->dst_type != DST_TYPE_IS_TERR)
+               return 0;
+
+       val = &state->tx_tuna[0];
+       switch (bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               val[6] = 6;
+               break;
+
+       case BANDWIDTH_7_MHZ:
+               val[6] = 7;
+               break;
+
+       case BANDWIDTH_8_MHZ:
+               val[6] = 8;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion)
+{
+       u8 *val;
+
+       state->inversion = inversion;
+
+       val = &state->tx_tuna[0];
+
+       val[8] &= ~0x80;
+
+       switch (inversion) {
+       case INVERSION_OFF:
+               break;
+       case INVERSION_ON:
+               val[8] |= 0x80;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec)
+{
+       state->fec = fec;
+       return 0;
+}
+
+static fe_code_rate_t dst_get_fec(struct dst_state* state)
+{
+       return state->fec;
+}
+
+static int dst_set_symbolrate(struct dst_state* state, u32 srate)
+{
+       u8 *val;
+       u32 symcalc;
+       u64 sval;
+
+       state->symbol_rate = srate;
+
+       if (state->dst_type == DST_TYPE_IS_TERR) {
+               return 0;
+       }
+       // dprintk("%s: set srate %u\n", __FUNCTION__, srate);
+       srate /= 1000;
+       val = &state->tx_tuna[0];
+
+       if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+               sval = srate;
+               sval <<= 20;
+               do_div(sval, 88000);
+               symcalc = (u32) sval;
+               // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
+               val[5] = (u8) (symcalc >> 12);
+               val[6] = (u8) (symcalc >> 4);
+               val[7] = (u8) (symcalc << 4);
+       } else {
+               val[5] = (u8) (srate >> 16) & 0x7f;
+               val[6] = (u8) (srate >> 8);
+               val[7] = (u8) srate;
+       }
+       val[8] &= ~0x20;
+       if (srate > 8000)
+               val[8] |= 0x20;
+       return 0;
+}
+
+static u8 dst_check_sum(u8 * buf, u32 len)
+{
+       u32 i;
+       u8 val = 0;
+       if (!len)
+               return 0;
+       for (i = 0; i < len; i++) {
+               val += buf[i];
+       }
+       return ((~val) + 1);
+}
+
+struct dst_types {
+       char *mstr;
+       int offs;
+       u8 dst_type;
+       u32 type_flags;
+};
+
+static struct dst_types dst_tlist[] = {
+       {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
+       {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
+       {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204},
+       {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
+       {"DST-CI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
+       {"DSTMCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
+       {"DSTFCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
+       {"DCTNEW",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
+       {"DCT-CI",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
+       {"DTTDIG",  1, DST_TYPE_IS_TERR, 0}
+};
+
+/* DCTNEW and DCT-CI are guesses */
+
+static void dst_type_flags_print(u32 type_flags)
+{
+       printk("DST type flags :");
+       if (type_flags & DST_TYPE_HAS_NEWTUNE)
+               printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+       if (type_flags & DST_TYPE_HAS_TS204)
+               printk(" 0x%x ts204", DST_TYPE_HAS_TS204);
+       if (type_flags & DST_TYPE_HAS_SYMDIV)
+               printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
+       printk("\n");
+}
+
+static int dst_type_print(u8 type)
+{
+       char *otype;
+       switch (type) {
+       case DST_TYPE_IS_SAT:
+               otype = "satellite";
+               break;
+       case DST_TYPE_IS_TERR:
+               otype = "terrestrial";
+               break;
+       case DST_TYPE_IS_CABLE:
+               otype = "cable";
+               break;
+       default:
+               printk("%s: invalid dst type %d\n", __FUNCTION__, type);
+               return -EINVAL;
+       }
+       printk("DST type : %s\n", otype);
+       return 0;
+}
+
+static int dst_check_ci(struct dst_state *state)
+{
+       u8 txbuf[8];
+       u8 rxbuf[8];
+       int retval;
+       int i;
+       struct dst_types *dsp;
+       u8 use_dst_type;
+       u32 use_type_flags;
+
+       memset(txbuf, 0, sizeof(txbuf));
+       txbuf[1] = 6;
+       txbuf[7] = dst_check_sum(txbuf, 7);
+
+       dst_i2c_enable(state);
+       dst_reset8820(state);
+       retval = write_dst(state, txbuf, 8);
+       if (retval < 0) {
+               dst_i2c_disable(state);
+               dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
+               return retval;
+       }
+       msleep(3);
+       retval = read_dst(state, rxbuf, 1);
+       dst_i2c_disable(state);
+       if (retval < 0) {
+               dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
+               return retval;
+       }
+       if (rxbuf[0] != 0xff) {
+               dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]);
+               return retval;
+       }
+       if (!dst_wait_dst_ready(state))
+               return 0;
+       // dst_i2c_enable(i2c); Dimitri
+       retval = read_dst(state, rxbuf, 8);
+       dst_i2c_disable(state);
+       if (retval < 0) {
+               dprintk("%s: read not successful\n", __FUNCTION__);
+               return retval;
+       }
+       if (rxbuf[7] != dst_check_sum(rxbuf, 7)) {
+               dprintk("%s: checksum failure\n", __FUNCTION__);
+               return retval;
+       }
+       rxbuf[7] = '\0';
+       for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
+               if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
+                       use_type_flags = dsp->type_flags;
+                       use_dst_type = dsp->dst_type;
+                       printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
+                       break;
+               }
+       }
+       if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) {
+               printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]);
+               printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
+               use_dst_type = DST_TYPE_IS_SAT;
+               use_type_flags = DST_TYPE_HAS_SYMDIV;
+       }
+       dst_type_print(use_dst_type);
+
+       state->type_flags = use_type_flags;
+       state->dst_type = use_dst_type;
+       dst_type_flags_print(state->type_flags);
+
+       if (state->type_flags & DST_TYPE_HAS_TS204) {
+               dst_packsize(state, 204);
+       }
+       return 0;
+}
+
+static int dst_command(struct dst_state* state, u8 * data, u8 len)
+{
+       int retval;
+       u8 reply;
+
+       dst_i2c_enable(state);
+       dst_reset8820(state);
+       retval = write_dst(state, data, len);
+       if (retval < 0) {
+               dst_i2c_disable(state);
+               dprintk("%s: write not successful\n", __FUNCTION__);
+               return retval;
+       }
+       msleep(33);
+       retval = read_dst(state, &reply, 1);
+       dst_i2c_disable(state);
+       if (retval < 0) {
+               dprintk("%s: read verify  not successful\n", __FUNCTION__);
+               return retval;
+       }
+       if (reply != 0xff) {
+               dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+               return 0;
+       }
+       if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
+               return 0;
+       if (!dst_wait_dst_ready(state))
+               return 0;
+       // dst_i2c_enable(i2c); Per dimitri
+       retval = read_dst(state, state->rxbuffer, 8);
+       dst_i2c_disable(state);
+       if (retval < 0) {
+               dprintk("%s: read not successful\n", __FUNCTION__);
+               return 0;
+       }
+       if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
+               dprintk("%s: checksum failure\n", __FUNCTION__);
+               return 0;
+       }
+       return 0;
+}
+
+static int dst_get_signal(struct dst_state* state)
+{
+       int retval;
+       u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
+
+       if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
+               state->decode_lock = state->decode_strength = state->decode_snr = 0;
+               return 0;
+       }
+       if (0 == (state->diseq_flags & HAS_LOCK)) {
+               state->decode_lock = state->decode_strength = state->decode_snr = 0;
+               return 0;
+       }
+       if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
+               retval = dst_command(state, get_signal, 8);
+               if (retval < 0)
+                       return retval;
+               if (state->dst_type == DST_TYPE_IS_SAT) {
+                       state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
+                       state->decode_strength = state->rxbuffer[5] << 8;
+                       state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
+               } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
+                       state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
+                       state->decode_strength = state->rxbuffer[4] << 8;
+                       state->decode_snr = state->rxbuffer[3] << 8;
+               }
+               state->cur_jiff = jiffies;
+       }
+       return 0;
+}
+
+static int dst_tone_power_cmd(struct dst_state* state)
+{
+       u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
+
+       if (state->dst_type == DST_TYPE_IS_TERR)
+               return 0;
+
+       if (state->voltage == SEC_VOLTAGE_OFF)
+               paket[4] = 0;
+       else
+               paket[4] = 1;
+       if (state->tone == SEC_TONE_ON)
+               paket[2] = state->k22;
+       else
+               paket[2] = 0;
+       paket[7] = dst_check_sum(&paket[0], 7);
+       dst_command(state, paket, 8);
+       return 0;
+}
+
+static int dst_get_tuna(struct dst_state* state)
+{
+       int retval;
+       if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
+               return 0;
+       state->diseq_flags &= ~(HAS_LOCK);
+       if (!dst_wait_dst_ready(state))
+               return 0;
+       if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+               /* how to get variable length reply ???? */
+               retval = read_dst(state, state->rx_tuna, 10);
+       } else {
+               retval = read_dst(state, &state->rx_tuna[2], 8);
+       }
+       if (retval < 0) {
+               dprintk("%s: read not successful\n", __FUNCTION__);
+               return 0;
+       }
+       if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+               if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
+                       dprintk("%s: checksum failure?\n", __FUNCTION__);
+                       return 0;
+               }
+       } else {
+               if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
+                       dprintk("%s: checksum failure?\n", __FUNCTION__);
+                       return 0;
+               }
+       }
+       if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
+               return 0;
+       state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+
+       state->decode_lock = 1;
+       /*
+          dst->decode_n1 = (dst->rx_tuna[4] << 8) +
+          (dst->rx_tuna[5]);
+
+          dst->decode_n2 = (dst->rx_tuna[8] << 8) +
+          (dst->rx_tuna[7]);
+        */
+       state->diseq_flags |= HAS_LOCK;
+       /* dst->cur_jiff = jiffies; */
+       return 1;
+}
+
+static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+
+static int dst_write_tuna(struct dvb_frontend* fe)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+       int retval;
+       u8 reply;
+
+       dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags);
+       state->decode_freq = 0;
+       state->decode_lock = state->decode_strength = state->decode_snr = 0;
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               if (!(state->diseq_flags & HAS_POWER))
+                       dst_set_voltage(fe, SEC_VOLTAGE_13);
+       }
+       state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
+       dst_i2c_enable(state);
+       if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+               dst_reset8820(state);
+               state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
+               retval = write_dst(state, &state->tx_tuna[0], 10);
+       } else {
+               state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
+               retval = write_dst(state, &state->tx_tuna[2], 8);
+       }
+       if (retval < 0) {
+               dst_i2c_disable(state);
+               dprintk("%s: write not successful\n", __FUNCTION__);
+               return retval;
+       }
+       msleep(3);
+       retval = read_dst(state, &reply, 1);
+       dst_i2c_disable(state);
+       if (retval < 0) {
+               dprintk("%s: read verify  not successful\n", __FUNCTION__);
+               return retval;
+       }
+       if (reply != 0xff) {
+               dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+               return 0;
+       }
+       state->diseq_flags |= ATTEMPT_TUNE;
+       return dst_get_tuna(state);
+}
+
+/*
+ * line22k0    0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k1    0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k2    0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
+ * tone        0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
+ * data        0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
+ * power_off   0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
+ * power_on    0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
+ * Diseqc 1    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
+ * Diseqc 2    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
+ * Diseqc 3    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
+ * Diseqc 4    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
+ */
+
+static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+       u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
+
+       if (state->dst_type == DST_TYPE_IS_TERR)
+               return 0;
+
+       if (cmd->msg_len == 0 || cmd->msg_len > 4)
+               return -EINVAL;
+       memcpy(&paket[3], cmd->msg, cmd->msg_len);
+       paket[7] = dst_check_sum(&paket[0], 7);
+       dst_command(state, paket, 8);
+       return 0;
+}
+
+static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       u8 *val;
+       int need_cmd;
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       state->voltage = voltage;
+
+       if (state->dst_type == DST_TYPE_IS_TERR)
+               return 0;
+
+       need_cmd = 0;
+       val = &state->tx_tuna[0];
+       val[8] &= ~0x40;
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               if ((state->diseq_flags & HAS_POWER) == 0)
+                       need_cmd = 1;
+               state->diseq_flags |= HAS_POWER;
+               break;
+       case SEC_VOLTAGE_18:
+               if ((state->diseq_flags & HAS_POWER) == 0)
+                       need_cmd = 1;
+               state->diseq_flags |= HAS_POWER;
+               val[8] |= 0x40;
+               break;
+       case SEC_VOLTAGE_OFF:
+               need_cmd = 1;
+               state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (need_cmd) {
+               dst_tone_power_cmd(state);
+       }
+       return 0;
+}
+
+static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       u8 *val;
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       state->tone = tone;
+
+       if (state->dst_type == DST_TYPE_IS_TERR)
+               return 0;
+
+       val = &state->tx_tuna[0];
+
+       val[8] &= ~0x1;
+
+       switch (tone) {
+       case SEC_TONE_OFF:
+               break;
+       case SEC_TONE_ON:
+               val[8] |= 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+       dst_tone_power_cmd(state);
+       return 0;
+}
+
+static int dst_init(struct dvb_frontend* fe)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+       static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
+       static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
+       static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+       static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+       static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+       static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+       state->inversion = INVERSION_ON;
+       state->voltage = SEC_VOLTAGE_13;
+       state->tone = SEC_TONE_OFF;
+       state->symbol_rate = 29473000;
+       state->fec = FEC_AUTO;
+       state->diseq_flags = 0;
+       state->k22 = 0x02;
+       state->bandwidth = BANDWIDTH_7_MHZ;
+       state->cur_jiff = jiffies;
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               state->frequency = 950000;
+               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
+       } else if (state->dst_type == DST_TYPE_IS_TERR) {
+               state->frequency = 137000000;
+               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
+       } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+               state->frequency = 51000000;
+               memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
+       }
+
+       return 0;
+}
+
+static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       *status = 0;
+       if (state->diseq_flags & HAS_LOCK) {
+               dst_get_signal(state);
+               if (state->decode_lock)
+                       *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
+       }
+
+       return 0;
+}
+
+static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       dst_get_signal(state);
+       *strength = state->decode_strength;
+
+       return 0;
+}
+
+static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       dst_get_signal(state);
+       *snr = state->decode_snr;
+
+       return 0;
+}
+
+static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       dst_set_freq(state, p->frequency);
+       dst_set_inversion(state, p->inversion);
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               dst_set_fec(state, p->u.qpsk.fec_inner);
+               dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+       } else if (state->dst_type == DST_TYPE_IS_TERR) {
+               dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+       } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+               dst_set_fec(state, p->u.qam.fec_inner);
+               dst_set_symbolrate(state, p->u.qam.symbol_rate);
+       }
+       dst_write_tuna(fe);
+
+       return 0;
+}
+
+static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+       p->frequency = state->decode_freq;
+       p->inversion = state->inversion;
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               p->u.qpsk.symbol_rate = state->symbol_rate;
+               p->u.qpsk.fec_inner = dst_get_fec(state);
+       } else if (state->dst_type == DST_TYPE_IS_TERR) {
+               p->u.ofdm.bandwidth = state->bandwidth;
+       } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+               p->u.qam.symbol_rate = state->symbol_rate;
+               p->u.qam.fec_inner = dst_get_fec(state);
+               p->u.qam.modulation = QAM_AUTO;
+       }
+
+       return 0;
+}
+
+static void dst_release(struct dvb_frontend* fe)
+{
+       struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops;
+static struct dvb_frontend_ops dst_dvbs_ops;
+static struct dvb_frontend_ops dst_dvbc_ops;
+
+struct dvb_frontend* dst_attach(const struct dst_config* config,
+                               struct i2c_adapter* i2c,
+                               struct bt878 *bt)
+{
+       struct dst_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       state->bt = bt;
+
+       /* check if the demod is there */
+       if (dst_check_ci(state) < 0) goto error;
+
+       /* determine settings based on type */
+       switch (state->dst_type) {
+       case DST_TYPE_IS_TERR:
+               memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+               break;
+       case DST_TYPE_IS_CABLE:
+               memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+               break;
+       case DST_TYPE_IS_SAT:
+               memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+               break;
+       default:
+               printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
+               goto error;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops = {
+
+       .info = {
+               .name = "DST DVB-T",
+               .type = FE_OFDM,
+               .frequency_min = 137000000,
+               .frequency_max = 858000000,
+               .frequency_stepsize = 166667,
+               .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+       },
+
+       .release = dst_release,
+
+       .init = dst_init,
+
+       .set_frontend = dst_set_frontend,
+       .get_frontend = dst_get_frontend,
+
+       .read_status = dst_read_status,
+       .read_signal_strength = dst_read_signal_strength,
+       .read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_dvbs_ops = {
+
+       .info = {
+               .name = "DST DVB-S",
+               .type = FE_QPSK,
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+               .frequency_stepsize = 1000,     /* kHz for QPSK frontends */
+               .frequency_tolerance = 29500,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+       /*     . symbol_rate_tolerance  =       ???,*/
+               .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
+       },
+
+       .release = dst_release,
+
+       .init = dst_init,
+
+       .set_frontend = dst_set_frontend,
+       .get_frontend = dst_get_frontend,
+
+       .read_status = dst_read_status,
+       .read_signal_strength = dst_read_signal_strength,
+       .read_snr = dst_read_snr,
+
+       .diseqc_send_master_cmd = dst_set_diseqc,
+       .set_voltage = dst_set_voltage,
+       .set_tone = dst_set_tone,
+};
+
+static struct dvb_frontend_ops dst_dvbc_ops = {
+
+       .info = {
+               .name = "DST DVB-C",
+               .type = FE_QAM,
+               .frequency_stepsize = 62500,
+               .frequency_min = 51000000,
+               .frequency_max = 858000000,
+               .symbol_rate_min = 1000000,
+               .symbol_rate_max = 45000000,
+       /*     . symbol_rate_tolerance  =       ???,*/
+               .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
+       },
+
+       .release = dst_release,
+
+       .init = dst_init,
+
+       .set_frontend = dst_set_frontend,
+       .get_frontend = dst_get_frontend,
+
+       .read_status = dst_read_status,
+       .read_signal_strength = dst_read_signal_strength,
+       .read_snr = dst_read_snr,
+};
+
+MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_AUTHOR("Jamie Honan");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dst_attach);
diff --git a/drivers/media/dvb/bt8xx/dst.h b/drivers/media/dvb/bt8xx/dst.h
new file mode 100644 (file)
index 0000000..bcb418c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+    Frontend-driver for TwinHan DST Frontend
+
+    Copyright (C) 2003 Jamie Honan
+
+    This 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 DST_H
+#define DST_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/device.h>
+#include "bt878.h"
+
+struct dst_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+};
+
+extern struct dvb_frontend* dst_attach(const struct dst_config* config,
+                                      struct i2c_adapter* i2c,
+                                      struct bt878 *bt);
+
+#endif // DST_H
diff --git a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h
new file mode 100644 (file)
index 0000000..b3d5e6f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
+ *
+ * Copyright (C) 2003 Jamie Honan
+ */
+
+struct dst_gpio_enable {
+       u32     mask;
+       u32     enable;
+};
+
+struct dst_gpio_output {
+       u32     mask;
+       u32     highvals;
+};
+
+struct dst_gpio_read {
+       unsigned long value;
+};
+
+union dst_gpio_packet {
+       struct dst_gpio_enable enb;
+       struct dst_gpio_output outp;
+       struct dst_gpio_read rd;
+       int    psize;
+};
+
+#define DST_IG_ENABLE  0
+#define DST_IG_WRITE   1
+#define DST_IG_READ    2
+#define DST_IG_TS       3
+
+struct bt878;
+
+int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
+
+struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap);
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
new file mode 100644 (file)
index 0000000..2267140
--- /dev/null
@@ -0,0 +1,85 @@
+config DVB_CINERGYT2
+       tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver"
+       depends on DVB_CORE && USB
+       help
+         Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers
+
+         Say Y if you own such a device and want to use it.
+
+
+config DVB_CINERGYT2_TUNING
+       bool "sophisticated fine-tuning for CinergyT2 cards"
+       depends on DVB_CINERGYT2
+       help
+         Here you can fine-tune some parameters of the CinergyT2 driver.
+
+         Normally you don't need to touch this, but in exotic setups you
+         may fine-tune your setup and adjust e.g. DMA buffer sizes for
+         a particular application.
+
+
+config DVB_CINERGYT2_STREAM_URB_COUNT
+       int "Number of queued USB Request Blocks for Highspeed Stream Transfers"
+       depends on DVB_CINERGYT2_TUNING
+        default "32"
+       help
+         USB Request Blocks for Highspeed Stream transfers are scheduled in
+         a queue for the Host Controller.
+
+         Usually the default value is a safe choice.
+
+         You may increase this number if you are using this device in a 
+         Server Environment with many high-traffic USB Highspeed devices 
+         sharing the same USB bus.
+
+
+config DVB_CINERGYT2_STREAM_BUF_SIZE
+       int "Size of URB Stream Buffers for Highspeed Transfers"
+       depends on DVB_CINERGYT2_TUNING
+        default "512"
+       help
+         Should be a multiple of native buffer size of 512 bytes.
+         Default value is a safe choice.
+
+         You may increase this number if you are using this device in a 
+         Server Environment with many high-traffic USB Highspeed devices 
+         sharing the same USB bus.
+
+
+config DVB_CINERGYT2_QUERY_INTERVAL
+       int "Status update interval [milliseconds]"
+       depends on DVB_CINERGYT2_TUNING
+        default "250"
+       help
+         This is the interval for status readouts from the demodulator.
+         You may try lower values if you need more responsive signal quality
+         measurements.
+
+         Please keep in mind that these updates cause traffic on the tuner
+         control bus and thus may or may not affect receiption sensitivity.
+
+         The default value should be a safe choice for common applications.
+
+
+config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
+       bool "Register the onboard IR Remote Control Receiver as Input Device"
+       depends on DVB_CINERGYT2_TUNING
+        default "yes"
+       help
+         Enable this option if you want to use the onboard Infrared Remote 
+         Control Receiver as Linux-Input device.
+
+         Right now only the keycode table for the default Remote Control
+         delivered with the device is supported, please see the driver
+         source code to find out how to add support for other controls.
+
+
+config DVB_CINERGYT2_RC_QUERY_INTERVAL
+       int "Infrared Remote Controller update interval [milliseconds]"
+       depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
+        default "100"
+       help
+         If you have a very fast-repeating remote control you can try lower
+         values, for normal consumer receivers the default value should be
+         a safe choice.
+
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
new file mode 100644 (file)
index 0000000..c51aece
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
new file mode 100644 (file)
index 0000000..fc17763
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * TerraTec Cinergy T²/qanu USB2 DVB-T adapter.
+ *
+ * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
+ *                 Holger Waechtler <holger@qanu.de>
+ *
+ *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <linux/input.h>
+#include <linux/dvb/frontend.h>
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+
+
+
+
+
+
+
+
+
+#ifdef CONFIG_DVB_CINERGYT2_TUNING
+       #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT)
+       #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE)
+       #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL)
+       #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
+               #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL)
+               #define ENABLE_RC (1)
+       #endif
+#else
+       #define STREAM_URB_COUNT (32)
+       #define STREAM_BUF_SIZE (512)   /* bytes */
+       #define ENABLE_RC (1)
+       #define RC_QUERY_INTERVAL (100) /* milliseconds */
+       #define QUERY_INTERVAL (333)    /* milliseconds */
+#endif
+
+#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"
+
+static int debug;
+module_param_named(debug, debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level, args...) \
+do {                                                                   \
+       if ((debug & level)) {                                          \
+               printk("%s: %s(): ", __stringify(KBUILD_MODNAME),       \
+                      __FUNCTION__);                                   \
+               printk(args); }                                         \
+} while (0)
+
+enum cinergyt2_ep1_cmd {
+       CINERGYT2_EP1_PID_TABLE_RESET           = 0x01,
+       CINERGYT2_EP1_PID_SETUP                 = 0x02,
+       CINERGYT2_EP1_CONTROL_STREAM_TRANSFER   = 0x03,
+       CINERGYT2_EP1_SET_TUNER_PARAMETERS      = 0x04,
+       CINERGYT2_EP1_GET_TUNER_STATUS          = 0x05,
+       CINERGYT2_EP1_START_SCAN                = 0x06,
+       CINERGYT2_EP1_CONTINUE_SCAN             = 0x07,
+       CINERGYT2_EP1_GET_RC_EVENTS             = 0x08,
+       CINERGYT2_EP1_SLEEP_MODE                = 0x09
+};
+
+struct dvbt_set_parameters_msg {
+       uint8_t cmd;
+       uint32_t freq;
+       uint8_t bandwidth;
+       uint16_t tps;
+       uint8_t flags;
+} __attribute__((packed));
+
+struct dvbt_get_status_msg {
+       uint32_t freq;
+       uint8_t bandwidth;
+       uint16_t tps;
+       uint8_t flags;
+       uint16_t gain;
+       uint8_t snr;
+       uint32_t viterbi_error_rate;
+       uint32_t rs_error_rate;
+       uint32_t uncorrected_block_count;
+       uint8_t lock_bits;
+       uint8_t prev_lock_bits;
+} __attribute__((packed));
+
+static struct dvb_frontend_info cinergyt2_fe_info = {
+       .name = DRIVER_NAME,
+       .type = FE_OFDM,
+       .frequency_min = 174000000,
+       .frequency_max = 862000000,
+       .frequency_stepsize = 166667,
+       .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_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS
+};
+
+struct cinergyt2 {
+       struct dvb_demux demux;
+       struct usb_device *udev;
+       struct semaphore sem;
+       struct dvb_adapter *adapter;
+       struct dvb_device *fedev;
+       struct dmxdev dmxdev;
+       struct dvb_net dvbnet;
+
+       int streaming;
+       int sleeping;
+
+       struct dvbt_set_parameters_msg param;
+       struct dvbt_get_status_msg status;
+       struct work_struct query_work;
+
+       wait_queue_head_t poll_wq;
+       int pending_fe_events;
+
+       void *streambuf;
+       dma_addr_t streambuf_dmahandle;
+       struct urb *stream_urb[STREAM_URB_COUNT];
+
+#ifdef ENABLE_RC
+       struct input_dev rc_input_dev;
+       struct work_struct rc_query_work;
+       int rc_input_event;
+#endif
+};
+
+enum {
+       CINERGYT2_RC_EVENT_TYPE_NONE = 0x00,
+       CINERGYT2_RC_EVENT_TYPE_NEC  = 0x01,
+       CINERGYT2_RC_EVENT_TYPE_RC5  = 0x02
+};
+
+struct cinergyt2_rc_event {
+       char type;
+       uint32_t value;
+} __attribute__((packed));
+
+static const uint32_t rc_keys [] = {
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfe01eb04,     KEY_POWER,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfd02eb04,     KEY_1,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfc03eb04,     KEY_2,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfb04eb04,     KEY_3,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xfa05eb04,     KEY_4,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf906eb04,     KEY_5,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf807eb04,     KEY_6,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf708eb04,     KEY_7,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf609eb04,     KEY_8,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf50aeb04,     KEY_9,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf30ceb04,     KEY_0,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf40beb04,     KEY_VIDEO,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf20deb04,     KEY_REFRESH,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf10eeb04,     KEY_SELECT,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xf00feb04,     KEY_EPG,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xef10eb04,     KEY_UP,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xeb14eb04,     KEY_DOWN,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xee11eb04,     KEY_LEFT,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xec13eb04,     KEY_RIGHT,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xed12eb04,     KEY_OK, 
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xea15eb04,     KEY_TEXT,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe916eb04,     KEY_INFO,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe817eb04,     KEY_RED,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe718eb04,     KEY_GREEN,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe619eb04,     KEY_YELLOW,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe51aeb04,     KEY_BLUE,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe31ceb04,     KEY_VOLUMEUP,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe11eeb04,     KEY_VOLUMEDOWN,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe21deb04,     KEY_MUTE,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe41beb04,     KEY_CHANNELUP,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xe01feb04,     KEY_CHANNELDOWN,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xbf40eb04,     KEY_PAUSE,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xb34ceb04,     KEY_PLAY,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xa758eb04,     KEY_RECORD,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xab54eb04,     KEY_PREVIOUS,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xb748eb04,     KEY_STOP,
+       CINERGYT2_RC_EVENT_TYPE_NEC,    0xa35ceb04,     KEY_NEXT
+};
+
+static int cinergyt2_command (struct cinergyt2 *cinergyt2,
+                   char *send_buf, int send_buf_len,
+                             char *recv_buf, int recv_buf_len)
+{
+       int actual_len;
+       char dummy;
+       int ret;
+
+       ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1),
+                          send_buf, send_buf_len, &actual_len, HZ);
+
+       if (ret)
+               dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret);
+
+       if (!recv_buf)
+               recv_buf = &dummy;
+
+       ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1),
+                          recv_buf, recv_buf_len, &actual_len, HZ);
+
+       if (ret)
+               dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret);
+
+       return ret ? ret : actual_len;
+}
+
+static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable)
+{
+       char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 };
+       cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
+}
+
+static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
+{
+       char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 };
+       cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0);
+       cinergyt2->sleeping = sleep;
+}
+
+static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs);
+
+static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
+{
+       int err;
+
+       usb_fill_bulk_urb(urb,
+                         cinergyt2->udev,
+                         usb_rcvbulkpipe(cinergyt2->udev, 0x2),
+                         urb->transfer_buffer,
+                         STREAM_BUF_SIZE,
+                         cinergyt2_stream_irq,
+                         cinergyt2);
+
+       if ((err = usb_submit_urb(urb, GFP_ATOMIC)))
+               dprintk(1, "urb submission failed (err = %i)!\n", err);
+
+       return err;
+}
+
+static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs)
+{
+       struct cinergyt2 *cinergyt2 = urb->context;
+
+       if (urb->actual_length > 0)
+               dvb_dmx_swfilter(&cinergyt2->demux,
+                                urb->transfer_buffer, urb->actual_length);
+
+       if (cinergyt2->streaming)
+               cinergyt2_submit_stream_urb(cinergyt2, urb);
+}
+
+static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2)
+{
+       int i;
+
+       for (i=0; i<STREAM_URB_COUNT; i++)
+               if (cinergyt2->stream_urb[i])
+                       usb_free_urb(cinergyt2->stream_urb[i]);
+
+       pci_free_consistent(NULL, STREAM_URB_COUNT*STREAM_BUF_SIZE,
+                           cinergyt2->streambuf, cinergyt2->streambuf_dmahandle);
+}
+
+static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2)
+{
+       int i;
+
+       cinergyt2->streambuf = pci_alloc_consistent(NULL, 
+                                             STREAM_URB_COUNT*STREAM_BUF_SIZE,
+                                             &cinergyt2->streambuf_dmahandle);
+       if (!cinergyt2->streambuf) {
+               dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n");
+               return -ENOMEM;
+       }
+
+       memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE);
+
+       for (i=0; i<STREAM_URB_COUNT; i++) {
+               struct urb *urb;        
+
+               if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
+                       dprintk(1, "failed to alloc consistent stream urbs, bailing out!\n");
+                       cinergyt2_free_stream_urbs(cinergyt2);
+                       return -ENOMEM;
+               }
+
+               urb->transfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE;
+               urb->transfer_buffer_length = STREAM_BUF_SIZE;
+
+               cinergyt2->stream_urb[i] = urb;
+       }
+
+       return 0;
+}
+
+static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2)
+{
+       int i;
+
+       cinergyt2_control_stream_transfer(cinergyt2, 0);
+
+       for (i=0; i<STREAM_URB_COUNT; i++)
+               if (cinergyt2->stream_urb[i])
+                       usb_kill_urb(cinergyt2->stream_urb[i]);
+}
+
+static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2)
+{
+       int i, err;
+
+       for (i=0; i<STREAM_URB_COUNT; i++) {
+               if ((err = cinergyt2_submit_stream_urb(cinergyt2, cinergyt2->stream_urb[i]))) {
+                       cinergyt2_stop_stream_xfer(cinergyt2);
+                       dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err);
+                       return err;
+               }
+       }
+
+       cinergyt2_control_stream_transfer(cinergyt2, 1);
+       return 0;
+}
+
+static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct cinergyt2 *cinergyt2 = demux->priv;
+
+       if (down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+       
+       if (cinergyt2->streaming == 0)
+               cinergyt2_start_stream_xfer(cinergyt2);
+
+       cinergyt2->streaming++;
+       up(&cinergyt2->sem);
+       return 0;
+}
+
+static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct cinergyt2 *cinergyt2 = demux->priv;      
+
+       if (down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if (--cinergyt2->streaming == 0)
+               cinergyt2_stop_stream_xfer(cinergyt2);
+
+       up(&cinergyt2->sem);
+       return 0;
+}
+
+/**
+ *  convert linux-dvb frontend parameter set into TPS.
+ *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
+ *
+ *  This function is probably reusable and may better get placed in a support
+ *  library.
+ *
+ *  We replace errornous fields by default TPS fields (the ones with value 0).
+ */
+static uint16_t compute_tps (struct dvb_frontend_parameters *p)
+{
+       struct dvb_ofdm_parameters *op = &p->u.ofdm;
+       uint16_t tps = 0;
+
+       switch (op->code_rate_HP) {
+               case FEC_2_3:
+                       tps |= (1 << 7);
+                       break;
+               case FEC_3_4:
+                       tps |= (2 << 7);
+                       break;
+               case FEC_5_6:
+                       tps |= (3 << 7);
+                       break;
+               case FEC_7_8:
+                       tps |= (4 << 7);
+                       break;
+               case FEC_1_2:
+               case FEC_AUTO:
+               default:
+                       /* tps |= (0 << 7) */;
+       }
+
+       switch (op->code_rate_LP) {
+               case FEC_2_3:
+                       tps |= (1 << 4);
+                       break;
+               case FEC_3_4:
+                       tps |= (2 << 4);
+                       break;
+               case FEC_5_6:
+                       tps |= (3 << 4);
+                       break;
+               case FEC_7_8:
+                       tps |= (4 << 4);
+                       break;
+               case FEC_1_2:
+               case FEC_AUTO:
+               default:
+                       /* tps |= (0 << 4) */;
+       }
+
+       switch (op->constellation) {
+               case QAM_16:
+                       tps |= (1 << 13);
+                       break;
+               case QAM_64:
+                       tps |= (2 << 13);
+                       break;
+               case QPSK:
+               default:
+                       /* tps |= (0 << 13) */;
+       }
+
+       switch (op->transmission_mode) {
+               case TRANSMISSION_MODE_8K:
+                       tps |= (1 << 0);
+                       break;
+               case TRANSMISSION_MODE_2K:
+               default:
+                       /* tps |= (0 << 0) */;
+       }
+
+       switch (op->guard_interval) {
+               case GUARD_INTERVAL_1_16:
+                       tps |= (1 << 2);
+                       break;
+               case GUARD_INTERVAL_1_8:
+                       tps |= (2 << 2);
+                       break;
+               case GUARD_INTERVAL_1_4:
+                       tps |= (3 << 2);
+                       break;
+               case GUARD_INTERVAL_1_32:
+               default:
+                       /* tps |= (0 << 2) */;
+       }
+
+       switch (op->hierarchy_information) {
+               case HIERARCHY_1:
+                       tps |= (1 << 10);
+                       break;
+               case HIERARCHY_2:
+                       tps |= (2 << 10);
+                       break;
+               case HIERARCHY_4:
+                       tps |= (3 << 10);
+                       break;
+               case HIERARCHY_NONE:
+               default:
+                       /* tps |= (0 << 10) */;
+       }
+
+       return tps;
+}
+
+static int cinergyt2_open (struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct cinergyt2 *cinergyt2 = dvbdev->priv;
+       int err;
+
+       if ((err = dvb_generic_open(inode, file)))
+               return err;
+
+       if (down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+               cinergyt2_sleep(cinergyt2, 0);
+               schedule_delayed_work(&cinergyt2->query_work, HZ/2);
+}
+
+       up(&cinergyt2->sem);
+       return 0;
+}
+
+static int cinergyt2_release (struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct cinergyt2 *cinergyt2 = dvbdev->priv;
+
+       if (down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+               cancel_delayed_work(&cinergyt2->query_work);
+               flush_scheduled_work();
+               cinergyt2_sleep(cinergyt2, 1);
+       }
+
+       up(&cinergyt2->sem);
+
+       return dvb_generic_release(inode, file);
+       }
+
+static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait)
+       {
+       struct dvb_device *dvbdev = file->private_data;
+       struct cinergyt2 *cinergyt2 = dvbdev->priv;
+       poll_wait(file, &cinergyt2->poll_wq, wait);
+       return (POLLIN | POLLRDNORM | POLLPRI);
+       }
+
+
+static int cinergyt2_ioctl (struct inode *inode, struct file *file,
+                    unsigned cmd, unsigned long arg)
+       {
+       struct dvb_device *dvbdev = file->private_data;
+       struct cinergyt2 *cinergyt2 = dvbdev->priv;
+       struct dvbt_get_status_msg *stat = &cinergyt2->status;
+       fe_status_t status = 0;
+
+       switch (cmd) {
+       case FE_GET_INFO:
+               return copy_to_user((void*) arg, &cinergyt2_fe_info,
+                                   sizeof(struct dvb_frontend_info));
+
+       case FE_READ_STATUS:
+               if (0xffff - le16_to_cpu(stat->gain) > 30)
+                       status |= FE_HAS_SIGNAL;
+               if (stat->lock_bits & (1 << 6))
+                       status |= FE_HAS_LOCK;
+               if (stat->lock_bits & (1 << 5))
+                       status |= FE_HAS_SYNC;
+               if (stat->lock_bits & (1 << 4))
+                       status |= FE_HAS_CARRIER;
+               if (stat->lock_bits & (1 << 1))
+                       status |= FE_HAS_VITERBI;
+
+               return copy_to_user((void *) arg, &status, sizeof(status));
+
+       case FE_READ_BER:
+               return put_user(le32_to_cpu(stat->viterbi_error_rate),
+                               (__u32 __user *) arg);
+
+       case FE_READ_SIGNAL_STRENGTH:
+               return put_user(0xffff - le16_to_cpu(stat->gain),
+                               (__u16 __user *) arg);
+
+       case FE_READ_SNR:
+               return put_user((stat->snr << 8) | stat->snr,
+                               (__u16 __user *) arg);
+
+       case FE_READ_UNCORRECTED_BLOCKS:
+               /* UNC are already converted to host byte order... */
+               return put_user(stat->uncorrected_block_count,
+                               (__u32 __user *) arg);
+       
+       case FE_SET_FRONTEND:
+       {
+               struct dvbt_set_parameters_msg *param = &cinergyt2->param;
+               struct dvb_frontend_parameters p;
+               int err;
+
+               if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+                       return -EPERM;
+
+               if (copy_from_user(&p, (void *) arg, sizeof(p)))
+                       return -EFAULT;
+
+               if (down_interruptible(&cinergyt2->sem))
+                       return -ERESTARTSYS;
+
+               param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
+               param->tps = cpu_to_le16(compute_tps(&p));
+               param->freq = cpu_to_le32(p.frequency / 1000);
+               param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+
+               stat->lock_bits = 0;
+               cinergyt2->pending_fe_events++;
+               wake_up_interruptible(&cinergyt2->poll_wq);
+
+               err = cinergyt2_command(cinergyt2,
+                                       (char *) param, sizeof(*param),
+                                       NULL, 0);
+
+               up(&cinergyt2->sem);
+
+               return (err < 0) ? err : 0;
+       }
+
+       case FE_GET_FRONTEND:
+               /**
+                *  trivial to implement (see struct dvbt_get_status_msg).
+                *  equivalent to FE_READ ioctls, but needs 
+                *  TPS -> linux-dvb parameter set conversion. Feel free
+                *  to implement this and send us a patch if you need this
+                *  functionality.
+                */
+               break;
+
+       case FE_GET_EVENT:
+       {
+               /**
+                *  for now we only fill the status field. the parameters
+                *  are trivial to fill as soon FE_GET_FRONTEND is done.
+                */
+               struct dvb_frontend_event *e = (void *) arg;
+               if (cinergyt2->pending_fe_events == 0) {
+                       if (file->f_flags & O_NONBLOCK)
+                               return -EWOULDBLOCK;
+                       wait_event_interruptible(cinergyt2->poll_wq,
+                                                cinergyt2->pending_fe_events > 0);
+               }
+               cinergyt2->pending_fe_events = 0;
+               return cinergyt2_ioctl(inode, file, FE_READ_STATUS,
+                                       (unsigned long) &e->status);
+       }
+
+       default:
+               ;
+       }
+
+       return -EINVAL;
+}
+
+static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct cinergyt2 *cinergyt2 = dvbdev->priv;
+       int ret = 0;
+
+       lock_kernel();
+
+       if (vma->vm_flags & (VM_WRITE | VM_EXEC)) {
+               ret = -EPERM;
+               goto bailout;
+       }
+
+       if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) {
+               ret = -EINVAL;
+               goto bailout;
+       }
+
+        vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+       vma->vm_file = file;
+
+       ret = remap_pfn_range(vma, vma->vm_start,
+                             virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT,
+                             vma->vm_end - vma->vm_start,
+                             vma->vm_page_prot) ? -EAGAIN : 0;
+bailout:
+       unlock_kernel();
+       return ret;
+}
+
+static struct file_operations cinergyt2_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = cinergyt2_ioctl,
+       .poll           = cinergyt2_poll,
+       .open           = cinergyt2_open,
+       .release        = cinergyt2_release,
+       .mmap           = cinergyt2_mmap
+};
+
+static struct dvb_device cinergyt2_fe_template = {
+       .users = ~0,
+       .writers = 1,
+       .readers = (~0)-1,
+       .fops = &cinergyt2_fops
+};
+
+#ifdef ENABLE_RC
+static void cinergyt2_query_rc (void *data)
+{
+       struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data;
+       char buf [1] = { CINERGYT2_EP1_GET_RC_EVENTS };
+       struct cinergyt2_rc_event rc_events[12];
+       int n, len;
+
+       if (down_interruptible(&cinergyt2->sem))
+               return;
+
+       len = cinergyt2_command(cinergyt2, buf, sizeof(buf), 
+                            (char *) rc_events, sizeof(rc_events));
+
+       for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) {
+               int i;
+
+               if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
+                   rc_events[n].value == ~0)
+               {
+                       /**
+                        * keyrepeat bit. If we would handle this properly
+                        * we would need to emit down events as long the
+                        * keyrepeat goes, a up event if no further 
+                        * repeat bits occur. Would need a timer to implement
+                        * and no other driver does this, so we simply
+                        * emit the last key up/down sequence again.
+                        */
+               } else {
+                       cinergyt2->rc_input_event = KEY_MAX;
+                       for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) {
+                               if (rc_keys[i+0] == rc_events[n].type &&
+                                   rc_keys[i+1] == rc_events[n].value)
+                               {
+                                       cinergyt2->rc_input_event = rc_keys[i+2];
+                                       break;
+                               }
+                       }
+               }
+
+               if (cinergyt2->rc_input_event != KEY_MAX) {
+                       input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1);
+                       input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0);
+                       input_sync(&cinergyt2->rc_input_dev);
+               }
+       }
+
+       schedule_delayed_work(&cinergyt2->rc_query_work,
+                             msecs_to_jiffies(RC_QUERY_INTERVAL));
+
+       up(&cinergyt2->sem);
+}
+#endif
+
+static void cinergyt2_query (void *data)
+{
+       struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data;
+       char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS };
+       struct dvbt_get_status_msg *s = &cinergyt2->status;
+       uint8_t lock_bits;
+       uint32_t unc;
+
+       if (down_interruptible(&cinergyt2->sem))
+               return;
+
+       unc = s->uncorrected_block_count;
+       lock_bits = s->lock_bits;
+
+       cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s));
+
+       unc += le32_to_cpu(s->uncorrected_block_count);
+       s->uncorrected_block_count = unc;
+
+       if (lock_bits != s->lock_bits) {
+               wake_up_interruptible(&cinergyt2->poll_wq);
+               cinergyt2->pending_fe_events++;
+       }
+
+       schedule_delayed_work(&cinergyt2->query_work,
+                             msecs_to_jiffies(QUERY_INTERVAL));
+
+       up(&cinergyt2->sem);
+}
+
+static int cinergyt2_probe (struct usb_interface *intf,
+                 const struct usb_device_id *id)
+{
+       struct cinergyt2 *cinergyt2;
+       int i, err;
+
+       if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
+               dprintk(1, "out of memory?!?\n");
+               return -ENOMEM;
+       }
+
+       memset (cinergyt2, 0, sizeof (struct cinergyt2));
+       usb_set_intfdata (intf, (void *) cinergyt2);
+
+       init_MUTEX(&cinergyt2->sem);
+       init_waitqueue_head (&cinergyt2->poll_wq);
+       INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2);
+
+       cinergyt2->udev = interface_to_usbdev(intf);
+       cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
+       
+       if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) {
+               dprintk(1, "unable to allocate stream urbs\n");
+               kfree(cinergyt2);
+               return -ENOMEM;
+       }
+
+       dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE);
+
+       cinergyt2->demux.priv = cinergyt2;
+       cinergyt2->demux.filternum = 256;
+       cinergyt2->demux.feednum = 256;
+       cinergyt2->demux.start_feed = cinergyt2_start_feed;
+       cinergyt2->demux.stop_feed = cinergyt2_stop_feed;
+       cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING |
+                                        DMX_SECTION_FILTERING |
+                                        DMX_MEMORY_BASED_FILTERING;
+
+       if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) {
+               dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err);
+               goto bailout;
+       }
+
+       cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum;
+       cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx;
+       cinergyt2->dmxdev.capabilities = 0;
+
+       if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, cinergyt2->adapter)) < 0) {
+               dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err);
+               goto bailout;
+       }
+
+       if (dvb_net_init(cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx))
+               dprintk(1, "dvb_net_init() failed!\n");
+
+       dvb_register_device(cinergyt2->adapter, &cinergyt2->fedev,
+                           &cinergyt2_fe_template, cinergyt2,
+                           DVB_DEVICE_FRONTEND);
+
+#ifdef ENABLE_RC
+       init_input_dev(&cinergyt2->rc_input_dev);                       
+
+       cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY);
+       cinergyt2->rc_input_dev.keycodesize = sizeof(unsigned char);
+       cinergyt2->rc_input_dev.keycodemax = KEY_MAX;
+       cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control";
+
+       for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3)
+               set_bit(rc_keys[i+2], cinergyt2->rc_input_dev.keybit);
+
+       input_register_device(&cinergyt2->rc_input_dev);
+
+       cinergyt2->rc_input_event = KEY_MAX;
+       
+       INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2);
+       schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
+#endif
+       return 0;
+
+bailout:
+       dvb_dmxdev_release(&cinergyt2->dmxdev);
+       dvb_dmx_release(&cinergyt2->demux);
+       dvb_unregister_adapter (cinergyt2->adapter);
+       cinergyt2_free_stream_urbs (cinergyt2);
+       kfree(cinergyt2);
+       return -ENOMEM;
+}
+
+static void cinergyt2_disconnect (struct usb_interface *intf)
+{
+       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
+
+       if (down_interruptible(&cinergyt2->sem))
+               return;
+
+#ifdef ENABLE_RC
+       cancel_delayed_work(&cinergyt2->rc_query_work);
+       flush_scheduled_work();
+       input_unregister_device(&cinergyt2->rc_input_dev);
+#endif
+
+       cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx);
+       dvb_net_release(&cinergyt2->dvbnet);
+       dvb_dmxdev_release(&cinergyt2->dmxdev);
+       dvb_dmx_release(&cinergyt2->demux);
+
+       dvb_unregister_device(cinergyt2->fedev);
+       dvb_unregister_adapter(cinergyt2->adapter);
+
+       cinergyt2_free_stream_urbs(cinergyt2);
+       up(&cinergyt2->sem);
+       kfree(cinergyt2);
+}
+
+static int cinergyt2_suspend (struct usb_interface *intf, u32 state)
+{
+       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
+
+       if (down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if (state > 0) {        /* state 0 seems to mean DEVICE_PM_ON */
+               struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
+#ifdef ENABLE_RC
+               cancel_delayed_work(&cinergyt2->rc_query_work);
+#endif
+               cancel_delayed_work(&cinergyt2->query_work);
+               if (cinergyt2->streaming)
+                       cinergyt2_stop_stream_xfer(cinergyt2);
+               flush_scheduled_work();
+               cinergyt2_sleep(cinergyt2, 1);
+       }
+
+       up(&cinergyt2->sem);
+       return 0;
+}
+
+static int cinergyt2_resume (struct usb_interface *intf)
+{
+       struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
+       struct dvbt_set_parameters_msg *param = &cinergyt2->param;
+
+       if (down_interruptible(&cinergyt2->sem))
+               return -ERESTARTSYS;
+
+       if (!cinergyt2->sleeping) {
+               cinergyt2_sleep(cinergyt2, 0);
+               cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
+               if (cinergyt2->streaming)
+                       cinergyt2_start_stream_xfer(cinergyt2);
+               schedule_delayed_work(&cinergyt2->query_work, HZ/2);
+       }
+
+#ifdef ENABLE_RC
+       schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
+#endif
+       up(&cinergyt2->sem);
+       return 0;
+}
+
+static const struct usb_device_id cinergyt2_table [] __devinitdata = {
+       { USB_DEVICE(0x0ccd, 0x0038) },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(usb, cinergyt2_table);
+
+static struct usb_driver cinergyt2_driver = {
+       .owner          = THIS_MODULE,
+       .name   = "cinergyT2",
+       .probe          = cinergyt2_probe,
+       .disconnect     = cinergyt2_disconnect,
+       .suspend        = cinergyt2_suspend,
+       .resume         = cinergyt2_resume,
+       .id_table       = cinergyt2_table
+};
+
+static int __init cinergyt2_init (void)
+{
+       int err;
+
+       if ((err = usb_register(&cinergyt2_driver)) < 0)
+               dprintk(1, "usb_register() failed! (err %i)\n", err);
+
+       return err;
+}
+
+static void __exit cinergyt2_exit (void)
+{
+       usb_deregister(&cinergyt2_driver);
+}
+
+module_init (cinergyt2_init);
+module_exit (cinergyt2_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
+
diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig
new file mode 100644 (file)
index 0000000..7f73bbb
--- /dev/null
@@ -0,0 +1,57 @@
+config DVB_DIBUSB
+       tristate "DiBcom USB DVB-T devices (see help for device list)"
+       depends on DVB_CORE && USB
+       select FW_LOADER
+       select DVB_DIB3000MB
+       select DVB_DIB3000MC
+       help
+         Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
+         DiBcom (http://www.dibcom.fr).
+
+         Devices supported by this driver:
+
+           TwinhanDTV USB-Ter (VP7041)
+               TwinhanDTV Magic Box (VP7041e)
+           KWorld V-Stream XPERT DTV - DVB-T USB
+           Hama DVB-T USB-Box
+           DiBcom reference device (non-public)
+           Ultima Electronic/Artec T1 USB TVBOX
+           Compro Videomate DVB-U2000 - DVB-T USB
+           Grandtec DVB-T USB
+           Avermedia AverTV DVBT USB
+           Yakumo DVB-T mobile USB2.0
+
+         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)
+
+         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
new file mode 100644 (file)
index 0000000..ab990cd
--- /dev/null
@@ -0,0 +1,3 @@
+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.c b/drivers/media/dvb/dibusb/dvb-dibusb.c
new file mode 100644 (file)
index 0000000..e4237a9
--- /dev/null
@@ -0,0 +1,1032 @@
+/*
+ * Driver for mobile USB Budget DVB-T devices based on reference
+ * design made by DiBcom (http://www.dibcom.fr/)
+ *
+ * dvb-dibusb.c
+ *
+ * Copyright (C) 2004 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 <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/input.h>
+
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_filter.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+#include "dib3000.h"
+
+#include "dvb-dibusb.h"
+
+
+/* debug */
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk(level,args...) \
+           do { if ((debug & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l) if (debug) {\
+       int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
+       for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
+       deb_xfer("\n");\
+}
+
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able)).");
+#else
+#define dprintk(args...)
+#define debug_dump(b,l)
+#endif
+
+#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)
+
+static int pid_parse;
+module_param(pid_parse, int, 0x644);
+MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+static 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;
+
+       if (dib->feedcount &&
+               wbuf[0] == DIBUSB_REQ_I2C_WRITE &&
+               dib->dibdev->parm->type == DIBUSB1_1)
+               deb_err("BUG: writing to i2c, while TS-streaming destroys the stream."
+                               "(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]);
+                       
+       debug_dump(wbuf,wlen);
+
+       ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
+                       dib->dibdev->parm->cmd_pipe), 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->parm->result_pipe),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;
+}
+
+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);
+
+       deb_alot("wo: %d, wlen: %d, len: %d\n",wo,wlen,len);
+
+       sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
+       sndbuf[1] = (addr & 0xfe) | (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);
+}
+
+/*
+ * DVB stuff
+ */
+static 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\n",dib->feedcount,urb->status);
+
+       if (dib->feedcount > 0 && urb->status == 0) {
+               deb_ts("URB return len: %d\n",urb->actual_length);
+               if (urb->actual_length % 188)
+                       deb_ts("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188);
+
+               /* Francois recommends to drop not full-filled packets, even if they may 
+                * contain valid TS packets
+                */
+               if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready)
+               dvb_dmx_swfilter_packets(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length/188);
+               else
+                       deb_ts("URB dropped because of the " 
+                                       "actual_length or !dvb_is_ready (%d).\n",dib->dvb_is_ready);
+       } else 
+               deb_ts("URB dropped because of feedcount or status.\n");
+
+               usb_submit_urb(urb,GFP_KERNEL);
+}
+
+static int dibusb_ctrl_feed(struct usb_dibusb *dib, int pid, int onoff)
+{
+       if (dib->dibdev->parm->firmware_bug && dib->feedcount) {
+               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;
+                       }
+               } else {
+                       err("fifo_ctrl is not set.");
+                       return -ENODEV;
+               }
+       }
+
+       dib->feedcount += onoff ? 1 : -1;
+
+       if (dib->pid_parse) {
+       if (dib->xfer_ops.pid_ctrl != NULL) {
+               if (dib->xfer_ops.pid_ctrl(dib->fe,pid,onoff) < 0) {
+               err("no free pid in list.");
+               return -ENODEV;
+       }
+       } else {
+               err("no pid ctrl callback.");
+               return -ENODEV;
+       }
+       }
+       /*
+        * start the feed, either if there is the firmware bug or
+        * if this was the first pid to set.
+        */
+       if (dib->dibdev->parm->firmware_bug || dib->feedcount == onoff) {
+
+               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;
+                       }
+               } else {
+                       err("fifo_ctrl is not set.");
+                       return -ENODEV;
+}
+       }
+       return 0;
+}
+
+static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
+       deb_ts("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+       dvbdmxfeed->priv = dib;
+       return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,1);
+}
+
+static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct usb_dibusb *dib = (struct usb_dibusb *) dvbdmxfeed->priv;
+       if (dib == NULL) {
+               err("dib in dmxfeed->priv was NULL");
+               return -EINVAL;
+}
+       deb_ts("dvbdmxfeed pid: 0x%04x, feedtype: %d\n",
+                       dvbdmxfeed->pid, dvbdmxfeed->type);
+       return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,0);
+}
+
+/* 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; } 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 },
+};
+
+/*
+ * 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;
+       int i;
+       if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
+               return ret;
+
+       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(rc_keys)/sizeof(rc_keys[0]); i++) {
+                               if (rc_keys[i].c0 == rb[1] &&
+                                       rc_keys[i].c1 == rb[2] &&
+                                   rc_keys[i].c2 == rb[3]) {
+                                       dib->rc_input_event = rc_keys[i].key;
+                                       deb_rc("Translated key 0x%04x\n", dib->rc_input_event);
+                                       /* Signal down and up events for this key. */
+                                       input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1);
+                                       input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0);
+                                       input_sync(&dib->rc_input_dev);
+                                       break;
+                               }
+                       }
+                       break;
+               case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
+                       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. */
+                       deb_rc("Key repeat\n");
+                       break;
+               default:
+                       break;
+       }
+       
+       return 0;
+}
+
+#define RC_QUERY_INTERVAL (100)        /* milliseconds */
+
+/* Remote-control poll function - called every RC_QUERY_INTERVAL ms to see
+   whether the remote control has received anything. */
+static void dibusb_query_rc (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(RC_QUERY_INTERVAL));
+}
+
+/*
+ * Cypress controls
+ */
+
+#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 :).
+ */
+static int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
+{
+       u8 b[1] = { DIBUSB_REQ_INTR_READ };
+       return dibusb_write_usb(dib,b,1);
+}
+
+/*
+ * ioctl for power control
+ */
+static int dibusb_hw_sleep(struct usb_dibusb *dib)
+{
+       u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
+       return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+}
+
+#endif
+static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
+{
+       return dibusb_readwrite_usb(dib,buf,len,NULL,0);
+}
+
+/*
+ * 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;
+       b[0] = DIBUSB_REQ_SET_IOCTL;
+       b[1] = cmd;
+       memcpy(&b[2],param,size);
+
+       return dibusb_write_usb(dib,b,2+size);
+}
+
+static int dibusb_hw_wakeup(struct usb_dibusb *dib)
+{
+       u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
+       return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
+}
+
+/*
+ * I2C
+ */
+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;
+
+       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 int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
+               dvb_frontend_parameters* params);
+
+static struct dib3000_config thomson_cable_eu_config = {
+       .demod_address = 0x10,
+       .pll_addr = 194,
+       .pll_set = thomson_cable_eu_pll_set,
+};
+
+static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct
+               dvb_frontend_parameters* params)
+{
+       struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+       u8 buf[4];
+       struct i2c_msg msg = {
+               .addr = thomson_cable_eu_config.pll_addr,
+               .flags = 0,
+               .buf = buf,
+               .len = sizeof(buf)
+       };
+       u32 tfreq = (params->frequency + 36125000) / 62500;
+       int vu,p0,p1,p2;
+
+       if (params->frequency > 403250000)
+               vu = 1, p2 = 1, p1 = 0, p0 = 1;
+       else if (params->frequency > 115750000)
+               vu = 0, p2 = 1, p1 = 1, p0 = 0;
+       else if (params->frequency > 44250000)
+               vu = 0, p2 = 0, p1 = 1, p0 = 1;
+       else
+               return -EINVAL;
+
+       buf[0] = (tfreq >> 8) & 0x7f;
+       buf[1] = tfreq & 0xff;
+       buf[2] = 0x8e;
+       buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
+
+       if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+
+       msleep(1);
+       return 0;
+}
+
+static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
+               dvb_frontend_parameters *params);
+
+static struct dib3000_config panasonic_cofdm_env57h1xd5 = {
+       .demod_address = 0x18,
+       .pll_addr = 192,
+       .pll_set = panasonic_cofdm_env57h1xd5_pll_set,
+};
+
+static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct
+               dvb_frontend_parameters *params)
+{
+       struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
+       u8 buf[4];
+       u32 freq = params->frequency;
+       u32 tfreq = (freq + 36125000) / 1000000 * 6 + 1;
+       u8 TA, T210, R210, ctrl1, cp210, p4321;
+       struct i2c_msg msg = {
+               .addr = panasonic_cofdm_env57h1xd5.pll_addr,
+               .flags = 0,
+               .buf = buf,
+               .len = sizeof(buf)
+       };
+
+       if (freq > 858000000) {
+               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 < 470000000)
+               cp210 = 2;  // VHF Low and High band ch E12 to E4 to E12
+       else if (freq < 526000000)
+               cp210 = 4;  // UHF band Ch E21 to E27
+       else // if (freq < 862000000)
+               cp210 = 5;  // UHF band ch E28 to E69
+
+//*********************    BW select  *******************************
+       if (freq < 153000000)
+               p4321  = 1; // BW selected for VHF low
+       else if (freq < 470000000)
+               p4321  = 2; // BW selected for VHF high E5 to E12
+       else // if (freq < 862000000)
+               p4321  = 4; // BW selection for UHF E21 to E69
+
+       buf[0] = (tfreq >> 8) & 0xff;
+       buf[1] = (tfreq >> 0) & 0xff;
+       buf[2] = 0xff & ctrl1;
+       buf[3] =  (cp210 << 5) | (p4321);
+
+       if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+
+       msleep(1);
+       return 0;
+}
+
+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 void frontend_init(struct usb_dibusb* dib)
+{
+       switch (dib->dibdev->parm->type) {
+               case DIBUSB1_1:
+               case DIBUSB1_1_AN2235:
+       dib->fe = dib3000mb_attach(&thomson_cable_eu_config, &dib->i2c_adap,&dib->xfer_ops);
+                       break;
+               case DIBUSB2_0:
+                       dib->fe = dib3000mc_attach(&panasonic_cofdm_env57h1xd5,&dib->i2c_adap, &dib->xfer_ops);
+                       break;
+       }
+
+       if (dib->fe == NULL) {
+               printk("dvb-dibusb: A frontend driver was not found for device %04x/%04x\n",
+                      dib->udev->descriptor.idVendor,
+                      dib->udev->descriptor.idProduct);
+       } else {
+               if (dvb_register_frontend(dib->adapter, dib->fe)) {
+                       printk("dvb-dibusb: Frontend registration failed!\n");
+                       if (dib->fe->ops->release)
+                               dib->fe->ops->release(dib->fe);
+                       dib->fe = NULL;
+               }
+       }
+}
+
+static int dibusb_dvb_init(struct usb_dibusb *dib)
+{
+       int ret;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4)
+    if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC)) < 0) {
+#else
+    if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC ,
+                       THIS_MODULE)) < 0) {
+#endif
+               deb_info("dvb_register_adapter failed: error %d", ret);
+               goto err;
+       }
+       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 ((i2c_add_adapter(&dib->i2c_adap) < 0)) {
+               err("could not add i2c adapter");
+               goto err_i2c;
+       }
+
+       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 = 16;
+       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);
+
+       frontend_init(dib);
+
+       /* Start the remote-control polling. */
+       schedule_delayed_work(&dib->rc_query_work, msecs_to_jiffies(RC_QUERY_INTERVAL));
+
+       goto success;
+err_dmx_dev:
+       dvb_dmx_release(&dib->demux);
+err_dmx:
+       i2c_del_adapter(&dib->i2c_adap);
+err_i2c:
+       dvb_unregister_adapter(dib->adapter);
+err:
+       return ret;
+success:
+       dib->dvb_is_ready = 1;
+       return 0;
+}
+
+static int dibusb_dvb_exit(struct usb_dibusb *dib)
+{
+       cancel_delayed_work(&dib->rc_query_work);
+       flush_scheduled_work();
+       input_unregister_device(&dib->rc_input_dev);
+
+       dib->dvb_is_ready = 0;
+       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);
+       if (dib->fe != NULL) dvb_unregister_frontend(dib->fe);
+       i2c_del_adapter(&dib->i2c_adap);
+       dvb_unregister_adapter(dib->adapter);
+
+       return 0;
+}
+
+static int dibusb_exit(struct usb_dibusb *dib)
+{
+       int i;
+       if (dib->urb_list != NULL) {
+               for (i = 0; i < dib->dibdev->parm->num_urbs; i++) {
+                       if (dib->urb_list[i] != NULL) {
+                       deb_info("killing URB no. %d.\n",i);
+
+                               /* stop the URBs */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
+                               usb_unlink_urb(dib->urb_list[i]);
+#else
+                               usb_kill_urb(dib->urb_list[i]);
+#endif
+                       
+                       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);
+               }
+
+       pci_free_consistent(NULL,
+               dib->dibdev->parm->urb_buf_size*dib->dibdev->parm->num_urbs,dib->buffer,
+               dib->dma_handle);
+       return 0;
+}
+
+static int dibusb_init(struct usb_dibusb *dib)
+{
+       int ret,i,bufsize;
+       sema_init(&dib->usb_sem, 1);
+       sema_init(&dib->i2c_sem, 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->parm->cmd_pipe));
+       usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->result_pipe));
+       usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->data_pipe));
+
+       /* allocate the array for the data transfer URBs */
+       dib->urb_list = kmalloc(dib->dibdev->parm->num_urbs*sizeof(struct urb *),GFP_KERNEL);
+       if (dib->urb_list == NULL)
+               return -ENOMEM;
+       memset(dib->urb_list,0,dib->dibdev->parm->num_urbs*sizeof(struct urb *));
+
+       bufsize = dib->dibdev->parm->num_urbs*dib->dibdev->parm->urb_buf_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");
+               dibusb_exit(dib);
+               return -ENOMEM;
+       }
+       deb_info("allocation complete\n");
+       memset(dib->buffer,0,bufsize);
+
+       /* allocate and submit the URBs */
+       for (i = 0; i < dib->dibdev->parm->num_urbs; i++) {
+               if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_KERNEL))) {
+               dibusb_exit(dib);
+               return -ENOMEM;
+       }
+               deb_info("submitting URB no. %d\n",i);
+
+               usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
+                               usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->data_pipe),
+                               &dib->buffer[i*dib->dibdev->parm->urb_buf_size],
+                               dib->dibdev->parm->urb_buf_size,
+                               dibusb_urb_complete, dib);
+
+               dib->urb_list[i]->transfer_flags = 0;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
+               dib->urb_list[i]->timeout = 0;
+#endif
+
+               if ((ret = usb_submit_urb(dib->urb_list[i],GFP_KERNEL))) {
+                       err("could not submit buffer urb no. %d\n",i);
+                       dibusb_exit(dib);
+                       return ret;
+               }
+       }
+
+       dib->dvb_is_ready = 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";
+
+       for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i++)
+               set_bit(rc_keys[i].key, dib->rc_input_dev.keybit);
+
+       input_register_device(&dib->rc_input_dev);
+
+       dib->rc_input_event = KEY_MAX;
+
+       INIT_WORK(&dib->rc_query_work, dibusb_query_rc, dib);
+
+       dibusb_hw_wakeup(dib);
+
+       if ((ret = dibusb_dvb_init(dib))) {
+               dibusb_exit(dib);
+               return ret;
+       }
+       return 0;
+}
+
+/*
+ * 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, 5*HZ);
+}
+
+static int dibusb_loadfirmware(struct usb_device *udev,
+               struct dibusb_device *dibdev)
+{
+       const struct firmware *fw = NULL;
+       const char **fws;
+       u16 addr;
+       u8 *b,*p;
+       int ret = 0,i;
+
+       fws = dibdev->parm->fw_filenames;
+
+       for (i = 0; i < sizeof(fws)/sizeof(const char*); i++) {
+               if ((ret = request_firmware(&fw, fws[i], &udev->dev)) == 0) {
+                       info("using firmware file (%s).",fws[i]);
+                       break;
+               }
+               deb_info("tried to find '%s' firmware - unsuccessful. (%d)\n",
+                               fws[i],ret);
+       }
+
+       if (fw == NULL) {
+               err("did not find a valid firmware file. "
+                       "Please see linux/Documentation/dvb/ for more details on firmware-problems.");
+               return -EINVAL;
+       }
+       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->parm->usb_cpu_csreg,&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->parm->usb_cpu_csreg,&reset,1) != 1) {
+                       err("could not restart the USB controller CPU.");
+                       ret = -EINVAL;
+               }
+
+               kfree(p);
+       } else {
+               ret = -ENOMEM;
+       }
+       release_firmware(fw);
+
+       return ret;
+}
+
+/*
+ * 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_device *dibdev = NULL;
+
+       int ret = -ENOMEM,i,cold=0;
+
+       for (i = 0; i < DIBUSB_SUPPORTED_DEVICES; i++)
+               if (dibusb_devices[i].cold_product_id == udev->descriptor.idProduct ||
+                       dibusb_devices[i].warm_product_id == udev->descriptor.idProduct) {
+                       dibdev = &dibusb_devices[i];
+
+                       cold = dibdev->cold_product_id == udev->descriptor.idProduct;
+
+                       if (cold)
+                               info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
+                       else
+                               info("found a '%s' in warm state.",dibdev->name);
+               }
+
+       if (dibdev == NULL) {
+               err("something went very wrong, "
+                               "unknown product ID: %.4x",udev->descriptor.idProduct);
+               return -ENODEV;
+       }
+
+       if (cold)
+               ret = dibusb_loadfirmware(udev,dibdev);
+       else {
+               dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
+               if (dib == NULL) {
+                       err("no memory");
+                       return ret;
+               }
+               memset(dib,0,sizeof(struct usb_dibusb));
+
+               dib->pid_parse = 1;
+               switch (udev->speed) {
+                       case USB_SPEED_LOW:
+                               err("cannot handle USB speed because it is to sLOW.");
+                               break;
+                       case USB_SPEED_FULL:
+                               info("running at FULL speed, will use pid parsing.");
+                               break;
+                       case USB_SPEED_HIGH:
+                               if (!pid_parse) {
+                                       dib->pid_parse = 0;
+                               info("running at HIGH speed, will deliver the complete TS.");
+                               } else
+                                       info("running at HIGH speed, will use pid_parsing anyway.");
+                               break;
+                       case USB_SPEED_UNKNOWN: /* fall through */
+                       default:
+                               err("cannot handle USB speed because it is unkown.");
+                               break;
+               }
+
+               dib->udev = udev;
+               dib->dibdev = dibdev;
+
+               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) {
+               name = dib->dibdev->name;
+               dibusb_dvb_exit(dib);
+               dibusb_exit(dib);
+               kfree(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           = "dvb_dibusb",
+       .probe          = dibusb_probe,
+       .disconnect = dibusb_disconnect,
+       .id_table       = dibusb_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.h b/drivers/media/dvb/dibusb/dvb-dibusb.h
new file mode 100644 (file)
index 0000000..8a17fc0
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * dvb-dibusb.h
+ *
+ * Copyright (C) 2004 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.c .
+ */
+
+#ifndef __DVB_DIBUSB_H__
+#define __DVB_DIBUSB_H__
+
+#include "dib3000.h"
+
+typedef enum {
+       DIBUSB1_1 = 0,
+       DIBUSB2_0,
+       DIBUSB1_1_AN2235,
+} dibusb_type;
+
+static const char * dibusb_fw_filenames1_1[] = {
+       "dvb-dibusb-5.0.0.11.fw"
+};
+
+static const char * dibusb_fw_filenames1_1_an2235[] = {
+       "dvb-dibusb-an2235-1.fw"
+};
+
+static const char * dibusb_fw_filenames2_0[] = {
+       "dvb-dibusb-6.0.0.5.fw"
+};
+
+struct dibusb_device_parameter {
+       dibusb_type type;
+       u8 demod_addr;
+       const char **fw_filenames;
+       const char *usb_controller;
+       u16 usb_cpu_csreg;
+
+       int num_urbs;
+       int urb_buf_size;
+       int default_size;
+       int firmware_bug;
+
+       int cmd_pipe;
+       int result_pipe;
+       int data_pipe;
+};
+
+static struct dibusb_device_parameter dibusb_dev_parm[3] = {
+       {       .type = DIBUSB1_1,
+               .demod_addr = 0x10,
+               .fw_filenames = dibusb_fw_filenames1_1,
+               .usb_controller = "Cypress AN2135",
+               .usb_cpu_csreg = 0x7f92,
+
+               .num_urbs = 3,
+               .urb_buf_size = 4096,
+               .default_size = 188*21,
+               .firmware_bug = 1,
+
+               .cmd_pipe = 0x01,
+               .result_pipe = 0x81,
+               .data_pipe = 0x82,
+       },
+       {       .type = DIBUSB2_0,
+               .demod_addr = 0x18,
+               .fw_filenames = dibusb_fw_filenames2_0,
+               .usb_controller = "Cypress FX2",
+               .usb_cpu_csreg = 0xe600,
+
+               .num_urbs = 3,
+               .urb_buf_size = 40960,
+               .default_size = 188*210,
+               .firmware_bug = 0,
+
+               .cmd_pipe = 0x01,
+               .result_pipe = 0x81,
+               .data_pipe = 0x86,
+       },
+       {       .type = DIBUSB1_1_AN2235,
+               .demod_addr = 0x10,
+               .fw_filenames = dibusb_fw_filenames1_1_an2235,
+               .usb_controller = "Cypress CY7C64613 (AN2235)",
+               .usb_cpu_csreg = 0x7f92,
+
+               .num_urbs = 3,
+               .urb_buf_size = 4096,
+               .default_size = 188*21,
+               .firmware_bug = 1,
+
+               .cmd_pipe = 0x01,
+               .result_pipe = 0x81,
+               .data_pipe = 0x82,
+       }
+};
+
+struct dibusb_device {
+       const char *name;
+       u16 cold_product_id;
+       u16 warm_product_id;
+       struct dibusb_device_parameter *parm;
+};
+
+/* Vendor IDs */
+#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_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_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_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_YAKUMO_DTT200U_COLD                    0x0201
+#define USB_PID_YAKUMO_DTT200U_WARM                    0x0301
+
+#define DIBUSB_SUPPORTED_DEVICES       15
+
+/* USB Driver stuff */
+static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = {
+       {       .name = "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
+               .cold_product_id = USB_PID_TWINHAN_VP7041_COLD,
+               .warm_product_id = USB_PID_TWINHAN_VP7041_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+               .cold_product_id = USB_PID_KWORLD_VSTREAM_COLD,
+               .warm_product_id = USB_PID_KWORLD_VSTREAM_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Grandtec USB1.1 DVB-T/DiBcom USB1.1 DVB-T reference design (MOD3000)",
+               .cold_product_id = USB_PID_DIBCOM_MOD3000_COLD,
+               .warm_product_id = USB_PID_DIBCOM_MOD3000_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Artec T1 USB1.1 TVBOX with AN2135",
+               .cold_product_id = USB_PID_ULTIMA_TVBOX_COLD,
+               .warm_product_id = USB_PID_ULTIMA_TVBOX_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Artec T1 USB1.1 TVBOX with AN2235",
+               .cold_product_id = USB_PID_ULTIMA_TVBOX_AN2235_COLD,
+               .warm_product_id = USB_PID_ULTIMA_TVBOX_AN2235_WARM,
+               .parm = &dibusb_dev_parm[2],
+       },
+       {       .name = "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
+               .cold_product_id = USB_PID_ULTIMA_TVBOX_ANCHOR_COLD,
+               .warm_product_id = 0, /* undefined, this design becomes USB_PID_DIBCOM_MOD3000_WARM in warm state */
+               .parm = &dibusb_dev_parm[2],
+       },
+       {       .name = "Artec T1 USB2.0 TVBOX (please report the warm ID)",
+               .cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_COLD,
+               .warm_product_id = 0, /* don't know, it is most likely that the device will get another USB ID in warm state */
+               .parm = &dibusb_dev_parm[1],
+       },
+       {       .name = "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
+               .cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_COLD,
+               .warm_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_WARM, /* undefined, it could be that the device will get another USB ID in warm state */
+               .parm = &dibusb_dev_parm[1],
+       },
+       {       .name = "Compro Videomate DVB-U2000 - DVB-T USB1.1",
+               .cold_product_id = USB_PID_COMPRO_DVBU2000_COLD,
+               .warm_product_id = USB_PID_COMPRO_DVBU2000_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Compro Videomate DVB-U2000 - DVB-T USB1.1 (really ?? please report the name!)",
+               .cold_product_id = USB_PID_COMPRO_DVBU2000_UNK_COLD,
+               .warm_product_id = USB_PID_COMPRO_DVBU2000_UNK_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Unkown USB1.1 DVB-T device ???? please report the name to the author",
+               .cold_product_id = USB_PID_UNK_HYPER_PALTEK_COLD,
+               .warm_product_id = USB_PID_UNK_HYPER_PALTEK_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+               .cold_product_id = USB_PID_DIBCOM_MOD3001_COLD,
+               .warm_product_id = USB_PID_DIBCOM_MOD3001_WARM,
+               .parm = &dibusb_dev_parm[1],
+       },
+       {       .name = "Grandtec DVB-T USB1.1",
+               .cold_product_id = USB_PID_GRANDTEC_DVBT_USB_COLD,
+               .warm_product_id = USB_PID_GRANDTEC_DVBT_USB_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Avermedia AverTV DVBT USB1.1",
+               .cold_product_id = USB_PID_AVERMEDIA_DVBT_USB_COLD,
+               .warm_product_id = USB_PID_AVERMEDIA_DVBT_USB_WARM,
+               .parm = &dibusb_dev_parm[0],
+       },
+       {       .name = "Yakumo DVB-T mobile USB2.0",
+               .cold_product_id = USB_PID_YAKUMO_DTT200U_COLD,
+               .warm_product_id = USB_PID_YAKUMO_DTT200U_WARM,
+               .parm = &dibusb_dev_parm[1],
+       }
+};
+
+/* USB Driver stuff */
+/* table of devices that work with this driver */
+static struct usb_device_id dibusb_table [] = {
+       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_COLD) },
+       { USB_DEVICE(USB_VID_COMPRO,            USB_PID_COMPRO_DVBU2000_WARM) },
+       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_COLD) },
+       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3000_WARM) },
+       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3001_COLD) },
+       { USB_DEVICE(USB_VID_DIBCOM,            USB_PID_DIBCOM_MOD3001_WARM) },
+       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_COLD) },
+       { USB_DEVICE(USB_VID_EMPIA,                     USB_PID_KWORLD_VSTREAM_WARM) },
+       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_COLD) },
+       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_GRANDTEC_DVBT_USB_WARM) },
+       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_COLD) },
+       { USB_DEVICE(USB_VID_GRANDTEC,          USB_PID_DIBCOM_MOD3000_WARM) },
+       { USB_DEVICE(USB_VID_HYPER_PALTEK,      USB_PID_UNK_HYPER_PALTEK_COLD) },
+       { USB_DEVICE(USB_VID_HYPER_PALTEK,      USB_PID_UNK_HYPER_PALTEK_WARM) },
+       { USB_DEVICE(USB_VID_IMC_NETWORKS,      USB_PID_TWINHAN_VP7041_COLD) },
+       { USB_DEVICE(USB_VID_IMC_NETWORKS,      USB_PID_TWINHAN_VP7041_WARM) },
+       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_COLD) },
+       { USB_DEVICE(USB_VID_TWINHAN,           USB_PID_TWINHAN_VP7041_WARM) },
+       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_YAKUMO_DTT200U_COLD) },
+       { USB_DEVICE(USB_VID_AVERMEDIA,         USB_PID_YAKUMO_DTT200U_WARM) },
+       { USB_DEVICE(USB_PID_COMPRO_DVBU2000_UNK_COLD, USB_VID_COMPRO_UNK) },
+       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+
+/*
+ * 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
+       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+       { USB_DEVICE(USB_VID_CYPRESS,           USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
+       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
+#endif
+       { }                 /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dibusb_table);
+
+#define DIBUSB_I2C_TIMEOUT                             HZ*5
+
+struct usb_dibusb {
+       /* usb */
+       struct usb_device * udev;
+
+       struct dibusb_device * dibdev;
+
+       int feedcount;
+       int pid_parse;
+       struct dib3000_xfer_ops xfer_ops;
+
+       struct urb **urb_list;
+       u8 *buffer;
+       dma_addr_t dma_handle;
+
+       /* I2C */
+       struct i2c_adapter i2c_adap;
+       struct i2c_client i2c_client;
+
+       /* locking */
+       struct semaphore usb_sem;
+       struct semaphore i2c_sem;
+
+       /* dvb */
+       int dvb_is_ready;
+       struct dvb_adapter *adapter;
+       struct dmxdev dmxdev;
+       struct dvb_demux demux;
+       struct dvb_net dvb_net;
+       struct dvb_frontend* fe;
+
+       /* remote control */
+       struct input_dev rc_input_dev;
+       struct work_struct rc_query_work;
+       int rc_input_event;
+};
+
+
+/* types of first byte of each buffer */
+
+#define DIBUSB_REQ_START_READ                  0x00
+#define DIBUSB_REQ_START_DEMOD                 0x01
+#define DIBUSB_REQ_I2C_READ                    0x02
+#define DIBUSB_REQ_I2C_WRITE                   0x03
+
+/* prefix for reading the current RC key */
+#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
+
+/* 0x05 0xXX */
+#define DIBUSB_REQ_SET_STREAMING_MODE  0x05
+
+/* interrupt the internal read loop, when blocking */
+#define DIBUSB_REQ_INTR_READ                   0x06
+
+/* IO control
+ * 0x07 <cmd 1 byte> <param 32 bytes>
+ */
+#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
+
+#endif
diff --git a/drivers/media/dvb/frontends/at76c651.h b/drivers/media/dvb/frontends/at76c651.h
new file mode 100644 (file)
index 0000000..34054df
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * at76c651.c
+ *
+ * Atmel DVB-C Frontend Driver (at76c651)
+ *
+ * Copyright (C) 2001 fnbrd <fnbrd@gmx.de>
+ *             & 2002-2004 Andreas Oberritter <obi@linuxtv.org>
+ *             & 2003 Wolfram Joost <dbox2@frokaschwei.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.
+ *
+ * AT76C651
+ * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf
+ * http://www.atmel.com/atmel/acrobat/doc1320.pdf
+ */
+
+#ifndef AT76C651_H
+#define AT76C651_H
+
+#include <linux/dvb/frontend.h>
+
+struct at76c651_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* at76c651_attach(const struct at76c651_config* config,
+                                           struct i2c_adapter* i2c);
+
+#endif // AT76C651_H
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
new file mode 100644 (file)
index 0000000..26744e7
--- /dev/null
@@ -0,0 +1,445 @@
+#/*
+    Conexant cx22700 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+       Holger Waechtler <holger@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "cx22700.h"
+
+
+struct cx22700_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       const struct cx22700_config* config;
+
+       struct dvb_frontend frontend;
+};
+
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "cx22700: " args); \
+       } while (0)
+
+static u8 init_tab [] = {
+       0x04, 0x10,
+       0x05, 0x09,
+       0x06, 0x00,
+       0x08, 0x04,
+       0x09, 0x00,
+       0x0a, 0x01,
+       0x15, 0x40,
+       0x16, 0x10,
+       0x17, 0x87,
+       0x18, 0x17,
+       0x1a, 0x10,
+       0x25, 0x04,
+       0x2e, 0x00,
+       0x39, 0x00,
+       0x3a, 0x04,
+       0x45, 0x08,
+       0x46, 0x02,
+       0x47, 0x05,
+};
+
+
+static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf [] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+       dprintk ("%s\n", __FUNCTION__);
+
+       ret = i2c_transfer (state->i2c, &msg, 1);
+
+       if (ret != 1)
+               printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+                       __FUNCTION__, reg, data, ret);
+
+       return (ret != 1) ? -1 : 0;
+}
+
+static int cx22700_readreg (struct cx22700_state* state, u8 reg)
+{
+       int ret;
+       u8 b0 [] = { reg };
+       u8 b1 [] = { 0 };
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+                          { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+       dprintk ("%s\n", __FUNCTION__);
+
+       ret = i2c_transfer (state->i2c, msg, 2);
+
+       if (ret != 2) return -EIO;
+
+       return b1[0];
+}
+
+static int cx22700_set_inversion (struct cx22700_state* state, int inversion)
+{
+       u8 val;
+
+       dprintk ("%s\n", __FUNCTION__);
+
+       switch (inversion) {
+       case INVERSION_AUTO:
+               return -EOPNOTSUPP;
+       case INVERSION_ON:
+               val = cx22700_readreg (state, 0x09);
+               return cx22700_writereg (state, 0x09, val | 0x01);
+       case INVERSION_OFF:
+               val = cx22700_readreg (state, 0x09);
+               return cx22700_writereg (state, 0x09, val & 0xfe);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p)
+{
+       static const u8 qam_tab [4] = { 0, 1, 0, 2 };
+       static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
+       u8 val;
+
+       dprintk ("%s\n", __FUNCTION__);
+
+       if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
+               return -EINVAL;
+
+       if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
+
+       if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
+               return -EINVAL;
+
+       if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+           p->guard_interval > GUARD_INTERVAL_1_4)
+               return -EINVAL;
+
+       if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+           p->transmission_mode != TRANSMISSION_MODE_8K)
+               return -EINVAL;
+
+       if (p->constellation != QPSK &&
+           p->constellation != QAM_16 &&
+           p->constellation != QAM_64)
+               return -EINVAL;
+
+       if (p->hierarchy_information < HIERARCHY_NONE ||
+           p->hierarchy_information > HIERARCHY_4)
+               return -EINVAL;
+
+       if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ)
+               return -EINVAL;
+
+       if (p->bandwidth == BANDWIDTH_7_MHZ)
+               cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10));
+       else
+               cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10));
+
+       val = qam_tab[p->constellation - QPSK];
+       val |= p->hierarchy_information - HIERARCHY_NONE;
+
+       cx22700_writereg (state, 0x04, val);
+
+       val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
+       val |= fec_tab[p->code_rate_LP - FEC_1_2];
+
+       cx22700_writereg (state, 0x05, val);
+
+       val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
+       val |= p->transmission_mode - TRANSMISSION_MODE_2K;
+
+       cx22700_writereg (state, 0x06, val);
+
+       cx22700_writereg (state, 0x08, 0x04 | 0x02);  /* use user tps parameters */
+       cx22700_writereg (state, 0x08, 0x04);         /* restart aquisition */
+
+       return 0;
+}
+
+static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p)
+{
+       static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
+       static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
+                                                   FEC_5_6, FEC_7_8 };
+       u8 val;
+
+       dprintk ("%s\n", __FUNCTION__);
+
+       if (!(cx22700_readreg(state, 0x07) & 0x20))  /*  tps valid? */
+               return -EAGAIN;
+
+       val = cx22700_readreg (state, 0x01);
+
+       if ((val & 0x7) > 4)
+               p->hierarchy_information = HIERARCHY_AUTO;
+       else
+               p->hierarchy_information = HIERARCHY_NONE + (val & 0x7);
+
+       if (((val >> 3) & 0x3) > 2)
+               p->constellation = QAM_AUTO;
+       else
+               p->constellation = qam_tab[(val >> 3) & 0x3];
+
+       val = cx22700_readreg (state, 0x02);
+
+       if (((val >> 3) & 0x07) > 4)
+               p->code_rate_HP = FEC_AUTO;
+       else
+               p->code_rate_HP = fec_tab[(val >> 3) & 0x07];
+
+       if ((val & 0x07) > 4)
+               p->code_rate_LP = FEC_AUTO;
+       else
+               p->code_rate_LP = fec_tab[val & 0x07];
+
+       val = cx22700_readreg (state, 0x03);
+
+       p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
+       p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
+
+       return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+static int cx22700_init (struct dvb_frontend* fe)
+
+{      struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+       int i;
+
+       dprintk("cx22700_init: init chip\n");
+
+       cx22700_writereg (state, 0x00, 0x02);   /*  soft reset */
+       cx22700_writereg (state, 0x00, 0x00);
+
+       msleep(10);
+
+       for (i=0; i<sizeof(init_tab); i+=2)
+               cx22700_writereg (state, init_tab[i], init_tab[i+1]);
+
+       cx22700_writereg (state, 0x00, 0x01);
+
+       if (state->config->pll_init) {
+               cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
+               state->config->pll_init(fe);
+               cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
+       }
+
+       return 0;
+}
+
+static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+       u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+                  | (cx22700_readreg (state, 0x0e) << 1);
+       u8 sync = cx22700_readreg (state, 0x07);
+
+       *status = 0;
+
+       if (rs_ber < 0xff00)
+               *status |= FE_HAS_SIGNAL;
+
+       if (sync & 0x20)
+               *status |= FE_HAS_CARRIER;
+
+       if (sync & 0x10)
+               *status |= FE_HAS_VITERBI;
+
+       if (sync & 0x10)
+               *status |= FE_HAS_SYNC;
+
+       if (*status == 0x0f)
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+       *ber = cx22700_readreg (state, 0x0c) & 0x7f;
+       cx22700_writereg (state, 0x0c, 0x00);
+
+       return 0;
+}
+
+static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+       u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+                  | (cx22700_readreg (state, 0x0e) << 1);
+       *signal_strength = ~rs_ber;
+
+       return 0;
+}
+
+static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+       u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9)
+                  | (cx22700_readreg (state, 0x0e) << 1);
+       *snr = ~rs_ber;
+
+       return 0;
+}
+
+static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+       *ucblocks = cx22700_readreg (state, 0x0f);
+       cx22700_writereg (state, 0x0f, 0x00);
+
+       return 0;
+}
+
+static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+
+       cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
+       cx22700_writereg (state, 0x00, 0x00);
+
+       cx22700_writereg (state, 0x0a, 0x00);  /* open i2c bus switch */
+       state->config->pll_set(fe, p);
+       cx22700_writereg (state, 0x0a, 0x01);  /* close i2c bus switch */
+       cx22700_set_inversion (state, p->inversion);
+       cx22700_set_tps (state, &p->u.ofdm);
+       cx22700_writereg (state, 0x37, 0x01);  /* PAL loop filter off */
+       cx22700_writereg (state, 0x00, 0x01);  /* restart acquire */
+
+       return 0;
+}
+
+static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+       u8 reg09 = cx22700_readreg (state, 0x09);
+
+       p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
+       return cx22700_get_tps (state, &p->u.ofdm);
+}
+
+static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+        fesettings->min_delay_ms = 150;
+        fesettings->step_size = 166667;
+        fesettings->max_drift = 166667*2;
+        return 0;
+}
+
+static void cx22700_release(struct dvb_frontend* fe)
+{
+       struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops cx22700_ops;
+
+struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct cx22700_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct cx22700_state*) kmalloc(sizeof(struct cx22700_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
+
+       /* check if the demod is there */
+       if (cx22700_readreg(state, 0x07) < 0) goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops cx22700_ops = {
+
+       .info = {
+               .name                   = "Conexant CX22700 DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 470000000,
+               .frequency_max          = 860000000,
+               .frequency_stepsize     = 166667,
+               .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_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                     FE_CAN_RECOVER
+       },
+
+       .release = cx22700_release,
+
+       .init = cx22700_init,
+
+       .set_frontend = cx22700_set_frontend,
+       .get_frontend = cx22700_get_frontend,
+       .get_tune_settings = cx22700_get_tune_settings,
+
+       .read_status = cx22700_read_status,
+       .read_ber = cx22700_read_ber,
+       .read_signal_strength = cx22700_read_signal_strength,
+       .read_snr = cx22700_read_snr,
+       .read_ucblocks = cx22700_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx22700_attach);
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
new file mode 100644 (file)
index 0000000..c9145b4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    Conexant CX22700 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+       Holger Waechtler <holger@convergence.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 CX22700_H
+#define CX22700_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx22700_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif // CX22700_H
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
new file mode 100644 (file)
index 0000000..15ae903
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+    Conexant 22702 DVB OFDM demodulator driver
+
+    based on:
+        Alps TDMB7 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+         Holger Waechtler <holger@convergence.de>
+
+    Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "cx22702.h"
+
+
+struct cx22702_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct cx22702_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* previous uncorrected block counter */
+       u8 prevUCBlocks;
+};
+
+static int debug = 0;
+#define dprintk        if (debug) printk
+
+/* Register values to initialise the demod */
+static u8 init_tab [] = {
+       0x00, 0x00, /* Stop aquisition */
+       0x0B, 0x06,
+       0x09, 0x01,
+       0x0D, 0x41,
+       0x16, 0x32,
+       0x20, 0x0A,
+       0x21, 0x17,
+       0x24, 0x3e,
+       0x26, 0xff,
+       0x27, 0x10,
+       0x28, 0x00,
+       0x29, 0x00,
+       0x2a, 0x10,
+       0x2b, 0x00,
+       0x2c, 0x10,
+       0x2d, 0x00,
+       0x48, 0xd4,
+       0x49, 0x56,
+       0x6b, 0x1e,
+       0xc8, 0x02,
+       0xf8, 0x02,
+       0xf9, 0x00,
+       0xfa, 0x00,
+       0xfb, 0x00,
+       0xfc, 0x00,
+       0xfd, 0x00,
+};
+
+static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf [] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+                       __FUNCTION__, reg, data, ret);
+
+       return (ret != 1) ? -1 : 0;
+}
+
+static u8 cx22702_readreg (struct cx22702_state* state, u8 reg)
+{
+       int ret;
+       u8 b0 [] = { reg };
+       u8 b1 [] = { 0 };
+
+       struct i2c_msg msg [] = {
+               { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+               { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+       return b1[0];
+}
+
+static int cx22702_set_inversion (struct cx22702_state *state, int inversion)
+{
+       u8 val;
+
+       switch (inversion) {
+
+               case INVERSION_AUTO:
+                       return -EOPNOTSUPP;
+
+               case INVERSION_ON:
+                       val = cx22702_readreg (state, 0x0C);
+                       return cx22702_writereg (state, 0x0C, val | 0x01);
+
+               case INVERSION_OFF:
+                       val = cx22702_readreg (state, 0x0C);
+                       return cx22702_writereg (state, 0x0C, val & 0xfe);
+
+               default:
+                       return -EINVAL;
+
+       }
+
+}
+
+/* Retrieve the demod settings */
+static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p)
+{
+       u8 val;
+
+       /* Make sure the TPS regs are valid */
+       if (!(cx22702_readreg(state, 0x0A) & 0x20))
+               return -EAGAIN;
+
+       val = cx22702_readreg (state, 0x01);
+       switch( (val&0x18)>>3) {
+               case 0: p->constellation =   QPSK; break;
+               case 1: p->constellation = QAM_16; break;
+               case 2: p->constellation = QAM_64; break;
+       }
+       switch( val&0x07 ) {
+               case 0: p->hierarchy_information = HIERARCHY_NONE; break;
+               case 1: p->hierarchy_information =    HIERARCHY_1; break;
+               case 2: p->hierarchy_information =    HIERARCHY_2; break;
+               case 3: p->hierarchy_information =    HIERARCHY_4; break;
+       }
+
+
+       val = cx22702_readreg (state, 0x02);
+       switch( (val&0x38)>>3 ) {
+               case 0: p->code_rate_HP = FEC_1_2; break;
+               case 1: p->code_rate_HP = FEC_2_3; break;
+               case 2: p->code_rate_HP = FEC_3_4; break;
+               case 3: p->code_rate_HP = FEC_5_6; break;
+               case 4: p->code_rate_HP = FEC_7_8; break;
+       }
+       switch( val&0x07 ) {
+               case 0: p->code_rate_LP = FEC_1_2; break;
+               case 1: p->code_rate_LP = FEC_2_3; break;
+               case 2: p->code_rate_LP = FEC_3_4; break;
+               case 3: p->code_rate_LP = FEC_5_6; break;
+               case 4: p->code_rate_LP = FEC_7_8; break;
+       }
+
+
+       val = cx22702_readreg (state, 0x03);
+       switch( (val&0x0c)>>2 ) {
+               case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
+               case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
+               case 2: p->guard_interval =  GUARD_INTERVAL_1_8; break;
+               case 3: p->guard_interval =  GUARD_INTERVAL_1_4; break;
+}
+       switch( val&0x03 ) {
+               case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
+               case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+       }
+
+       return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       u8 val;
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       /* set PLL */
+        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+       state->config->pll_set(fe, p);
+        cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+
+       /* set inversion */
+       cx22702_set_inversion (state, p->inversion);
+
+       /* set bandwidth */
+       switch(p->u.ofdm.bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 );
+               break;
+       case BANDWIDTH_7_MHZ:
+               cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 );
+               break;
+       case BANDWIDTH_8_MHZ:
+               cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf );
+               break;
+       default:
+               dprintk ("%s: invalid bandwidth\n",__FUNCTION__);
+               return -EINVAL;
+       }
+
+
+       p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working
+
+       /* use auto configuration? */
+       if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) ||
+          (p->u.ofdm.constellation==QAM_AUTO) ||
+          (p->u.ofdm.code_rate_HP==FEC_AUTO) ||
+          (p->u.ofdm.code_rate_LP==FEC_AUTO) ||
+          (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) ||
+          (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) {
+
+               /* TPS Source - use hardware driven values */
+               cx22702_writereg(state, 0x06, 0x10);
+               cx22702_writereg(state, 0x07, 0x9);
+               cx22702_writereg(state, 0x08, 0xC1);
+               cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
+               cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+               cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
+               printk("%s: Autodetecting\n",__FUNCTION__);
+               return 0;
+       }
+
+       /* manually programmed values */
+       val=0;
+       switch(p->u.ofdm.constellation) {
+               case   QPSK: val = (val&0xe7); break;
+               case QAM_16: val = (val&0xe7)|0x08; break;
+               case QAM_64: val = (val&0xe7)|0x10; break;
+               default:
+                       dprintk ("%s: invalid constellation\n",__FUNCTION__);
+                       return -EINVAL;
+       }
+       switch(p->u.ofdm.hierarchy_information) {
+               case HIERARCHY_NONE: val = (val&0xf8); break;
+               case    HIERARCHY_1: val = (val&0xf8)|1; break;
+               case    HIERARCHY_2: val = (val&0xf8)|2; break;
+               case    HIERARCHY_4: val = (val&0xf8)|3; break;
+               default:
+                       dprintk ("%s: invalid hierarchy\n",__FUNCTION__);
+                       return -EINVAL;
+       }
+       cx22702_writereg (state, 0x06, val);
+
+       val=0;
+       switch(p->u.ofdm.code_rate_HP) {
+               case FEC_NONE:
+               case FEC_1_2: val = (val&0xc7); break;
+               case FEC_2_3: val = (val&0xc7)|0x08; break;
+               case FEC_3_4: val = (val&0xc7)|0x10; break;
+               case FEC_5_6: val = (val&0xc7)|0x18; break;
+               case FEC_7_8: val = (val&0xc7)|0x20; break;
+               default:
+                       dprintk ("%s: invalid code_rate_HP\n",__FUNCTION__);
+                       return -EINVAL;
+       }
+       switch(p->u.ofdm.code_rate_LP) {
+               case FEC_NONE:
+               case FEC_1_2: val = (val&0xf8); break;
+               case FEC_2_3: val = (val&0xf8)|1; break;
+               case FEC_3_4: val = (val&0xf8)|2; break;
+               case FEC_5_6: val = (val&0xf8)|3; break;
+               case FEC_7_8: val = (val&0xf8)|4; break;
+               default:
+                       dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__);
+                       return -EINVAL;
+       }
+       cx22702_writereg (state, 0x07, val);
+
+       val=0;
+       switch(p->u.ofdm.guard_interval) {
+               case GUARD_INTERVAL_1_32: val = (val&0xf3); break;
+               case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break;
+               case  GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break;
+               case  GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break;
+               default:
+                       dprintk ("%s: invalid guard_interval\n",__FUNCTION__);
+                       return -EINVAL;
+       }
+       switch(p->u.ofdm.transmission_mode) {
+               case TRANSMISSION_MODE_2K: val = (val&0xfc); break;
+               case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break;
+               default:
+                       dprintk ("%s: invalid transmission_mode\n",__FUNCTION__);
+                       return -EINVAL;
+       }
+       cx22702_writereg(state, 0x08, val);
+       cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 );
+       cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
+
+       /* Begin channel aquisition */
+       cx22702_writereg(state, 0x00, 0x01);
+
+       return 0;
+}
+
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int cx22702_init (struct dvb_frontend* fe)
+{
+       int i;
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       cx22702_writereg (state, 0x00, 0x02);
+
+       msleep(10);
+
+       for (i=0; i<sizeof(init_tab); i+=2)
+               cx22702_writereg (state, init_tab[i], init_tab[i+1]);
+
+
+       /* init PLL */
+       if (state->config->pll_init) {
+               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+               state->config->pll_init(fe);
+               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+       }
+
+       return 0;
+}
+
+static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+       u8 reg0A;
+       u8 reg23;
+
+                       *status = 0;
+
+       reg0A = cx22702_readreg (state, 0x0A);
+       reg23 = cx22702_readreg (state, 0x23);
+
+                       dprintk ("%s: status demod=0x%02x agc=0x%02x\n"
+                               ,__FUNCTION__,reg0A,reg23);
+
+                       if(reg0A & 0x10) {
+                               *status |= FE_HAS_LOCK;
+                               *status |= FE_HAS_VITERBI;
+                               *status |= FE_HAS_SYNC;
+                       }
+
+                       if(reg0A & 0x20)
+                               *status |= FE_HAS_CARRIER;
+
+                       if(reg23 < 0xf0)
+                               *status |= FE_HAS_SIGNAL;
+
+       return 0;
+                       }
+
+static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber)
+               {
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       if(cx22702_readreg (state, 0xE4) & 0x02) {
+                               /* Realtime statistics */
+               *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
+                       | (cx22702_readreg (state, 0xDF)&0x7F);
+                       } else {
+               /* Averagtine statistics */
+               *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
+                       | cx22702_readreg (state, 0xDF);
+               }
+
+       return 0;
+               }
+
+static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+               {
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       *signal_strength = cx22702_readreg (state, 0x23);
+
+       return 0;
+}
+
+static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       u16 rs_ber=0;
+       if(cx22702_readreg (state, 0xE4) & 0x02) {
+               /* Realtime statistics */
+               rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7
+                       | (cx22702_readreg (state, 0xDF)& 0x7F);
+       } else {
+               /* Averagine statistics */
+               rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8
+                       | cx22702_readreg (state, 0xDF);
+       }
+       *snr = ~rs_ber;
+
+       return 0;
+}
+
+static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       u8 _ucblocks;
+
+       /* RS Uncorrectable Packet Count then reset */
+       _ucblocks = cx22702_readreg (state, 0xE3);
+       if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks);
+       else *ucblocks = state->prevUCBlocks - _ucblocks;
+       state->prevUCBlocks = _ucblocks;
+
+       return 0;
+}
+
+static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+
+       u8 reg0C = cx22702_readreg (state, 0x0C);
+
+       p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
+       return cx22702_get_tps (state, &p->u.ofdm);
+}
+
+static void cx22702_release(struct dvb_frontend* fe)
+{
+       struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv;
+               kfree(state);
+       }
+
+static struct dvb_frontend_ops cx22702_ops;
+
+struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct cx22702_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
+       state->prevUCBlocks = 0;
+
+       /* check if the demod is there */
+       if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops cx22702_ops = {
+
+       .info = {
+               .name                   = "Conexant CX22702 DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 177000000,
+               .frequency_max          = 858000000,
+               .frequency_stepsize     = 166666,
+               .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_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+               FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+               FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+       },
+
+       .release = cx22702_release,
+
+       .init = cx22702_init,
+
+       .set_frontend = cx22702_set_tps,
+       .get_frontend = cx22702_get_frontend,
+
+       .read_status = cx22702_read_status,
+       .read_ber = cx22702_read_ber,
+       .read_signal_strength = cx22702_read_signal_strength,
+       .read_snr = cx22702_read_snr,
+       .read_ucblocks = cx22702_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cx22702_attach);
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
new file mode 100644 (file)
index 0000000..6e34f99
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    Conexant 22702 DVB OFDM demodulator driver
+
+    based on:
+        Alps TDMB7 DVB OFDM demodulator driver
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+         Holger Waechtler <holger@convergence.de>
+
+    Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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 CX22702_H
+#define CX22702_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx22702_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif // CX22702_H
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
new file mode 100644 (file)
index 0000000..6b663f4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    cx24110 - Single Chip Satellite Channel Receiver driver module
+
+    Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on
+    work
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.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 CX24110_H
+#define CX24110_H
+
+#include <linux/dvb/frontend.h>
+
+struct cx24110_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+                                          struct i2c_adapter* i2c);
+
+extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data);
+
+#endif // CX24110_H
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
new file mode 100644 (file)
index 0000000..3a1b892
--- /dev/null
@@ -0,0 +1,145 @@
+#include "dib3000-common.h"
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
+#endif
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...) dprintk(0x02,args)
+#define deb_srch(args...) dprintk(0x04,args)
+
+
+int dib3000_read_reg(struct dib3000_state *state, u16 reg)
+{
+       u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+       u8 rb[2];
+       struct i2c_msg msg[] = {
+               { .addr = state->config.demod_address, .flags = 0,        .buf = wb, .len = 2 },
+               { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+       };
+
+       if (i2c_transfer(state->i2c, msg, 2) != 2)
+               deb_i2c("i2c read error\n");
+
+       deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
+                       (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
+
+       return (rb[0] << 8) | rb[1];
+}
+
+int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
+{
+       u8 b[] = {
+               (reg >> 8) & 0xff, reg & 0xff,
+               (val >> 8) & 0xff, val & 0xff,
+       };
+       struct i2c_msg msg[] = {
+               { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
+       };
+       deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
+
+       return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+int dib3000_init_pid_list(struct dib3000_state *state, int num)
+{
+       int i;
+       if (state != NULL) {
+               state->pid_list = kmalloc(sizeof(struct dib3000_pid) * num,GFP_KERNEL);
+               if (state->pid_list == NULL)
+                       return -ENOMEM;
+
+               deb_info("initializing %d pids for the pid_list.\n",num);
+               state->pid_list_lock = SPIN_LOCK_UNLOCKED;
+               memset(state->pid_list,0,num*(sizeof(struct dib3000_pid)));
+               for (i=0; i < num; i++) {
+                       state->pid_list[i].pid = 0;
+                       state->pid_list[i].active = 0;
+               }
+               state->feedcount = 0;
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+void dib3000_dealloc_pid_list(struct dib3000_state *state)
+{
+       if (state != NULL && state->pid_list != NULL)
+               kfree(state->pid_list);
+}
+
+/* fetch a pid from pid_list */
+int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids, int pid,
+               spinlock_t *pid_list_lock,int onoff)
+{
+       int i,ret = -1;
+       unsigned long flags;
+
+       spin_lock_irqsave(pid_list_lock,flags);
+       for (i=0; i < num_pids; i++)
+               if (onoff) {
+                       if (!pid_list[i].active) {
+                               pid_list[i].pid = pid;
+                               pid_list[i].active = 1;
+                               ret = i;
+                               break;
+                       }
+               } else {
+                       if (pid_list[i].active && pid_list[i].pid == pid) {
+                               pid_list[i].pid = 0;
+                               pid_list[i].active = 0;
+                               ret = i;
+                               break;
+                       }
+               }
+
+       deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off");
+
+       spin_unlock_irqrestore(pid_list_lock,flags);
+       return ret;
+}
+
+int dib3000_search_status(u16 irq,u16 lock)
+{
+       if (irq & 0x02) {
+               if (lock & 0x01) {
+                       deb_srch("auto search succeeded\n");
+                       return 1; // auto search succeeded
+               } else {
+                       deb_srch("auto search not successful\n");
+                       return 0; // auto search failed
+               }
+       } else if (irq & 0x01)  {
+               deb_srch("auto search failed\n");
+               return 0; // auto search failed
+       }
+       return -1; // try again
+}
+
+/* for auto search */
+u16 dib3000_seq[2][2][2] =     /* fft,gua,   inv   */
+       { /* fft */
+               { /* gua */
+                       { 0, 1 },                   /*  0   0   { 0,1 } */
+                       { 3, 9 },                   /*  0   1   { 0,1 } */
+               },
+               {
+                       { 2, 5 },                   /*  1   0   { 0,1 } */
+                       { 6, 11 },                  /*  1   1   { 0,1 } */
+               }
+       };
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
+MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000_seq);
+
+EXPORT_SYMBOL(dib3000_read_reg);
+EXPORT_SYMBOL(dib3000_write_reg);
+EXPORT_SYMBOL(dib3000_init_pid_list);
+EXPORT_SYMBOL(dib3000_dealloc_pid_list);
+EXPORT_SYMBOL(dib3000_get_pid_index);
+EXPORT_SYMBOL(dib3000_search_status);
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
new file mode 100644 (file)
index 0000000..2537a12
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * .h-files for the common use of the frontend drivers made by DiBcom
+ * DiBcom 3000-MB/MC/P
+ *
+ * DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004 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.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ *
+ */
+
+#ifndef DIB3000_COMMON_H
+#define DIB3000_COMMON_H
+
+#include "dvb_frontend.h"
+#include "dib3000.h"
+
+/* info and err, taken from usb.h, if there is anything available like by default,
+ * please change !
+ */
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+
+/* a PID for the pid_filter list, when in use */
+struct dib3000_pid
+{
+       u16 pid;
+       int active;
+};
+
+/* frontend state */
+struct dib3000_state {
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+/* configuration settings */
+       struct dib3000_config config;
+
+       spinlock_t pid_list_lock;
+       struct dib3000_pid *pid_list;
+
+       int feedcount;
+
+       struct dvb_frontend frontend;
+       int timing_offset;
+       int timing_offset_comp_done;
+};
+
+/* commonly used methods by the dib3000mb/mc/p frontend */
+extern int dib3000_read_reg(struct dib3000_state *state, u16 reg);
+extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val);
+
+extern int dib3000_init_pid_list(struct dib3000_state *state, int num);
+extern void dib3000_dealloc_pid_list(struct dib3000_state *state);
+extern int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids,
+       int pid, spinlock_t *pid_list_lock,int onoff);
+
+extern int dib3000_search_status(u16 irq,u16 lock);
+
+/* handy shortcuts */
+#define rd(reg) dib3000_read_reg(state,reg)
+
+#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
+       { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+
+#define wr_foreach(a,v) { int i; \
+       if (sizeof(a) != sizeof(v)) \
+               err("sizeof: %d %d is different",sizeof(a),sizeof(v));\
+       for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+               wr(a[i],v[i]); \
+       }
+
+#define set_or(reg,val) wr(reg,rd(reg) | val)
+
+#define set_and(reg,val) wr(reg,rd(reg) & val)
+
+
+/* debug */
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk(level,args...) \
+    do { if ((debug & level)) { printk(args); } } while (0)
+#else
+#define dprintk(args...) do { } while (0)
+#endif
+
+/* mask for enabling a specific pid for the pid_filter */
+#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
+
+/* common values for tuning */
+#define DIB3000_ALPHA_0                                        (     0)
+#define DIB3000_ALPHA_1                                        (     1)
+#define DIB3000_ALPHA_2                                        (     2)
+#define DIB3000_ALPHA_4                                        (     4)
+
+#define DIB3000_CONSTELLATION_QPSK             (     0)
+#define DIB3000_CONSTELLATION_16QAM            (     1)
+#define DIB3000_CONSTELLATION_64QAM            (     2)
+
+#define DIB3000_GUARD_TIME_1_32                        (     0)
+#define DIB3000_GUARD_TIME_1_16                        (     1)
+#define DIB3000_GUARD_TIME_1_8                 (     2)
+#define DIB3000_GUARD_TIME_1_4                 (     3)
+
+#define DIB3000_TRANSMISSION_MODE_2K   (     0)
+#define DIB3000_TRANSMISSION_MODE_8K   (     1)
+
+#define DIB3000_SELECT_LP                              (     0)
+#define DIB3000_SELECT_HP                              (     1)
+
+#define DIB3000_FEC_1_2                                        (     1)
+#define DIB3000_FEC_2_3                                        (     2)
+#define DIB3000_FEC_3_4                                        (     3)
+#define DIB3000_FEC_5_6                                        (     5)
+#define DIB3000_FEC_7_8                                        (     7)
+
+#define DIB3000_HRCH_OFF                               (     0)
+#define DIB3000_HRCH_ON                                        (     1)
+
+#define DIB3000_DDS_INVERSION_OFF              (     0)
+#define DIB3000_DDS_INVERSION_ON               (     1)
+
+#define DIB3000_TUNER_WRITE_ENABLE(a)  (0xffff & (a << 7))
+#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 7) | (1 << 7)))
+
+/* for auto search */
+extern u16 dib3000_seq[2][2][2];
+
+#define DIB3000_REG_MANUFACTOR_ID              (  1025)
+#define DIB3000_I2C_ID_DIBCOM                  (0x01b3)
+
+#define DIB3000_REG_DEVICE_ID                  (  1026)
+#define DIB3000MB_DEVICE_ID                            (0x3000)
+#define DIB3000MC_DEVICE_ID                            (0x3001)
+#define DIB3000P_DEVICE_ID                             (0x3002)
+
+#endif // DIB3000_COMMON_H
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
new file mode 100644 (file)
index 0000000..c6b6cae
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * public header file of the frontend drivers for mobile DVB-T demodulators
+ * DiBcom 3000-MB and DiBcom 3000-MC/P (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004 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.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ *
+ */
+
+#ifndef DIB3000_H
+#define DIB3000_H
+
+#include <linux/dvb/frontend.h>
+
+struct dib3000_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* The i2c address of the PLL */
+       u8 pll_addr;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend *fe);
+       int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
+};
+
+struct dib3000_xfer_ops
+{
+       /* pid and transfer handling is done in the demodulator */
+       int (*pid_parse)(struct dvb_frontend *fe, int onoff);
+       int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff);
+       int (*pid_ctrl)(struct dvb_frontend *fe, int pid, int onoff);
+};
+
+extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+                                            struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops);
+
+extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
+                                            struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops);
+#endif // DIB3000_H
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
new file mode 100644 (file)
index 0000000..37eaa74
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB
+ * DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004 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.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "dib3000-common.h"
+#include "dib3000mb_priv.h"
+#include "dib3000.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
+#endif
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_xfer(args...) dprintk(0x02,args)
+#define deb_setf(args...) dprintk(0x04,args)
+#define deb_getf(args...) dprintk(0x08,args)
+
+static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep);
+
+static int dib3000mb_set_frontend(struct dvb_frontend* fe,
+               struct dvb_frontend_parameters *fep, int tuner)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+       fe_code_rate_t fe_cr = FEC_NONE;
+       int search_state,seq;
+
+       if (tuner) {
+               wr(DIB3000MB_REG_TUNER,
+                               DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
+               state->config.pll_set(fe, fep);
+               wr(DIB3000MB_REG_TUNER,
+                               DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
+
+               deb_setf("bandwidth: ");
+               switch (ofdm->bandwidth) {
+                       case BANDWIDTH_8_MHZ:
+                               deb_setf("8 MHz\n");
+                               wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
+                               wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+                               break;
+                       case BANDWIDTH_7_MHZ:
+                               deb_setf("7 MHz\n");
+                               wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[1]);
+                               wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_7mhz);
+                               break;
+                       case BANDWIDTH_6_MHZ:
+                               deb_setf("6 MHz\n");
+                               wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[0]);
+                               wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_6mhz);
+                               break;
+                       case BANDWIDTH_AUTO:
+                               return -EOPNOTSUPP;
+                       default:
+                               err("unkown bandwidth value.");
+                               return -EINVAL;
+               }
+       }
+       wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
+
+       deb_setf("transmission mode: ");
+       switch (ofdm->transmission_mode) {
+               case TRANSMISSION_MODE_2K:
+                       deb_setf("2k\n");
+                       wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K);
+                       break;
+               case TRANSMISSION_MODE_8K:
+                       deb_setf("8k\n");
+                       wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K);
+                       break;
+               case TRANSMISSION_MODE_AUTO:
+                       deb_setf("auto\n");
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       deb_setf("guard: ");
+       switch (ofdm->guard_interval) {
+               case GUARD_INTERVAL_1_32:
+                       deb_setf("1_32\n");
+                       wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32);
+                       break;
+               case GUARD_INTERVAL_1_16:
+                       deb_setf("1_16\n");
+                       wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16);
+                       break;
+               case GUARD_INTERVAL_1_8:
+                       deb_setf("1_8\n");
+                       wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8);
+                       break;
+               case GUARD_INTERVAL_1_4:
+                       deb_setf("1_4\n");
+                       wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4);
+                       break;
+               case GUARD_INTERVAL_AUTO:
+                       deb_setf("auto\n");
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       deb_setf("inversion: ");
+       switch (fep->inversion) {
+               case INVERSION_OFF:
+                       deb_setf("off\n");
+                       wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF);
+                       break;
+               case INVERSION_AUTO:
+                       deb_setf("auto ");
+                       break;
+               case INVERSION_ON:
+                       deb_setf("on\n");
+                       wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       deb_setf("constellation: ");
+       switch (ofdm->constellation) {
+               case QPSK:
+                       deb_setf("qpsk\n");
+                       wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK);
+                       break;
+               case QAM_16:
+                       deb_setf("qam16\n");
+                       wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM);
+                       break;
+               case QAM_64:
+                       deb_setf("qam64\n");
+                       wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM);
+                       break;
+               case QAM_AUTO:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       deb_setf("hierachy: "); 
+       switch (ofdm->hierarchy_information) {
+               case HIERARCHY_NONE:
+                       deb_setf("none ");
+                       /* fall through */
+               case HIERARCHY_1:
+                       deb_setf("alpha=1\n");  
+                       wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1);
+                       break;
+               case HIERARCHY_2:
+                       deb_setf("alpha=2\n");  
+                       wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2);
+                       break;
+               case HIERARCHY_4:
+                       deb_setf("alpha=4\n");  
+                       wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4);
+                       break;
+               case HIERARCHY_AUTO:
+                       deb_setf("alpha=auto\n");       
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       deb_setf("hierarchy: ");
+       if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+               deb_setf("none\n");
+               wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF);
+               wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP);
+               fe_cr = ofdm->code_rate_HP;
+       } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
+               deb_setf("on\n");
+               wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON);
+               wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP);
+               fe_cr = ofdm->code_rate_LP;
+       }
+       deb_setf("fec: ");
+       switch (fe_cr) {
+               case FEC_1_2:
+                       deb_setf("1_2\n");
+                       wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2);
+                       break;
+               case FEC_2_3:
+                       deb_setf("2_3\n");
+                       wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3);
+                       break;
+               case FEC_3_4:
+                       deb_setf("3_4\n");
+                       wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4);
+                       break;
+               case FEC_5_6:
+                       deb_setf("5_6\n");
+                       wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6);
+                       break;
+               case FEC_7_8:
+                       deb_setf("7_8\n");
+                       wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8);
+                       break;
+               case FEC_NONE:
+                       deb_setf("none ");
+                       break;
+               case FEC_AUTO:
+                       deb_setf("auto\n");
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       seq = dib3000_seq
+               [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
+               [ofdm->guard_interval == GUARD_INTERVAL_AUTO]
+               [fep->inversion == INVERSION_AUTO];
+
+       deb_setf("seq? %d\n",seq);
+
+       wr(DIB3000MB_REG_SEQ,seq);
+
+       wr(DIB3000MB_REG_ISI,seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE);
+
+       if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) {
+               if (ofdm->guard_interval == GUARD_INTERVAL_1_8) {
+                       wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_2K_1_8);
+               } else {
+                       wr(DIB3000MB_REG_SYNC_IMPROVEMENT,DIB3000MB_SYNC_IMPROVE_DEFAULT);
+               }
+
+               wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_2K);
+       } else {
+               wr(DIB3000MB_REG_UNK_121,DIB3000MB_UNK_121_DEFAULT);
+       }
+
+       wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_OFF);
+       wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
+       wr(DIB3000MB_REG_MOBILE_MODE,DIB3000MB_MOBILE_MODE_OFF);
+
+       wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_high);
+
+       wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_ACTIVATE);
+
+       wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AGC+DIB3000MB_RESTART_CTRL);
+       wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+
+       /* wait for AGC lock */
+       msleep(70);
+
+       wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
+
+       /* something has to be auto searched */
+       if (ofdm->constellation == QAM_AUTO ||
+               ofdm->hierarchy_information == HIERARCHY_AUTO ||
+               fe_cr == FEC_AUTO ||
+               fep->inversion == INVERSION_AUTO) {
+               int as_count=0;
+
+               deb_setf("autosearch enabled.\n");      
+
+               wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
+
+               wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AUTO_SEARCH);
+               wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+
+               while ((search_state =
+                               dib3000_search_status(
+                                       rd(DIB3000MB_REG_AS_IRQ_PENDING),
+                                       rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100)
+                       msleep(1);
+
+               deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
+
+               if (search_state == 1) {
+                       struct dvb_frontend_parameters feps;
+                       if (dib3000mb_get_frontend(fe, &feps) == 0) {
+                               deb_setf("reading tuning data from frontend succeeded.\n");
+                               return dib3000mb_set_frontend(fe, &feps, 0);
+                       }
+               }
+
+       } else {
+               wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL);
+               wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF);
+       }
+
+       return 0;
+}
+
+static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP);
+
+       wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC);
+
+       wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE);
+       wr(DIB3000MB_REG_RESET_DEVICE,DIB3000MB_RESET_DEVICE_RST);
+
+       wr(DIB3000MB_REG_CLOCK,DIB3000MB_CLOCK_DEFAULT);
+
+       wr(DIB3000MB_REG_ELECT_OUT_MODE,DIB3000MB_ELECT_OUT_MODE_ON);
+
+       wr(DIB3000MB_REG_DDS_FREQ_MSB,DIB3000MB_DDS_FREQ_MSB);
+       wr(DIB3000MB_REG_DDS_FREQ_LSB,DIB3000MB_DDS_FREQ_LSB);
+
+       wr_foreach(dib3000mb_reg_timing_freq,dib3000mb_timing_freq[2]);
+
+       wr_foreach(dib3000mb_reg_impulse_noise,
+                       dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]);
+
+       wr_foreach(dib3000mb_reg_agc_gain,dib3000mb_default_agc_gain);
+
+       wr(DIB3000MB_REG_PHASE_NOISE,DIB3000MB_PHASE_NOISE_DEFAULT);
+
+       wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase);
+
+       wr_foreach(dib3000mb_reg_lock_duration,dib3000mb_default_lock_duration);
+
+       wr_foreach(dib3000mb_reg_agc_bandwidth,dib3000mb_agc_bandwidth_low);
+
+       wr(DIB3000MB_REG_LOCK0_MASK,DIB3000MB_LOCK0_DEFAULT);
+       wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4);
+       wr(DIB3000MB_REG_LOCK2_MASK,DIB3000MB_LOCK2_DEFAULT);
+       wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]);
+
+       wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz);
+
+       wr(DIB3000MB_REG_UNK_68,DIB3000MB_UNK_68);
+       wr(DIB3000MB_REG_UNK_69,DIB3000MB_UNK_69);
+       wr(DIB3000MB_REG_UNK_71,DIB3000MB_UNK_71);
+       wr(DIB3000MB_REG_UNK_77,DIB3000MB_UNK_77);
+       wr(DIB3000MB_REG_UNK_78,DIB3000MB_UNK_78);
+       wr(DIB3000MB_REG_ISI,DIB3000MB_ISI_INHIBIT);
+       wr(DIB3000MB_REG_UNK_92,DIB3000MB_UNK_92);
+       wr(DIB3000MB_REG_UNK_96,DIB3000MB_UNK_96);
+       wr(DIB3000MB_REG_UNK_97,DIB3000MB_UNK_97);
+       wr(DIB3000MB_REG_UNK_106,DIB3000MB_UNK_106);
+       wr(DIB3000MB_REG_UNK_107,DIB3000MB_UNK_107);
+       wr(DIB3000MB_REG_UNK_108,DIB3000MB_UNK_108);
+       wr(DIB3000MB_REG_UNK_122,DIB3000MB_UNK_122);
+       wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF);
+       wr(DIB3000MB_REG_BERLEN,DIB3000MB_BERLEN_DEFAULT);
+
+       wr_foreach(dib3000mb_reg_filter_coeffs,dib3000mb_filter_coeffs);
+
+       wr(DIB3000MB_REG_MOBILE_ALGO,DIB3000MB_MOBILE_ALGO_ON);
+       wr(DIB3000MB_REG_MULTI_DEMOD_MSB,DIB3000MB_MULTI_DEMOD_MSB);
+       wr(DIB3000MB_REG_MULTI_DEMOD_LSB,DIB3000MB_MULTI_DEMOD_LSB);
+
+       wr(DIB3000MB_REG_OUTPUT_MODE,DIB3000MB_OUTPUT_MODE_SLAVE);
+
+       wr(DIB3000MB_REG_FIFO_142,DIB3000MB_FIFO_142);
+       wr(DIB3000MB_REG_MPEG2_OUT_MODE,DIB3000MB_MPEG2_OUT_MODE_188);
+       wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE);
+       wr(DIB3000MB_REG_FIFO,DIB3000MB_FIFO_INHIBIT);
+       wr(DIB3000MB_REG_FIFO_146,DIB3000MB_FIFO_146);
+       wr(DIB3000MB_REG_FIFO_147,DIB3000MB_FIFO_147);
+
+       wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF);
+
+       if (state->config.pll_init) {
+               wr(DIB3000MB_REG_TUNER,
+                       DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
+               state->config.pll_init(fe);
+               wr(DIB3000MB_REG_TUNER,
+                       DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
+       }
+
+       return 0;
+}
+
+static int dib3000mb_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+       fe_code_rate_t *cr;
+       u16 tps_val;
+       int inv_test1,inv_test2;
+       u32 dds_val, threshold = 0x800000;
+
+       if (!rd(DIB3000MB_REG_TPS_LOCK))
+               return 0;
+
+       dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB);
+       if (dds_val < threshold)
+               inv_test1 = 0;
+       else if (dds_val == threshold)
+               inv_test1 = 1;
+       else
+               inv_test1 = 2;
+
+       dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB);
+       if (dds_val < threshold)
+               inv_test2 = 0;
+       else if (dds_val == threshold)
+               inv_test2 = 1;
+       else
+               inv_test2 = 2;
+
+       fep->inversion =
+               ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
+               ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
+               INVERSION_ON : INVERSION_OFF;
+
+       deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+
+       switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) {
+               case DIB3000_CONSTELLATION_QPSK:
+                       deb_getf("QPSK ");
+                       ofdm->constellation = QPSK;
+                       break;
+               case DIB3000_CONSTELLATION_16QAM:
+                       deb_getf("QAM16 ");
+                       ofdm->constellation = QAM_16;
+                       break;
+               case DIB3000_CONSTELLATION_64QAM:
+                       deb_getf("QAM64 ");
+                       ofdm->constellation = QAM_64;
+                       break;
+               default:
+                       err("Unexpected constellation returned by TPS (%d)", tps_val);
+                       break;
+       }
+       deb_getf("TPS: %d\n", tps_val);
+
+       if (rd(DIB3000MB_REG_TPS_HRCH)) {
+               deb_getf("HRCH ON\n");
+               cr = &ofdm->code_rate_LP;
+               ofdm->code_rate_HP = FEC_NONE;
+               switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) {
+                       case DIB3000_ALPHA_0:
+                               deb_getf("HIERARCHY_NONE ");
+                               ofdm->hierarchy_information = HIERARCHY_NONE;
+                               break;
+                       case DIB3000_ALPHA_1:
+                               deb_getf("HIERARCHY_1 ");
+                               ofdm->hierarchy_information = HIERARCHY_1;
+                               break;
+                       case DIB3000_ALPHA_2:
+                               deb_getf("HIERARCHY_2 ");
+                               ofdm->hierarchy_information = HIERARCHY_2;
+                               break;
+                       case DIB3000_ALPHA_4:
+                               deb_getf("HIERARCHY_4 ");
+                               ofdm->hierarchy_information = HIERARCHY_4;
+                               break;
+                       default:
+                               err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
+                               break;
+               }
+               deb_getf("TPS: %d\n", tps_val);
+
+               tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP);
+       } else {
+               deb_getf("HRCH OFF\n");
+               cr = &ofdm->code_rate_HP;
+               ofdm->code_rate_LP = FEC_NONE;
+               ofdm->hierarchy_information = HIERARCHY_NONE;
+
+               tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP);
+       }
+
+       switch (tps_val) {
+               case DIB3000_FEC_1_2:
+                       deb_getf("FEC_1_2 ");
+                       *cr = FEC_1_2;
+                       break;
+               case DIB3000_FEC_2_3:
+                       deb_getf("FEC_2_3 ");
+                       *cr = FEC_2_3;
+                       break;
+               case DIB3000_FEC_3_4:
+                       deb_getf("FEC_3_4 ");
+                       *cr = FEC_3_4;
+                       break;
+               case DIB3000_FEC_5_6:
+                       deb_getf("FEC_5_6 ");
+                       *cr = FEC_4_5;
+                       break;
+               case DIB3000_FEC_7_8:
+                       deb_getf("FEC_7_8 ");
+                       *cr = FEC_7_8;
+                       break;
+               default:
+                       err("Unexpected FEC returned by TPS (%d)", tps_val);
+                       break;
+       }
+       deb_getf("TPS: %d\n",tps_val);
+
+       switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) {
+               case DIB3000_GUARD_TIME_1_32:
+                       deb_getf("GUARD_INTERVAL_1_32 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_32;
+                       break;
+               case DIB3000_GUARD_TIME_1_16:
+                       deb_getf("GUARD_INTERVAL_1_16 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_16;
+                       break;
+               case DIB3000_GUARD_TIME_1_8:
+                       deb_getf("GUARD_INTERVAL_1_8 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_8;
+                       break;
+               case DIB3000_GUARD_TIME_1_4:
+                       deb_getf("GUARD_INTERVAL_1_4 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_4;
+                       break;
+               default:
+                       err("Unexpected Guard Time returned by TPS (%d)", tps_val);
+                       break;
+       }
+       deb_getf("TPS: %d\n", tps_val);
+
+       switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) {
+               case DIB3000_TRANSMISSION_MODE_2K:
+                       deb_getf("TRANSMISSION_MODE_2K ");
+                       ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+                       break;
+               case DIB3000_TRANSMISSION_MODE_8K:
+                       deb_getf("TRANSMISSION_MODE_8K ");
+                       ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+                       break;
+               default:
+                       err("unexpected transmission mode return by TPS (%d)", tps_val);
+                       break;
+       }
+       deb_getf("TPS: %d\n", tps_val);
+
+       return 0;
+}
+
+static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       *stat = 0;
+
+       if (rd(DIB3000MB_REG_AGC_LOCK))
+               *stat |= FE_HAS_SIGNAL;
+       if (rd(DIB3000MB_REG_CARRIER_LOCK))
+               *stat |= FE_HAS_CARRIER;
+       if (rd(DIB3000MB_REG_VIT_LCK))
+               *stat |= FE_HAS_VITERBI;
+       if (rd(DIB3000MB_REG_TS_SYNC_LOCK))
+               *stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
+
+       deb_info("actual status is %2x\n",*stat);
+
+       deb_getf("tps %x %x %x %x %x\n",
+                       rd(DIB3000MB_REG_TPS_1),
+                       rd(DIB3000MB_REG_TPS_2),
+                       rd(DIB3000MB_REG_TPS_3),
+                       rd(DIB3000MB_REG_TPS_4),
+                       rd(DIB3000MB_REG_TPS_5));
+       
+       deb_info("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n",
+                       rd(DIB3000MB_REG_TPS_LOCK),
+                       rd(DIB3000MB_REG_TPS_QAM),
+                       rd(DIB3000MB_REG_TPS_HRCH),
+                       rd(DIB3000MB_REG_TPS_VIT_ALPHA),
+                       rd(DIB3000MB_REG_TPS_CODE_RATE_HP),
+                       rd(DIB3000MB_REG_TPS_CODE_RATE_LP),
+                       rd(DIB3000MB_REG_TPS_GUARD_TIME),
+                       rd(DIB3000MB_REG_TPS_FFT),
+                       rd(DIB3000MB_REG_TPS_CELL_ID));
+
+       //*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+       return 0;
+}
+
+static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) );
+       return 0;
+}
+/*
+ * Amaury:
+ * signal strength is measured with dBm (power compared to mW)
+ * the standard range is -90dBm(low power) to -10 dBm (strong power),
+ * but the calibration is done for -100 dBm to 0dBm
+ */
+
+#define DIB3000MB_AGC_REF_dBm          -14
+#define DIB3000MB_GAIN_SLOPE_dBm       100
+#define DIB3000MB_GAIN_DELTA_dBm       -2
+static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+/* TODO log10 
+       u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER), 
+               n_agc_power = rd(DIB3000MB_REG_AGC_POWER),
+               rf_power = rd(DIB3000MB_REG_RF_POWER);
+       double rf_power_dBm, ad_power_dBm, minar_power_dBm;
+       
+       if (n_agc_power == 0 )
+               n_agc_power = 1 ;
+
+       ad_power_dBm    = 10 * log10 ( (float)n_agc_power / (float)(1<<16) );
+       minor_power_dBm = ad_power_dBm - DIB3000MB_AGC_REF_dBm;
+       rf_power_dBm = (-DIB3000MB_GAIN_SLOPE_dBm * (float)rf_power / (float)(1<<16) + 
+                       DIB3000MB_GAIN_DELTA_dBm) + minor_power_dBm;
+       // relative rf_power 
+       *strength = (u16) ((rf_power_dBm + 100) / 100 * 0xffff);
+*/
+       *strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170;
+       return 0;
+}
+
+/*
+ * Amaury: 
+ * snr is the signal quality measured in dB.
+ * snr = 10*log10(signal power / noise power)
+ * the best quality is near 35dB (cable transmission & good modulator)
+ * the minimum without errors depend of transmission parameters
+ * some indicative values are given in en300744 Annex A
+ * ex : 16QAM 2/3 (Gaussian)  = 11.1 dB
+ *
+ * If SNR is above 20dB, BER should be always 0.
+ * choose 0dB as the minimum
+ */
+static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER);
+       int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) |
+               rd(DIB3000MB_REG_NOISE_POWER_LSB);
+/*
+       float snr_dBm=0;
+
+       if (sigpow > 0 && icipow > 0)
+               snr_dBm = 10.0 * log10( (float) (sigpow<<8) / (float)icipow )  ;
+       else if (sigpow > 0)
+               snr_dBm = 35;
+       
+       *snr = (u16) ((snr_dBm / 35) * 0xffff);
+*/
+       *snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1);
+       return 0;
+}
+
+static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       *unc = rd(DIB3000MB_REG_UNC);
+       return 0;
+}
+
+static int dib3000mb_sleep(struct dvb_frontend* fe)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN);
+       return 0;
+}
+
+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;
+}
+
+static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe)
+{
+       return dib3000mb_fe_init(fe, 0);
+}
+
+static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
+{
+       return dib3000mb_set_frontend(fe, fep, 1);
+}
+
+static void dib3000mb_release(struct dvb_frontend* fe)
+{
+       struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+/* pid filter and transfer stuff */
+static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff)
+{
+       struct dib3000_state *state = fe->demodulator_priv;
+       int index = dib3000_get_pid_index(state->pid_list, DIB3000MB_NUM_PIDS, pid, &state->pid_list_lock,onoff);
+       pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
+
+       if (index >= 0) {
+               wr(index+DIB3000MB_REG_FIRST_PID,pid);
+       } else {
+               err("no more pids for filtering.");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff)
+{
+       struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+
+       deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
+       if (onoff) {
+               wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE);
+       } else {
+               wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT);
+       }
+       return 0;
+       }
+
+static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff)
+{
+       //struct dib3000_state *state = fe->demodulator_priv;
+       /* switch it off and on */
+       return 0;
+       }
+
+static struct dvb_frontend_ops dib3000mb_ops;
+
+struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+                                     struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
+{
+       struct dib3000_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->i2c = i2c;
+       memcpy(&state->config,config,sizeof(struct dib3000_config));
+       memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
+
+       /* check for the correct demod */
+       if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
+               goto error;
+
+       if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID)
+               goto error;
+
+       if (dib3000_init_pid_list(state,DIB3000MB_NUM_PIDS))
+               goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+
+       /* set the xfer operations */
+       xfer_ops->pid_parse = dib3000mb_pid_parse;
+       xfer_ops->fifo_ctrl = dib3000mb_fifo_control;
+       xfer_ops->pid_ctrl = dib3000mb_pid_control;
+
+       return &state->frontend;
+
+error:
+       if (state)
+       kfree(state);
+       return NULL;
+       }
+
+static struct dvb_frontend_ops dib3000mb_ops = {
+
+       .info = {
+               .name                   = "DiBcom 3000-MB DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 44250000,
+               .frequency_max          = 867250000,
+               .frequency_stepsize     = 62500,
+               .caps = FE_CAN_INVERSION_AUTO |
+                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                               FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                               FE_CAN_TRANSMISSION_MODE_AUTO |
+                               FE_CAN_GUARD_INTERVAL_AUTO |
+                               FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = dib3000mb_release,
+
+       .init = dib3000mb_fe_init_nonmobile,
+       .sleep = dib3000mb_sleep,
+
+       .set_frontend = dib3000mb_set_frontend_and_tuner,
+       .get_frontend = dib3000mb_get_frontend,
+       .get_tune_settings = dib3000mb_fe_get_tune_settings,
+
+       .read_status = dib3000mb_read_status,
+       .read_ber = dib3000mb_read_ber,
+       .read_signal_strength = dib3000mb_read_signal_strength,
+       .read_snr = dib3000mb_read_snr,
+       .read_ucblocks = dib3000mb_read_unc_blocks,
+};
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000mb_attach);
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
new file mode 100644 (file)
index 0000000..57e61aa
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * dib3000mb_priv.h
+ *
+ * Copyright (C) 2004 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 dib3000mb.c .
+ */
+
+#ifndef __DIB3000MB_PRIV_H_INCLUDED__
+#define __DIB3000MB_PRIV_H_INCLUDED__
+
+/* register addresses and some of their default values */
+
+/* restart subsystems */
+#define DIB3000MB_REG_RESTART                  (     0)
+
+#define DIB3000MB_RESTART_OFF                  (     0)
+#define DIB3000MB_RESTART_AUTO_SEARCH          (1 << 1)
+#define DIB3000MB_RESTART_CTRL                         (1 << 2)
+#define DIB3000MB_RESTART_AGC                          (1 << 3)
+
+/* FFT size */
+#define DIB3000MB_REG_FFT                              (     1)
+
+/* Guard time */
+#define DIB3000MB_REG_GUARD_TIME               (     2)
+
+/* QAM */
+#define DIB3000MB_REG_QAM                              (     3)
+
+/* Alpha coefficient high priority Viterbi algorithm */
+#define DIB3000MB_REG_VIT_ALPHA                        (     4)
+
+/* spectrum inversion */
+#define DIB3000MB_REG_DDS_INV                  (     5)
+
+/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */
+#define DIB3000MB_REG_DDS_FREQ_MSB             (     6)
+#define DIB3000MB_REG_DDS_FREQ_LSB             (     7)
+#define DIB3000MB_DDS_FREQ_MSB                         (   178)
+#define DIB3000MB_DDS_FREQ_LSB                         (  8990)
+
+/* timing frequency (carrier spacing) */
+static u16 dib3000mb_reg_timing_freq[] = { 8,9 };
+static u16 dib3000mb_timing_freq[][2] = {
+       { 126 , 48873 }, /* 6 MHz */
+       { 147 , 57019 }, /* 7 MHz */
+       { 168 , 65164 }, /* 8 MHz */
+};
+
+/* impulse noise parameter */
+/* 36 ??? */
+
+static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 };
+
+enum dib3000mb_impulse_noise_type {
+       DIB3000MB_IMPNOISE_OFF,
+       DIB3000MB_IMPNOISE_MOBILE,
+       DIB3000MB_IMPNOISE_FIXED,
+       DIB3000MB_IMPNOISE_DEFAULT
+};
+
+static u16 dib3000mb_impulse_noise_values[][5] = {
+       { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */
+       { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */
+       { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */
+       { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */
+};
+
+/*
+ * Dual Automatic-Gain-Control
+ * - gains RF in tuner (AGC1)
+ * - gains IF after filtering (AGC2)
+ */
+
+/* also from 16 to 18 */
+static u16 dib3000mb_reg_agc_gain[] = {
+       19,20,21,22,23,24,25,26,27,28,29,30,31,32
+};
+
+static u16 dib3000mb_default_agc_gain[] =
+       { 0x0001, 52429,   623, 128, 166, 195, 61,   /* RF ??? */
+         0x0001, 53766, 38011,   0,  90,  33, 23 }; /* IF ??? */
+
+/* phase noise */
+/* 36 is set when setting the impulse noise */
+static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 };
+
+static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 };
+
+/* lock duration */
+static u16 dib3000mb_reg_lock_duration[] = { 39,40 };
+static u16 dib3000mb_default_lock_duration[] = { 135, 135 };
+
+/* AGC loop bandwidth */
+static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 };
+
+static u16 dib3000mb_agc_bandwidth_low[]  =
+       { 2088, 10, 2088, 10, 3448, 5, 3448, 5 };
+static u16 dib3000mb_agc_bandwidth_high[] =
+       { 2349,  5, 2349,  5, 2586, 2, 2586, 2 };
+
+/*
+ * lock0 definition (coff_lock)
+ */
+#define DIB3000MB_REG_LOCK0_MASK               (    51)
+#define DIB3000MB_LOCK0_DEFAULT                                (     4)
+
+/*
+ * lock1 definition (cpil_lock)
+ * for auto search
+ * which values hide behind the lock masks
+ */
+#define DIB3000MB_REG_LOCK1_MASK               (    52)
+#define DIB3000MB_LOCK1_SEARCH_4                       (0x0004)
+#define DIB3000MB_LOCK1_SEARCH_2048                    (0x0800)
+#define DIB3000MB_LOCK1_DEFAULT                                (0x0001)
+
+/*
+ * lock2 definition (fec_lock) */
+#define DIB3000MB_REG_LOCK2_MASK               (    53)
+#define DIB3000MB_LOCK2_DEFAULT                                (0x0080)
+
+/*
+ * SEQ ? what was that again ... :)
+ * changes when, inversion, guard time and fft is
+ * either automatically detected or not
+ */
+#define DIB3000MB_REG_SEQ                              (    54)
+
+/* bandwidth */
+static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 };
+static u16 dib3000mb_bandwidth_6mhz[] =
+       { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_7mhz[] =
+       { 0, 28, 64421,  96, 39973, 483,  3255, 0, 1000, 0, 1010, 1, 45264 };
+
+static u16 dib3000mb_bandwidth_8mhz[] =
+       { 0, 25, 23600,  84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 };
+
+#define DIB3000MB_REG_UNK_68                           (    68)
+#define DIB3000MB_UNK_68                                               (     0)
+
+#define DIB3000MB_REG_UNK_69                           (    69)
+#define DIB3000MB_UNK_69                                               (     0)
+
+#define DIB3000MB_REG_UNK_71                           (    71)
+#define DIB3000MB_UNK_71                                               (     0)
+
+#define DIB3000MB_REG_UNK_77                           (    77)
+#define DIB3000MB_UNK_77                                               (     6)
+
+#define DIB3000MB_REG_UNK_78                           (    78)
+#define DIB3000MB_UNK_78                                               (0x0080)
+
+/* isi */
+#define DIB3000MB_REG_ISI                              (    79)
+#define DIB3000MB_ISI_ACTIVATE                         (     0)
+#define DIB3000MB_ISI_INHIBIT                          (     1)
+
+/* sync impovement */
+#define DIB3000MB_REG_SYNC_IMPROVEMENT (    84)
+#define DIB3000MB_SYNC_IMPROVE_2K_1_8          (     3)
+#define DIB3000MB_SYNC_IMPROVE_DEFAULT         (     0)
+
+/* phase noise compensation inhibition */
+#define DIB3000MB_REG_PHASE_NOISE              (    87)
+#define DIB3000MB_PHASE_NOISE_DEFAULT  (     0)
+
+#define DIB3000MB_REG_UNK_92                           (    92)
+#define DIB3000MB_UNK_92                                               (0x0080)
+
+#define DIB3000MB_REG_UNK_96                           (    96)
+#define DIB3000MB_UNK_96                                               (0x0010)
+
+#define DIB3000MB_REG_UNK_97                           (    97)
+#define DIB3000MB_UNK_97                                               (0x0009)
+
+/* mobile mode ??? */
+#define DIB3000MB_REG_MOBILE_MODE              (   101)
+#define DIB3000MB_MOBILE_MODE_ON                       (     1)
+#define DIB3000MB_MOBILE_MODE_OFF                      (     0)
+
+#define DIB3000MB_REG_UNK_106                  (   106)
+#define DIB3000MB_UNK_106                                      (0x0080)
+
+#define DIB3000MB_REG_UNK_107                  (   107)
+#define DIB3000MB_UNK_107                                      (0x0080)
+
+#define DIB3000MB_REG_UNK_108                  (   108)
+#define DIB3000MB_UNK_108                                      (0x0080)
+
+/* fft */
+#define DIB3000MB_REG_UNK_121                  (   121)
+#define DIB3000MB_UNK_121_2K                           (     7)
+#define DIB3000MB_UNK_121_DEFAULT                      (     5)
+
+#define DIB3000MB_REG_UNK_122                  (   122)
+#define DIB3000MB_UNK_122                                      (  2867)
+
+/* QAM for mobile mode */
+#define DIB3000MB_REG_MOBILE_MODE_QAM  (   126)
+#define DIB3000MB_MOBILE_MODE_QAM_64           (     3)
+#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16      (     1)
+#define DIB3000MB_MOBILE_MODE_QAM_OFF          (     0)
+
+/*
+ * data diversity when having more than one chip on-board
+ * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY
+ */
+#define DIB3000MB_REG_DATA_IN_DIVERSITY                (   127)
+#define DIB3000MB_DATA_DIVERSITY_IN_OFF                        (     0)
+#define DIB3000MB_DATA_DIVERSITY_IN_ON                 (     2)
+
+/* vit hrch */
+#define DIB3000MB_REG_VIT_HRCH                 (   128)
+
+/* vit code rate */
+#define DIB3000MB_REG_VIT_CODE_RATE            (   129)
+
+/* vit select hp */
+#define DIB3000MB_REG_VIT_HP                   (   130)
+
+/* time frame for Bit-Error-Rate calculation */
+#define DIB3000MB_REG_BERLEN                   (   135)
+#define DIB3000MB_BERLEN_LONG                          (     0)
+#define DIB3000MB_BERLEN_DEFAULT                       (     1)
+#define DIB3000MB_BERLEN_MEDIUM                                (     2)
+#define DIB3000MB_BERLEN_SHORT                         (     3)
+
+/* 142 - 152 FIFO parameters
+ * which is what ?
+ */
+
+#define DIB3000MB_REG_FIFO_142                 (   142)
+#define DIB3000MB_FIFO_142                                     (     0)
+
+/* MPEG2 TS output mode */
+#define DIB3000MB_REG_MPEG2_OUT_MODE   (   143)
+#define DIB3000MB_MPEG2_OUT_MODE_204           (     0)
+#define DIB3000MB_MPEG2_OUT_MODE_188           (     1)
+
+#define DIB3000MB_REG_PID_PARSE                        (   144)
+#define DIB3000MB_PID_PARSE_INHIBIT            (     0)
+#define DIB3000MB_PID_PARSE_ACTIVATE   (     1)
+
+#define DIB3000MB_REG_FIFO                             (   145)
+#define DIB3000MB_FIFO_INHIBIT                         (     1)
+#define DIB3000MB_FIFO_ACTIVATE                                (     0)
+
+#define DIB3000MB_REG_FIFO_146                 (   146)
+#define DIB3000MB_FIFO_146                                     (     3)
+
+#define DIB3000MB_REG_FIFO_147                 (   147)
+#define DIB3000MB_FIFO_147                                     (0x0100)
+
+/*
+ * pidfilter
+ * it is not a hardware pidfilter but a filter which drops all pids
+ * except the ones set. Necessary because of the limited USB1.1 bandwidth.
+ * regs 153-168
+ */
+
+#define DIB3000MB_REG_FIRST_PID                        (   153)
+#define DIB3000MB_NUM_PIDS                             (    16)
+
+/*
+ * output mode
+ * USB devices have to use 'slave'-mode
+ * see also DIB3000MB_REG_ELECT_OUT_MODE
+ */
+#define DIB3000MB_REG_OUTPUT_MODE              (   169)
+#define DIB3000MB_OUTPUT_MODE_GATED_CLK                (     0)
+#define DIB3000MB_OUTPUT_MODE_CONT_CLK         (     1)
+#define DIB3000MB_OUTPUT_MODE_SERIAL           (     2)
+#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY   (     5)
+#define DIB3000MB_OUTPUT_MODE_SLAVE                    (     6)
+
+/* irq event mask */
+#define DIB3000MB_REG_IRQ_EVENT_MASK           (   170)
+#define DIB3000MB_IRQ_EVENT_MASK                               (     0)
+
+/* filter coefficients */
+static u16 dib3000mb_reg_filter_coeffs[] = {
+       171, 172, 173, 174, 175, 176, 177, 178,
+       179, 180, 181, 182, 183, 184, 185, 186,
+       188, 189, 190, 191, 192, 194
+};
+
+static u16 dib3000mb_filter_coeffs[] = {
+        226,  160,   29,
+        979,  998,   19,
+         22, 1019, 1006,
+       1022,   12,    6,
+       1017, 1017,    3,
+          6,       1019,
+       1021,    2,    3,
+          1,          0,
+};
+
+/*
+ * mobile algorithm (when you are moving with your device)
+ * but not faster than 90 km/h
+ */
+#define DIB3000MB_REG_MOBILE_ALGO              (   195)
+#define DIB3000MB_MOBILE_ALGO_ON                       (     0)
+#define DIB3000MB_MOBILE_ALGO_OFF                      (     1)
+
+/* multiple demodulators algorithm */
+#define DIB3000MB_REG_MULTI_DEMOD_MSB  (   206)
+#define DIB3000MB_REG_MULTI_DEMOD_LSB  (   207)
+
+/* terminator, no more demods */
+#define DIB3000MB_MULTI_DEMOD_MSB                      ( 32767)
+#define DIB3000MB_MULTI_DEMOD_LSB                      (  4095)
+
+/* bring the device into a known  */
+#define DIB3000MB_REG_RESET_DEVICE             (  1024)
+#define DIB3000MB_RESET_DEVICE                         (0x812c)
+#define DIB3000MB_RESET_DEVICE_RST                     (     0)
+
+/* hardware clock configuration */
+#define DIB3000MB_REG_CLOCK                            (  1027)
+#define DIB3000MB_CLOCK_DEFAULT                                (0x9000)
+#define DIB3000MB_CLOCK_DIVERSITY                      (0x92b0)
+
+/* power down config */
+#define DIB3000MB_REG_POWER_CONTROL            (  1028)
+#define DIB3000MB_POWER_DOWN                           (     1)
+#define DIB3000MB_POWER_UP                                     (     0)
+
+/* electrical output mode */
+#define DIB3000MB_REG_ELECT_OUT_MODE   (  1029)
+#define DIB3000MB_ELECT_OUT_MODE_OFF           (     0)
+#define DIB3000MB_ELECT_OUT_MODE_ON                    (     1)
+
+/* set the tuner i2c address */
+#define DIB3000MB_REG_TUNER                            (  1089)
+
+/* monitoring registers (read only) */
+
+/* agc loop locked (size: 1) */
+#define DIB3000MB_REG_AGC_LOCK                 (   324)
+
+/* agc power (size: 16) */
+#define DIB3000MB_REG_AGC_POWER                        (   325)
+
+/* agc1 value (16) */
+#define DIB3000MB_REG_AGC1_VALUE               (   326)
+
+/* agc2 value (16) */
+#define DIB3000MB_REG_AGC2_VALUE               (   327)
+
+/* total RF power (16), can be used for signal strength */
+#define DIB3000MB_REG_RF_POWER                 (   328)
+
+/* dds_frequency with offset (24) */
+#define DIB3000MB_REG_DDS_VALUE_MSB            (   339)
+#define DIB3000MB_REG_DDS_VALUE_LSB            (   340)
+
+/* timing offset signed (24) */
+#define DIB3000MB_REG_TIMING_OFFSET_MSB        (   341)
+#define DIB3000MB_REG_TIMING_OFFSET_LSB        (   342)
+
+/* fft start position (13) */
+#define DIB3000MB_REG_FFT_WINDOW_POS   (   353)
+
+/* carriers locked (1) */
+#define DIB3000MB_REG_CARRIER_LOCK             (   355)
+
+/* noise power (24) */
+#define DIB3000MB_REG_NOISE_POWER_MSB  (   372)
+#define DIB3000MB_REG_NOISE_POWER_LSB  (   373)
+
+#define DIB3000MB_REG_MOBILE_NOISE_MSB (   374)
+#define DIB3000MB_REG_MOBILE_NOISE_LSB (   375)
+
+/*
+ * signal power (16), this and the above can be
+ * used to calculate the signal/noise - ratio
+ */
+#define DIB3000MB_REG_SIGNAL_POWER             (   380)
+
+/* mer (24) */
+#define DIB3000MB_REG_MER_MSB                  (   381)
+#define DIB3000MB_REG_MER_LSB                  (   382)
+
+/*
+ * Transmission Parameter Signalling (TPS)
+ * the following registers can be used to get TPS-information.
+ * The values are according to the DVB-T standard.
+ */
+
+/* TPS locked (1) */
+#define DIB3000MB_REG_TPS_LOCK                 (   394)
+
+/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */
+#define DIB3000MB_REG_TPS_QAM                  (   398)
+
+/* hierarchy from TPS (1) */
+#define DIB3000MB_REG_TPS_HRCH                 (   399)
+
+/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */
+#define DIB3000MB_REG_TPS_VIT_ALPHA            (   400)
+
+/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */
+#define DIB3000MB_REG_TPS_CODE_RATE_HP (   401)
+
+/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */
+#define DIB3000MB_REG_TPS_CODE_RATE_LP (   402)
+
+/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */
+#define DIB3000MB_REG_TPS_GUARD_TIME   (   403)
+
+/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */
+#define DIB3000MB_REG_TPS_FFT                  (   404)
+
+/* cell id from TPS (16) */
+#define DIB3000MB_REG_TPS_CELL_ID              (   406)
+
+/* TPS (68) */
+#define DIB3000MB_REG_TPS_1                            (   408)
+#define DIB3000MB_REG_TPS_2                            (   409)
+#define DIB3000MB_REG_TPS_3                            (   410)
+#define DIB3000MB_REG_TPS_4                            (   411)
+#define DIB3000MB_REG_TPS_5                            (   412)
+
+/* bit error rate (before RS correction) (21) */
+#define DIB3000MB_REG_BER_MSB                  (   414)
+#define DIB3000MB_REG_BER_LSB                  (   415)
+
+/* packet error rate (uncorrected TS packets) (16) */
+#define DIB3000MB_REG_PACKET_ERROR_RATE        (   417)
+
+/* uncorrected packet count (16) */
+#define DIB3000MB_REG_UNC                              (   420)
+
+/* viterbi locked (1) */
+#define DIB3000MB_REG_VIT_LCK                  (   421)
+
+/* viterbi inidcator (16) */
+#define DIB3000MB_REG_VIT_INDICATOR            (   422)
+
+/* transport stream sync lock (1) */
+#define DIB3000MB_REG_TS_SYNC_LOCK             (   423)
+
+/* transport stream RS lock (1) */
+#define DIB3000MB_REG_TS_RS_LOCK               (   424)
+
+/* lock mask 0 value (1) */
+#define DIB3000MB_REG_LOCK0_VALUE              (   425)
+
+/* lock mask 1 value (1) */
+#define DIB3000MB_REG_LOCK1_VALUE              (   426)
+
+/* lock mask 2 value (1) */
+#define DIB3000MB_REG_LOCK2_VALUE              (   427)
+
+/* interrupt pending for auto search */
+#define DIB3000MB_REG_AS_IRQ_PENDING   (   434)
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
new file mode 100644 (file)
index 0000000..8015c21
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P
+ * DiBcom (http://www.dibcom.fr/)
+ *
+ * Copyright (C) 2004 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.
+ *
+ * Acknowledgements
+ *
+ *  Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
+ *  sources, on which this driver (and the dvb-dibusb) are based.
+ *
+ * see Documentation/dvb/README.dibusb for more information
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "dib3000-common.h"
+#include "dib3000mc_priv.h"
+#include "dib3000.h"
+
+/* Version information */
+#define DRIVER_VERSION "0.1"
+#define DRIVER_DESC "DiBcom 3000-MC DVB-T demodulator driver"
+#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+static int debug;
+module_param(debug, int, 0x644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
+#endif
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_xfer(args...) dprintk(0x02,args)
+#define deb_setf(args...) dprintk(0x04,args)
+#define deb_getf(args...) dprintk(0x08,args)
+
+
+static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
+       fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
+{
+       switch (transmission_mode) {
+               case TRANSMISSION_MODE_2K:
+                       wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]);
+                       break;
+               case TRANSMISSION_MODE_8K:
+                       wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]);
+                       break;
+               default:
+                       break;
+       }
+
+       switch (bandwidth) {
+/*             case BANDWIDTH_5_MHZ:
+                       wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]);
+                       break; */
+               case BANDWIDTH_6_MHZ:
+                       wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]);
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]);
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]);
+                       break;
+               default:
+                       break;
+       }
+
+       switch (mode) {
+               case 0: /* no impulse */ /* fall through */
+                       wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]);
+                       break;
+               case 1: /* new algo */
+                       wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]);
+                       set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */
+                       break;
+               default: /* old algo */
+                       wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]);
+                       break;
+       }
+       return 0;
+}
+
+static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset,
+               fe_transmit_mode_t fft, fe_bandwidth_t bw)
+{
+       u16 timf_msb,timf_lsb;
+       s32 tim_offset,tim_sgn;
+       u64 comp1,comp2,comp=0;
+
+       switch (bw) {
+               case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break;
+               case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break;
+               case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break;
+               default: err("unknown bandwidth (%d)",bw); break;
+       }
+       timf_msb = (comp >> 16) & 0xff;
+       timf_lsb = (comp & 0xffff);
+
+       // Update the timing offset ;
+       if (upd_offset > 0) {
+               if (!state->timing_offset_comp_done) {
+                       msleep(200);
+                       state->timing_offset_comp_done = 1;
+               }
+               tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB);
+               if ((tim_offset & 0x2000) == 0x2000)
+                       tim_offset |= 0xC000;
+               if (fft == TRANSMISSION_MODE_2K)
+                       tim_offset <<= 2;
+               state->timing_offset += tim_offset;
+       }
+
+       tim_offset = state->timing_offset;
+       if (tim_offset < 0) {
+               tim_sgn = 1;
+               tim_offset = -tim_offset;
+       } else
+               tim_sgn = 0;
+
+       comp1 =  (u32)tim_offset * (u32)timf_lsb ;
+       comp2 =  (u32)tim_offset * (u32)timf_msb ;
+       comp  = ((comp1 >> 16) + comp2) >> 7;
+
+       if (tim_sgn == 0)
+               comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp;
+       else
+               comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ;
+
+       timf_msb = (comp >> 16) & 0xff;
+       timf_lsb = comp & 0xffff;
+
+       wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb);
+       wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb);
+       return 0;
+}
+
+static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost)
+{
+       if (boost) {
+               wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON);
+       } else {
+               wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF);
+       }
+       switch (bw) {
+               case BANDWIDTH_8_MHZ:
+                       wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz);
+                       break;
+               case BANDWIDTH_6_MHZ:
+                       wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz);
+                       break;
+/*             case BANDWIDTH_5_MHZ:
+                       wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz);
+                       break;*/
+               case BANDWIDTH_AUTO:
+                       return -EOPNOTSUPP;
+               default:
+                       err("unknown bandwidth value (%d).",bw);
+                       return -EINVAL;
+       }
+       if (boost) {
+               u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) +
+                       rd(DIB3000MC_REG_BW_TIMOUT_LSB);
+               timeout *= 85; timeout >>= 7;
+               wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff);
+               wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff);
+       }
+       return 0;
+}
+
+static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep);
+
+static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep, int tuner)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+       fe_code_rate_t fe_cr = FEC_NONE;
+       int search_state, seq;
+       u16 val;
+       u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0;
+
+       if (tuner) {
+               wr(DIB3000MC_REG_TUNER,
+                               DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr));
+               state->config.pll_set(fe, fep);
+               wr(DIB3000MC_REG_TUNER,
+                               DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr));
+       }
+
+       dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
+       dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
+
+       wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
+       wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
+
+/* Default cfg isi offset adp */
+       wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
+
+       wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
+       wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
+       wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
+
+       wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
+       if (ofdm->bandwidth == BANDWIDTH_8_MHZ) {
+               wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
+       } else {
+               wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
+       }
+
+       switch (ofdm->transmission_mode) {
+               case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
+               case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break;
+               case TRANSMISSION_MODE_AUTO: break;
+               default: return -EINVAL;
+       }
+       switch (ofdm->guard_interval) {
+               case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
+               case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
+               case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break;
+               case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break;
+               case GUARD_INTERVAL_AUTO: break;
+               default: return -EINVAL;
+       }
+       switch (ofdm->constellation) {
+               case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break;
+               case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
+               case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
+               case QAM_AUTO: break;
+               default: return -EINVAL;
+       }
+       switch (ofdm->hierarchy_information) {
+               case HIERARCHY_NONE: /* fall through */
+               case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break;
+               case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break;
+               case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break;
+               case HIERARCHY_AUTO: break;
+               default: return -EINVAL;
+       }
+       if (ofdm->hierarchy_information == HIERARCHY_NONE) {
+               hrch = DIB3000_HRCH_OFF;
+               sel_hp = DIB3000_SELECT_HP;
+               fe_cr = ofdm->code_rate_HP;
+       } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
+               hrch = DIB3000_HRCH_ON;
+               sel_hp = DIB3000_SELECT_LP;
+               fe_cr = ofdm->code_rate_LP;
+       }
+       switch (fe_cr) {
+               case FEC_1_2: cr = DIB3000_FEC_1_2; break;
+               case FEC_2_3: cr = DIB3000_FEC_2_3; break;
+               case FEC_3_4: cr = DIB3000_FEC_3_4; break;
+               case FEC_5_6: cr = DIB3000_FEC_5_6; break;
+               case FEC_7_8: cr = DIB3000_FEC_7_8; break;
+               case FEC_NONE: break;
+               case FEC_AUTO: break;
+               default: return -EINVAL;
+       }
+
+       wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft));
+       wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch));
+
+       switch (fep->inversion) {
+               case INVERSION_OFF:
+                       wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
+                       break;
+               case INVERSION_AUTO:
+                       break;
+               case INVERSION_ON:
+                       wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       seq = dib3000_seq
+               [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
+               [ofdm->guard_interval == GUARD_INTERVAL_AUTO]
+               [fep->inversion == INVERSION_AUTO];
+
+       deb_setf("seq? %d\n", seq);
+       wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
+
+       dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
+
+       val = rd(DIB3000MC_REG_DEMOD_PARM);
+       wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
+       wr(DIB3000MC_REG_DEMOD_PARM,val);
+
+       msleep(70);
+
+       wr_foreach(dib3000mc_reg_agc_bandwidth, dib3000mc_agc_bandwidth);
+
+       /* something has to be auto searched */
+       if (ofdm->constellation == QAM_AUTO ||
+               ofdm->hierarchy_information == HIERARCHY_AUTO ||
+               ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
+               ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
+               fe_cr == FEC_AUTO ||
+               fep->inversion == INVERSION_AUTO
+               ) {
+               int as_count=0;
+
+               deb_setf("autosearch enabled.\n");
+
+               val = rd(DIB3000MC_REG_DEMOD_PARM);
+               wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
+               wr(DIB3000MC_REG_DEMOD_PARM,val);
+
+               while ((search_state = dib3000_search_status(
+                                       rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
+                       msleep(10);
+
+               deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
+
+               if (search_state == 1) {
+                       struct dvb_frontend_parameters feps;
+                       feps.u.ofdm.bandwidth = ofdm->bandwidth; /* bw is not auto searched */;
+                       if (dib3000mc_get_frontend(fe, &feps) == 0) {
+                               deb_setf("reading tuning data from frontend succeeded.\n");
+                               return dib3000mc_set_frontend(fe, &feps, 0);
+                       }
+               }
+       } else {
+               wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
+               wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[qam]);
+               /* set_offset_cfg */
+               wr_foreach(dib3000mc_reg_offset,
+                               dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
+
+//             dib3000mc_set_timing(1,ofdm->transmission_mode,ofdm->bandwidth);
+
+//             wr(DIB3000MC_REG_LOCK_MASK,DIB3000MC_ACTIVATE_LOCK_MASK); /* activates some locks if needed */
+
+/*             set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
+               set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF);
+               wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_ON);
+               wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_OFF);*/
+       }
+
+       return 0;
+}
+
+
+static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       state->timing_offset = 0;
+       state->timing_offset_comp_done = 0;
+
+       wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
+       wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
+       wr(DIB3000MC_REG_RST_I2C_ADDR,
+               DIB3000MC_DEMOD_ADDR(state->config.demod_address) |
+               DIB3000MC_DEMOD_ADDR_ON);
+
+       wr(DIB3000MC_REG_RST_I2C_ADDR,
+               DIB3000MC_DEMOD_ADDR(state->config.demod_address));
+
+       wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
+       wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
+
+       wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
+       wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
+       wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
+       wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
+
+       wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
+       wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
+
+       wr(33,5);
+       wr(36,81);
+       wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
+
+       wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
+       wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
+
+       /* mobile mode - portable reception */
+       wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
+
+/* TUNER_PANASONIC_ENV57H12D5: */
+       wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
+       wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
+       wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
+
+       wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
+       wr(26,0x6680);
+       wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
+       wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
+       wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
+       wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
+
+       wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
+       wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
+
+       wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
+
+       wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
+       wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
+
+       dib3000mc_set_timing(state,0,TRANSMISSION_MODE_2K,BANDWIDTH_8_MHZ);
+//     wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
+
+       wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
+       wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
+       wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
+
+       dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
+
+/* output mode control, just the MPEG2_SLAVE */
+       set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
+       wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
+       wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
+       wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
+
+/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
+       wr(DIB3000MC_REG_OUTMODE,
+               DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
+                       rd(DIB3000MC_REG_OUTMODE)));
+
+       wr(DIB3000MC_REG_SMO_MODE,
+                       DIB3000MC_SMO_MODE_DEFAULT |
+                       DIB3000MC_SMO_MODE_188);
+
+       wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
+       wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
+*/
+/* diversity */
+       wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
+       wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
+
+       wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
+
+       set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
+
+
+/*     if (state->config->pll_init) {
+               wr(DIB3000MC_REG_TUNER,
+                       DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr));
+               state->config->pll_init(fe);
+               wr(DIB3000MC_REG_TUNER,
+                       DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr));
+       }*/
+       return 0;
+}
+
+static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+                                 struct dvb_frontend_parameters *fep)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
+       fe_code_rate_t *cr;
+       u16 tps_val,cr_val;
+       int inv_test1,inv_test2;
+       u32 dds_val, threshold = 0x1000000;
+
+       if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507))
+               return 0;
+
+       dds_val = ((rd(DIB3000MC_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
+       if (dds_val < threshold)
+               inv_test1 = 0;
+       else if (dds_val == threshold)
+               inv_test1 = 1;
+       else
+               inv_test1 = 2;
+
+       dds_val = ((rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
+       if (dds_val < threshold)
+               inv_test2 = 0;
+       else if (dds_val == threshold)
+               inv_test2 = 1;
+       else
+               inv_test2 = 2;
+
+       fep->inversion =
+               ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
+               ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
+               INVERSION_ON : INVERSION_OFF;
+
+       deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+
+       tps_val = rd(DIB3000MC_REG_TUNING_PARM);
+
+       switch (DIB3000MC_TP_QAM(tps_val)) {
+               case DIB3000_CONSTELLATION_QPSK:
+                       deb_getf("QPSK ");
+                       ofdm->constellation = QPSK;
+                       break;
+               case DIB3000_CONSTELLATION_16QAM:
+                       deb_getf("QAM16 ");
+                       ofdm->constellation = QAM_16;
+                       break;
+               case DIB3000_CONSTELLATION_64QAM:
+                       deb_getf("QAM64 ");
+                       ofdm->constellation = QAM_64;
+                       break;
+               default:
+                       err("Unexpected constellation returned by TPS (%d)", tps_val);
+                       break;
+       }
+
+       if (DIB3000MC_TP_HRCH(tps_val)) {
+               deb_getf("HRCH ON ");
+               cr = &ofdm->code_rate_LP;
+               ofdm->code_rate_HP = FEC_NONE;
+               switch (DIB3000MC_TP_ALPHA(tps_val)) {
+                       case DIB3000_ALPHA_0:
+                               deb_getf("HIERARCHY_NONE ");
+                               ofdm->hierarchy_information = HIERARCHY_NONE;
+                               break;
+                       case DIB3000_ALPHA_1:
+                               deb_getf("HIERARCHY_1 ");
+                               ofdm->hierarchy_information = HIERARCHY_1;
+                               break;
+                       case DIB3000_ALPHA_2:
+                               deb_getf("HIERARCHY_2 ");
+                               ofdm->hierarchy_information = HIERARCHY_2;
+                               break;
+                       case DIB3000_ALPHA_4:
+                               deb_getf("HIERARCHY_4 ");
+                               ofdm->hierarchy_information = HIERARCHY_4;
+                               break;
+                       default:
+                               err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
+                               break;
+               }
+               cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val);
+       } else {
+               deb_getf("HRCH OFF ");
+               cr = &ofdm->code_rate_HP;
+               ofdm->code_rate_LP = FEC_NONE;
+               ofdm->hierarchy_information = HIERARCHY_NONE;
+               cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val);
+       }
+
+       switch (cr_val) {
+               case DIB3000_FEC_1_2:
+                       deb_getf("FEC_1_2 ");
+                       *cr = FEC_1_2;
+                       break;
+               case DIB3000_FEC_2_3:
+                       deb_getf("FEC_2_3 ");
+                       *cr = FEC_2_3;
+                       break;
+               case DIB3000_FEC_3_4:
+                       deb_getf("FEC_3_4 ");
+                       *cr = FEC_3_4;
+                       break;
+               case DIB3000_FEC_5_6:
+                       deb_getf("FEC_5_6 ");
+                       *cr = FEC_4_5;
+                       break;
+               case DIB3000_FEC_7_8:
+                       deb_getf("FEC_7_8 ");
+                       *cr = FEC_7_8;
+                       break;
+               default:
+                       err("Unexpected FEC returned by TPS (%d)", tps_val);
+                       break;
+       }
+
+       switch (DIB3000MC_TP_GUARD(tps_val)) {
+               case DIB3000_GUARD_TIME_1_32:
+                       deb_getf("GUARD_INTERVAL_1_32 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_32;
+                       break;
+               case DIB3000_GUARD_TIME_1_16:
+                       deb_getf("GUARD_INTERVAL_1_16 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_16;
+                       break;
+               case DIB3000_GUARD_TIME_1_8:
+                       deb_getf("GUARD_INTERVAL_1_8 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_8;
+                       break;
+               case DIB3000_GUARD_TIME_1_4:
+                       deb_getf("GUARD_INTERVAL_1_4 ");
+                       ofdm->guard_interval = GUARD_INTERVAL_1_4;
+                       break;
+               default:
+                       err("Unexpected Guard Time returned by TPS (%d)", tps_val);
+                       break;
+       }
+
+       switch (DIB3000MC_TP_FFT(tps_val)) {
+               case DIB3000_TRANSMISSION_MODE_2K:
+                       deb_getf("TRANSMISSION_MODE_2K ");
+                       ofdm->transmission_mode = TRANSMISSION_MODE_2K;
+                       break;
+               case DIB3000_TRANSMISSION_MODE_8K:
+                       deb_getf("TRANSMISSION_MODE_8K ");
+                       ofdm->transmission_mode = TRANSMISSION_MODE_8K;
+                       break;
+               default:
+                       err("unexpected transmission mode return by TPS (%d)", tps_val);
+                       break;
+       }
+       return 0;
+}
+
+static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       u16 lock = rd(DIB3000MC_REG_LOCKING);
+
+       *stat = 0;
+       if (DIB3000MC_AGC_LOCK(lock))
+               *stat |= FE_HAS_SIGNAL;
+       if (DIB3000MC_CARRIER_LOCK(lock))
+               *stat |= FE_HAS_CARRIER;
+       if (DIB3000MC_TPS_LOCK(lock)) /* VIT_LOCK ? */
+               *stat |= FE_HAS_VITERBI;
+       if (DIB3000MC_MPEG_SYNC_LOCK(lock))
+               *stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
+
+       deb_info("actual status is %2x\n",*stat);
+
+       return 0;
+}
+
+static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       *ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
+       return 0;
+}
+
+static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT);
+       return 0;
+}
+
+/* see dib3000mb.c for calculation comments */
+static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+       u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
+       *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
+
+       deb_info("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
+       return 0;
+}
+
+/* see dib3000mb.c for calculation comments */
+static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB),
+               val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
+       u16 sig,noise;
+
+       sig =   (((val >> 6) & 0xff) << 8) + (val & 0x3f);
+       noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3);
+       if (noise == 0)
+               *snr = 0xffff;
+       else
+               *snr = (u16) sig/noise;
+
+       deb_info("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
+       deb_info("noise:  mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
+       deb_info("snr: %d\n",*snr);
+       return 0;
+}
+
+static int dib3000mc_sleep(struct dvb_frontend* fe)
+{
+       struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv;
+
+       set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
+       wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
+       wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN);
+       wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN);
+       return 0;
+}
+
+static int dib3000mc_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;
+}
+
+static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe)
+{
+       return dib3000mc_fe_init(fe, 0);
+}
+
+static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
+{
+       return dib3000mc_set_frontend(fe, fep, 1);
+}
+
+static void dib3000mc_release(struct dvb_frontend* fe)
+{
+       struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+       dib3000_dealloc_pid_list(state);
+       kfree(state);
+}
+
+/* pid filter and transfer stuff */
+static int dib3000mc_pid_control(struct dvb_frontend *fe,int pid,int onoff)
+{
+       struct dib3000_state *state = fe->demodulator_priv;
+       int index = dib3000_get_pid_index(state->pid_list, DIB3000MC_NUM_PIDS, pid, &state->pid_list_lock,onoff);
+       pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
+
+       if (index >= 0) {
+               wr(index+DIB3000MC_REG_FIRST_PID,pid);
+       } else {
+               err("no more pids for filtering.");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
+{
+       struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv;
+       u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
+       deb_xfer("%s fifo",onoff ? "enabling" : "disabling");
+       if (onoff) {
+               wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
+       } else {
+               wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
+       }
+       return 0;
+}
+
+static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
+{
+       struct dib3000_state *state = fe->demodulator_priv;
+       u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
+       deb_xfer("%s pid parsing",onoff ? "enabling" : "disabling");
+       if (onoff) {
+               wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
+       } else {
+               wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
+       }
+       return 0;
+}
+
+static struct dvb_frontend_ops dib3000mc_ops;
+
+struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
+                                     struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops)
+{
+       struct dib3000_state* state = NULL;
+       u16 devid;
+
+       /* allocate memory for the internal state */
+       state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->i2c = i2c;
+       memcpy(&state->config,config,sizeof(struct dib3000_config));
+       memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
+
+       /* check for the correct demod */
+       if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
+               goto error;
+
+       devid = rd(DIB3000_REG_DEVICE_ID);
+       if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
+               goto error;
+
+
+       switch (devid) {
+               case DIB3000MC_DEVICE_ID:
+                       info("Found a DiBcom 3000-MC.");
+                       break;
+               case DIB3000P_DEVICE_ID:
+                       info("Found a DiBcom 3000-P.");
+                       break;
+       }
+
+       if (dib3000_init_pid_list(state,DIB3000MC_NUM_PIDS))
+               goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+
+       /* set the xfer operations */
+       xfer_ops->pid_parse = dib3000mc_pid_parse;
+       xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
+       xfer_ops->pid_ctrl = dib3000mc_pid_control;
+
+       return &state->frontend;
+
+error:
+       if (state)
+               kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops dib3000mc_ops = {
+
+       .info = {
+               .name                   = "DiBcom 3000-MC/P DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 44250000,
+               .frequency_max          = 867250000,
+               .frequency_stepsize     = 62500,
+               .caps = FE_CAN_INVERSION_AUTO |
+                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                               FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                               FE_CAN_TRANSMISSION_MODE_AUTO |
+                               FE_CAN_GUARD_INTERVAL_AUTO |
+                               FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = dib3000mc_release,
+
+       .init = dib3000mc_fe_init_nonmobile,
+       .sleep = dib3000mc_sleep,
+
+       .set_frontend = dib3000mc_set_frontend_and_tuner,
+       .get_frontend = dib3000mc_get_frontend,
+       .get_tune_settings = dib3000mc_fe_get_tune_settings,
+
+       .read_status = dib3000mc_read_status,
+       .read_ber = dib3000mc_read_ber,
+       .read_signal_strength = dib3000mc_read_signal_strength,
+       .read_snr = dib3000mc_read_snr,
+       .read_ucblocks = dib3000mc_read_unc_blocks,
+};
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dib3000mc_attach);
diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h
new file mode 100644 (file)
index 0000000..21ccc13
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * dib3000mc_priv.h
+ *
+ * Copyright (C) 2004 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 dib3000mc.c .
+ */
+
+#ifndef __DIB3000MC_PRIV_H__
+#define __DIB3000MC_PRIV_H__
+
+/* info and err, taken from usb.h, if there is anything available like by default,
+ * please change !
+ */
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+
+// defines the phase noise algorithm to be used (O:Inhib, 1:CPE on)
+#define DEF_PHASE_NOISE_MODE                0
+
+// define Mobille algorithms
+#define DEF_MOBILE_MODE      Auto_Reception
+
+// defines the tuner type
+#define DEF_TUNER_TYPE   TUNER_PANASONIC_ENV57H13D5
+
+// defines the impule noise algorithm to be used
+#define DEF_IMPULSE_NOISE_MODE      0
+
+// defines the MPEG2 data output format
+#define DEF_MPEG2_OUTPUT_188       0
+
+// defines the MPEG2 data output format
+#define DEF_OUTPUT_MODE       MPEG2_PARALLEL_CONTINUOUS_CLOCK
+
+/*
+ * Demodulator parameters
+ * reg: 0  1 1  1 11 11 111
+ *         | |  |  |  |  |
+ *         | |  |  |  |  +-- alpha (000=0, 001=1, 010=2, 100=4)
+ *         | |  |  |  +----- constellation (00=QPSK, 01=16QAM, 10=64QAM)
+ *         | |  |  +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4)
+ *         | |  +----------- transmission mode (0=2k, 1=8k)
+ *         | |
+ *         | +-------------- restart autosearch for parameters
+ *         +---------------- restart the demodulator
+ * reg: 181      1 111 1
+ *               |  |  |
+ *               |  |  +- FEC applies for HP or LP (0=LP, 1=HP)
+ *               |  +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8)
+ *               +------- hierarchy on (0=no, 1=yes)
+ */
+
+/* demodulator tuning parameter and restart options */
+#define DIB3000MC_REG_DEMOD_PARM               (     0)
+#define DIB3000MC_DEMOD_PARM(a,c,g,t)  ( \
+                (0x7 & a) | \
+               ((0x3 & c) << 3) | \
+               ((0x3 & g) << 5) | \
+               ((0x1 & t) << 7) )
+#define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON       (1 << 8)
+#define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF      (0 << 8)
+#define DIB3000MC_DEMOD_RST_DEMOD_ON           (1 << 9)
+#define DIB3000MC_DEMOD_RST_DEMOD_OFF          (0 << 9)
+
+/* register for hierarchy parameters */
+#define DIB3000MC_REG_HRCH_PARM                        (   181)
+#define DIB3000MC_HRCH_PARM(s,f,h)             ( \
+                (0x1 & s) | \
+               ((0x7 & f) << 1) | \
+               ((0x1 & h) << 4) )
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_1                            (     1)
+#define DIB3000MC_UNK_1                                        (  0x04)
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_2                            (     2)
+#define DIB3000MC_UNK_2                                        (  0x04)
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_3                            (     3)
+#define DIB3000MC_UNK_3                                        (0x1000)
+
+#define DIB3000MC_REG_UNK_4                            (     4)
+#define DIB3000MC_UNK_4                                        (0x0814)
+
+/* timeout ??? */
+#define DIB3000MC_REG_SEQ_TPS                  (     5)
+#define DIB3000MC_SEQ_TPS_DEFAULT              (     1)
+#define DIB3000MC_SEQ_TPS(s,t)                 ( \
+               ((s & 0x0f) << 4) | \
+               ((t & 0x01) << 8) )
+#define DIB3000MC_IS_TPS(v)                            ((v << 8) & 0x1)
+#define DIB3000MC_IS_AS(v)                             ((v >> 4) & 0xf)
+
+/* parameters for the bandwidth */
+#define DIB3000MC_REG_BW_TIMOUT_MSB            (     6)
+#define DIB3000MC_REG_BW_TIMOUT_LSB            (     7)
+
+static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 };
+
+/*static u16 dib3000mc_bandwidth_5mhz[] =
+       { 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/
+
+static u16 dib3000mc_bandwidth_6mhz[] =
+       { 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 };
+
+static u16 dib3000mc_bandwidth_7mhz[] =
+       { 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
+
+static u16 dib3000mc_bandwidth_8mhz[] =
+       { 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0b0 };
+
+static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
+static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
+
+/* lock mask */
+#define DIB3000MC_REG_LOCK_MASK                        (    15)
+#define DIB3000MC_ACTIVATE_LOCK_MASK   (0x0800)
+
+/* reset the uncorrected packet count (??? do it 5 times) */
+#define DIB3000MC_REG_RST_UNC                  (    18)
+#define DIB3000MC_RST_UNC_ON                   (     1)
+#define DIB3000MC_RST_UNC_OFF                  (     0)
+
+#define DIB3000MC_REG_UNK_19                   (    19)
+#define DIB3000MC_UNK_19                               (     0)
+
+/* DDS frequency value (IF position) and inversion bit */
+#define DIB3000MC_REG_INVERSION                        (    21)
+#define DIB3000MC_REG_SET_DDS_FREQ_MSB (    21)
+#define DIB3000MC_DDS_FREQ_MSB_INV_OFF (0x0164)
+#define DIB3000MC_DDS_FREQ_MSB_INV_ON  (0x0364)
+
+#define DIB3000MC_REG_SET_DDS_FREQ_LSB (    22)
+#define DIB3000MC_DDS_FREQ_LSB                 (0x463d)
+
+/* timing frequencies setting */
+#define DIB3000MC_REG_TIMING_FREQ_MSB  (    23)
+#define DIB3000MC_REG_TIMING_FREQ_LSB  (    24)
+#define DIB3000MC_CLOCK_REF                            (0x151fd1)
+
+//static u16 dib3000mc_reg_timing_freq[] = { 23,24 };
+
+//static u16 dib3000mc_timing_freq[][2] = {
+//     { 0x69, 0x9f18 }, /* 5 MHz */
+//     { 0x7e ,0xbee9 }, /* 6 MHz */
+//     { 0x93 ,0xdebb }, /* 7 MHz */
+//     { 0xa8 ,0xfe8c }, /* 8 MHz */
+//};
+
+/* timeout ??? */
+static u16 dib3000mc_reg_offset[] = { 26,33 };
+
+static u16 dib3000mc_offset[][2] = {
+       { 26240, 5 }, /* default */
+       { 30336, 6 }, /* 8K */
+       { 38528, 8 }, /* 2K */
+};
+
+#define DIB3000MC_REG_ISI                              (    29)
+#define DIB3000MC_ISI_DEFAULT                  (0x1073)
+#define DIB3000MC_ISI_ACTIVATE                 (0x0000)
+#define DIB3000MC_ISI_INHIBIT                  (0x0200)
+
+/* impulse noise control */
+static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
+
+static u16 dib3000mc_imp_noise_ctl[][2] = {
+       { 0x1294, 0xfff8 }, /* mode 0 */
+       { 0x1294, 0xfff8 }, /* mode 1 */
+       { 0x1294, 0xfff8 }, /* mode 2 */
+       { 0x1294, 0xfff8 }, /* mode 3 */
+       { 0x1294, 0xfff8 }, /* mode 4 */
+};
+
+/* AGC registers */
+static u16 dib3000mc_reg_agc[] = {
+       36,37,38,39,42,43,44,45,46,47,48,49
+};
+
+static u16 dib3000mc_agc_tuner[][12] = {
+       {       0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666,
+               0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019
+       }, /* TUNER_PANASONIC_ENV77H04D5, */
+
+       {       0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a,
+               0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e
+       }, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */
+
+       {       0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff,
+               0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040
+       }, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */
+
+       {       0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29,
+               0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537
+       }, /* TUNER_PROVIDER_X */
+       /* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */
+};
+
+/* AGC loop bandwidth */
+static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 };
+static u16 dib3000mc_agc_bandwidth[]  = { 0x119,0x330 };
+
+static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 };
+static u16 dib3000mc_agc_bandwidth_general[] =
+       { 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
+
+#define DIB3000MC_REG_IMP_NOISE_55             (    55)
+#define DIB3000MC_IMP_NEW_ALGO(w)              (w | (1<<10))
+
+/* Impulse noise params */
+static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 };
+static u16 dib3000mc_impluse_noise[][3] = {
+       { 0x489, 0x89, 0x72 }, /* 5 MHz */
+       { 0x4a5, 0xa5, 0x89 }, /* 6 MHz */
+       { 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */
+       { 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */
+};
+
+static u16 dib3000mc_reg_fft[] = {
+       58,59,60,61,62,63,64,65,66,67,68,69,
+       70,71,72,73,74,75,76,77,78,79,80,81,
+       82,83,84,85,86
+};
+
+static u16 dib3000mc_fft_modes[][29] = {
+       {       0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
+               0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
+               0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
+               0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+               0x3ffe, 0x5b3, 0x3feb, 0x76,   0x0, 0xd
+       }, /* fft mode 0 */
+       {       0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
+               0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
+               0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
+               0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
+               0x3ffe, 0x5b3, 0x3feb, 0x0,  0x8200, 0xd
+       }, /* fft mode 1 */
+};
+
+#define DIB3000MC_REG_UNK_88                   (    88)
+#define DIB3000MC_UNK_88                               (0x0410)
+
+static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 };
+static u16 dib3000mc_bw[][6] = {
+       { 0,0,0,0,0,0 }, /* 5 MHz */
+       { 0,0,0,0,0,0 }, /* 6 MHz */
+       { 0,0,0,0,0,0 }, /* 7 MHz */
+       { 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */
+};
+
+
+/* phase noise control */
+#define DIB3000MC_REG_UNK_99                   (    99)
+#define DIB3000MC_UNK_99                               (0x0220)
+
+#define DIB3000MC_REG_SCAN_BOOST               (   100)
+#define DIB3000MC_SCAN_BOOST_ON                        ((11 << 6) + 6)
+#define DIB3000MC_SCAN_BOOST_OFF               ((16 << 6) + 9)
+
+/* timeout ??? */
+#define DIB3000MC_REG_UNK_110                  (   110)
+#define DIB3000MC_UNK_110                              (  3277)
+
+#define DIB3000MC_REG_UNK_111                  (   111)
+#define DIB3000MC_UNK_111_PH_N_MODE_0  (     0)
+#define DIB3000MC_UNK_111_PH_N_MODE_1  (1 << 1)
+
+/* superious rm config */
+#define DIB3000MC_REG_UNK_120                  (   120)
+#define DIB3000MC_UNK_120                              (  8207)
+
+#define DIB3000MC_REG_UNK_133                  (   133)
+#define DIB3000MC_UNK_133                              ( 15564)
+
+#define DIB3000MC_REG_UNK_134                  (   134)
+#define DIB3000MC_UNK_134                              (     0)
+
+/* adapter config for constellation */
+static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 };
+
+static u16 dib3000mc_adp_cfg[][4] = {
+       { 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK  */
+       { 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */
+       { 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */
+};
+
+static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 };
+
+static u16 dib3000mc_mobile_mode[][5] = {
+       { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */
+       { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */
+       { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */
+       { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */
+};
+
+#define DIB3000MC_REG_DIVERSITY1               (   177)
+#define DIB3000MC_DIVERSITY1_DEFAULT   (     1)
+
+#define DIB3000MC_REG_DIVERSITY2               (   178)
+#define DIB3000MC_DIVERSITY2_DEFAULT   (     1)
+
+#define DIB3000MC_REG_DIVERSITY3               (   180)
+#define DIB3000MC_DIVERSITY3_IN_OFF            (0xfff0)
+#define DIB3000MC_DIVERSITY3_IN_ON             (0xfff6)
+
+#define DIB3000MC_REG_FEC_CFG                  (   195)
+#define DIB3000MC_FEC_CFG                              (  0x10)
+
+#define DIB3000MC_REG_SMO_MODE                 (   206)
+#define DIB3000MC_SMO_MODE_DEFAULT             (1 << 2)
+#define DIB3000MC_SMO_MODE_FIFO_FLUSH  (1 << 3)
+#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH        ~DIB3000MC_SMO_MODE_FIFO_FLUSH
+#define DIB3000MC_SMO_MODE_PID_PARSE   (1 << 4)
+#define DIB3000MC_SMO_MODE_NO_PID_PARSE        ~DIB3000MC_SMO_MODE_PID_PARSE
+#define DIB3000MC_SMO_MODE_188                 (1 << 5)
+#define DIB3000MC_SMO_MODE_SLAVE               (DIB3000MC_SMO_MODE_DEFAULT | \
+                       DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
+
+#define DIB3000MC_REG_FIFO_THRESHOLD   (   207)
+#define DIB3000MC_FIFO_THRESHOLD_DEFAULT       (  1792)
+#define DIB3000MC_FIFO_THRESHOLD_SLAVE (   512)
+/*
+ * pidfilter
+ * it is not a hardware pidfilter but a filter which drops all pids
+ * except the ones set. When connected to USB1.1 bandwidth this is important.
+ * DiB3000-MC/P can filter up to 32 PIDs
+ */
+#define DIB3000MC_REG_FIRST_PID                        (   212)
+#define DIB3000MC_NUM_PIDS                             (    32)
+
+#define DIB3000MC_REG_OUTMODE                  (   244)
+#define DIB3000MC_OM_PARALLEL_GATED_CLK        (     0)
+#define DIB3000MC_OM_PAR_CONT_CLK              (1 << 11)
+#define DIB3000MC_OM_SERIAL                            (2 << 11)
+#define DIB3000MC_OM_DIVOUT_ON                 (4 << 11)
+#define DIB3000MC_OM_SLAVE                             (DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK)
+
+#define DIB3000MC_REG_RF_POWER                 (   392)
+
+#define DIB3000MC_REG_FFT_POSITION             (   407)
+
+#define DIB3000MC_REG_DDS_FREQ_MSB             (   414)
+#define DIB3000MC_REG_DDS_FREQ_LSB             (   415)
+
+#define DIB3000MC_REG_TIMING_OFFS_MSB  (   416)
+#define DIB3000MC_REG_TIMING_OFFS_LSB  (   417)
+
+#define DIB3000MC_REG_TUNING_PARM              (   458)
+#define DIB3000MC_TP_QAM(v)                            ((v >> 13) & 0x03)
+#define DIB3000MC_TP_HRCH(v)                   ((v >> 12) & 0x01)
+#define DIB3000MC_TP_ALPHA(v)                  ((v >> 9) & 0x07)
+#define DIB3000MC_TP_FFT(v)                            ((v >> 8) & 0x01)
+#define DIB3000MC_TP_FEC_CR_HP(v)              ((v >> 5) & 0x07)
+#define DIB3000MC_TP_FEC_CR_LP(v)              ((v >> 2) & 0x07)
+#define DIB3000MC_TP_GUARD(v)                  (v & 0x03)
+
+#define DIB3000MC_REG_SIGNAL_NOISE_MSB (   483)
+#define DIB3000MC_REG_SIGNAL_NOISE_LSB (   484)
+
+#define DIB3000MC_REG_MER                              (   485)
+
+#define DIB3000MC_REG_BER_MSB                  (   500)
+#define DIB3000MC_REG_BER_LSB                  (   501)
+
+#define DIB3000MC_REG_PACKET_ERRORS            (   503)
+
+#define DIB3000MC_REG_PACKET_ERROR_COUNT       (   506)
+
+#define DIB3000MC_REG_LOCK_507                 (   507)
+#define DIB3000MC_LOCK_507                             (0x0002) // ? name correct ?
+
+#define DIB3000MC_REG_LOCKING                  (   509)
+#define DIB3000MC_AGC_LOCK(v)                  (v & 0x8000)
+#define DIB3000MC_CARRIER_LOCK(v)              (v & 0x2000)
+#define DIB3000MC_MPEG_SYNC_LOCK(v)            (v & 0x0080)
+#define DIB3000MC_MPEG_DATA_LOCK(v)            (v & 0x0040)
+#define DIB3000MC_TPS_LOCK(v)                  (v & 0x0004)
+
+#define DIB3000MC_REG_AS_IRQ                   (   511)
+#define DIB3000MC_AS_IRQ_SUCCESS               (1 << 1)
+#define DIB3000MC_AS_IRQ_FAIL                  (     1)
+
+#define DIB3000MC_REG_TUNER                            (   769)
+
+#define DIB3000MC_REG_RST_I2C_ADDR             (  1024)
+#define DIB3000MC_DEMOD_ADDR_ON                        (     1)
+#define DIB3000MC_DEMOD_ADDR(a)                        ((a << 3) & 0x03F0)
+
+#define DIB3000MC_REG_RESTART                  (  1027)
+#define DIB3000MC_RESTART_OFF                  (0x0000)
+#define DIB3000MC_RESTART_AGC                  (0x0800)
+#define DIB3000MC_RESTART_CONFIG               (0x8000)
+
+#define DIB3000MC_REG_RESTART_VIT              (  1028)
+#define DIB3000MC_RESTART_VIT_OFF              (     0)
+#define DIB3000MC_RESTART_VIT_ON               (     1)
+
+#define DIB3000MC_REG_CLK_CFG_1                        (  1031)
+#define DIB3000MC_CLK_CFG_1_POWER_UP   (     0)
+#define DIB3000MC_CLK_CFG_1_POWER_DOWN (0xffff)
+
+#define DIB3000MC_REG_CLK_CFG_2                        (  1032)
+#define DIB3000MC_CLK_CFG_2_PUP_FIXED  (0x012c)
+#define DIB3000MC_CLK_CFG_2_PUP_PORT   (0x0104)
+#define DIB3000MC_CLK_CFG_2_PUP_MOBILE  (0x0000)
+#define DIB3000MC_CLK_CFG_2_POWER_DOWN (0xffff)
+
+#define DIB3000MC_REG_CLK_CFG_3                        (  1033)
+#define DIB3000MC_CLK_CFG_3_POWER_UP   (     0)
+#define DIB3000MC_CLK_CFG_3_POWER_DOWN (0xfff5)
+
+#define DIB3000MC_REG_CLK_CFG_7                        (  1037)
+#define DIB3000MC_CLK_CFG_7_INIT               ( 12592)
+#define DIB3000MC_CLK_CFG_7_POWER_UP   (~0x0003)
+#define DIB3000MC_CLK_CFG_7_PWR_DOWN   (0x0003)
+#define DIB3000MC_CLK_CFG_7_DIV_IN_OFF (1 << 8)
+
+/* was commented out ??? */
+#define DIB3000MC_REG_CLK_CFG_8                        (  1038)
+#define DIB3000MC_CLK_CFG_8_POWER_UP   (0x160c)
+
+#define DIB3000MC_REG_CLK_CFG_9                        (  1039)
+#define DIB3000MC_CLK_CFG_9_POWER_UP   (     0)
+
+/* also clock ??? */
+#define DIB3000MC_REG_ELEC_OUT                 (  1040)
+#define DIB3000MC_ELEC_OUT_HIGH_Z              (     0)
+#define DIB3000MC_ELEC_OUT_DIV_OUT_ON  (     1)
+#define DIB3000MC_ELEC_OUT_SLAVE               (     3)
+
+#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.h b/drivers/media/dvb/frontends/dvb_dummy_fe.h
new file mode 100644 (file)
index 0000000..8210f19
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  Driver for Dummy Frontend
+ *
+ *  Written by Emard <emard@softhome.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef DVB_DUMMY_FE_H
+#define DVB_DUMMY_FE_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
+extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
+extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
+
+#endif // DVB_DUMMY_FE_H
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
new file mode 100644 (file)
index 0000000..af4cb09
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+    driver for LSI L64781 COFDM demodulator
+
+    Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
+                       for Convergence Integrated Media GmbH
+                       Marko Kohtala <marko.kohtala@nokia.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "l64781.h"
+
+
+struct l64781_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       const struct l64781_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* private demodulator data */
+       int first:1;
+};
+
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "l64781: " args); \
+       } while (0)
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
+static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf [] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+       if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
+               dprintk ("%s: write_reg error (reg == %02x) = %02x!\n",
+                        __FUNCTION__, reg, ret);
+
+       return (ret != 1) ? -1 : 0;
+}
+
+static int l64781_readreg (struct l64781_state* state, u8 reg)
+{
+       int ret;
+       u8 b0 [] = { reg };
+       u8 b1 [] = { 0 };
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+                          { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) return ret;
+
+       return b1[0];
+}
+
+static void apply_tps (struct l64781_state* state)
+{
+       l64781_writereg (state, 0x2a, 0x00);
+       l64781_writereg (state, 0x2a, 0x01);
+
+       /* This here is a little bit questionable because it enables
+          the automatic update of TPS registers. I think we'd need to
+          handle the IRQ from FE to update some other registers as
+          well, or at least implement some magic to tuning to correct
+          to the TPS received from transmission. */
+       l64781_writereg (state, 0x2a, 0x02);
+}
+
+
+static void reset_afc (struct l64781_state* state)
+{
+       /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for
+          timing offset */
+       l64781_writereg (state, 0x07, 0x9e); /* stall AFC */
+       l64781_writereg (state, 0x08, 0);    /* AFC INIT FREQ */
+       l64781_writereg (state, 0x09, 0);
+       l64781_writereg (state, 0x0a, 0);
+       l64781_writereg (state, 0x07, 0x8e);
+       l64781_writereg (state, 0x0e, 0);    /* AGC gain to zero in beginning */
+       l64781_writereg (state, 0x11, 0x80); /* stall TIM */
+       l64781_writereg (state, 0x10, 0);    /* TIM_OFFSET_LSB */
+       l64781_writereg (state, 0x12, 0);
+       l64781_writereg (state, 0x13, 0);
+       l64781_writereg (state, 0x11, 0x00);
+}
+
+static int reset_and_configure (struct l64781_state* state)
+{
+       u8 buf [] = { 0x06 };
+       struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 };
+       // NOTE: this is correct in writing to address 0x00
+
+       return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV;
+}
+
+static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+       /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */
+       static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 };
+       /* QPSK, QAM_16, QAM_64 */
+       static const u8 qam_tab [] = { 2, 4, 0, 6 };
+       static const u8 bw_tab [] = { 8, 7, 6 };  /* 8Mhz, 7MHz, 6MHz */
+       static const u8 guard_tab [] = { 1, 2, 4, 8 };
+       /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */
+       static const u32 ppm = 8000;
+       struct dvb_ofdm_parameters *p = &param->u.ofdm;
+       u32 ddfs_offset_fixed;
+/*     u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */
+/*                     bw_tab[p->bandWidth]<<10)/15625; */
+       u32 init_freq;
+       u32 spi_bias;
+       u8 val0x04;
+       u8 val0x05;
+       u8 val0x06;
+       int bw = p->bandwidth - BANDWIDTH_8_MHZ;
+
+       state->config->pll_set(fe, param);
+
+       if (param->inversion != INVERSION_ON &&
+           param->inversion != INVERSION_OFF)
+               return -EINVAL;
+
+       if (bw < 0 || bw > 2)
+               return -EINVAL;
+
+       if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 &&
+           p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 &&
+           p->code_rate_HP != FEC_7_8)
+               return -EINVAL;
+
+       if (p->hierarchy_information != HIERARCHY_NONE &&
+           (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 &&
+            p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 &&
+            p->code_rate_LP != FEC_7_8))
+               return -EINVAL;
+
+       if (p->constellation != QPSK && p->constellation != QAM_16 &&
+           p->constellation != QAM_64)
+               return -EINVAL;
+
+       if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+           p->transmission_mode != TRANSMISSION_MODE_8K)
+               return -EINVAL;
+
+       if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+           p->guard_interval > GUARD_INTERVAL_1_4)
+               return -EINVAL;
+
+       if (p->hierarchy_information < HIERARCHY_NONE ||
+           p->hierarchy_information > HIERARCHY_4)
+               return -EINVAL;
+
+       ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000;
+
+       /* This works up to 20000 ppm, it overflows if too large ppm! */
+       init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) /
+                       bw_tab[p->bandwidth] & 0xFFFFFF);
+
+       /* SPI bias calculation is slightly modified to fit in 32bit */
+       /* will work for high ppm only... */
+       spi_bias = 378 * (1 << 10);
+       spi_bias *= 16;
+       spi_bias *= bw_tab[p->bandwidth];
+       spi_bias *= qam_tab[p->constellation];
+       spi_bias /= p->code_rate_HP + 1;
+       spi_bias /= (guard_tab[p->guard_interval] + 32);
+       spi_bias *= 1000ULL;
+       spi_bias /= 1000ULL + ppm/1000;
+       spi_bias *= p->code_rate_HP;
+
+       val0x04 = (p->transmission_mode << 2) | p->guard_interval;
+       val0x05 = fec_tab[p->code_rate_HP];
+
+       if (p->hierarchy_information != HIERARCHY_NONE)
+               val0x05 |= (p->code_rate_LP - FEC_1_2) << 3;
+
+       val0x06 = (p->hierarchy_information << 2) | p->constellation;
+
+       l64781_writereg (state, 0x04, val0x04);
+       l64781_writereg (state, 0x05, val0x05);
+       l64781_writereg (state, 0x06, val0x06);
+
+       reset_afc (state);
+
+       /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */
+       l64781_writereg (state, 0x15,
+                        p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3);
+       l64781_writereg (state, 0x16, init_freq & 0xff);
+       l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff);
+       l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff);
+
+       l64781_writereg (state, 0x1b, spi_bias & 0xff);
+       l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff);
+       l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) |
+               (param->inversion == INVERSION_ON ? 0x80 : 0x00));
+
+       l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff);
+       l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f);
+
+       l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
+       l64781_readreg (state, 0x01);  /*  dto. */
+
+       apply_tps (state);
+
+       return 0;
+}
+
+static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+       int tmp;
+
+
+       tmp = l64781_readreg(state, 0x04);
+       switch(tmp & 3) {
+       case 0:
+               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       }
+       switch((tmp >> 2) & 3) {
+       case 0:
+               param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       default:
+               printk("Unexpected value for transmission_mode\n");
+       }
+
+
+
+       tmp = l64781_readreg(state, 0x05);
+       switch(tmp & 7) {
+       case 0:
+               param->u.ofdm.code_rate_HP = FEC_1_2;
+               break;
+       case 1:
+               param->u.ofdm.code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               param->u.ofdm.code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               param->u.ofdm.code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               param->u.ofdm.code_rate_HP = FEC_7_8;
+               break;
+       default:
+               printk("Unexpected value for code_rate_HP\n");
+       }
+       switch((tmp >> 3) & 7) {
+       case 0:
+               param->u.ofdm.code_rate_LP = FEC_1_2;
+               break;
+       case 1:
+               param->u.ofdm.code_rate_LP = FEC_2_3;
+               break;
+       case 2:
+               param->u.ofdm.code_rate_LP = FEC_3_4;
+               break;
+       case 3:
+               param->u.ofdm.code_rate_LP = FEC_5_6;
+               break;
+       case 4:
+               param->u.ofdm.code_rate_LP = FEC_7_8;
+               break;
+       default:
+               printk("Unexpected value for code_rate_LP\n");
+       }
+
+
+       tmp = l64781_readreg(state, 0x06);
+       switch(tmp & 3) {
+       case 0:
+               param->u.ofdm.constellation = QPSK;
+               break;
+       case 1:
+               param->u.ofdm.constellation = QAM_16;
+               break;
+       case 2:
+               param->u.ofdm.constellation = QAM_64;
+               break;
+       default:
+               printk("Unexpected value for constellation\n");
+       }
+       switch((tmp >> 2) & 7) {
+       case 0:
+               param->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+               break;
+       case 1:
+               param->u.ofdm.hierarchy_information = HIERARCHY_1;
+               break;
+       case 2:
+               param->u.ofdm.hierarchy_information = HIERARCHY_2;
+               break;
+       case 3:
+               param->u.ofdm.hierarchy_information = HIERARCHY_4;
+               break;
+       default:
+               printk("Unexpected value for hierarchy\n");
+       }
+
+
+       tmp = l64781_readreg (state, 0x1d);
+       param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF;
+
+       tmp = (int) (l64781_readreg (state, 0x08) |
+                    (l64781_readreg (state, 0x09) << 8) |
+                    (l64781_readreg (state, 0x0a) << 16));
+       param->frequency += tmp;
+
+       return 0;
+}
+
+static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+       int sync = l64781_readreg (state, 0x32);
+       int gain = l64781_readreg (state, 0x0e);
+
+       l64781_readreg (state, 0x00);  /*  clear interrupt registers... */
+       l64781_readreg (state, 0x01);  /*  dto. */
+
+       *status = 0;
+
+       if (gain > 5)
+               *status |= FE_HAS_SIGNAL;
+
+       if (sync & 0x02) /* VCXO locked, this criteria should be ok */
+               *status |= FE_HAS_CARRIER;
+
+       if (sync & 0x20)
+               *status |= FE_HAS_VITERBI;
+
+       if (sync & 0x40)
+               *status |= FE_HAS_SYNC;
+
+       if (sync == 0x7f)
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int l64781_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+       /*   XXX FIXME: set up counting period (reg 0x26...0x28)
+        */
+       *ber = l64781_readreg (state, 0x39)
+           | (l64781_readreg (state, 0x3a) << 8);
+
+       return 0;
+}
+
+static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+       u8 gain = l64781_readreg (state, 0x0e);
+       *signal_strength = (gain << 8) | gain;
+
+       return 0;
+}
+
+static int l64781_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+       u8 avg_quality = 0xff - l64781_readreg (state, 0x33);
+       *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/
+
+       return 0;
+}
+
+static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+       *ucblocks = l64781_readreg (state, 0x37)
+          | (l64781_readreg (state, 0x38) << 8);
+
+       return 0;
+}
+
+static int l64781_sleep(struct dvb_frontend* fe)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+       /* Power down */
+       return l64781_writereg (state, 0x3e, 0x5a);
+}
+
+static int l64781_init(struct dvb_frontend* fe)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+
+        reset_and_configure (state);
+
+       /* Power up */
+       l64781_writereg (state, 0x3e, 0xa5);
+
+       /* Reset hard */
+       l64781_writereg (state, 0x2a, 0x04);
+       l64781_writereg (state, 0x2a, 0x00);
+
+       /* Set tuner specific things */
+       /* AFC_POL, set also in reset_afc */
+       l64781_writereg (state, 0x07, 0x8e);
+
+       /* Use internal ADC */
+       l64781_writereg (state, 0x0b, 0x81);
+
+       /* AGC loop gain, and polarity is positive */
+       l64781_writereg (state, 0x0c, 0x84);
+
+       /* Internal ADC outputs two's complement */
+       l64781_writereg (state, 0x0d, 0x8c);
+
+       /* With ppm=8000, it seems the DTR_SENSITIVITY will result in
+           value of 2 with all possible bandwidths and guard
+           intervals, which is the initial value anyway. */
+        /*l64781_writereg (state, 0x19, 0x92);*/
+
+       /* Everything is two's complement, soft bit and CSI_OUT too */
+       l64781_writereg (state, 0x1e, 0x09);
+
+       if (state->config->pll_init) state->config->pll_init(fe);
+
+       /* delay a bit after first init attempt */
+       if (state->first) {
+               state->first = 0;
+               msleep(200);
+       }
+
+       return 0;
+}
+
+static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+        fesettings->min_delay_ms = 200;
+        fesettings->step_size = 166667;
+        fesettings->max_drift = 166667*2;
+        return 0;
+}
+
+static void l64781_release(struct dvb_frontend* fe)
+{
+       struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops l64781_ops;
+
+struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+                                  struct i2c_adapter* i2c)
+{
+       struct l64781_state* state = NULL;
+       int reg0x3e = -1;
+       u8 b0 [] = { 0x1a };
+       u8 b1 [] = { 0x00 };
+       struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+                          { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+       /* allocate memory for the internal state */
+       state = (struct l64781_state*) kmalloc(sizeof(struct l64781_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
+       state->first = 1;
+
+       /**
+        *  the L64781 won't show up before we send the reset_and_configure()
+        *  broadcast. If nothing responds there is no L64781 on the bus...
+        */
+       if (reset_and_configure(state) < 0) {
+               dprintk("No response to reset and configure broadcast...\n");
+               goto error;
+       }
+
+       /* The chip always responds to reads */
+       if (i2c_transfer(state->i2c, msg, 2) != 2) {
+               dprintk("No response to read on I2C bus\n");
+               goto error;
+       }
+
+       /* Save current register contents for bailout */
+       reg0x3e = l64781_readreg(state, 0x3e);
+
+       /* Reading the POWER_DOWN register always returns 0 */
+       if (reg0x3e != 0) {
+               dprintk("Device doesn't look like L64781\n");
+               goto error;
+       }
+
+       /* Turn the chip off */
+       l64781_writereg (state, 0x3e, 0x5a);
+
+       /* Responds to all reads with 0 */
+       if (l64781_readreg(state, 0x1a) != 0) {
+               dprintk("Read 1 returned unexpcted value\n");
+               goto error;
+       }
+
+       /* Turn the chip on */
+       l64781_writereg (state, 0x3e, 0xa5);
+
+       /* Responds with register default value */
+       if (l64781_readreg(state, 0x1a) != 0xa1) {
+               dprintk("Read 2 returned unexpcted value\n");
+               goto error;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e);  /* restore reg 0x3e */
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops l64781_ops = {
+
+       .info = {
+               .name = "LSI L64781 DVB-T",
+               .type = FE_OFDM,
+       /*      .frequency_min = ???,*/
+       /*      .frequency_max = ???,*/
+               .frequency_stepsize = 166666,
+       /*      .frequency_tolerance = ???,*/
+       /*      .symbol_rate_tolerance = ???,*/
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                     FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                     FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                     FE_CAN_MUTE_TS
+       },
+
+       .release = l64781_release,
+
+       .init = l64781_init,
+       .sleep = l64781_sleep,
+
+       .set_frontend = apply_frontend_param,
+       .get_frontend = get_frontend,
+       .get_tune_settings = l64781_get_tune_settings,
+
+       .read_status = l64781_read_status,
+       .read_ber = l64781_read_ber,
+       .read_signal_strength = l64781_read_signal_strength,
+       .read_snr = l64781_read_snr,
+       .read_ucblocks = l64781_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler, Marko Kohtala");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(l64781_attach);
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
new file mode 100644 (file)
index 0000000..259dfff
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    driver for LSI L64781 COFDM demodulator
+
+    Copyright (C) 2001 Holger Waechtler <holger@convergence.de>
+                       for Convergence Integrated Media GmbH
+                       Marko Kohtala <marko.kohtala@nokia.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef L64781_H
+#define L64781_H
+
+#include <linux/dvb/frontend.h>
+
+struct l64781_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+
+extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+                                         struct i2c_adapter* i2c);
+
+#endif // L64781_H
diff --git a/drivers/media/dvb/frontends/mt312_priv.h b/drivers/media/dvb/frontends/mt312_priv.h
new file mode 100644 (file)
index 0000000..5e0b95b
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+    Driver for Zarlink MT312 QPSK Frontend
+
+    Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _DVB_FRONTENDS_MT312_PRIV
+#define _DVB_FRONTENDS_MT312_PRIV
+
+enum mt312_reg_addr {
+       QPSK_INT_H = 0,
+       QPSK_INT_M = 1,
+       QPSK_INT_L = 2,
+       FEC_INT = 3,
+       QPSK_STAT_H = 4,
+       QPSK_STAT_L = 5,
+       FEC_STATUS = 6,
+       LNB_FREQ_H = 7,
+       LNB_FREQ_L = 8,
+       M_SNR_H = 9,
+       M_SNR_L = 10,
+       VIT_ERRCNT_H = 11,
+       VIT_ERRCNT_M = 12,
+       VIT_ERRCNT_L = 13,
+       RS_BERCNT_H = 14,
+       RS_BERCNT_M = 15,
+       RS_BERCNT_L = 16,
+       RS_UBC_H = 17,
+       RS_UBC_L = 18,
+       SIG_LEVEL = 19,
+       GPP_CTRL = 20,
+       RESET = 21,
+       DISEQC_MODE = 22,
+       SYM_RATE_H = 23,
+       SYM_RATE_L = 24,
+       VIT_MODE = 25,
+       QPSK_CTRL = 26,
+       GO = 27,
+       IE_QPSK_H = 28,
+       IE_QPSK_M = 29,
+       IE_QPSK_L = 30,
+       IE_FEC = 31,
+       QPSK_STAT_EN = 32,
+       FEC_STAT_EN = 33,
+       SYS_CLK = 34,
+       DISEQC_RATIO = 35,
+       DISEQC_INSTR = 36,
+       FR_LIM = 37,
+       FR_OFF = 38,
+       AGC_CTRL = 39,
+       AGC_INIT = 40,
+       AGC_REF = 41,
+       AGC_MAX = 42,
+       AGC_MIN = 43,
+       AGC_LK_TH = 44,
+       TS_AGC_LK_TH = 45,
+       AGC_PWR_SET = 46,
+       QPSK_MISC = 47,
+       SNR_THS_LOW = 48,
+       SNR_THS_HIGH = 49,
+       TS_SW_RATE = 50,
+       TS_SW_LIM_L = 51,
+       TS_SW_LIM_H = 52,
+       CS_SW_RATE_1 = 53,
+       CS_SW_RATE_2 = 54,
+       CS_SW_RATE_3 = 55,
+       CS_SW_RATE_4 = 56,
+       CS_SW_LIM = 57,
+       TS_LPK = 58,
+       TS_LPK_M = 59,
+       TS_LPK_L = 60,
+       CS_KPROP_H = 61,
+       CS_KPROP_L = 62,
+       CS_KINT_H = 63,
+       CS_KINT_L = 64,
+       QPSK_SCALE = 65,
+       TLD_OUTCLK_TH = 66,
+       TLD_INCLK_TH = 67,
+       FLD_TH = 68,
+       PLD_OUTLK3 = 69,
+       PLD_OUTLK2 = 70,
+       PLD_OUTLK1 = 71,
+       PLD_OUTLK0 = 72,
+       PLD_INLK3 = 73,
+       PLD_INLK2 = 74,
+       PLD_INLK1 = 75,
+       PLD_INLK0 = 76,
+       PLD_ACC_TIME = 77,
+       SWEEP_PAR = 78,
+       STARTUP_TIME = 79,
+       LOSSLOCK_TH = 80,
+       FEC_LOCK_TM = 81,
+       LOSSLOCK_TM = 82,
+       VIT_ERRPER_H = 83,
+       VIT_ERRPER_M = 84,
+       VIT_ERRPER_L = 85,
+       VIT_SETUP = 86,
+       VIT_REF0 = 87,
+       VIT_REF1 = 88,
+       VIT_REF2 = 89,
+       VIT_REF3 = 90,
+       VIT_REF4 = 91,
+       VIT_REF5 = 92,
+       VIT_REF6 = 93,
+       VIT_MAXERR = 94,
+       BA_SETUPT = 95,
+       OP_CTRL = 96,
+       FEC_SETUP = 97,
+       PROG_SYNC = 98,
+       AFC_SEAR_TH = 99,
+       CSACC_DIF_TH = 100,
+       QPSK_LK_CT = 101,
+       QPSK_ST_CT = 102,
+       MON_CTRL = 103,
+       QPSK_RESET = 104,
+       QPSK_TST_CT = 105,
+       QPSK_TST_ST = 106,
+       TEST_R = 107,
+       AGC_H = 108,
+       AGC_M = 109,
+       AGC_L = 110,
+       FREQ_ERR1_H = 111,
+       FREQ_ERR1_M = 112,
+       FREQ_ERR1_L = 113,
+       FREQ_ERR2_H = 114,
+       FREQ_ERR2_L = 115,
+       SYM_RAT_OP_H = 116,
+       SYM_RAT_OP_L = 117,
+       DESEQC2_INT = 118,
+       DISEQC2_STAT = 119,
+       DISEQC2_FIFO = 120,
+       DISEQC2_CTRL1 = 121,
+       DISEQC2_CTRL2 = 122,
+       MONITOR_H = 123,
+       MONITOR_L = 124,
+       TEST_MODE = 125,
+       ID = 126,
+       CONFIG = 127
+};
+
+enum mt312_model_id {
+       ID_VP310 = 1,
+       ID_MT312 = 3
+};
+
+#endif                         /* DVB_FRONTENDS_MT312_PRIV */
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
new file mode 100644 (file)
index 0000000..86a4627
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *      and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "mt352_priv.h"
+#include "mt352.h"
+
+struct mt352_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct mt352_config* config;
+
+       struct dvb_frontend frontend;
+};
+
+static int debug;
+#define dprintk(args...) \
+do {                                                                   \
+               if (debug) printk(KERN_DEBUG "mt352: " args); \
+} while (0)
+
+int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0,
+                              .buf = ibuf, .len = ilen };
+       int err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1) {
+               dprintk("mt352_write() failed (err = %d)!\n", err);
+               return err;
+}
+
+       return 0;
+}
+
+static u8 mt352_read_register(struct mt352_state* state, u8 reg)
+{
+       int ret;
+       u8 b0 [] = { reg };
+       u8 b1 [] = { 0 };
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address,
+                                   .flags = 0,
+                                   .buf = b0, .len = 1 },
+                                 { .addr = state->config->demod_address,
+                                   .flags = I2C_M_RD,
+                                   .buf = b1, .len = 1 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+       return b1[0];
+}
+
+
+
+
+
+
+
+
+
+
+
+
+static int mt352_sleep(struct dvb_frontend* fe)
+{
+       static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
+
+       mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
+
+       return 0;
+}
+
+static int mt352_set_parameters(struct dvb_frontend* fe,
+                               struct dvb_frontend_parameters *param)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+       unsigned char buf[14];
+       unsigned int tps = 0;
+       struct dvb_ofdm_parameters *op = &param->u.ofdm;
+       int i;
+
+       switch (op->code_rate_HP) {
+               case FEC_2_3:
+                       tps |= (1 << 7);
+                       break;
+               case FEC_3_4:
+                       tps |= (2 << 7);
+                       break;
+               case FEC_5_6:
+                       tps |= (3 << 7);
+                       break;
+               case FEC_7_8:
+                       tps |= (4 << 7);
+                       break;
+               case FEC_1_2:
+               case FEC_AUTO:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       switch (op->code_rate_LP) {
+               case FEC_2_3:
+                       tps |= (1 << 4);
+                       break;
+               case FEC_3_4:
+                       tps |= (2 << 4);
+                       break;
+               case FEC_5_6:
+                       tps |= (3 << 4);
+                       break;
+               case FEC_7_8:
+                       tps |= (4 << 4);
+                       break;
+               case FEC_1_2:
+               case FEC_AUTO:
+                       break;
+               case FEC_NONE:
+                       if (op->hierarchy_information == HIERARCHY_AUTO ||
+                           op->hierarchy_information == HIERARCHY_NONE)
+                               break;
+               default:
+                       return -EINVAL;
+       }
+
+       switch (op->constellation) {
+               case QPSK:
+                       break;
+               case QAM_AUTO:
+               case QAM_16:
+                       tps |= (1 << 13);
+                       break;
+               case QAM_64:
+                       tps |= (2 << 13);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       switch (op->transmission_mode) {
+               case TRANSMISSION_MODE_2K:
+               case TRANSMISSION_MODE_AUTO:
+                       break;
+               case TRANSMISSION_MODE_8K:
+                       tps |= (1 << 0);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       switch (op->guard_interval) {
+               case GUARD_INTERVAL_1_32:
+               case GUARD_INTERVAL_AUTO:
+                       break;
+               case GUARD_INTERVAL_1_16:
+                       tps |= (1 << 2);
+                       break;
+               case GUARD_INTERVAL_1_8:
+                       tps |= (2 << 2);
+                       break;
+               case GUARD_INTERVAL_1_4:
+                       tps |= (3 << 2);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       switch (op->hierarchy_information) {
+               case HIERARCHY_AUTO:
+               case HIERARCHY_NONE:
+                       break;
+               case HIERARCHY_1:
+                       tps |= (1 << 10);
+                       break;
+               case HIERARCHY_2:
+                       tps |= (2 << 10);
+                       break;
+               case HIERARCHY_4:
+                       tps |= (3 << 10);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+
+       buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */
+
+       buf[1] = msb(tps);      /* TPS_GIVEN_(1|0) */
+       buf[2] = lsb(tps);
+
+       buf[3] = 0x50;
+
+       /**
+        *  these settings assume 20.48MHz f_ADC, for other tuners you might
+        *  need other values. See p. 33 in the MT352 Design Manual.
+        */
+       if (op->bandwidth == BANDWIDTH_8_MHZ) {
+               buf[4] = 0x72;  /* TRL_NOMINAL_RATE_(1|0) */
+               buf[5] = 0x49;
+       } else if (op->bandwidth == BANDWIDTH_7_MHZ) {
+               buf[4] = 0x64;
+               buf[5] = 0x00;
+       } else {                /* 6MHz */
+               buf[4] = 0x55;
+               buf[5] = 0xb7;
+       }
+
+       buf[6] = 0x31;  /* INPUT_FREQ_(1|0), 20.48MHz clock, 36.166667MHz IF */
+       buf[7] = 0x05;  /* see MT352 Design Manual page 32 for details */
+
+       state->config->pll_set(fe, param, buf+8);
+
+       buf[13] = 0x01; /* TUNER_GO!! */
+
+       /* Only send the tuning request if the tuner doesn't have the requested
+        * parameters already set.  Enhances tuning time and prevents stream
+        * breakup when retuning the same transponder. */
+       for (i = 1; i < 13; i++)
+               if (buf[i] != mt352_read_register(state, i + 0x50)) {
+                       mt352_write(fe, buf, sizeof(buf));
+                       break;
+               }
+
+       return 0;
+}
+
+static int mt352_get_parameters(struct dvb_frontend* fe,
+                               struct dvb_frontend_parameters *param)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+       u16 tps;
+       u16 div;
+       u8 trl;
+       struct dvb_ofdm_parameters *op = &param->u.ofdm;
+       static const u8 tps_fec_to_api[8] =
+       {
+               FEC_1_2,
+               FEC_2_3,
+               FEC_3_4,
+               FEC_5_6,
+               FEC_7_8,
+               FEC_AUTO,
+               FEC_AUTO,
+               FEC_AUTO
+       };
+
+       if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 )
+       {
+               return -EINVAL;
+       }
+
+       /* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because
+        * the mt352 sometimes works with the wrong parameters
+        */
+       tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0);
+       div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0);
+       trl = mt352_read_register(state, TRL_NOMINAL_RATE_1);
+
+       op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+       op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+       switch ( (tps >> 13) & 3)
+       {
+               case 0:
+                       op->constellation = QPSK;
+                       break;
+               case 1:
+                       op->constellation = QAM_16;
+                       break;
+               case 2:
+                       op->constellation = QAM_64;
+                       break;
+               default:
+                       op->constellation = QAM_AUTO;
+                       break;
+       }
+
+       op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K;
+
+       switch ( (tps >> 2) & 3)
+       {
+               case 0:
+                       op->guard_interval = GUARD_INTERVAL_1_32;
+                       break;
+               case 1:
+                       op->guard_interval = GUARD_INTERVAL_1_16;
+                       break;
+               case 2:
+                       op->guard_interval = GUARD_INTERVAL_1_8;
+                       break;
+               case 3:
+                       op->guard_interval = GUARD_INTERVAL_1_4;
+                       break;
+               default:
+                       op->guard_interval = GUARD_INTERVAL_AUTO;
+                       break;
+       }
+
+       switch ( (tps >> 10) & 7)
+       {
+               case 0:
+                       op->hierarchy_information = HIERARCHY_NONE;
+                       break;
+               case 1:
+                       op->hierarchy_information = HIERARCHY_1;
+                       break;
+               case 2:
+                       op->hierarchy_information = HIERARCHY_2;
+                       break;
+               case 3:
+                       op->hierarchy_information = HIERARCHY_4;
+                       break;
+               default:
+                       op->hierarchy_information = HIERARCHY_AUTO;
+                       break;
+       }
+
+       param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000;
+
+       if (trl == 0x72)
+       {
+               op->bandwidth = BANDWIDTH_8_MHZ;
+       }
+       else if (trl == 0x64)
+       {
+               op->bandwidth = BANDWIDTH_7_MHZ;
+       }
+       else
+       {
+               op->bandwidth = BANDWIDTH_6_MHZ;
+       }
+
+
+       if (mt352_read_register(state, STATUS_2) & 0x02)
+               param->inversion = INVERSION_OFF;
+       else
+               param->inversion = INVERSION_ON;
+
+       return 0;
+}
+
+static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+       u8 r;
+
+               *status = 0;
+       r = mt352_read_register (state, STATUS_0);
+               if (r & (1 << 4))
+                       *status = FE_HAS_CARRIER;
+               if (r & (1 << 1))
+                       *status |= FE_HAS_VITERBI;
+               if (r & (1 << 5))
+                       *status |= FE_HAS_LOCK;
+
+       r = mt352_read_register (state, STATUS_1);
+               if (r & (1 << 1))
+                       *status |= FE_HAS_SYNC;
+
+       r = mt352_read_register (state, STATUS_3);
+               if (r & (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 mt352_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+
+       *ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) |
+              (mt352_read_register (state, RS_ERR_CNT_1) << 8) |
+              (mt352_read_register (state, RS_ERR_CNT_0));
+
+                       return 0;
+       }
+
+static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+
+       u16 signal = (mt352_read_register (state, AGC_GAIN_3) << 8) |
+                    (mt352_read_register (state, AGC_GAIN_2));
+
+       *strength = ~signal;
+       return 0;
+}
+
+static int mt352_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+
+       u8 _snr = mt352_read_register (state, SNR);
+       *snr = (_snr << 8) | _snr;
+
+       return 0;
+}
+
+static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+
+       *ucblocks = (mt352_read_register (state,  RS_UBC_1) << 8) |
+                   (mt352_read_register (state,  RS_UBC_0));
+
+       return 0;
+       }
+
+static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+       fe_tune_settings->min_delay_ms = 800;
+       fe_tune_settings->step_size = 0;
+       fe_tune_settings->max_drift = 0;
+
+       return 0;
+       }
+
+static int mt352_init(struct dvb_frontend* fe)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+
+       static u8 mt352_reset_attach [] = { RESET, 0xC0 };
+
+       if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 ||
+           (mt352_read_register(state, CONFIG) & 0x20) == 0) {
+
+       /* Do a "hard" reset */
+               mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
+               return state->config->demod_init(fe);
+       }
+
+       return 0;
+       }
+
+static void mt352_release(struct dvb_frontend* fe)
+{
+       struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv;
+               kfree(state);
+       }
+
+static struct dvb_frontend_ops mt352_ops;
+
+struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+                                 struct i2c_adapter* i2c)
+{
+       struct mt352_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct mt352_state*) kmalloc(sizeof(struct mt352_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
+
+       /* check if the demod is there */
+       if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops mt352_ops = {
+
+       .info = {
+               .name                   = "Zarlink MT352 DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 174000000,
+               .frequency_max          = 862000000,
+               .frequency_stepsize     = 166667,
+               .frequency_tolerance    = 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_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_HIERARCHY_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_MUTE_TS
+       },
+
+       .release = mt352_release,
+
+       .init = mt352_init,
+       .sleep = mt352_sleep,
+
+       .set_frontend = mt352_set_parameters,
+       .get_frontend = mt352_get_parameters,
+       .get_tune_settings = mt352_get_tune_settings,
+
+       .read_status = mt352_read_status,
+       .read_ber = mt352_read_ber,
+       .read_signal_strength = mt352_read_signal_strength,
+       .read_snr = mt352_read_snr,
+       .read_ucblocks = mt352_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver");
+MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(mt352_attach);
+EXPORT_SYMBOL(mt352_write);
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
new file mode 100644 (file)
index 0000000..635095b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *      and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 MT352_H
+#define MT352_H
+
+#include <linux/dvb/frontend.h>
+
+struct mt352_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* Initialise the demodulator and PLL. Cannot be NULL */
+       int (*demod_init)(struct dvb_frontend* fe);
+
+       /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
+        * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
+        * byte1-4: PLL configuration.
+        */
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
+};
+
+extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+                                        struct i2c_adapter* i2c);
+
+extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
+
+#endif // MT352_H
diff --git a/drivers/media/dvb/frontends/mt352_priv.h b/drivers/media/dvb/frontends/mt352_priv.h
new file mode 100644 (file)
index 0000000..44ad0d4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *  Driver for Zarlink DVB-T MT352 demodulator
+ *
+ *  Written by Holger Waechtler <holger@qanu.de>
+ *      and Daniel Mack <daniel@qanu.de>
+ *
+ *  AVerMedia AVerTV DVB-T 771 support by
+ *       Wolfram Joost <dbox2@frokaschwei.de>
+ *
+ *  Support for Samsung TDTC9251DH01C(M) tuner
+ *  Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it>
+ *                     Amauri  Celani  <acelani@essegi.net>
+ *
+ *  DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by
+ *       Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 _MT352_PRIV_
+#define _MT352_PRIV_
+
+#define ID_MT352        0x13
+
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
+enum mt352_reg_addr {
+       STATUS_0           = 0x00,
+       STATUS_1           = 0x01,
+       STATUS_2           = 0x02,
+       STATUS_3           = 0x03,
+       STATUS_4           = 0x04,
+       INTERRUPT_0        = 0x05,
+       INTERRUPT_1        = 0x06,
+       INTERRUPT_2        = 0x07,
+       INTERRUPT_3        = 0x08,
+       SNR                = 0x09,
+       VIT_ERR_CNT_2      = 0x0A,
+       VIT_ERR_CNT_1      = 0x0B,
+       VIT_ERR_CNT_0      = 0x0C,
+       RS_ERR_CNT_2       = 0x0D,
+       RS_ERR_CNT_1       = 0x0E,
+       RS_ERR_CNT_0       = 0x0F,
+       RS_UBC_1           = 0x10,
+       RS_UBC_0           = 0x11,
+       AGC_GAIN_3         = 0x12,
+       AGC_GAIN_2         = 0x13,
+       AGC_GAIN_1         = 0x14,
+       AGC_GAIN_0         = 0x15,
+       FREQ_OFFSET_2      = 0x17,
+       FREQ_OFFSET_1      = 0x18,
+       FREQ_OFFSET_0      = 0x19,
+       TIMING_OFFSET_1    = 0x1A,
+       TIMING_OFFSET_0    = 0x1B,
+       CHAN_FREQ_1        = 0x1C,
+       CHAN_FREQ_0        = 0x1D,
+       TPS_RECEIVED_1     = 0x1E,
+       TPS_RECEIVED_0     = 0x1F,
+       TPS_CURRENT_1      = 0x20,
+       TPS_CURRENT_0      = 0x21,
+       TPS_CELL_ID_1      = 0x22,
+       TPS_CELL_ID_0      = 0x23,
+       TPS_MISC_DATA_2    = 0x24,
+       TPS_MISC_DATA_1    = 0x25,
+       TPS_MISC_DATA_0    = 0x26,
+       RESET              = 0x50,
+       TPS_GIVEN_1        = 0x51,
+       TPS_GIVEN_0        = 0x52,
+       ACQ_CTL            = 0x53,
+       TRL_NOMINAL_RATE_1 = 0x54,
+       TRL_NOMINAL_RATE_0 = 0x55,
+       INPUT_FREQ_1       = 0x56,
+       INPUT_FREQ_0       = 0x57,
+       TUNER_ADDR         = 0x58,
+       CHAN_START_1       = 0x59,
+       CHAN_START_0       = 0x5A,
+       CONT_1             = 0x5B,
+       CONT_0             = 0x5C,
+       TUNER_GO           = 0x5D,
+       STATUS_EN_0        = 0x5F,
+       STATUS_EN_1        = 0x60,
+       INTERRUPT_EN_0     = 0x61,
+       INTERRUPT_EN_1     = 0x62,
+       INTERRUPT_EN_2     = 0x63,
+       INTERRUPT_EN_3     = 0x64,
+       AGC_TARGET         = 0x67,
+       AGC_CTL            = 0x68,
+       CAPT_RANGE         = 0x75,
+       SNR_SELECT_1       = 0x79,
+       SNR_SELECT_0       = 0x7A,
+       RS_ERR_PER_1       = 0x7C,
+       RS_ERR_PER_0       = 0x7D,
+       CHIP_ID            = 0x7F,
+       CHAN_STOP_1        = 0x80,
+       CHAN_STOP_0        = 0x81,
+       CHAN_STEP_1        = 0x82,
+       CHAN_STEP_0        = 0x83,
+       FEC_LOCK_TIME      = 0x85,
+       OFDM_LOCK_TIME     = 0x86,
+       ACQ_DELAY          = 0x87,
+       SCAN_CTL           = 0x88,
+       CLOCK_CTL          = 0x89,
+       CONFIG             = 0x8A,
+       MCLK_RATIO         = 0x8B,
+       GPP_CTL            = 0x8C,
+       ADC_CTL_1          = 0x8E,
+       ADC_CTL_0          = 0x8F
+};
+
+/* here we assume 1/6MHz == 166.66kHz stepsize */
+#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+
+#endif                          /* _MT352_PRIV_ */
diff --git a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb/frontends/nxt6000_priv.h
new file mode 100644 (file)
index 0000000..64b1a89
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Public Include File for DRV6000 users
+ * (ie. NxtWave Communications - NXT6000 demodulator driver)
+ *
+ * Copyright (C) 2001 NxtWave Communications, Inc.
+ *
+ */
+
+/*  Nxt6000 Register Addresses and Bit Masks */
+
+/* Maximum Register Number */
+#define MAXNXT6000REG          (0x9A)
+
+/* 0x1B A_VIT_BER_0  aka 0x3A */
+#define A_VIT_BER_0            (0x1B)
+
+/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */
+#define A_VIT_BER_TIMER_0      (0x1D)
+
+/* 0x21 RS_COR_STAT */
+#define RS_COR_STAT            (0x21)
+#define RSCORESTATUS           (0x03)
+
+/* 0x22 RS_COR_INTEN */
+#define RS_COR_INTEN           (0x22)
+
+/* 0x23 RS_COR_INSTAT */
+#define RS_COR_INSTAT          (0x23)
+#define INSTAT_ERROR           (0x04)
+#define LOCK_LOSS_BITS         (0x03)
+
+/* 0x24 RS_COR_SYNC_PARAM */
+#define RS_COR_SYNC_PARAM      (0x24)
+#define SYNC_PARAM             (0x03)
+
+/* 0x25 BER_CTRL */
+#define BER_CTRL               (0x25)
+#define BER_ENABLE             (0x02)
+#define BER_RESET              (0x01)
+
+/* 0x26 BER_PAY */
+#define BER_PAY                (0x26)
+
+/* 0x27 BER_PKT_L */
+#define BER_PKT_L              (0x27)
+#define BER_PKTOVERFLOW        (0x80)
+
+/* 0x30 VIT_COR_CTL */
+#define VIT_COR_CTL            (0x30)
+#define BER_CONTROL            (0x02)
+#define VIT_COR_MASK           (0x82)
+#define VIT_COR_RESYNC         (0x80)
+
+
+/* 0x32 VIT_SYNC_STATUS */
+#define VIT_SYNC_STATUS        (0x32)
+#define VITINSYNC              (0x80)
+
+/* 0x33 VIT_COR_INTEN */
+#define VIT_COR_INTEN          (0x33)
+#define GLOBAL_ENABLE          (0x80)
+
+/* 0x34 VIT_COR_INTSTAT */
+#define VIT_COR_INTSTAT        (0x34)
+#define BER_DONE               (0x08)
+#define BER_OVERFLOW           (0x10)
+
+                            /* 0x38 OFDM_BERTimer *//* Use the alias registers */
+#define A_VIT_BER_TIMER_0      (0x1D)
+
+                            /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */
+#define A_VIT_BER_0            (0x1B)
+
+/* 0x40 OFDM_COR_CTL */
+#define OFDM_COR_CTL           (0x40)
+#define COREACT                (0x20)
+#define HOLDSM                 (0x10)
+#define WAIT_AGC               (0x02)
+#define WAIT_SYR               (0x03)
+
+/* 0x41 OFDM_COR_STAT */
+#define OFDM_COR_STAT          (0x41)
+#define COR_STATUS             (0x0F)
+#define MONITOR_TPS            (0x06)
+#define TPSLOCKED              (0x40)
+#define AGCLOCKED              (0x10)
+
+/* 0x42 OFDM_COR_INTEN */
+#define OFDM_COR_INTEN         (0x42)
+#define TPSRCVBAD              (0x04)
+#define TPSRCVCHANGED         (0x02)
+#define TPSRCVUPDATE           (0x01)
+
+/* 0x43 OFDM_COR_INSTAT */
+#define OFDM_COR_INSTAT        (0x43)
+
+/* 0x44 OFDM_COR_MODEGUARD */
+#define OFDM_COR_MODEGUARD     (0x44)
+#define FORCEMODE              (0x08)
+#define FORCEMODE8K                       (0x04)
+
+/* 0x45 OFDM_AGC_CTL */
+#define OFDM_AGC_CTL           (0x45)
+#define INITIAL_AGC_BW            (0x08)
+#define AGCNEG                 (0x02)
+#define AGCLAST                                   (0x10)
+
+/* 0x48 OFDM_AGC_TARGET */
+#define OFDM_AGC_TARGET                   (0x48)
+#define OFDM_AGC_TARGET_DEFAULT (0x28)
+#define OFDM_AGC_TARGET_IMPULSE (0x38)
+
+/* 0x49 OFDM_AGC_GAIN_1 */
+#define OFDM_AGC_GAIN_1        (0x49)
+
+/* 0x4B OFDM_ITB_CTL */
+#define OFDM_ITB_CTL           (0x4B)
+#define ITBINV                 (0x01)
+
+/* 0x4C OFDM_ITB_FREQ_1 */
+#define OFDM_ITB_FREQ_1        (0x4C)
+
+/* 0x4D OFDM_ITB_FREQ_2 */
+#define OFDM_ITB_FREQ_2        (0x4D)
+
+/* 0x4E  OFDM_CAS_CTL */
+#define OFDM_CAS_CTL           (0x4E)
+#define ACSDIS                 (0x40)
+#define CCSEN                  (0x80)
+
+/* 0x4F CAS_FREQ */
+#define CAS_FREQ               (0x4F)
+
+/* 0x51 OFDM_SYR_CTL */
+#define OFDM_SYR_CTL           (0x51)
+#define SIXTH_ENABLE           (0x80)
+#define SYR_TRACKING_DISABLE   (0x01)
+
+/* 0x52 OFDM_SYR_STAT */
+#define OFDM_SYR_STAT             (0x52)
+#define GI14_2K_SYR_LOCK          (0x13)
+#define GI14_8K_SYR_LOCK          (0x17)
+#define GI14_SYR_LOCK             (0x10)
+
+/* 0x55 OFDM_SYR_OFFSET_1 */
+#define OFDM_SYR_OFFSET_1      (0x55)
+
+/* 0x56 OFDM_SYR_OFFSET_2 */
+#define OFDM_SYR_OFFSET_2      (0x56)
+
+/* 0x58 OFDM_SCR_CTL */
+#define OFDM_SCR_CTL           (0x58)
+#define SYR_ADJ_DECAY_MASK     (0x70)
+#define SYR_ADJ_DECAY          (0x30)
+
+/* 0x59 OFDM_PPM_CTL_1 */
+#define OFDM_PPM_CTL_1         (0x59)
+#define PPMMAX_MASK            (0x30)
+#define PPM256                            (0x30)
+
+/* 0x5B OFDM_TRL_NOMINALRATE_1 */
+#define OFDM_TRL_NOMINALRATE_1 (0x5B)
+
+/* 0x5C OFDM_TRL_NOMINALRATE_2 */
+#define OFDM_TRL_NOMINALRATE_2 (0x5C)
+
+/* 0x5D OFDM_TRL_TIME_1 */
+#define OFDM_TRL_TIME_1        (0x5D)
+
+/* 0x60 OFDM_CRL_FREQ_1 */
+#define OFDM_CRL_FREQ_1        (0x60)
+
+/* 0x63 OFDM_CHC_CTL_1 */
+#define OFDM_CHC_CTL_1         (0x63)
+#define MANMEAN1               (0xF0);
+#define CHCFIR                 (0x01)
+
+/* 0x64 OFDM_CHC_SNR */
+#define OFDM_CHC_SNR           (0x64)
+
+/* 0x65 OFDM_BDI_CTL */
+#define OFDM_BDI_CTL           (0x65)
+#define LP_SELECT              (0x02)
+
+/* 0x67 OFDM_TPS_RCVD_1 */
+#define OFDM_TPS_RCVD_1        (0x67)
+#define TPSFRAME               (0x03)
+
+/* 0x68 OFDM_TPS_RCVD_2 */
+#define OFDM_TPS_RCVD_2        (0x68)
+
+/* 0x69 OFDM_TPS_RCVD_3 */
+#define OFDM_TPS_RCVD_3        (0x69)
+
+/* 0x6A OFDM_TPS_RCVD_4 */
+#define OFDM_TPS_RCVD_4        (0x6A)
+
+/* 0x6B OFDM_TPS_RESERVED_1 */
+#define OFDM_TPS_RESERVED_1    (0x6B)
+
+/* 0x6C OFDM_TPS_RESERVED_2 */
+#define OFDM_TPS_RESERVED_2    (0x6C)
+
+/* 0x73 OFDM_MSC_REV */
+#define OFDM_MSC_REV           (0x73)
+
+/* 0x76 OFDM_SNR_CARRIER_2 */
+#define OFDM_SNR_CARRIER_2     (0x76)
+#define MEAN_MASK              (0x80)
+#define MEANBIT                (0x80)
+
+/* 0x80 ANALOG_CONTROL_0 */
+#define ANALOG_CONTROL_0       (0x80)
+#define POWER_DOWN_ADC         (0x40)
+
+/* 0x81 ENABLE_TUNER_IIC */
+#define ENABLE_TUNER_IIC       (0x81)
+#define ENABLE_TUNER_BIT       (0x01)
+
+/* 0x82 EN_DMD_RACQ */
+#define EN_DMD_RACQ            (0x82)
+#define EN_DMD_RACQ_REG_VAL    (0x81)
+#define EN_DMD_RACQ_REG_VAL_14 (0x01)
+
+/* 0x84 SNR_COMMAND */
+#define SNR_COMMAND            (0x84)
+#define SNRStat                (0x80)
+
+/* 0x85 SNRCARRIERNUMBER_LSB */
+#define SNRCARRIERNUMBER_LSB   (0x85)
+
+/* 0x87 SNRMINTHRESHOLD_LSB */
+#define SNRMINTHRESHOLD_LSB    (0x87)
+
+/* 0x89 SNR_PER_CARRIER_LSB */
+#define SNR_PER_CARRIER_LSB    (0x89)
+
+/* 0x8B SNRBELOWTHRESHOLD_LSB */
+#define SNRBELOWTHRESHOLD_LSB  (0x8B)
+
+/* 0x91 RF_AGC_VAL_1 */
+#define RF_AGC_VAL_1           (0x91)
+
+/* 0x92 RF_AGC_STATUS */
+#define RF_AGC_STATUS          (0x92)
+
+/* 0x98 DIAG_CONFIG */
+#define DIAG_CONFIG            (0x98)
+#define DIAG_MASK              (0x70)
+#define TB_SET                 (0x10)
+#define TRAN_SELECT            (0x07)
+#define SERIAL_SELECT          (0x01)
+
+/* 0x99 SUB_DIAG_MODE_SEL */
+#define SUB_DIAG_MODE_SEL      (0x99)
+#define CLKINVERSION           (0x01)
+
+/* 0x9A TS_FORMAT */
+#define TS_FORMAT              (0x9A)
+#define ERROR_SENSE            (0x08)
+#define VALID_SENSE            (0x04)
+#define SYNC_SENSE             (0x02)
+#define GATED_CLOCK            (0x01)
+
+#define NXT6000ASICDEVICE      (0x0b)
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
new file mode 100644 (file)
index 0000000..4a8178d
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+    Driver for Spase SP8870 demodulator
+
+    Copyright (C) 1999 Juergen Peitz
+
+    This 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.
+
+*/
+/*
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+ * download/extract it, and then copy it to /usr/lib/hotplug/firmware.
+ */
+#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "sp8870.h"
+
+
+struct sp8870_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       const struct sp8870_config* config;
+
+       struct dvb_frontend frontend;
+
+       /* demodulator private data */
+       u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "sp8870: " args); \
+       } while (0)
+
+/* firmware size for sp8870 */
+#define SP8870_FIRMWARE_SIZE 16382
+
+/* starting point for firmware in file 'Sc_main.mc' */
+#define SP8870_FIRMWARE_OFFSET 0x0A
+
+static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
+{
+        u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
+       int err;
+
+        if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+               dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+               return -EREMOTEIO;
+       }
+
+        return 0;
+}
+
+static int sp8870_readreg (struct sp8870_state* state, u16 reg)
+{
+       int ret;
+       u8 b0 [] = { reg >> 8 , reg & 0xff };
+       u8 b1 [] = { 0, 0 };
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+                          { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+
+       ret = i2c_transfer (state->i2c, msg, 2);
+
+       if (ret != 2) {
+               dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+               return -1;
+       }
+
+       return (b1[0] << 8 | b1[1]);
+}
+
+static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
+{
+       struct i2c_msg msg;
+       char *fw_buf = fw->data;
+       int fw_pos;
+       u8 tx_buf[255];
+       int tx_len;
+       int err = 0;
+
+       dprintk ("%s: ...\n", __FUNCTION__);
+
+       if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
+               return -EINVAL;
+
+       // system controller stop
+       sp8870_writereg(state, 0x0F00, 0x0000);
+
+       // instruction RAM register hiword
+       sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF));
+
+       // instruction RAM MWR
+       sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16));
+
+       // do firmware upload
+       fw_pos = SP8870_FIRMWARE_OFFSET;
+       while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
+               tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
+               // write register 0xCF0A
+               tx_buf[0] = 0xCF;
+               tx_buf[1] = 0x0A;
+               memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len);
+               msg.addr = state->config->demod_address;
+               msg.flags = 0;
+               msg.buf = tx_buf;
+               msg.len = tx_len + 2;
+               if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+                       printk("%s: firmware upload failed!\n", __FUNCTION__);
+                       printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err);
+                       return err;
+               }
+               fw_pos += tx_len;
+       }
+
+       dprintk ("%s: done!\n", __FUNCTION__);
+       return 0;
+};
+
+static void sp8870_microcontroller_stop (struct sp8870_state* state)
+{
+       sp8870_writereg(state, 0x0F08, 0x000);
+       sp8870_writereg(state, 0x0F09, 0x000);
+
+       // microcontroller STOP
+       sp8870_writereg(state, 0x0F00, 0x000);
+}
+
+static void sp8870_microcontroller_start (struct sp8870_state* state)
+{
+       sp8870_writereg(state, 0x0F08, 0x000);
+       sp8870_writereg(state, 0x0F09, 0x000);
+
+       // microcontroller START
+       sp8870_writereg(state, 0x0F00, 0x001);
+       // not documented but if we don't read 0x0D01 out here
+       // we don't get a correct data valid signal
+       sp8870_readreg(state, 0x0D01);
+}
+
+static int sp8870_read_data_valid_signal(struct sp8870_state* state)
+{
+       return (sp8870_readreg(state, 0x0D02) > 0);
+}
+
+static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05)
+{
+       int known_parameters = 1;
+
+       *reg0xc05 = 0x000;
+
+       switch (p->u.ofdm.constellation) {
+       case QPSK:
+               break;
+       case QAM_16:
+               *reg0xc05 |= (1 << 10);
+               break;
+       case QAM_64:
+               *reg0xc05 |= (2 << 10);
+               break;
+       case QAM_AUTO:
+               known_parameters = 0;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       switch (p->u.ofdm.hierarchy_information) {
+       case HIERARCHY_NONE:
+               break;
+       case HIERARCHY_1:
+               *reg0xc05 |= (1 << 7);
+               break;
+       case HIERARCHY_2:
+               *reg0xc05 |= (2 << 7);
+               break;
+       case HIERARCHY_4:
+               *reg0xc05 |= (3 << 7);
+               break;
+       case HIERARCHY_AUTO:
+               known_parameters = 0;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       switch (p->u.ofdm.code_rate_HP) {
+       case FEC_1_2:
+               break;
+       case FEC_2_3:
+               *reg0xc05 |= (1 << 3);
+               break;
+       case FEC_3_4:
+               *reg0xc05 |= (2 << 3);
+               break;
+       case FEC_5_6:
+               *reg0xc05 |= (3 << 3);
+               break;
+       case FEC_7_8:
+               *reg0xc05 |= (4 << 3);
+               break;
+       case FEC_AUTO:
+               known_parameters = 0;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       if (known_parameters)
+               *reg0xc05 |= (2 << 1);  /* use specified parameters */
+       else
+               *reg0xc05 |= (1 << 1);  /* enable autoprobing */
+
+       return 0;
+}
+
+static int sp8870_wake_up(struct sp8870_state* state)
+{
+       // enable TS output and interface pins
+       return sp8870_writereg(state, 0xC18, 0x00D);
+}
+
+static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
+                                          struct dvb_frontend_parameters *p)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+       int  err;
+       u16 reg0xc05;
+
+       if ((err = configure_reg0xc05(p, &reg0xc05)))
+               return err;
+
+       // system controller stop
+       sp8870_microcontroller_stop(state);
+
+       // set tuner parameters
+       sp8870_writereg(state, 0x206, 0x001);
+       state->config->pll_set(fe, p);
+       sp8870_writereg(state, 0x206, 0x000);
+
+       // sample rate correction bit [23..17]
+       sp8870_writereg(state, 0x0319, 0x000A);
+
+       // sample rate correction bit [16..0]
+       sp8870_writereg(state, 0x031A, 0x0AAB);
+
+       // integer carrier offset
+       sp8870_writereg(state, 0x0309, 0x0400);
+
+       // fractional carrier offset
+       sp8870_writereg(state, 0x030A, 0x0000);
+
+       // filter for 6/7/8 Mhz channel
+       if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+               sp8870_writereg(state, 0x0311, 0x0002);
+       else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+               sp8870_writereg(state, 0x0311, 0x0001);
+       else
+               sp8870_writereg(state, 0x0311, 0x0000);
+
+       // scan order: 2k first = 0x0000, 8k first = 0x0001
+       if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K)
+               sp8870_writereg(state, 0x0338, 0x0000);
+       else
+               sp8870_writereg(state, 0x0338, 0x0001);
+
+       sp8870_writereg(state, 0xc05, reg0xc05);
+
+       // read status reg in order to clear pending irqs
+       sp8870_readreg(state, 0x200);
+
+       // system controller start
+       sp8870_microcontroller_start(state);
+
+       return 0;
+}
+
+static int sp8870_init (struct dvb_frontend* fe)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+        const struct firmware *fw = NULL;
+
+       sp8870_wake_up(state);
+       if (state->initialised) return 0;
+       state->initialised = 1;
+
+       dprintk ("%s\n", __FUNCTION__);
+
+
+       /* request the firmware, this will block until someone uploads it */
+       printk("sp8870: waiting for firmware upload...\n");
+       if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
+               printk("sp8870: no firmware upload (timeout or file not found?)\n");
+               release_firmware(fw);
+               return -EIO;
+       }
+
+       if (sp8870_firmware_upload(state, fw)) {
+               printk("sp8870: writing firmware to device failed\n");
+               release_firmware(fw);
+               return -EIO;
+       }
+
+       /* enable TS output and interface pins */
+       sp8870_writereg(state, 0xc18, 0x00d);
+
+       // system controller stop
+       sp8870_microcontroller_stop(state);
+
+       // ADC mode
+       sp8870_writereg(state, 0x0301, 0x0003);
+
+       // Reed Solomon parity bytes passed to output
+       sp8870_writereg(state, 0x0C13, 0x0001);
+
+       // MPEG clock is suppressed if no valid data
+       sp8870_writereg(state, 0x0C14, 0x0001);
+
+       /* bit 0x010: enable data valid signal */
+       sp8870_writereg(state, 0x0D00, 0x010);
+       sp8870_writereg(state, 0x0D01, 0x000);
+
+       /* setup PLL */
+       if (state->config->pll_init) {
+               sp8870_writereg(state, 0x206, 0x001);
+               state->config->pll_init(fe);
+               sp8870_writereg(state, 0x206, 0x000);
+       }
+
+       return 0;
+}
+
+static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+       int status;
+       int signal;
+
+       *fe_status = 0;
+
+       status = sp8870_readreg (state, 0x0200);
+       if (status < 0)
+               return -EIO;
+
+       signal = sp8870_readreg (state, 0x0303);
+       if (signal < 0)
+               return -EIO;
+
+       if (signal > 0x0F)
+               *fe_status |= FE_HAS_SIGNAL;
+       if (status & 0x08)
+               *fe_status |= FE_HAS_SYNC;
+       if (status & 0x04)
+               *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI;
+
+       return 0;
+}
+
+static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+       int ret;
+       u32 tmp;
+
+       *ber = 0;
+
+       ret = sp8870_readreg(state, 0xC08);
+       if (ret < 0)
+               return -EIO;
+
+       tmp = ret & 0x3F;
+
+       ret = sp8870_readreg(state, 0xC07);
+       if (ret < 0)
+               return -EIO;
+
+        tmp = ret << 6;
+
+       if (tmp >= 0x3FFF0)
+               tmp = ~0;
+
+       *ber = tmp;
+
+       return 0;
+}
+
+static int sp8870_read_signal_strength(struct dvb_frontend* fe,  u16 * signal)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+       int ret;
+       u16 tmp;
+
+       *signal = 0;
+
+       ret = sp8870_readreg (state, 0x306);
+       if (ret < 0)
+               return -EIO;
+
+       tmp = ret << 8;
+
+       ret = sp8870_readreg (state, 0x303);
+       if (ret < 0)
+               return -EIO;
+
+       tmp |= ret;
+
+       if (tmp)
+               *signal = 0xFFFF - tmp;
+
+       return 0;
+}
+
+static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+       int ret;
+
+       *ublocks = 0;
+
+       ret = sp8870_readreg(state, 0xC0C);
+       if (ret < 0)
+               return -EIO;
+
+       if (ret == 0xFFFF)
+               ret = ~0;
+
+       *ublocks = ret;
+
+       return 0;
+}
+
+// number of trials to recover from lockup
+#define MAXTRIALS 5
+// maximum checks for data valid signal
+#define MAXCHECKS 100
+
+// only for debugging: counter for detected lockups
+static int lockups = 0;
+// only for debugging: counter for channel switches
+static int switches = 0;
+
+static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+
+       /*
+           The firmware of the sp8870 sometimes locks up after setting frontend parameters.
+           We try to detect this by checking the data valid signal.
+           If it is not set after MAXCHECKS we try to recover the lockup by setting
+           the frontend parameters again.
+       */
+
+       int err = 0;
+       int valid = 0;
+       int trials = 0;
+       int check_count = 0;
+
+       dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency);
+
+       for (trials = 1; trials <= MAXTRIALS; trials++) {
+
+               if ((err = sp8870_set_frontend_parameters(fe, p)))
+                       return err;
+
+               for (check_count = 0; check_count < MAXCHECKS; check_count++) {
+//                     valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
+                       valid = sp8870_read_data_valid_signal(state);
+                       if (valid) {
+                               dprintk("%s: delay = %i usec\n",
+                                       __FUNCTION__, check_count * 10);
+                               break;
+                       }
+                       udelay(10);
+               }
+               if (valid)
+                       break;
+       }
+
+       if (!valid) {
+               printk("%s: firmware crash!!!!!!\n", __FUNCTION__);
+               return -EIO;
+       }
+
+       if (debug) {
+               if (valid) {
+                       if (trials > 1) {
+                               printk("%s: firmware lockup!!!\n", __FUNCTION__);
+                               printk("%s: recovered after %i trial(s))\n",  __FUNCTION__, trials - 1);
+                               lockups++;
+                       }
+               }
+               switches++;
+               printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups);
+       }
+
+       return 0;
+}
+
+static int sp8870_sleep(struct dvb_frontend* fe)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+
+       // tristate TS output and disable interface pins
+       return sp8870_writereg(state, 0xC18, 0x000);
+}
+
+static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+        fesettings->min_delay_ms = 350;
+        fesettings->step_size = 0;
+        fesettings->max_drift = 0;
+        return 0;
+}
+
+static void sp8870_release(struct dvb_frontend* fe)
+{
+       struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops sp8870_ops;
+
+struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+                                  struct i2c_adapter* i2c)
+{
+       struct sp8870_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct sp8870_state*) kmalloc(sizeof(struct sp8870_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
+       state->initialised = 0;
+
+       /* check if the demod is there */
+       if (sp8870_readreg(state, 0x0200) < 0) goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops sp8870_ops = {
+
+       .info = {
+               .name                   = "Spase SP8870 DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 470000000,
+               .frequency_max          = 860000000,
+               .frequency_stepsize     = 166666,
+               .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_QPSK | FE_CAN_QAM_16 |
+                                         FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                                         FE_CAN_HIERARCHY_AUTO |  FE_CAN_RECOVER
+       },
+
+       .release = sp8870_release,
+
+       .init = sp8870_init,
+       .sleep = sp8870_sleep,
+
+       .set_frontend = sp8870_set_frontend,
+       .get_tune_settings = sp8870_get_tune_settings,
+
+       .read_status = sp8870_read_status,
+       .read_ber = sp8870_read_ber,
+       .read_signal_strength = sp8870_read_signal_strength,
+       .read_ucblocks = sp8870_read_uncorrected_blocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
+MODULE_AUTHOR("Juergen Peitz");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(sp8870_attach);
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
new file mode 100644 (file)
index 0000000..f3b555d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Driver for Spase SP8870 demodulator
+
+    Copyright (C) 1999 Juergen Peitz
+
+    This 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 SP8870_H
+#define SP8870_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct sp8870_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+       /* request firmware for device */
+       int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+                                         struct i2c_adapter* i2c);
+
+#endif // SP8870_H
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
new file mode 100644 (file)
index 0000000..6a05d8f
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+   Driver for the Spase sp887x demodulator
+*/
+
+#ifndef SP887X_H
+#define SP887X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct sp887x_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+
+       /* this should return the actual frequency tuned to */
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+       /* request firmware for device */
+       int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+                                         struct i2c_adapter* i2c);
+
+#endif // SP887X_H
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
new file mode 100644 (file)
index 0000000..67dc53f
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+    Driver for STV0297 demodulator
+
+    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
+    Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "stv0297.h"
+
+struct stv0297_state {
+
+        struct i2c_adapter* i2c;
+
+        struct dvb_frontend_ops ops;
+
+        const struct stv0297_config* config;
+
+        struct dvb_frontend frontend;
+
+        int freq_off;
+
+       unsigned long base_freq;
+
+       u8 pwm;
+};
+
+#if 1
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+#define STV0297_CLOCK_KHZ   28900
+
+static u8 init_tab [] = {
+  0x00, 0x09,
+  0x01, 0x69,
+  0x03, 0x00,
+  0x04, 0x00,
+  0x07, 0x00,
+  0x08, 0x00,
+  0x20, 0x00,
+  0x21, 0x40,
+  0x22, 0x00,
+  0x23, 0x00,
+  0x24, 0x40,
+  0x25, 0x88,
+  0x30, 0xff,
+  0x31, 0x00,
+  0x32, 0xff,
+  0x33, 0x00,
+  0x34, 0x50,
+  0x35, 0x7f,
+  0x36, 0x00,
+  0x37, 0x20,
+  0x38, 0x00,
+  0x40, 0x1c,
+  0x41, 0xff,
+  0x42, 0x29,
+       0x43, 0x00,
+  0x44, 0xff,
+  0x45, 0x00,
+  0x46, 0x00,
+  0x49, 0x04,
+  0x4a, 0xff,
+  0x4b, 0x7f,
+  0x52, 0x30,
+  0x55, 0xae,
+  0x56, 0x47,
+  0x57, 0xe1,
+  0x58, 0x3a,
+  0x5a, 0x1e,
+  0x5b, 0x34,
+  0x60, 0x00,
+  0x63, 0x00,
+  0x64, 0x00,
+  0x65, 0x00,
+  0x66, 0x00,
+  0x67, 0x00,
+  0x68, 0x00,
+  0x69, 0x00,
+  0x6a, 0x02,
+  0x6b, 0x00,
+  0x70, 0xff,
+  0x71, 0x00,
+  0x72, 0x00,
+  0x73, 0x00,
+  0x74, 0x0c,
+  0x80, 0x00,
+  0x81, 0x00,
+  0x82, 0x00,
+  0x83, 0x00,
+  0x84, 0x04,
+  0x85, 0x80,
+  0x86, 0x24,
+  0x87, 0x78,
+  0x88, 0x00,
+  0x89, 0x00,
+  0x90, 0x01,
+  0x91, 0x01,
+  0xa0, 0x00,
+  0xa1, 0x00,
+  0xa2, 0x00,
+  0xb0, 0x91,
+  0xb1, 0x0b,
+  0xc0, 0x53,
+  0xc1, 0x70,
+  0xc2, 0x12,
+  0xd0, 0x00,
+  0xd1, 0x00,
+  0xd2, 0x00,
+  0xd3, 0x00,
+  0xd4, 0x00,
+  0xd5, 0x00,
+  0xde, 0x00,
+  0xdf, 0x00,
+  0x61, 0x49,
+  0x62, 0x0b,
+  0x53, 0x08,
+  0x59, 0x08,
+};
+
+
+static int stv0297_writereg (struct stv0297_state* state, u8 reg, u8 data)
+{
+        int ret;
+        u8 buf [] = { reg, data };
+        struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+        ret = i2c_transfer (state->i2c, &msg, 1);
+
+        if (ret != 1)
+                dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+                  "ret == %i)\n", __FUNCTION__, reg, data, ret);
+
+        return (ret != 1) ? -1 : 0;
+}
+
+static int stv0297_readreg (struct stv0297_state* state, u8 reg)
+{
+        int ret;
+        u8 b0[] = { reg };
+        u8 b1[] = { 0 };
+        struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+                                  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+        // this device needs a STOP between the register and data
+        if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) {
+               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+                return -1;
+        }
+        if ((ret = i2c_transfer (state->i2c, &msg[1], 1)) != 1) {
+               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+                return -1;
+        }
+
+        return b1[0];
+}
+
+static int stv0297_writereg_mask (struct stv0297_state* state, u8 reg, u8 mask, u8 data)
+{
+        int val;
+
+        val = stv0297_readreg(state, reg);
+        val &= ~mask;
+        val |= (data & mask);
+        stv0297_writereg(state, reg, val);
+
+        return 0;
+}
+
+static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len)
+{
+        int ret;
+        struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+                                  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+
+        // this device needs a STOP between the register and data
+        if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) {
+               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+                return -1;
+        }
+        if ((ret = i2c_transfer (state->i2c, &msg[1], 1)) != 1) {
+               dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+                return -1;
+        }
+
+        return 0;
+}
+
+static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate)
+{
+       long tmp;
+
+       tmp = 131072L * srate;  /* 131072 = 2^17  */
+       tmp = tmp / (STV0297_CLOCK_KHZ / 4);    /* 1/4 = 2^-2 */
+       tmp = tmp * 8192L;      /* 8192 = 2^13 */
+
+        stv0297_writereg (state, 0x55,(unsigned char)(tmp & 0xFF));
+        stv0297_writereg (state, 0x56,(unsigned char)(tmp>> 8));
+        stv0297_writereg (state, 0x57,(unsigned char)(tmp>>16));
+        stv0297_writereg (state, 0x58,(unsigned char)(tmp>>24));
+}
+
+static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate)
+{
+       long tmp;
+
+       tmp = (long) fshift *262144L;   /* 262144 = 2*18 */
+       tmp /= symrate;
+       tmp *= 1024;            /* 1024 = 2*10   */
+
+        // adjust
+        if (tmp >= 0) {
+                tmp += 500000;
+        } else {
+                tmp -= 500000;
+        }
+       tmp /= 1000000;
+
+        stv0297_writereg(state, 0x60, tmp & 0xFF);
+        stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0);
+}
+
+static void stv0297_set_carrieroffset(struct stv0297_state* state, long offset)
+{
+       long tmp;
+
+       /* symrate is hardcoded to 10000 */
+       tmp = offset * 26844L;  /* (2**28)/10000 */
+       if (tmp < 0)
+               tmp += 0x10000000;
+       tmp &= 0x0FFFFFFF;
+
+       stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF));
+       stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8));
+       stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16));
+       stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f);
+}
+
+static long stv0297_get_carrieroffset(struct stv0297_state* state)
+{
+        s32 raw;
+       long tmp;
+
+        stv0297_writereg(state,0x6B, 0x00);
+
+        raw =   stv0297_readreg(state,0x66);
+        raw |= (stv0297_readreg(state,0x67) << 8);
+        raw |= (stv0297_readreg(state,0x68) << 16);
+        raw |= (stv0297_readreg(state,0x69) & 0x0F) << 24;
+
+        tmp = raw;
+       tmp /= 26844L;
+
+       return tmp;
+}
+
+static void stv0297_set_initialdemodfreq(struct stv0297_state* state, long freq)
+{
+/*
+        s64 tmp;
+
+        if (freq > 10000) freq -= STV0297_CLOCK_KHZ;
+
+        tmp = freq << 16;
+        do_div(tmp, STV0297_CLOCK_KHZ);
+        if (tmp > 0xffff) tmp = 0xffff; // check this calculation
+
+        stv0297_writereg_mask(state, 0x25, 0x80, 0x80);
+        stv0297_writereg(state, 0x21, tmp >> 8);
+        stv0297_writereg(state, 0x20, tmp);
+*/
+}
+
+static int stv0297_set_qam(struct stv0297_state* state, fe_modulation_t modulation)
+{
+        int val = 0;
+
+        switch(modulation) {
+        case QAM_16:
+                val = 0;
+                break;
+
+        case QAM_32:
+                val = 1;
+                break;
+
+        case QAM_64:
+                val = 4;
+                break;
+
+        case QAM_128:
+                val = 2;
+                break;
+
+        case QAM_256:
+                val = 3;
+                break;
+
+        default:
+                return -EINVAL;
+        }
+
+        stv0297_writereg_mask(state, 0x00, 0x70, val << 4);
+
+        return 0;
+}
+
+static int stv0297_set_inversion(struct stv0297_state* state, fe_spectral_inversion_t inversion)
+{
+        int val = 0;
+
+        switch(inversion) {
+        case INVERSION_OFF:
+                val = 0;
+                break;
+
+        case INVERSION_ON:
+                val = 1;
+                break;
+
+        default:
+                return -EINVAL;
+        }
+
+        stv0297_writereg_mask(state, 0x83, 0x08, val << 3);
+
+        return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+int stv0297_enable_plli2c(struct dvb_frontend* fe)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+
+        stv0297_writereg(state, 0x87, 0x78);
+        stv0297_writereg(state, 0x86, 0xc8);
+
+        return 0;
+}
+
+static int stv0297_init (struct dvb_frontend* fe)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        int i;
+
+       /* soft reset */
+        stv0297_writereg_mask(state, 0x80, 1, 1);
+        stv0297_writereg_mask(state, 0x80, 1, 0);
+
+       /* reset deinterleaver */
+        stv0297_writereg_mask(state, 0x81, 1, 1);
+        stv0297_writereg_mask(state, 0x81, 1, 0);
+
+       /* load init table */
+        for (i=0; i<sizeof(init_tab); i+=2) {
+                stv0297_writereg (state, init_tab[i], init_tab[i+1]);
+        }
+
+       /* set a dummy symbol rate */
+        stv0297_set_symbolrate(state, 6900);
+
+       /* invert AGC1 polarity */
+        stv0297_writereg_mask(state, 0x88, 0x10, 0x10);
+
+       /* setup bit error counting */
+        stv0297_writereg_mask(state, 0xA0, 0x80, 0x00);
+        stv0297_writereg_mask(state, 0xA0, 0x10, 0x00);
+        stv0297_writereg_mask(state, 0xA0, 0x08, 0x00);
+        stv0297_writereg_mask(state, 0xA0, 0x07, 0x04);
+
+       /* min + max PWM */
+        stv0297_writereg(state, 0x4a, 0x00);
+        stv0297_writereg(state, 0x4b, state->pwm);
+        msleep(200);
+
+       if (state->config->pll_init)
+               state->config->pll_init(fe);
+
+        return 0;
+}
+
+static int stv0297_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+
+        u8 sync = stv0297_readreg (state, 0xDF);
+
+        *status = 0;
+        if (sync & 0x80)
+               *status |=
+                       FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
+        return 0;
+}
+
+static int stv0297_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        u8 BER[3];
+
+        stv0297_writereg (state, 0xA0, 0x80);  // Start Counting bit errors for 4096 Bytes
+        mdelay(25);                            // Hopefully got 4096 Bytes
+        stv0297_readregs (state, 0xA0, BER, 3);
+        mdelay(25);
+        *ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096);
+
+        return 0;
+}
+
+
+static int stv0297_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        u8 STRENGTH[2];
+
+        stv0297_readregs (state, 0x41, STRENGTH, 2);
+        *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
+
+        return 0;
+}
+
+static int stv0297_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        u8 SNR[2];
+
+        stv0297_readregs (state, 0x07, SNR, 2);
+        *snr = SNR[1] << 8 | SNR[0];
+
+        return 0;
+}
+
+static int stv0297_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+
+        *ucblocks = (stv0297_readreg (state, 0xD5) << 8)
+                   | stv0297_readreg (state, 0xD4);
+
+        return 0;
+}
+
+static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        int u_threshold;
+        int initial_u;
+        int blind_u;
+        int delay;
+        int sweeprate;
+        int carrieroffset;
+        unsigned long starttime;
+        unsigned long timeout;
+
+        switch(p->u.qam.modulation) {
+        case QAM_16:
+        case QAM_32:
+        case QAM_64:
+          delay = 100;
+          sweeprate = 1500;
+          break;
+
+        case QAM_128:
+          delay = 150;
+          sweeprate = 1000;
+          break;
+
+        case QAM_256:
+          delay = 200;
+          sweeprate = 500;
+          break;
+
+        default:
+          return -EINVAL;
+        }
+
+        // determine inversion dependant parameters
+        carrieroffset = -330;
+        switch(p->inversion) {
+        case INVERSION_OFF:
+          break;
+
+        case INVERSION_ON:
+          sweeprate = -sweeprate;
+          carrieroffset = -carrieroffset;
+          break;
+
+        default:
+          return -EINVAL;
+        }
+
+        state->config->pll_set(fe, p);
+
+       /* clear software interrupts */
+       stv0297_writereg(state, 0x82, 0x0);
+
+       /* set initial demodulation frequency */
+        stv0297_set_initialdemodfreq(state, state->freq_off + 7250);
+
+       /* setup AGC */
+        stv0297_writereg_mask(state, 0x43, 0x10, 0x00);
+        stv0297_writereg(state, 0x41, 0x00);
+        stv0297_writereg_mask(state, 0x42, 0x03, 0x01);
+        stv0297_writereg_mask(state, 0x36, 0x60, 0x00);
+        stv0297_writereg_mask(state, 0x36, 0x18, 0x00);
+        stv0297_writereg_mask(state, 0x71, 0x80, 0x80);
+        stv0297_writereg(state, 0x72, 0x00);
+        stv0297_writereg(state, 0x73, 0x00);
+        stv0297_writereg_mask(state, 0x74, 0x0F, 0x00);
+        stv0297_writereg_mask(state, 0x43, 0x08, 0x00);
+        stv0297_writereg_mask(state, 0x71, 0x80, 0x00);
+
+       /* setup STL */
+        stv0297_writereg_mask(state, 0x5a, 0x20, 0x20);
+        stv0297_writereg_mask(state, 0x5b, 0x02, 0x02);
+        stv0297_writereg_mask(state, 0x5b, 0x02, 0x00);
+        stv0297_writereg_mask(state, 0x5b, 0x01, 0x00);
+        stv0297_writereg_mask(state, 0x5a, 0x40, 0x40);
+
+       /* disable frequency sweep */
+        stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
+
+       /* reset deinterleaver */
+        stv0297_writereg_mask(state, 0x81, 0x01, 0x01);
+        stv0297_writereg_mask(state, 0x81, 0x01, 0x00);
+
+       /* ??? */
+        stv0297_writereg_mask(state, 0x83, 0x20, 0x20);
+        stv0297_writereg_mask(state, 0x83, 0x20, 0x00);
+
+       /* reset equaliser */
+        u_threshold = stv0297_readreg(state, 0x00) & 0xf;
+        initial_u = stv0297_readreg(state, 0x01) >> 4;
+        blind_u = stv0297_readreg(state, 0x01) & 0xf;
+        stv0297_writereg_mask(state, 0x84, 0x01, 0x01);
+        stv0297_writereg_mask(state, 0x84, 0x01, 0x00);
+        stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold);
+        stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4);
+        stv0297_writereg_mask(state, 0x01, 0x0f, blind_u);
+
+       /* data comes from internal A/D */
+        stv0297_writereg_mask(state, 0x87, 0x80, 0x00);
+
+       /* clear phase registers */
+        stv0297_writereg(state, 0x63, 0x00);
+        stv0297_writereg(state, 0x64, 0x00);
+        stv0297_writereg(state, 0x65, 0x00);
+        stv0297_writereg(state, 0x66, 0x00);
+        stv0297_writereg(state, 0x67, 0x00);
+        stv0297_writereg(state, 0x68, 0x00);
+        stv0297_writereg_mask(state, 0x69, 0x0f, 0x00);
+
+       /* set parameters */
+        stv0297_set_qam(state, p->u.qam.modulation);
+        stv0297_set_symbolrate(state, p->u.qam.symbol_rate/1000);
+       stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000);
+        stv0297_set_carrieroffset(state, carrieroffset);
+        stv0297_set_inversion(state, p->inversion);
+
+       /* kick off lock */
+        stv0297_writereg_mask(state, 0x88, 0x08, 0x08);
+        stv0297_writereg_mask(state, 0x5a, 0x20, 0x00);
+        stv0297_writereg_mask(state, 0x6a, 0x01, 0x01);
+        stv0297_writereg_mask(state, 0x43, 0x40, 0x40);
+        stv0297_writereg_mask(state, 0x5b, 0x30, 0x00);
+        stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c);
+        stv0297_writereg_mask(state, 0x03, 0x03, 0x03);
+        stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
+
+       /* wait for WGAGC lock */
+        starttime = jiffies;
+        timeout = jiffies + (200*HZ)/1000;
+        while(time_before(jiffies, timeout)) {
+                msleep(10);
+               if (stv0297_readreg(state, 0x43) & 0x08)
+                       break;
+        }
+        if (time_after(jiffies, timeout)) {
+                goto timeout;
+        }
+        msleep(20);
+
+       /* wait for equaliser partial convergence */
+        timeout = jiffies + (50*HZ)/1000;
+        while(time_before(jiffies, timeout)) {
+                msleep(10);
+
+                if (stv0297_readreg(state, 0x82) & 0x04) {
+                       break;
+                }
+        }
+       if (time_after(jiffies, timeout)) {
+                goto timeout;
+        }
+
+       /* wait for equaliser full convergence */
+        timeout = jiffies + (delay*HZ)/1000;
+        while(time_before(jiffies, timeout)) {
+                msleep(10);
+
+                if (stv0297_readreg(state, 0x82) & 0x08) {
+                        break;
+                }
+        }
+        if (time_after(jiffies, timeout)) {
+                goto timeout;
+        }
+
+       /* disable sweep */
+        stv0297_writereg_mask(state, 0x6a, 1, 0);
+        stv0297_writereg_mask(state, 0x88, 8, 0);
+
+       /* wait for main lock */
+        timeout = jiffies + (20*HZ)/1000;
+        while(time_before(jiffies, timeout)) {
+                msleep(10);
+
+                if (stv0297_readreg(state, 0xDF) & 0x80) {
+                        break;
+                }
+        }
+        if (time_after(jiffies, timeout)) {
+                goto timeout;
+        }
+        msleep(100);
+
+       /* is it still locked after that delay? */
+        if (!(stv0297_readreg(state, 0xDF) & 0x80)) {
+                goto timeout;
+        }
+
+       /* success!! */
+        stv0297_writereg_mask(state, 0x5a, 0x40, 0x00);
+        state->freq_off = stv0297_get_carrieroffset(state);
+        state->base_freq = p->frequency;
+        return 0;
+
+timeout:
+        stv0297_writereg_mask(state, 0x6a, 0x01, 0x00);
+        return 0;
+}
+
+static int stv0297_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        int reg_00, reg_83;
+
+        reg_00 = stv0297_readreg(state, 0x00);
+        reg_83 = stv0297_readreg(state, 0x83);
+
+        p->frequency = state->base_freq + state->freq_off;
+        p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF;
+       p->u.qam.symbol_rate = 0;
+        p->u.qam.fec_inner = 0;
+
+        switch((reg_00 >> 4) & 0x7) {
+       case 0:
+               p->u.qam.modulation = QAM_16;
+               break;
+       case 1:
+               p->u.qam.modulation = QAM_32;
+               break;
+       case 2:
+               p->u.qam.modulation = QAM_128;
+               break;
+       case 3:
+               p->u.qam.modulation = QAM_256;
+               break;
+       case 4:
+               p->u.qam.modulation = QAM_64;
+               break;
+        }
+
+        return 0;
+}
+
+static void stv0297_release(struct dvb_frontend* fe)
+{
+        struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv;
+        kfree(state);
+}
+
+static struct dvb_frontend_ops stv0297_ops;
+
+struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+                                   struct i2c_adapter *i2c, int pwm)
+{
+        struct stv0297_state* state = NULL;
+
+        /* allocate memory for the internal state */
+        state = (struct stv0297_state*) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+        /* setup the state */
+        state->config = config;
+        state->i2c = i2c;
+        memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
+        state->freq_off = 0;
+        state->base_freq = 0;
+        state->pwm = pwm;
+
+        /* check if the demod is there */
+       if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20)
+               goto error;
+
+        /* create dvb_frontend */
+        state->frontend.ops = &state->ops;
+        state->frontend.demodulator_priv = state;
+        return &state->frontend;
+
+error:
+       if (state)
+               kfree(state);
+        return NULL;
+}
+
+static struct dvb_frontend_ops stv0297_ops = {
+
+        .info = {
+                .name                  = "ST STV0297 DVB-C",
+                .type                  = FE_QAM,
+                .frequency_min         = 64000000,
+                .frequency_max         = 1300000000,
+                .frequency_stepsize    = 62500,
+                .symbol_rate_min       = 870000,
+                .symbol_rate_max       = 11700000,
+                .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
+
+        .release = stv0297_release,
+
+        .init = stv0297_init,
+
+        .set_frontend = stv0297_set_frontend,
+        .get_frontend = stv0297_get_frontend,
+
+        .read_status = stv0297_read_status,
+        .read_ber = stv0297_read_ber,
+        .read_signal_strength = stv0297_read_signal_strength,
+        .read_snr = stv0297_read_snr,
+        .read_ucblocks = stv0297_read_ucblocks,
+};
+
+MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver");
+MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(stv0297_attach);
+EXPORT_SYMBOL(stv0297_enable_plli2c);
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
new file mode 100644 (file)
index 0000000..355aa87
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+    Driver for STV0297 demodulator
+
+    Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.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 STV0297_H
+#define STV0297_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0297_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+                                          struct i2c_adapter* i2c, int pwm);
+extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
+
+#endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
new file mode 100644 (file)
index 0000000..79457a8
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+    Driver for ST STV0299 demodulator
+
+    Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+       <ralph@convergence.de>,
+       <holger@convergence.de>,
+       <js@convergence.de>
+
+
+    Philips SU1278/SH
+
+    Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de>
+
+
+    LG TDQF-S001F
+
+    Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net>
+                    & Andreas Oberritter <obi@linuxtv.org>
+
+
+    Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B
+
+    Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>:
+
+    Support for Philips SU1278 on Technotrend hardware
+
+    Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef STV0299_H
+#define STV0299_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#define STV0229_LOCKOUTPUT_0  0
+#define STV0229_LOCKOUTPUT_1  1
+#define STV0229_LOCKOUTPUT_CF 2
+#define STV0229_LOCKOUTPUT_LK 3
+
+#define STV0299_VOLT13_OP0 0
+#define STV0299_VOLT13_OP1 1
+
+struct stv0299_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* inittab - array of pairs of values.
+        * First of each pair is the register, second is the value.
+        * List should be terminated with an 0xff, 0xff pair.
+        */
+       u8* inittab;
+
+       /* master clock to use */
+       u32 mclk;
+
+       /* does the inversion require inversion? */
+       u8 invert:1;
+
+       /* Should the enhanced tuning code be used? */
+       u8 enhanced_tuning:1;
+
+       /* Skip reinitialisation? */
+       u8 skip_reinit:1;
+
+       /* LOCK OUTPUT setting */
+       u8 lock_output:2;
+
+       /* Is 13v controlled by OP0 or OP1? */
+       u8 volt13_op0_op1:1;
+
+       /* minimum delay before retuning */
+       int min_delay_ms;
+
+       /* Set the symbol rate */
+       int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
+
+extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif // STV0299_H
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
new file mode 100644 (file)
index 0000000..df0b844
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+    TDA10021  - Single Chip Cable Channel Receiver driver module
+               used on the the Siemens DVB-C cards
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+                   Suppport for TDA10021
+
+    This 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/config.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda10021.h"
+
+
+struct tda10021_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct tda10021_config* config;
+
+       struct dvb_frontend frontend;
+
+       u8 pwm;
+       u8 reg0;
+};
+
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...)
+#endif
+
+static int verbose;
+
+#define XIN 57840000UL
+#define DISABLE_INVERSION(reg0)                do { reg0 |= 0x20; } while (0)
+#define ENABLE_INVERSION(reg0)         do { reg0 &= ~0x20; } while (0)
+#define HAS_INVERSION(reg0)            (!(reg0 & 0x20))
+
+#define FIN (XIN >> 4)
+
+int tda10021_inittab_size = 0x40;
+static u8 tda10021_inittab[0x40]=
+{
+       0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
+       0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
+       0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
+       0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
+       0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
+       0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
+       0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
+};
+
+static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
+{
+        u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+        int ret;
+
+       ret = i2c_transfer (state->i2c, &msg, 1);
+       if (ret != 1)
+               printk("DVB: TDA10021(%d): %s, writereg error "
+                       "(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+                       state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
+
+       msleep(10);
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+
+static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
+{
+       u8 b0 [] = { reg };
+       u8 b1 [] = { 0 };
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+                                 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+       int ret;
+
+       ret = i2c_transfer (state->i2c, msg, 2);
+       if (ret != 2)
+               printk("DVB: TDA10021(%d): %s: readreg error (ret == %i)\n",
+                               state->frontend.dvb->num, __FUNCTION__, ret);
+       return b1[0];
+}
+
+//get access to tuner
+static int lock_tuner(struct tda10021_state* state)
+{
+       u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
+       struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+       if(i2c_transfer(state->i2c, &msg, 1) != 1)
+       {
+               printk("tda10021: lock tuner fails\n");
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+//release access from tuner
+static int unlock_tuner(struct tda10021_state* state)
+{
+       u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
+       struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+       if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
+       {
+               printk("tda10021: unlock tuner fails\n");
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
+                               fe_spectral_inversion_t inversion)
+{
+       reg0 |= state->reg0 & 0x63;
+
+       if (INVERSION_ON == inversion)
+               ENABLE_INVERSION(reg0);
+       else if (INVERSION_OFF == inversion)
+               DISABLE_INVERSION(reg0);
+
+       tda10021_writereg (state, 0x00, reg0 & 0xfe);
+       tda10021_writereg (state, 0x00, reg0 | 0x01);
+
+       state->reg0 = reg0;
+       return 0;
+}
+
+static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
+{
+       s32 BDR;
+       s32 BDRI;
+       s16 SFIL=0;
+       u16 NDEC = 0;
+       u32 tmp, ratio;
+
+       if (symbolrate > XIN/2)
+               symbolrate = XIN/2;
+       if (symbolrate < 500000)
+               symbolrate = 500000;
+
+       if (symbolrate < XIN/16) NDEC = 1;
+       if (symbolrate < XIN/32) NDEC = 2;
+       if (symbolrate < XIN/64) NDEC = 3;
+
+       if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
+       if (symbolrate < (u32)(XIN/16))  SFIL = 0;
+       if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
+       if (symbolrate < (u32)(XIN/32))  SFIL = 0;
+       if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
+       if (symbolrate < (u32)(XIN/64))  SFIL = 0;
+       if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+
+       symbolrate <<= NDEC;
+       ratio = (symbolrate << 4) / FIN;
+       tmp =  ((symbolrate << 4) % FIN) << 8;
+       ratio = (ratio << 8) + tmp / FIN;
+       tmp = (tmp % FIN) << 8;
+       ratio = (ratio << 8) + (tmp + FIN/2) / FIN;
+
+       BDR = ratio;
+       BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
+
+       if (BDRI > 0xFF)
+               BDRI = 0xFF;
+
+       SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
+
+       NDEC = (NDEC << 6) | tda10021_inittab[0x03];
+
+       tda10021_writereg (state, 0x03, NDEC);
+       tda10021_writereg (state, 0x0a, BDR&0xff);
+       tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
+       tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
+
+       tda10021_writereg (state, 0x0d, BDRI);
+       tda10021_writereg (state, 0x0e, SFIL);
+
+       return 0;
+}
+
+
+
+
+
+
+
+
+
+
+static int tda10021_init (struct dvb_frontend *fe)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+       int i;
+
+       dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
+
+       //tda10021_writereg (fe, 0, 0);
+
+       for (i=0; i<tda10021_inittab_size; i++)
+               tda10021_writereg (state, i, tda10021_inittab[i]);
+
+       tda10021_writereg (state, 0x34, state->pwm);
+
+       //Comment by markus
+       //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
+       //0x2A[4] == BYPPLL -> Power down mode (default 1)
+       //0x2A[5] == LCK -> PLL Lock Flag
+       //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
+
+       //Activate PLL
+       tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
+
+       if (state->config->pll_init) {
+               lock_tuner(state);
+               state->config->pll_init(fe);
+               unlock_tuner(state);
+       }
+
+       return 0;
+}
+
+static int tda10021_set_parameters (struct dvb_frontend *fe,
+                           struct dvb_frontend_parameters *p)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+       //table for QAM4-QAM256 ready  QAM4  QAM16 QAM32 QAM64 QAM128 QAM256
+       //CONF
+       static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c,  0x10 };
+       //AGCREF value
+       static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78,  0x5c };
+       //LTHR value
+       static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36,  0x26 };
+       //MSETH
+       static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34,  0x23 };
+       //AREF
+       static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e,  0x6b };
+
+       int qam = p->u.qam.modulation;
+
+       if (qam < 0 || qam > 5)
+               return -EINVAL;
+
+       //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
+
+       lock_tuner(state);
+       state->config->pll_set(fe, p);
+       unlock_tuner(state);
+
+       tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
+       tda10021_writereg (state, 0x34, state->pwm);
+
+       tda10021_writereg (state, 0x01, reg0x01[qam]);
+       tda10021_writereg (state, 0x05, reg0x05[qam]);
+       tda10021_writereg (state, 0x08, reg0x08[qam]);
+       tda10021_writereg (state, 0x09, reg0x09[qam]);
+
+       tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
+
+       return 0;
+}
+
+static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+       int sync;
+
+       *status = 0;
+       //0x11[0] == EQALGO -> Equalizer algorithms state
+       //0x11[1] == CARLOCK -> Carrier locked
+       //0x11[2] == FSYNC -> Frame synchronisation
+       //0x11[3] == FEL -> Front End locked
+       //0x11[6] == NODVB -> DVB Mode Information
+       sync = tda10021_readreg (state, 0x11);
+
+       if (sync & 2)
+               *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
+
+       if (sync & 4)
+               *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
+
+       if (sync & 8)
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+       u32 _ber = tda10021_readreg(state, 0x14) |
+                 (tda10021_readreg(state, 0x15) << 8) |
+                ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
+       *ber = 10 * _ber;
+
+       return 0;
+}
+
+static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+       u8 gain = tda10021_readreg(state, 0x17);
+       *strength = (gain << 8) | gain;
+
+       return 0;
+}
+
+static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+       u8 quality = ~tda10021_readreg(state, 0x18);
+       *snr = (quality << 8) | quality;
+
+       return 0;
+}
+
+static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+       *ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
+       if (*ucblocks == 0x7f)
+               *ucblocks = 0xffffffff;
+
+       /* reset uncorrected block counter */
+       tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
+       tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
+
+       return 0;
+}
+
+static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+       int sync;
+       s8 afc = 0;
+
+       sync = tda10021_readreg(state, 0x11);
+       afc = tda10021_readreg(state, 0x19);
+       if (verbose) {
+               /* AFC only valid when carrier has been recovered */
+               printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
+                                 "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
+                       state->frontend.dvb->num, afc,
+                      -((s32)p->u.qam.symbol_rate * afc) >> 10);
+       }
+
+       p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
+       p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+       p->u.qam.fec_inner = FEC_NONE;
+       p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+
+       if (sync & 2)
+               p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+
+       return 0;
+}
+
+static int tda10021_sleep(struct dvb_frontend* fe)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+
+       tda10021_writereg (state, 0x1b, 0x02);  /* pdown ADC */
+       tda10021_writereg (state, 0x00, 0x80);  /* standby */
+
+       return 0;
+}
+
+static void tda10021_release(struct dvb_frontend* fe)
+{
+       struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops tda10021_ops;
+
+struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+                                    struct i2c_adapter* i2c,
+                                    u8 pwm)
+{
+       struct tda10021_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct tda10021_state*) kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
+       state->pwm = pwm;
+       state->reg0 = tda10021_inittab[0];
+
+       /* check if the demod is there */
+       if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops tda10021_ops = {
+
+       .info = {
+               .name = "Philips TDA10021 DVB-C",
+               .type = FE_QAM,
+               .frequency_stepsize = 62500,
+               .frequency_min = 51000000,
+               .frequency_max = 858000000,
+               .symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
+               .symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
+       #if 0
+               .frequency_tolerance = ???,
+               .symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
+       #endif
+               .caps = 0x400 | //FE_CAN_QAM_4
+                       FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+                       FE_CAN_FEC_AUTO
+       },
+
+       .release = tda10021_release,
+
+       .init = tda10021_init,
+       .sleep = tda10021_sleep,
+
+       .set_frontend = tda10021_set_parameters,
+       .get_frontend = tda10021_get_frontend,
+
+       .read_status = tda10021_read_status,
+       .read_ber = tda10021_read_ber,
+       .read_signal_strength = tda10021_read_signal_strength,
+       .read_snr = tda10021_read_snr,
+       .read_ucblocks = tda10021_read_ucblocks,
+};
+
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
+
+MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10021_attach);
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
new file mode 100644 (file)
index 0000000..a34a941
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    TDA10021  - Single Chip Cable Channel Receiver driver module
+               used on the the Siemens DVB-C cards
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+                   Suppport for TDA10021
+
+    This 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 TDA10021_H
+#define TDA10021_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda10021_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+                                           struct i2c_adapter* i2c,
+                                           u8 pwm);
+
+#endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
new file mode 100644 (file)
index 0000000..e452fc0
--- /dev/null
@@ -0,0 +1,56 @@
+  /*
+     Driver for Philips tda1004xh OFDM Frontend
+
+     (c) 2004 Andrew de Quincey
+
+     This 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 TDA1004X_H
+#define TDA1004X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda1004x_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* does the "inversion" need inverted? */
+       u8 invert:1;
+
+       /* Does the OCLK signal need inverted? */
+       u8 invert_oclk:1;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+
+       /* request firmware for device */
+       int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+                                           struct i2c_adapter* i2c);
+
+extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+                                           struct i2c_adapter* i2c);
+
+extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data);
+
+#endif // TDA1004X_H
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
new file mode 100644 (file)
index 0000000..03c4366
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+    Driver for Philips TDA8083 based QPSK Demodulator
+
+    Copyright (C) 2001 Convergence Integrated Media GmbH
+
+    written by Ralph Metzler <ralph@convergence.de>
+
+    adoption to the new DVB frontend API and diagnostic ioctl's
+    by Holger Waechtler <holger@convergence.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "dvb_frontend.h"
+#include "tda8083.h"
+
+
+struct tda8083_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct tda8083_config* config;
+
+       struct dvb_frontend frontend;
+};
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "tda8083: " args); \
+       } while (0)
+
+
+static u8 tda8083_init_tab [] = {
+       0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
+       0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
+       0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
+       0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
+       0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00
+};
+
+
+static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data)
+{
+       int ret;
+       u8 buf [] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+
+        ret = i2c_transfer(state->i2c, &msg, 1);
+
+        if (ret != 1)
+                dprintk ("%s: writereg error (reg %02x, ret == %i)\n",
+                       __FUNCTION__, reg, ret);
+
+        return (ret != 1) ? -1 : 0;
+}
+
+
+static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len)
+{
+       int ret;
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = &reg1, .len = 1 },
+                          { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               dprintk ("%s: readreg error (reg %02x, ret == %i)\n",
+                       __FUNCTION__, reg1, ret);
+
+        return ret == 2 ? 0 : -1;
+}
+
+
+static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg)
+{
+       u8 val;
+
+       tda8083_readregs (state, reg, &val, 1);
+
+       return val;
+}
+
+
+
+static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion)
+{
+       /*  XXX FIXME: implement other modes than FEC_AUTO */
+       if (inversion == INVERSION_AUTO)
+               return 0;
+
+       return -EINVAL;
+}
+
+
+static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec)
+{
+       if (fec == FEC_AUTO)
+               return tda8083_writereg (state, 0x07, 0xff);
+
+       if (fec >= FEC_1_2 && fec <= FEC_8_9)
+               return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec));
+
+       return -EINVAL;
+}
+
+
+static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state)
+{
+       u8 index;
+       static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
+                                      FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 };
+
+       index = tda8083_readreg(state, 0x0e) & 0x07;
+
+       return fec_tab [index];
+}
+
+
+static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate)
+{
+        u32 ratio;
+       u32 tmp;
+       u8 filter;
+
+       if (srate > 32000000)
+                srate = 32000000;
+        if (srate < 500000)
+                srate = 500000;
+
+       filter = 0;
+       if (srate < 24000000)
+               filter = 2;
+       if (srate < 16000000)
+               filter = 3;
+
+       tmp = 31250 << 16;
+       ratio = tmp / srate;
+
+       tmp = (tmp % srate) << 8;
+       ratio = (ratio << 8) + tmp / srate;
+
+       tmp = (tmp % srate) << 8;
+       ratio = (ratio << 8) + tmp / srate;
+
+       dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio);
+
+       tda8083_writereg (state, 0x05, filter);
+       tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff);
+       tda8083_writereg (state, 0x03, (ratio >>  8) & 0xff);
+       tda8083_writereg (state, 0x04, (ratio      ) & 0xff);
+
+       tda8083_writereg (state, 0x00, 0x3c);
+       tda8083_writereg (state, 0x00, 0x04);
+
+       return 1;
+}
+
+
+static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout)
+{
+       unsigned long start = jiffies;
+
+       while (jiffies - start < timeout &&
+               !(tda8083_readreg(state, 0x02) & 0x80))
+       {
+               msleep(50);
+       };
+}
+
+static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone)
+{
+       tda8083_writereg (state, 0x26, 0xf1);
+
+       switch (tone) {
+       case SEC_TONE_OFF:
+               return tda8083_writereg (state, 0x29, 0x00);
+       case SEC_TONE_ON:
+               return tda8083_writereg (state, 0x29, 0x80);
+       default:
+               return -EINVAL;
+       };
+}
+
+
+static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage)
+{
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               return tda8083_writereg (state, 0x20, 0x00);
+       case SEC_VOLTAGE_18:
+               return tda8083_writereg (state, 0x20, 0x11);
+       default:
+               return -EINVAL;
+       };
+}
+
+static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst)
+{
+       switch (burst) {
+       case SEC_MINI_A:
+               tda8083_writereg (state, 0x29, (5 << 2));  /* send burst A */
+               break;
+       case SEC_MINI_B:
+               tda8083_writereg (state, 0x29, (7 << 2));  /* send B */
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       tda8083_wait_diseqc_fifo (state, 100);
+
+       return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int tda8083_send_diseqc_msg (struct dvb_frontend* fe,
+                                   struct dvb_diseqc_master_cmd *m)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+       int i;
+
+       tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */
+
+       for (i=0; i<m->msg_len; i++)
+               tda8083_writereg (state, 0x23 + i, m->msg[i]);
+
+       tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */
+
+       tda8083_wait_diseqc_fifo (state, 100);
+
+       return 0;
+}
+
+static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       u8 signal = ~tda8083_readreg (state, 0x01);
+       u8 sync = tda8083_readreg (state, 0x02);
+
+       *status = 0;
+
+       if (signal > 10)
+               *status |= FE_HAS_SIGNAL;
+
+       if (sync & 0x01)
+               *status |= FE_HAS_CARRIER;
+
+       if (sync & 0x02)
+               *status |= FE_HAS_VITERBI;
+
+       if (sync & 0x10)
+               *status |= FE_HAS_SYNC;
+
+       if ((sync & 0x1f) == 0x1f)
+               *status |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       u8 signal = ~tda8083_readreg (state, 0x01);
+       *strength = (signal << 8) | signal;
+
+       return 0;
+}
+
+static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       u8 _snr = tda8083_readreg (state, 0x08);
+       *snr = (_snr << 8) | _snr;
+
+       return 0;
+}
+
+static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       state->config->pll_set(fe, p);
+       tda8083_set_inversion (state, p->inversion);
+       tda8083_set_fec (state, p->u.qpsk.fec_inner);
+       tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
+
+       tda8083_writereg (state, 0x00, 0x3c);
+       tda8083_writereg (state, 0x00, 0x04);
+
+       return 0;
+}
+
+static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       /*  FIXME: get symbolrate & frequency offset...*/
+       /*p->frequency = ???;*/
+       p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ?
+                       INVERSION_ON : INVERSION_OFF;
+       p->u.qpsk.fec_inner = tda8083_get_fec (state);
+       /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/
+
+       return 0;
+}
+
+static int tda8083_sleep(struct dvb_frontend* fe)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       tda8083_writereg (state, 0x00, 0x02);
+       return 0;
+}
+
+static int tda8083_init(struct dvb_frontend* fe)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+       int i;
+
+       for (i=0; i<44; i++)
+               tda8083_writereg (state, i, tda8083_init_tab[i]);
+
+       if (state->config->pll_init) state->config->pll_init(fe);
+
+       tda8083_writereg (state, 0x00, 0x3c);
+       tda8083_writereg (state, 0x00, 0x04);
+
+       return 0;
+}
+
+static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       tda8083_send_diseqc_burst (state, burst);
+       tda8083_writereg (state, 0x00, 0x3c);
+       tda8083_writereg (state, 0x00, 0x04);
+
+       return 0;
+}
+
+static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       tda8083_set_tone (state, tone);
+       tda8083_writereg (state, 0x00, 0x3c);
+       tda8083_writereg (state, 0x00, 0x04);
+
+       return 0;
+}
+
+static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+
+       tda8083_set_voltage (state, voltage);
+       tda8083_writereg (state, 0x00, 0x3c);
+       tda8083_writereg (state, 0x00, 0x04);
+
+       return 0;
+}
+
+static void tda8083_release(struct dvb_frontend* fe)
+{
+       struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops tda8083_ops;
+
+struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct tda8083_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct tda8083_state*) kmalloc(sizeof(struct tda8083_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
+
+       /* check if the demod is there */
+       if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops tda8083_ops = {
+
+       .info = {
+               .name                   = "Philips TDA8083 DVB-S",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,     /* FIXME: guessed! */
+               .frequency_max          = 1400000,    /* FIXME: guessed! */
+               .frequency_stepsize     = 125,   /* kHz for QPSK frontends */
+       /*      .frequency_tolerance    = ???,*/
+               .symbol_rate_min        = 1000000,   /* FIXME: guessed! */
+               .symbol_rate_max        = 45000000,  /* FIXME: guessed! */
+       /*      .symbol_rate_tolerance  = ???,*/
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_MUTE_TS
+       },
+
+       .release = tda8083_release,
+
+       .init = tda8083_init,
+       .sleep = tda8083_sleep,
+
+       .set_frontend = tda8083_set_frontend,
+       .get_frontend = tda8083_get_frontend,
+
+       .read_status = tda8083_read_status,
+       .read_signal_strength = tda8083_read_signal_strength,
+       .read_snr = tda8083_read_snr,
+
+       .diseqc_send_master_cmd = tda8083_send_diseqc_msg,
+       .diseqc_send_burst = tda8083_diseqc_send_burst,
+       .set_tone = tda8083_diseqc_set_tone,
+       .set_voltage = tda8083_diseqc_set_voltage,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator");
+MODULE_AUTHOR("Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda8083_attach);
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
new file mode 100644 (file)
index 0000000..4666633
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend
+
+    Copyright (C) 2001 Convergence Integrated Media GmbH
+
+    written by Ralph Metzler <ralph@convergence.de>
+
+    adoption to the new DVB frontend API and diagnostic ioctl's
+    by Holger Waechtler <holger@convergence.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 TDA8083_H
+#define TDA8083_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda8083_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif // TDA8083_H
diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c
new file mode 100644 (file)
index 0000000..5b8828b
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * tda80xx.c
+ *
+ * Philips TDA8044 / TDA8083 QPSK demodulator driver
+ *
+ * Copyright (C) 2001 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2002-2004 Andreas Oberritter <obi@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "tda80xx.h"
+
+enum {
+       ID_TDA8044 = 0x04,
+       ID_TDA8083 = 0x05,
+};
+
+
+struct tda80xx_state {
+
+       struct i2c_adapter* i2c;
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct tda80xx_config* config;
+
+       struct dvb_frontend frontend;
+
+       u32 clk;
+       int afc_loop;
+       struct work_struct worklet;
+       fe_code_rate_t code_rate;
+       fe_spectral_inversion_t spectral_inversion;
+       fe_status_t status;
+       u8 id;
+};
+
+static int debug = 1;
+#define dprintk        if (debug) printk
+
+static u8 tda8044_inittab_pre[] = {
+       0x02, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea,
+       0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x58,
+       0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68,
+       0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x00,
+       0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00
+};
+
+static u8 tda8044_inittab_post[] = {
+       0x04, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea,
+       0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x50,
+       0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68,
+       0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x6c,
+       0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00
+};
+
+static u8 tda8083_inittab[] = {
+       0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea,
+       0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10,
+       0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8,
+       0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00,
+       0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00
+};
+
+static __inline__ u32 tda80xx_div(u32 a, u32 b)
+{
+       return (a + (b / 2)) / b;
+}
+
+static __inline__ u32 tda80xx_gcd(u32 a, u32 b)
+{
+       u32 r;
+
+       while ((r = a % b)) {
+               a = b;
+               b = r;
+       }
+
+       return b;
+}
+
+static int tda80xx_read(struct tda80xx_state* state, u8 reg, u8 *buf, u8 len)
+{
+       int ret;
+       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 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               dprintk("%s: readreg error (reg %02x, ret == %i)\n",
+                               __FUNCTION__, reg, ret);
+
+       mdelay(10);
+
+       return (ret == 2) ? 0 : -EREMOTEIO;
+}
+
+static int tda80xx_write(struct tda80xx_state* state, u8 reg, const u8 *buf, u8 len)
+{
+       int ret;
+       u8 wbuf[len + 1];
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = wbuf, .len = len + 1 };
+
+       wbuf[0] = reg;
+       memcpy(&wbuf[1], buf, len);
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               dprintk("%s: i2c xfer error (ret == %i)\n", __FUNCTION__, ret);
+
+       mdelay(10);
+
+       return (ret == 1) ? 0 : -EREMOTEIO;
+}
+
+static __inline__ u8 tda80xx_readreg(struct tda80xx_state* state, u8 reg)
+{
+       u8 val;
+
+       tda80xx_read(state, reg, &val, 1);
+
+       return val;
+}
+
+static __inline__ int tda80xx_writereg(struct tda80xx_state* state, u8 reg, u8 data)
+{
+       return tda80xx_write(state, reg, &data, 1);
+}
+
+static int tda80xx_set_parameters(struct tda80xx_state* state,
+                                 fe_spectral_inversion_t inversion,
+                                 u32 symbol_rate,
+                                 fe_code_rate_t fec_inner)
+{
+       u8 buf[15];
+       u64 ratio;
+       u32 clk;
+       u32 k;
+       u32 sr = symbol_rate;
+       u32 gcd;
+       u8 scd;
+
+       if (symbol_rate > (state->clk * 3) / 16)
+               scd = 0;
+       else if (symbol_rate > (state->clk * 3) / 32)
+               scd = 1;
+       else if (symbol_rate > (state->clk * 3) / 64)
+               scd = 2;
+       else
+               scd = 3;
+
+       clk = scd ? (state->clk / (scd * 2)) : state->clk;
+
+       /*
+        * Viterbi decoder:
+        * Differential decoding off
+        * Spectral inversion unknown
+        * QPSK modulation
+        */
+       if (inversion == INVERSION_ON)
+               buf[0] = 0x60;
+       else if (inversion == INVERSION_OFF)
+               buf[0] = 0x20;
+       else
+               buf[0] = 0x00;
+
+       /*
+        * CLK ratio:
+        * system clock frequency is up to 64 or 96 MHz
+        *
+        * formula:
+        * r = k * clk / symbol_rate
+        *
+        * k:   2^21 for caa 0..3,
+        *      2^20 for caa 4..5,
+        *      2^19 for caa 6..7
+        */
+       if (symbol_rate <= (clk * 3) / 32)
+               k = (1 << 19);
+       else if (symbol_rate <= (clk * 3) / 16)
+               k = (1 << 20);
+       else
+               k = (1 << 21);
+
+       gcd = tda80xx_gcd(clk, sr);
+       clk /= gcd;
+       sr /= gcd;
+
+       gcd = tda80xx_gcd(k, sr);
+       k /= gcd;
+       sr /= gcd;
+
+       ratio = (u64)k * (u64)clk;
+       do_div(ratio, sr);
+
+       buf[1] = ratio >> 16;
+       buf[2] = ratio >> 8;
+       buf[3] = ratio;
+
+       /* nyquist filter roll-off factor 35% */
+       buf[4] = 0x20;
+
+       clk = scd ? (state->clk / (scd * 2)) : state->clk;
+
+       /* Anti Alias Filter */
+       if (symbol_rate < (clk * 3) / 64)
+               printk("tda80xx: unsupported symbol rate: %u\n", symbol_rate);
+       else if (symbol_rate <= clk / 16)
+               buf[4] |= 0x07;
+       else if (symbol_rate <= (clk * 3) / 32)
+               buf[4] |= 0x06;
+       else if (symbol_rate <= clk / 8)
+               buf[4] |= 0x05;
+       else if (symbol_rate <= (clk * 3) / 16)
+               buf[4] |= 0x04;
+       else if (symbol_rate <= clk / 4)
+               buf[4] |= 0x03;
+       else if (symbol_rate <= (clk * 3) / 8)
+               buf[4] |= 0x02;
+       else if (symbol_rate <= clk / 2)
+               buf[4] |= 0x01;
+       else
+               buf[4] |= 0x00;
+
+       /* Sigma Delta converter */
+       buf[5] = 0x00;
+
+       /* FEC: Possible puncturing rates */
+       if (fec_inner == FEC_NONE)
+               buf[6] = 0x00;
+       else if ((fec_inner >= FEC_1_2) && (fec_inner <= FEC_8_9))
+               buf[6] = (1 << (8 - fec_inner));
+       else if (fec_inner == FEC_AUTO)
+               buf[6] = 0xff;
+       else
+               return -EINVAL;
+
+       /* carrier lock detector threshold value */
+       buf[7] = 0x30;
+       /* AFC1: proportional part settings */
+       buf[8] = 0x42;
+       /* AFC1: integral part settings */
+       buf[9] = 0x98;
+       /* PD: Leaky integrator SCPC mode */
+       buf[10] = 0x28;
+       /* AFC2, AFC1 controls */
+       buf[11] = 0x30;
+       /* PD: proportional part settings */
+       buf[12] = 0x42;
+       /* PD: integral part settings */
+       buf[13] = 0x99;
+       /* AGC */
+       buf[14] = 0x50 | scd;
+
+       printk("symbol_rate=%u clk=%u\n", symbol_rate, clk);
+
+       return tda80xx_write(state, 0x01, buf, sizeof(buf));
+}
+
+static int tda80xx_set_clk(struct tda80xx_state* state)
+{
+       u8 buf[2];
+
+       /* CLK proportional part */
+       buf[0] = (0x06 << 5) | 0x08;    /* CMP[2:0], CSP[4:0] */
+       /* CLK integral part */
+       buf[1] = (0x04 << 5) | 0x1a;    /* CMI[2:0], CSI[4:0] */
+
+       return tda80xx_write(state, 0x17, buf, sizeof(buf));
+}
+
+#if 0
+static int tda80xx_set_scpc_freq_offset(struct tda80xx_state* state)
+{
+       /* a constant value is nonsense here imho */
+       return tda80xx_writereg(state, 0x22, 0xf9);
+}
+#endif
+
+static int tda80xx_close_loop(struct tda80xx_state* state)
+{
+       u8 buf[2];
+
+       /* PD: Loop closed, LD: lock detect enable, SCPC: Sweep mode - AFC1 loop closed */
+       buf[0] = 0x68;
+       /* AFC1: Loop closed, CAR Feedback: 8192 */
+       buf[1] = 0x70;
+
+       return tda80xx_write(state, 0x0b, buf, sizeof(buf));
+}
+
+static irqreturn_t tda80xx_irq(int irq, void *priv, struct pt_regs *pt)
+{
+       schedule_work(priv);
+
+       return IRQ_HANDLED;
+}
+
+static void tda80xx_read_status_int(struct tda80xx_state* state)
+{
+       u8 val;
+
+       static const fe_spectral_inversion_t inv_tab[] = {
+               INVERSION_OFF, INVERSION_ON
+       };
+
+       static const fe_code_rate_t fec_tab[] = {
+               FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4,
+               FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8,
+       };
+
+       val = tda80xx_readreg(state, 0x02);
+
+       state->status = 0;
+
+       if (val & 0x01) /* demodulator lock */
+               state->status |= FE_HAS_SIGNAL;
+       if (val & 0x02) /* clock recovery lock */
+               state->status |= FE_HAS_CARRIER;
+       if (val & 0x04) /* viterbi lock */
+               state->status |= FE_HAS_VITERBI;
+       if (val & 0x08) /* deinterleaver lock (packet sync) */
+               state->status |= FE_HAS_SYNC;
+       if (val & 0x10) /* derandomizer lock (frame sync) */
+               state->status |= FE_HAS_LOCK;
+       if (val & 0x20) /* frontend can not lock */
+               state->status |= FE_TIMEDOUT;
+
+       if ((state->status & (FE_HAS_CARRIER)) && (state->afc_loop)) {
+               printk("tda80xx: closing loop\n");
+               tda80xx_close_loop(state);
+               state->afc_loop = 0;
+       }
+
+       if (state->status & (FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK)) {
+               val = tda80xx_readreg(state, 0x0e);
+               state->code_rate = fec_tab[val & 0x07];
+               if (state->status & (FE_HAS_SYNC | FE_HAS_LOCK))
+                       state->spectral_inversion = inv_tab[(val >> 7) & 0x01];
+               else
+                       state->spectral_inversion = INVERSION_AUTO;
+       }
+       else {
+               state->code_rate = FEC_AUTO;
+       }
+}
+
+static void tda80xx_worklet(void *priv)
+{
+       struct tda80xx_state *state = priv;
+
+       tda80xx_writereg(state, 0x00, 0x04);
+       enable_irq(state->config->irq);
+
+       tda80xx_read_status_int(state);
+}
+
+static void tda80xx_wait_diseqc_fifo(struct tda80xx_state* state)
+{
+       size_t i;
+
+       for (i = 0; i < 100; i++) {
+               if (tda80xx_readreg(state, 0x02) & 0x80)
+                       break;
+               msleep(10);
+       }
+}
+
+static int tda8044_init(struct dvb_frontend* fe)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+       int ret;
+
+       /*
+        * this function is a mess...
+        */
+
+       if ((ret = tda80xx_write(state, 0x00, tda8044_inittab_pre, sizeof(tda8044_inittab_pre))))
+               return ret;
+
+       tda80xx_writereg(state, 0x0f, 0x50);
+#if 1
+       tda80xx_writereg(state, 0x20, 0x8F);            /* FIXME */
+       tda80xx_writereg(state, 0x20, state->config->volt18setting);    /* FIXME */
+       //tda80xx_writereg(state, 0x00, 0x04);
+       tda80xx_writereg(state, 0x00, 0x0C);
+#endif
+       //tda80xx_writereg(state, 0x00, 0x08); /* Reset AFC1 loop filter */
+
+       tda80xx_write(state, 0x00, tda8044_inittab_post, sizeof(tda8044_inittab_post));
+
+       if (state->config->pll_init) {
+               tda80xx_writereg(state, 0x1c, 0x80);
+               state->config->pll_init(fe);
+               tda80xx_writereg(state, 0x1c, 0x00);
+       }
+
+       return 0;
+}
+
+static int tda8083_init(struct dvb_frontend* fe)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab));
+
+       if (state->config->pll_init) {
+               tda80xx_writereg(state, 0x1c, 0x80);
+               state->config->pll_init(fe);
+               tda80xx_writereg(state, 0x1c, 0x00);
+       }
+
+       return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               return tda80xx_writereg(state, 0x20, state->config->volt13setting);
+       case SEC_VOLTAGE_18:
+               return tda80xx_writereg(state, 0x20, state->config->volt18setting);
+       case SEC_VOLTAGE_OFF:
+               return tda80xx_writereg(state, 0x20, 0);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       switch (tone) {
+       case SEC_TONE_OFF:
+               return tda80xx_writereg(state, 0x29, 0x00);
+       case SEC_TONE_ON:
+               return tda80xx_writereg(state, 0x29, 0x80);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       if (cmd->msg_len > 6)
+               return -EINVAL;
+
+       tda80xx_writereg(state, 0x29, 0x08 | (cmd->msg_len - 3));
+       tda80xx_write(state, 0x23, cmd->msg, cmd->msg_len);
+       tda80xx_writereg(state, 0x29, 0x0c | (cmd->msg_len - 3));
+       tda80xx_wait_diseqc_fifo(state);
+
+       return 0;
+}
+
+static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       switch (cmd) {
+       case SEC_MINI_A:
+               tda80xx_writereg(state, 0x29, 0x14);
+               break;
+       case SEC_MINI_B:
+               tda80xx_writereg(state, 0x29, 0x1c);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       tda80xx_wait_diseqc_fifo(state);
+
+       return 0;
+}
+
+static int tda80xx_sleep(struct dvb_frontend* fe)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       tda80xx_writereg(state, 0x00, 0x02);    /* enter standby */
+
+       return 0;
+}
+
+static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       tda80xx_writereg(state, 0x1c, 0x80);
+       state->config->pll_set(fe, p);
+       tda80xx_writereg(state, 0x1c, 0x00);
+
+       tda80xx_set_parameters(state, p->inversion, p->u.qpsk.symbol_rate, p->u.qpsk.fec_inner);
+       tda80xx_set_clk(state);
+       //tda80xx_set_scpc_freq_offset(state);
+       state->afc_loop = 1;
+
+       return 0;
+}
+
+static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       if (!state->config->irq)
+               tda80xx_read_status_int(state);
+
+       p->inversion = state->spectral_inversion;
+       p->u.qpsk.fec_inner = state->code_rate;
+
+       return 0;
+}
+
+static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       if (!state->config->irq)
+               tda80xx_read_status_int(state);
+       *status = state->status;
+
+       return 0;
+}
+
+static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+       int ret;
+       u8 buf[3];
+
+       if ((ret = tda80xx_read(state, 0x0b, buf, sizeof(buf))))
+               return ret;
+
+       *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2];
+
+       return 0;
+}
+
+static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       u8 gain = ~tda80xx_readreg(state, 0x01);
+       *strength = (gain << 8) | gain;
+
+       return 0;
+}
+
+static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       u8 quality = tda80xx_readreg(state, 0x08);
+       *snr = (quality << 8) | quality;
+
+       return 0;
+}
+
+static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       *ucblocks = tda80xx_readreg(state, 0x0f);
+       if (*ucblocks == 0xff)
+               *ucblocks = 0xffffffff;
+
+       return 0;
+}
+
+static int tda80xx_init(struct dvb_frontend* fe)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       switch(state->id) {
+       case ID_TDA8044:
+               return tda8044_init(fe);
+
+       case ID_TDA8083:
+               return tda8083_init(fe);
+       }
+       return 0;
+}
+
+static void tda80xx_release(struct dvb_frontend* fe)
+{
+       struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv;
+
+       if (state->config->irq)
+               free_irq(state->config->irq, &state->worklet);
+
+       kfree(state);
+}
+
+static struct dvb_frontend_ops tda80xx_ops;
+
+struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config,
+                                   struct i2c_adapter* i2c)
+{
+       struct tda80xx_state* state = NULL;
+       int ret;
+
+       /* allocate memory for the internal state */
+       state = (struct tda80xx_state*) kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &tda80xx_ops, sizeof(struct dvb_frontend_ops));
+       state->spectral_inversion = INVERSION_AUTO;
+       state->code_rate = FEC_AUTO;
+       state->status = 0;
+       state->afc_loop = 0;
+
+       /* check if the demod is there */
+       if (tda80xx_writereg(state, 0x89, 0x00) < 0) goto error;
+       state->id = tda80xx_readreg(state, 0x00);
+
+       switch (state->id) {
+       case ID_TDA8044:
+               state->clk = 96000000;
+               printk("tda80xx: Detected tda8044\n");
+               break;
+
+       case ID_TDA8083:
+               state->clk = 64000000;
+               printk("tda80xx: Detected tda8083\n");
+               break;
+
+       default:
+               goto error;
+       }
+
+       /* setup IRQ */
+       if (state->config->irq) {
+               INIT_WORK(&state->worklet, tda80xx_worklet, state);
+               if ((ret = request_irq(state->config->irq, tda80xx_irq, SA_ONESHOT, "tda80xx", &state->worklet)) < 0) {
+                       printk(KERN_ERR "tda80xx: request_irq failed (%d)\n", ret);
+                       goto error;
+               }
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops tda80xx_ops = {
+
+       .info = {
+               .name = "Philips TDA80xx DVB-S",
+               .type = FE_QPSK,
+               .frequency_min = 500000,
+               .frequency_max = 2700000,
+               .frequency_stepsize = 125,
+               .symbol_rate_min = 4500000,
+               .symbol_rate_max = 45000000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_MUTE_TS
+       },
+
+       .release = tda80xx_release,
+
+       .init = tda80xx_init,
+       .sleep = tda80xx_sleep,
+
+       .set_frontend = tda80xx_set_frontend,
+       .get_frontend = tda80xx_get_frontend,
+
+       .read_status = tda80xx_read_status,
+       .read_ber = tda80xx_read_ber,
+       .read_signal_strength = tda80xx_read_signal_strength,
+       .read_snr = tda80xx_read_snr,
+       .read_ucblocks = tda80xx_read_ucblocks,
+
+       .diseqc_send_master_cmd = tda80xx_send_diseqc_msg,
+       .diseqc_send_burst = tda80xx_send_diseqc_burst,
+       .set_tone = tda80xx_set_tone,
+       .set_voltage = tda80xx_set_voltage,
+};
+
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("Philips TDA8044 / TDA8083 DVB-S Demodulator driver");
+MODULE_AUTHOR("Felix Domke, Andreas Oberritter");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda80xx_attach);
diff --git a/drivers/media/dvb/frontends/tda80xx.h b/drivers/media/dvb/frontends/tda80xx.h
new file mode 100644 (file)
index 0000000..cd639a0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * tda80xx.c
+ *
+ * Philips TDA8044 / TDA8083 QPSK demodulator driver
+ *
+ * Copyright (C) 2001 Felix Domke <tmbinc@elitedvb.net>
+ * Copyright (C) 2002-2004 Andreas Oberritter <obi@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA80XX_H
+#define TDA80XX_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda80xx_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* IRQ to use (0=>no IRQ used) */
+       u32 irq;
+
+       /* Register setting to use for 13v */
+       u8 volt13setting;
+
+       /* Register setting to use for 18v */
+       u8 volt18setting;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif // TDA80XX_H
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
new file mode 100644 (file)
index 0000000..8739fec
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+    VES1820  - Single Chip Cable Channel Receiver driver module
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.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 VES1820_H
+#define VES1820_H
+
+#include <linux/dvb/frontend.h>
+
+#define VES1820_SELAGC_PWM 0
+#define VES1820_SELAGC_SIGNAMPERR 1
+
+struct ves1820_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* value of XIN to use */
+       u32 xin;
+
+       /* does inversion need inverted? */
+       u8 invert:1;
+
+       /* SELAGC control */
+       u8 selagc:1;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+                                          struct i2c_adapter* i2c,
+                                          u8 pwm);
+
+#endif // VES1820_H
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
new file mode 100644 (file)
index 0000000..1627e37
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+    Driver for VES1893 and VES1993 QPSK Demodulators
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
+    Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
+    Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef VES1X93_H
+#define VES1X93_H
+
+#include <linux/dvb/frontend.h>
+
+struct ves1x93_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* value of XIN to use */
+       u32 xin;
+
+       /* should PWM be inverted? */
+       u8 invert_pwm:1;
+
+       /* PLL maintenance */
+       int (*pll_init)(struct dvb_frontend* fe);
+       int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+};
+
+extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif // VES1X93_H
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
new file mode 100644 (file)
index 0000000..ff0e521
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * TTUSB DEC Frontend Driver
+ *
+ * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "dvb_frontend.h"
+#include "ttusbdecfe.h"
+
+
+#define LOF_HI                 10600000
+#define LOF_LO                 9750000
+
+struct ttusbdecfe_state {
+
+       struct dvb_frontend_ops ops;
+
+       /* configuration settings */
+       const struct ttusbdecfe_config* config;
+
+       struct dvb_frontend frontend;
+
+       u8 hi_band;
+       u8 voltage;
+};
+
+
+static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+                 FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+       u8 b[] = { 0x00, 0x00, 0x00, 0x03,
+                  0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x01,
+                  0x00, 0x00, 0x00, 0xff,
+                  0x00, 0x00, 0x00, 0xff };
+
+       u32 freq = htonl(p->frequency / 1000);
+       memcpy(&b[4], &freq, sizeof (u32));
+       state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
+
+       return 0;
+}
+
+static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+       struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+       u8 b[] = { 0x00, 0x00, 0x00, 0x01,
+                  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 };
+       u32 freq;
+       u32 sym_rate;
+       u32 band;
+       u32 lnb_voltage;
+
+       freq = htonl(p->frequency +
+              (state->hi_band ? LOF_HI : LOF_LO));
+       memcpy(&b[4], &freq, sizeof(u32));
+       sym_rate = htonl(p->u.qam.symbol_rate);
+       memcpy(&b[12], &sym_rate, sizeof(u32));
+       band = htonl(state->hi_band ? LOF_HI : LOF_LO);
+       memcpy(&b[24], &band, sizeof(u32));
+       lnb_voltage = htonl(state->voltage);
+       memcpy(&b[28], &lnb_voltage, sizeof(u32));
+
+       state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
+
+       return 0;
+}
+
+static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+{
+       struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+       u8 b[] = { 0x00, 0xff, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00 };
+
+       memcpy(&b[4], cmd->msg, cmd->msg_len);
+
+       state->config->send_command(fe, 0x72,
+                                   sizeof(b) - (6 - cmd->msg_len), b,
+                                   NULL, NULL);
+
+       return 0;
+}
+
+
+static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+       struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+       state->hi_band = (SEC_TONE_ON == tone);
+
+       return 0;
+}
+
+
+static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+       struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               state->voltage = 13;
+               break;
+       case SEC_VOLTAGE_18:
+               state->voltage = 18;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void ttusbdecfe_release(struct dvb_frontend* fe)
+{
+       struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbt_ops;
+
+struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config)
+{
+       struct ttusbdecfe_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
+
+struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config)
+{
+       struct ttusbdecfe_state* state = NULL;
+
+       /* allocate memory for the internal state */
+       state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+       if (state == NULL) goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->voltage = 0;
+       state->hi_band = 0;
+       memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       if (state) kfree(state);
+       return NULL;
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
+
+       .info = {
+               .name                   = "TechnoTrend/Hauppauge DEC2000-t Frontend",
+               .type                   = FE_OFDM,
+               .frequency_min          = 51000000,
+               .frequency_max          = 858000000,
+               .frequency_stepsize     = 62500,
+               .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = ttusbdecfe_release,
+
+       .set_frontend = ttusbdecfe_dvbt_set_frontend,
+
+       .read_status = ttusbdecfe_read_status,
+};
+
+static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
+
+       .info = {
+               .name                   = "TechnoTrend/Hauppauge DEC3000-s Frontend",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 125,
+               .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_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO,
+       },
+
+       .release = ttusbdecfe_release,
+
+       .set_frontend = ttusbdecfe_dvbs_set_frontend,
+
+       .read_status = ttusbdecfe_read_status,
+
+       .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
+       .set_voltage = ttusbdecfe_dvbs_set_voltage,
+       .set_tone = ttusbdecfe_dvbs_set_tone,
+};
+
+MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver");
+MODULE_AUTHOR("Alex Woods/Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ttusbdecfe_dvbt_attach);
+EXPORT_SYMBOL(ttusbdecfe_dvbs_attach);
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h b/drivers/media/dvb/ttusb-dec/ttusbdecfe.h
new file mode 100644 (file)
index 0000000..15ccc3d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * TTUSB DEC Driver
+ *
+ * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef TTUSBDECFE_H
+#define TTUSBDECFE_H
+
+#include <linux/dvb/frontend.h>
+
+struct ttusbdecfe_config
+{
+       int (*send_command)(struct dvb_frontend* fe, const u8 command,
+                           int param_length, const u8 params[],
+                           int *result_length, u8 cmd_result[]);
+};
+
+extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config);
+
+extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config);
+
+#endif // TTUSBDECFE_H
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
new file mode 100644 (file)
index 0000000..8db3503
--- /dev/null
@@ -0,0 +1,916 @@
+/*
+ * Colour AR M64278(VGA) driver for Video4Linux
+ *
+ * Copyright (C) 2003  Takeo Takahashi <takahashi.takeo@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Some code is taken from AR driver sample program for M3T-M32700UT.
+ *
+ * AR driver sample (M32R SDK):
+ *     Copyright (c) 2003 RENESAS TECHNOROGY CORPORATION
+ *     AND RENESAS SOLUTIONS CORPORATION
+ *     All Rights Reserved.
+ *
+ * 2003-09-01: Support w3cam by Takeo Takahashi
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/videodev.h>
+
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#if 0
+#define DEBUG(n, args...) printk(args)
+#define CHECK_LOST     1
+#else
+#define DEBUG(n, args...)
+#define CHECK_LOST     0
+#endif
+
+/*
+ * USE_INT is always 0, interrupt mode is not available
+ * on linux due to lack of speed
+ */
+#define USE_INT                0       /* Don't modify */
+
+#define VERSION        "0.03"
+
+#define ar_inl(addr)           inl((unsigned long)(addr))
+#define ar_outl(val, addr)     outl((unsigned long)(val),(unsigned long)(addr))
+
+extern struct cpuinfo_m32r     boot_cpu_data;
+
+/*
+ * CCD pixel size
+ *     Note that M32700UT does not support CIF mode, but QVGA is
+ *     supported by M32700UT hardware using VGA mode of AR LSI.
+ *
+ *     Supported: VGA  (Normal mode, Interlace mode)
+ *                QVGA (Always Interlace mode of VGA)
+ *
+ */
+#define AR_WIDTH_VGA           640
+#define AR_HEIGHT_VGA          480
+#define AR_WIDTH_QVGA          320
+#define AR_HEIGHT_QVGA         240
+#define MIN_AR_WIDTH           AR_WIDTH_QVGA
+#define MIN_AR_HEIGHT          AR_HEIGHT_QVGA
+#define MAX_AR_WIDTH           AR_WIDTH_VGA
+#define MAX_AR_HEIGHT          AR_HEIGHT_VGA
+
+/* bits & bytes per pixel */
+#define AR_BITS_PER_PIXEL      16
+#define AR_BYTES_PER_PIXEL     (AR_BITS_PER_PIXEL/8)
+
+/* line buffer size */
+#define AR_LINE_BYTES_VGA      (AR_WIDTH_VGA * AR_BYTES_PER_PIXEL)
+#define AR_LINE_BYTES_QVGA     (AR_WIDTH_QVGA * AR_BYTES_PER_PIXEL)
+#define MAX_AR_LINE_BYTES      AR_LINE_BYTES_VGA
+
+/* frame size & type */
+#define AR_FRAME_BYTES_VGA \
+       (AR_WIDTH_VGA * AR_HEIGHT_VGA * AR_BYTES_PER_PIXEL)
+#define AR_FRAME_BYTES_QVGA \
+       (AR_WIDTH_QVGA * AR_HEIGHT_QVGA * AR_BYTES_PER_PIXEL)
+#define MAX_AR_FRAME_BYTES \
+       (MAX_AR_WIDTH * MAX_AR_HEIGHT * AR_BYTES_PER_PIXEL)
+
+#define AR_MAX_FRAME           15
+
+/* capture size */
+#define AR_SIZE_VGA            0
+#define AR_SIZE_QVGA           1
+
+/* capture mode */
+#define AR_MODE_INTERLACE      0
+#define AR_MODE_NORMAL         1
+
+struct ar_device {
+       struct video_device *vdev;
+       unsigned int start_capture;     /* duaring capture in INT. mode. */
+#if USE_INT
+       unsigned char *line_buff;       /* DMA line buffer */
+#endif
+       unsigned char *frame[MAX_AR_HEIGHT];    /* frame data */
+       short size;                     /* capture size */
+       short mode;                     /* capture mode */
+       int width, height;
+       int frame_bytes, line_bytes;
+       wait_queue_head_t wait;
+       struct semaphore lock;
+};
+
+static int video_nr = -1;      /* video device number (first free) */
+static unsigned char   yuv[MAX_AR_FRAME_BYTES];
+
+/* module parameters */
+/* default frequency */
+#define DEFAULT_FREQ   50      /* 50 or 75 (MHz) is available as BCLK */
+static int freq = DEFAULT_FREQ;        /* BCLK: available 50 or 70 (MHz) */
+static int vga = 0;            /* default mode(0:QVGA mode, other:VGA mode) */
+static int vga_interlace = 0;  /* 0 is normal mode for, else interlace mode */
+MODULE_PARM(freq, "i");
+MODULE_PARM(vga, "i");
+MODULE_PARM(vga_interlace, "i");
+
+static int ar_initialize(struct video_device *dev);
+
+static inline void wait_for_vsync(void)
+{
+       while (ar_inl(ARVCR0) & ARVCR0_VDS)     /* wait for VSYNC */
+               cpu_relax();
+       while (!(ar_inl(ARVCR0) & ARVCR0_VDS))  /* wait for VSYNC */
+               cpu_relax();
+}
+
+static inline void wait_acknowledge(void)
+{
+       int i;
+
+       for (i = 0; i < 1000; i++)
+               cpu_relax();
+       while (ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK)
+               cpu_relax();
+}
+
+/*******************************************************************
+ * I2C functions
+ *******************************************************************/
+void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2,
+        unsigned long data3)
+{
+       int i;
+
+       /* Slave Address */
+       ar_outl(addr, PLDI2CDATA);
+       wait_for_vsync();
+
+       /* Start */
+       ar_outl(1, PLDI2CCND);
+       wait_acknowledge();
+
+       /* Transfer data 1 */
+       ar_outl(data1, PLDI2CDATA);
+       wait_for_vsync();
+       ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+       wait_acknowledge();
+
+       /* Transfer data 2 */
+       ar_outl(data2, PLDI2CDATA);
+       wait_for_vsync();
+       ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+       wait_acknowledge();
+
+       if (n == 3) {
+               /* Transfer data 3 */
+               ar_outl(data3, PLDI2CDATA);
+               wait_for_vsync();
+               ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN);
+               wait_acknowledge();
+       }
+
+       /* Stop */
+       for (i = 0; i < 100; i++)
+               cpu_relax();
+       ar_outl(2, PLDI2CCND);
+       ar_outl(2, PLDI2CCND);
+
+       while (ar_inl(PLDI2CSTS) & PLDI2CSTS_BB)
+               cpu_relax();
+}
+
+
+void init_iic(void)
+{
+       DEBUG(1, "init_iic:\n");
+
+       /*
+        * ICU Setting (iic)
+        */
+       /* I2C Setting */
+       ar_outl(0x0, PLDI2CCR);         /* I2CCR Disable                   */
+       ar_outl(0x0300, PLDI2CMOD);     /* I2CMOD ACK/8b-data/7b-addr/auto */
+       ar_outl(0x1, PLDI2CACK);        /* I2CACK ACK                      */
+
+       /* I2C CLK */
+       /* 50MH-100k */
+       if (freq == 75) {
+               ar_outl(369, PLDI2CFREQ);       /* BCLK = 75MHz */
+       } else if (freq == 50) {
+               ar_outl(244, PLDI2CFREQ);       /* BCLK = 50MHz */
+       } else {
+               ar_outl(244, PLDI2CFREQ);       /* default: BCLK = 50MHz */
+       }
+       ar_outl(0x1, PLDI2CCR);         /* I2CCR Enable */
+}
+
+/**************************************************************************
+ *
+ * Video4Linux Interface functions
+ *
+ **************************************************************************/
+
+static inline void disable_dma(void)
+{
+       ar_outl(0x8000, M32R_DMAEN_PORTL);      /* disable DMA0 */
+}
+
+static inline void enable_dma(void)
+{
+       ar_outl(0x8080, M32R_DMAEN_PORTL);      /* enable DMA0 */
+}
+
+static inline void clear_dma_status(void)
+{
+       ar_outl(0x8000, M32R_DMAEDET_PORTL);    /* clear status */
+}
+
+static inline void wait_for_vertical_sync(int exp_line)
+{
+#if CHECK_LOST
+       int tmout = 10000;      /* FIXME */
+       int l;
+
+       /*
+        * check HCOUNT because we cannot check vertical sync.
+        */
+       for (; tmout >= 0; tmout--) {
+               l = ar_inl(ARVHCOUNT);
+               if (l == exp_line)
+                       break;
+       }
+       if (tmout < 0)
+               printk("arv: lost %d -> %d\n", exp_line, l);
+#else
+       while (ar_inl(ARVHCOUNT) != exp_line)
+               cpu_relax();
+#endif
+}
+
+static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+       struct video_device *v = video_devdata(file);
+       struct ar_device *ar = v->priv;
+       long ret = ar->frame_bytes;             /* return read bytes */
+       unsigned long arvcr1 = 0;
+       unsigned long flags;
+       unsigned char *p;
+       int h, w;
+       unsigned char *py, *pu, *pv;
+#if ! USE_INT
+       int l;
+#endif
+
+       DEBUG(1, "ar_read()\n");
+
+       if (ar->size == AR_SIZE_QVGA)
+               arvcr1 |= ARVCR1_QVGA;
+       if (ar->mode == AR_MODE_NORMAL)
+               arvcr1 |= ARVCR1_NORMAL;
+
+       down(&ar->lock);
+
+#if USE_INT
+       local_irq_save(flags);
+       disable_dma();
+       ar_outl(0xa1871300, M32R_DMA0CR0_PORTL);
+       ar_outl(0x01000000, M32R_DMA0CR1_PORTL);
+
+       /* set AR FIFO address as source(BSEL5) */
+       ar_outl(ARDATA32, M32R_DMA0CSA_PORTL);
+       ar_outl(ARDATA32, M32R_DMA0RSA_PORTL);
+       ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);     /* destination addr. */
+       ar_outl(ar->line_buff, M32R_DMA0RDA_PORTL);     /* reload address */
+       ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL);  /* byte count (bytes) */
+       ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL);  /* reload count (bytes) */
+
+       /*
+        * Okey , kicks AR LSI to invoke an interrupt
+        */
+       ar->start_capture = 0;
+       ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1);
+       local_irq_restore(flags);
+       /* .... AR interrupts .... */
+       interruptible_sleep_on(&ar->wait);
+       if (signal_pending(current)) {
+               printk("arv: interrupted while get frame data.\n");
+               ret = -EINTR;
+               goto out_up;
+       }
+#else  /* ! USE_INT */
+       /* polling */
+       ar_outl(arvcr1, ARVCR1);
+       disable_dma();
+       ar_outl(0x8000, M32R_DMAEDET_PORTL);
+       ar_outl(0xa0861300, M32R_DMA0CR0_PORTL);
+       ar_outl(0x01000000, M32R_DMA0CR1_PORTL);
+       ar_outl(ARDATA32, M32R_DMA0CSA_PORTL);
+       ar_outl(ARDATA32, M32R_DMA0RSA_PORTL);
+       ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL);
+       ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL);
+
+       local_irq_save(flags);
+       while (ar_inl(ARVHCOUNT) != 0)          /* wait for 0 */
+               cpu_relax();
+       if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
+               for (h = 0; h < ar->height; h++) {
+                       wait_for_vertical_sync(h);
+                       if (h < (AR_HEIGHT_VGA/2))
+                               l = h << 1;
+                       else
+                               l = (((h - (AR_HEIGHT_VGA/2)) << 1) + 1);
+                       ar_outl(virt_to_phys(ar->frame[l]), M32R_DMA0CDA_PORTL);
+                       enable_dma();
+                       while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000))
+                               cpu_relax();
+                       disable_dma();
+                       clear_dma_status();
+                       ar_outl(0xa0861300, M32R_DMA0CR0_PORTL);
+               }
+       } else {
+               for (h = 0; h < ar->height; h++) {
+                       wait_for_vertical_sync(h);
+                       ar_outl(virt_to_phys(ar->frame[h]), M32R_DMA0CDA_PORTL);
+                       enable_dma();
+                       while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000))
+                               cpu_relax();
+                       disable_dma();
+                       clear_dma_status();
+                       ar_outl(0xa0861300, M32R_DMA0CR0_PORTL);
+               }
+       }
+       local_irq_restore(flags);
+#endif /* ! USE_INT */
+
+       /*
+        * convert YUV422 to YUV422P
+        *      +--------------------+
+        *      |  Y0,Y1,...         |
+        *      |  ..............Yn  |
+        *      +--------------------+
+        *      |  U0,U1,........Un  |
+        *      +--------------------+
+        *      |  V0,V1,........Vn  |
+        *      +--------------------+
+        */
+       py = yuv;
+       pu = py + (ar->frame_bytes / 2);
+       pv = pu + (ar->frame_bytes / 4);
+       for (h = 0; h < ar->height; h++) {
+               p = ar->frame[h];
+               for (w = 0; w < ar->line_bytes; w += 4) {
+                       *py++ = *p++;
+                       *pu++ = *p++;
+                       *py++ = *p++;
+                       *pv++ = *p++;
+               }
+       }
+       if (copy_to_user(buf, yuv, ar->frame_bytes)) {
+               printk("arv: failed while copy_to_user yuv.\n");
+               ret = -EFAULT;
+               goto out_up;
+       }
+       DEBUG(1, "ret = %d\n", ret);
+out_up:
+       up(&ar->lock);
+       return ret;
+}
+
+static int ar_do_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, void *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct ar_device *ar = dev->priv;
+
+       DEBUG(1, "ar_ioctl()\n");
+       switch(cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability *b = arg;
+               DEBUG(1, "VIDIOCGCAP:\n");
+               strcpy(b->name, ar->vdev->name);
+               b->type = VID_TYPE_CAPTURE;
+               b->channels = 0;
+               b->audios = 0;
+               b->maxwidth = MAX_AR_WIDTH;
+               b->maxheight = MAX_AR_HEIGHT;
+               b->minwidth = MIN_AR_WIDTH;
+               b->minheight = MIN_AR_HEIGHT;
+               return 0;
+       }
+       case VIDIOCGCHAN:
+               DEBUG(1, "VIDIOCGCHAN:\n");
+               return 0;
+       case VIDIOCSCHAN:
+               DEBUG(1, "VIDIOCSCHAN:\n");
+               return 0;
+       case VIDIOCGTUNER:
+               DEBUG(1, "VIDIOCGTUNER:\n");
+               return 0;
+       case VIDIOCSTUNER:
+               DEBUG(1, "VIDIOCSTUNER:\n");
+               return 0;
+       case VIDIOCGPICT:
+               DEBUG(1, "VIDIOCGPICT:\n");
+               return 0;
+       case VIDIOCSPICT:
+               DEBUG(1, "VIDIOCSPICT:\n");
+               return 0;
+       case VIDIOCCAPTURE:
+               DEBUG(1, "VIDIOCCAPTURE:\n");
+               return -EINVAL;
+       case VIDIOCGWIN:
+       {
+               struct video_window *w = arg;
+               DEBUG(1, "VIDIOCGWIN:\n");
+               memset(w, 0, sizeof(w));
+               w->width = ar->width;
+               w->height = ar->height;
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window *w = arg;
+               DEBUG(1, "VIDIOCSWIN:\n");
+               if ((w->width != AR_WIDTH_VGA || w->height != AR_HEIGHT_VGA) &&
+                   (w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA))
+                               return -EINVAL;
+
+               down(&ar->lock);
+               ar->width = w->width;
+               ar->height = w->height;
+               if (ar->width == AR_WIDTH_VGA) {
+                       ar->size = AR_SIZE_VGA;
+                       ar->frame_bytes = AR_FRAME_BYTES_VGA;
+                       ar->line_bytes = AR_LINE_BYTES_VGA;
+                       if (vga_interlace)
+                               ar->mode = AR_MODE_INTERLACE;
+                       else
+                               ar->mode = AR_MODE_NORMAL;
+               } else {
+                       ar->size = AR_SIZE_QVGA;
+                       ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+                       ar->line_bytes = AR_LINE_BYTES_QVGA;
+                       ar->mode = AR_MODE_INTERLACE;
+               }
+               up(&ar->lock);
+               return 0;
+       }
+       case VIDIOCGFBUF:
+               DEBUG(1, "VIDIOCGFBUF:\n");
+               return -EINVAL;
+       case VIDIOCSFBUF:
+               DEBUG(1, "VIDIOCSFBUF:\n");
+               return -EINVAL;
+       case VIDIOCKEY:
+               DEBUG(1, "VIDIOCKEY:\n");
+               return 0;
+       case VIDIOCGFREQ:
+               DEBUG(1, "VIDIOCGFREQ:\n");
+               return -EINVAL;
+       case VIDIOCSFREQ:
+               DEBUG(1, "VIDIOCSFREQ:\n");
+               return -EINVAL;
+       case VIDIOCGAUDIO:
+               DEBUG(1, "VIDIOCGAUDIO:\n");
+               return -EINVAL;
+       case VIDIOCSAUDIO:
+               DEBUG(1, "VIDIOCSAUDIO:\n");
+               return -EINVAL;
+       case VIDIOCSYNC:
+               DEBUG(1, "VIDIOCSYNC:\n");
+               return -EINVAL;
+       case VIDIOCMCAPTURE:
+               DEBUG(1, "VIDIOCMCAPTURE:\n");
+               return -EINVAL;
+       case VIDIOCGMBUF:
+               DEBUG(1, "VIDIOCGMBUF:\n");
+               return -EINVAL;
+       case VIDIOCGUNIT:
+               DEBUG(1, "VIDIOCGUNIT:\n");
+               return -EINVAL;
+       case VIDIOCGCAPTURE:
+               DEBUG(1, "VIDIOCGCAPTURE:\n");
+               return -EINVAL;
+       case VIDIOCSCAPTURE:
+               DEBUG(1, "VIDIOCSCAPTURE:\n");
+               return -EINVAL;
+       case VIDIOCSPLAYMODE:
+               DEBUG(1, "VIDIOCSPLAYMODE:\n");
+               return -EINVAL;
+       case VIDIOCSWRITEMODE:
+               DEBUG(1, "VIDIOCSWRITEMODE:\n");
+               return -EINVAL;
+       case VIDIOCGPLAYINFO:
+               DEBUG(1, "VIDIOCGPLAYINFO:\n");
+               return -EINVAL;
+       case VIDIOCSMICROCODE:
+               DEBUG(1, "VIDIOCSMICROCODE:\n");
+               return -EINVAL;
+       case VIDIOCGVBIFMT:
+               DEBUG(1, "VIDIOCGVBIFMT:\n");
+               return -EINVAL;
+       case VIDIOCSVBIFMT:
+               DEBUG(1, "VIDIOCSVBIFMT:\n");
+               return -EINVAL;
+       default:
+               DEBUG(1, "Unknown ioctl(0x%08x)\n", cmd);
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+                   unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, ar_do_ioctl);
+}
+
+#if USE_INT
+/*
+ * Interrupt handler
+ */
+static void ar_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+       struct ar_device *ar = dev;
+       unsigned int line_count;
+       unsigned int line_number;
+       unsigned int arvcr1;
+
+       line_count = ar_inl(ARVHCOUNT);                 /* line number */
+       if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) {
+               /* operations for interlace mode */
+               if ( line_count < (AR_HEIGHT_VGA/2) )   /* even line */
+                       line_number = (line_count << 1);
+               else                                    /* odd line */
+                       line_number =
+                       (((line_count - (AR_HEIGHT_VGA/2)) << 1) + 1);
+       } else {
+               line_number = line_count;
+       }
+
+       if (line_number == 0) {
+               /*
+                * It is an interrupt for line 0.
+                * we have to start capture.
+                */
+               disable_dma();
+#if 0
+               ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);     /* needless? */
+#endif
+               memcpy(ar->frame[0], ar->line_buff, ar->line_bytes);
+#if 0
+               ar_outl(0xa1861300, M32R_DMA0CR0_PORTL);
+#endif
+               enable_dma();
+               ar->start_capture = 1;                  /* during capture */
+               return;
+       }
+
+       if (ar->start_capture == 1 && line_number <= (ar->height - 1)) {
+               disable_dma();
+               memcpy(ar->frame[line_number], ar->line_buff, ar->line_bytes);
+
+               /*
+                * if captured all line of a frame, disable AR interrupt
+                * and wake a process up.
+                */
+               if (line_number == (ar->height - 1)) {  /* end  of line */
+
+                       ar->start_capture = 0;
+
+                       /* disable AR interrupt request */
+                       arvcr1 = ar_inl(ARVCR1);
+                       arvcr1 &= ~ARVCR1_HIEN;         /* clear int. flag */
+                       ar_outl(arvcr1, ARVCR1);        /* disable */
+                       wake_up_interruptible(&ar->wait);
+               } else {
+#if 0
+                       ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL);
+                       ar_outl(0xa1861300, M32R_DMA0CR0_PORTL);
+#endif
+                       enable_dma();
+               }
+       }
+}
+#endif
+
+/*
+ * ar_initialize()
+ *     ar_initialize() is called by video_register_device() and
+ *     initializes AR LSI and peripherals.
+ *
+ *     -1 is returned in all failures.
+ *     0 is returned in success.
+ *
+ */
+static int ar_initialize(struct video_device *dev)
+{
+       struct ar_device *ar = (struct ar_device *)dev->priv;
+       unsigned long cr = 0;
+       int i,found=0;
+
+       DEBUG(1, "ar_initialize:\n");
+
+       /*
+        * initialize AR LSI
+        */
+       ar_outl(0, ARVCR0);             /* assert reset of AR LSI */
+       for (i = 0; i < 0x18; i++)      /* wait for over 10 cycles @ 27MHz */
+               cpu_relax();
+       ar_outl(ARVCR0_RST, ARVCR0);    /* negate reset of AR LSI (enable) */
+       for (i = 0; i < 0x40d; i++)     /* wait for over 420 cycles @ 27MHz */
+               cpu_relax();
+
+       /* AR uses INT3 of CPU as interrupt pin. */
+       ar_outl(ARINTSEL_INT3, ARINTSEL);
+
+       if (ar->size == AR_SIZE_QVGA)
+               cr |= ARVCR1_QVGA;
+       if (ar->mode == AR_MODE_NORMAL)
+               cr |= ARVCR1_NORMAL;
+       ar_outl(cr, ARVCR1);
+
+       /*
+        * Initialize IIC so that CPU can communicate with AR LSI,
+        * and send boot commands to AR LSI.
+        */
+       init_iic();
+
+       for (i = 0; i < 0x100000; i++) {        /* > 0xa1d10,  56ms */
+               if ((ar_inl(ARVCR0) & ARVCR0_VDS)) {    /* VSYNC */
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found == 0)
+               return -ENODEV;
+
+       printk("arv: Initializing ");
+
+       iic(2,0x78,0x11,0x01,0x00);     /* start */
+       iic(3,0x78,0x12,0x00,0x06);
+       iic(3,0x78,0x12,0x12,0x30);
+       iic(3,0x78,0x12,0x15,0x58);
+       iic(3,0x78,0x12,0x17,0x30);
+       printk(".");
+       iic(3,0x78,0x12,0x1a,0x97);
+       iic(3,0x78,0x12,0x1b,0xff);
+       iic(3,0x78,0x12,0x1c,0xff);
+       iic(3,0x78,0x12,0x26,0x10);
+       iic(3,0x78,0x12,0x27,0x00);
+       printk(".");
+       iic(2,0x78,0x34,0x02,0x00);
+       iic(2,0x78,0x7a,0x10,0x00);
+       iic(2,0x78,0x80,0x39,0x00);
+       iic(2,0x78,0x81,0xe6,0x00);
+       iic(2,0x78,0x8d,0x00,0x00);
+       printk(".");
+       iic(2,0x78,0x8e,0x0c,0x00);
+       iic(2,0x78,0x8f,0x00,0x00);
+#if 0
+       iic(2,0x78,0x90,0x00,0x00);     /* AWB on=1 off=0 */
+#endif
+       iic(2,0x78,0x93,0x01,0x00);
+       iic(2,0x78,0x94,0xcd,0x00);
+       iic(2,0x78,0x95,0x00,0x00);
+       printk(".");
+       iic(2,0x78,0x96,0xa0,0x00);
+       iic(2,0x78,0x97,0x00,0x00);
+       iic(2,0x78,0x98,0x60,0x00);
+       iic(2,0x78,0x99,0x01,0x00);
+       iic(2,0x78,0x9a,0x19,0x00);
+       printk(".");
+       iic(2,0x78,0x9b,0x02,0x00);
+       iic(2,0x78,0x9c,0xe8,0x00);
+       iic(2,0x78,0x9d,0x02,0x00);
+       iic(2,0x78,0x9e,0x2e,0x00);
+       iic(2,0x78,0xb8,0x78,0x00);
+       iic(2,0x78,0xba,0x05,0x00);
+#if 0
+       iic(2,0x78,0x83,0x8c,0x00);     /* brightness */
+#endif
+       printk(".");
+
+       /* color correction */
+       iic(3,0x78,0x49,0x00,0x95);     /* a            */
+       iic(3,0x78,0x49,0x01,0x96);     /* b            */
+       iic(3,0x78,0x49,0x03,0x85);     /* c            */
+       iic(3,0x78,0x49,0x04,0x97);     /* d            */
+       iic(3,0x78,0x49,0x02,0x7e);     /* e(Lo)        */
+       iic(3,0x78,0x49,0x05,0xa4);     /* f(Lo)        */
+       iic(3,0x78,0x49,0x06,0x04);     /* e(Hi)        */
+       iic(3,0x78,0x49,0x07,0x04);     /* e(Hi)        */
+       iic(2,0x78,0x48,0x01,0x00);     /* on=1 off=0   */
+
+       printk(".");
+       iic(2,0x78,0x11,0x00,0x00);     /* end */
+       printk(" done\n");
+       return 0;
+}
+
+
+void ar_release(struct video_device *vfd)
+{
+       struct ar_device *ar = vfd->priv;
+       down(&ar->lock);
+       video_device_release(vfd);
+}
+
+/****************************************************************************
+ *
+ * Video4Linux Module functions
+ *
+ ****************************************************************************/
+static struct file_operations ar_fops = {
+       .owner          = THIS_MODULE,
+       .open           = video_exclusive_open,
+       .release        = video_exclusive_release,
+       .read           = ar_read,
+       .ioctl          = ar_ioctl,
+       .llseek         = no_llseek,
+};
+
+static struct video_device ar_template = {
+       .owner          = THIS_MODULE,
+       .name           = "Colour AR VGA",
+       .type           = VID_TYPE_CAPTURE,
+       .hardware       = VID_HARDWARE_ARV,
+       .fops           = &ar_fops,
+       .release        = ar_release,
+       .minor          = -1,
+};
+
+#define ALIGN4(x)      ((((int)(x)) & 0x3) == 0)
+static struct ar_device ardev;
+
+static int __init ar_init(void)
+{
+       struct ar_device *ar;
+       int ret;
+       int i;
+
+       DEBUG(1, "ar_init:\n");
+       ret = -EIO;
+       printk(KERN_INFO "arv: Colour AR VGA driver %s\n", VERSION);
+
+       ar = &ardev;
+       memset(ar, 0, sizeof(struct ar_device));
+
+#if USE_INT
+       /* allocate a DMA buffer for 1 line.  */
+       ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA);
+       if (ar->line_buff == NULL || ! ALIGN4(ar->line_buff)) {
+               printk("arv: buffer allocation failed for DMA.\n");
+               ret = -ENOMEM;
+               goto out_end;
+       }
+#endif
+       /* allocate buffers for a frame */
+       for (i = 0; i < MAX_AR_HEIGHT; i++) {
+               ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL);
+               if (ar->frame[i] == NULL || ! ALIGN4(ar->frame[i])) {
+                       printk("arv: buffer allocation failed for frame.\n");
+                       ret = -ENOMEM;
+                       goto out_line_buff;
+               }
+       }
+
+       ar->vdev = video_device_alloc();
+       if (!ar->vdev) {
+               printk(KERN_ERR "arv: video_device_alloc() failed\n");
+               return -ENOMEM;
+       }
+       memcpy(ar->vdev, &ar_template, sizeof(ar_template));
+       ar->vdev->priv = ar;
+
+       if (vga) {
+               ar->width       = AR_WIDTH_VGA;
+               ar->height      = AR_HEIGHT_VGA;
+               ar->size        = AR_SIZE_VGA;
+               ar->frame_bytes = AR_FRAME_BYTES_VGA;
+               ar->line_bytes  = AR_LINE_BYTES_VGA;
+               if (vga_interlace)
+                       ar->mode = AR_MODE_INTERLACE;
+               else
+                       ar->mode = AR_MODE_NORMAL;
+       } else {
+               ar->width       = AR_WIDTH_QVGA;
+               ar->height      = AR_HEIGHT_QVGA;
+               ar->size        = AR_SIZE_QVGA;
+               ar->frame_bytes = AR_FRAME_BYTES_QVGA;
+               ar->line_bytes  = AR_LINE_BYTES_QVGA;
+               ar->mode        = AR_MODE_INTERLACE;
+       }
+       init_MUTEX(&ar->lock);
+       init_waitqueue_head(&ar->wait);
+
+#if USE_INT
+       if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)) {
+               printk("arv: request_irq(%d) failed.\n", M32R_IRQ_INT3);
+               ret = -EIO;
+               goto out_irq;
+       }
+#endif
+
+       if (ar_initialize(ar->vdev) != 0) {
+               printk("arv: M64278 not found.\n");
+               ret = -ENODEV;
+               goto out_dev;
+       }
+
+       /*
+        * ok, we can initialize h/w according to parameters,
+        * so register video device as a frame grabber type.
+        * device is named "video[0-64]".
+        * video_register_device() initializes h/w using ar_initialize().
+        */
+       if (video_register_device(ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) {
+               /* return -1, -ENFILE(full) or others */
+               printk("arv: register video (Colour AR) failed.\n");
+               ret = -ENODEV;
+               goto out_dev;
+       }
+
+       printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n",
+               ar->vdev->minor, M32R_IRQ_INT3, freq);
+
+       return 0;
+
+out_dev:
+#if USE_INT
+       free_irq(M32R_IRQ_INT3, ar);
+
+out_irq:
+#endif
+       for (i = 0; i < MAX_AR_HEIGHT; i++) {
+               if (ar->frame[i])
+                       kfree(ar->frame[i]);
+       }
+
+out_line_buff:
+#if USE_INT
+       kfree(ar->line_buff);
+
+out_end:
+#endif
+       return ret;
+}
+
+
+static int __init ar_init_module(void)
+{
+       freq = (boot_cpu_data.bus_clock / 1000000);
+       printk("arv: Bus clock %d\n", freq);
+       if (freq != 50 && freq != 75)
+               freq = DEFAULT_FREQ;
+       return ar_init();
+}
+
+static void __exit ar_cleanup_module(void)
+{
+       struct ar_device *ar;
+       int i;
+
+       ar = &ardev;
+       video_unregister_device(ar->vdev);
+#if USE_INT
+       free_irq(M32R_IRQ_INT3, ar);
+#endif
+       for (i = 0; i < MAX_AR_HEIGHT; i++) {
+               if (ar->frame[i])
+                       kfree(ar->frame[i]);
+       }
+#if USE_INT
+       kfree(ar->line_buff);
+#endif
+}
+
+module_init(ar_init_module);
+module_exit(ar_cleanup_module);
+
+MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>");
+MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
new file mode 100644 (file)
index 0000000..ef56a5d
--- /dev/null
@@ -0,0 +1,904 @@
+/*
+ * $Id: cx88-blackbird.c,v 1.17 2004/11/07 13:17:15 kraxel Exp $
+ *
+ *  Support for a cx23416 mpeg encoder via cx2388x host port.
+ *  "blackbird" reference design.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ *  Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+#include "cx88.h"
+
+MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int mpegbufs = 8;
+module_param(mpegbufs,int,0644);
+MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
+
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
+
+#define dprintk(level,fmt, arg...)     if (debug >= level) \
+       printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg)
+
+static LIST_HEAD(cx8802_devlist);
+
+/* ------------------------------------------------------------------ */
+
+#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
+#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
+
+/* defines below are from ivtv-driver.h */
+
+#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
+
+/* Registers */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/)
+#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/)
+
+/* ------------------------------------------------------------------ */
+
+static void host_setup(struct cx88_core *core)
+{
+       /* toggle reset of the host */
+       cx_write(MO_GPHST_SOFT_RST, 1);
+       udelay(100);
+       cx_write(MO_GPHST_SOFT_RST, 0);
+       udelay(100);
+
+       /* host port setup */
+       cx_write(MO_GPHST_WSC, 0x44444444U);
+       cx_write(MO_GPHST_XFR, 0);
+       cx_write(MO_GPHST_WDTH, 15);
+       cx_write(MO_GPHST_HDSHK, 0);
+       cx_write(MO_GPHST_MUX16, 0x44448888U);
+       cx_write(MO_GPHST_MODE, 0);
+}
+
+/* ------------------------------------------------------------------ */
+
+#define P1_MDATA0 0x390000
+#define P1_MDATA1 0x390001
+#define P1_MDATA2 0x390002
+#define P1_MDATA3 0x390003
+#define P1_MADDR2 0x390004
+#define P1_MADDR1 0x390005
+#define P1_MADDR0 0x390006
+#define P1_RDATA0 0x390008
+#define P1_RDATA1 0x390009
+#define P1_RDATA2 0x39000A
+#define P1_RDATA3 0x39000B
+#define P1_RADDR0 0x39000C
+#define P1_RADDR1 0x39000D
+#define P1_RRDWR  0x39000E
+
+static int wait_ready_gpio0_bit1(struct cx88_core *core, u32 state)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1);
+       u32 gpio0,need;
+
+       need = state ? 2 : 0;
+       for (;;) {
+               gpio0 = cx_read(MO_GP0_IO) & 2;
+               if (need == gpio0)
+                       return 0;
+               if (time_after(jiffies,timeout))
+                       return -1;
+               udelay(1);
+       }
+}
+
+static int memory_write(struct cx88_core *core, u32 address, u32 value)
+{
+       /* Warning: address is dword address (4 bytes) */
+       cx_writeb(P1_MDATA0, (unsigned int)value);
+       cx_writeb(P1_MDATA1, (unsigned int)(value >> 8));
+       cx_writeb(P1_MDATA2, (unsigned int)(value >> 16));
+       cx_writeb(P1_MDATA3, (unsigned int)(value >> 24));
+       cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40);
+       cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));
+       cx_writeb(P1_MADDR0, (unsigned int)address);
+       cx_read(P1_MDATA0);
+       cx_read(P1_MADDR0);
+
+       return wait_ready_gpio0_bit1(core,1);
+}
+
+static int memory_read(struct cx88_core *core, u32 address, u32 *value)
+{
+        int retval;
+       u32 val;
+
+       /* Warning: address is dword address (4 bytes) */
+       cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0);
+       cx_writeb(P1_MADDR1, (unsigned int)(address >> 8));
+       cx_writeb(P1_MADDR0, (unsigned int)address);
+       cx_read(P1_MADDR0);
+
+       retval = wait_ready_gpio0_bit1(core,1);
+
+       cx_writeb(P1_MDATA3, 0);
+       val     = (unsigned char)cx_read(P1_MDATA3) << 24;
+       cx_writeb(P1_MDATA2, 0);
+       val    |= (unsigned char)cx_read(P1_MDATA2) << 16;
+       cx_writeb(P1_MDATA1, 0);
+       val    |= (unsigned char)cx_read(P1_MDATA1) << 8;
+       cx_writeb(P1_MDATA0, 0);
+       val    |= (unsigned char)cx_read(P1_MDATA0);
+
+       *value  = val;
+       return retval;
+}
+
+static int register_write(struct cx88_core *core, u32 address, u32 value)
+{
+       cx_writeb(P1_RDATA0, (unsigned int)value);
+       cx_writeb(P1_RDATA1, (unsigned int)(value >> 8));
+       cx_writeb(P1_RDATA2, (unsigned int)(value >> 16));
+       cx_writeb(P1_RDATA3, (unsigned int)(value >> 24));
+       cx_writeb(P1_RADDR0, (unsigned int)address);
+       cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));
+       cx_writeb(P1_RRDWR, 1);
+       cx_read(P1_RDATA0);
+       cx_read(P1_RADDR0);
+
+       return wait_ready_gpio0_bit1(core,1);
+#if 0
+       udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */
+       /* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */
+#endif
+}
+
+
+static int register_read(struct cx88_core *core, u32 address, u32 *value)
+{
+       int retval;
+       u32 val;
+
+       cx_writeb(P1_RADDR0, (unsigned int)address);
+       cx_writeb(P1_RADDR1, (unsigned int)(address >> 8));
+       cx_writeb(P1_RRDWR, 0);
+       cx_read(P1_RADDR0);
+
+       retval  = wait_ready_gpio0_bit1(core,1);
+       val     = (unsigned char)cx_read(P1_RDATA0);
+       val    |= (unsigned char)cx_read(P1_RDATA1) << 8;
+       val    |= (unsigned char)cx_read(P1_RDATA2) << 16;
+       val    |= (unsigned char)cx_read(P1_RDATA3) << 24;
+
+       *value  = val;
+       return retval;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+                            u32 inputcnt, u32 outputcnt, ...)
+{
+       unsigned long timeout;
+       u32 value, flag, retval;
+       int i;
+       va_list args;
+       va_start(args, outputcnt);
+
+       dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
+
+       /* this may not be 100% safe if we can't read any memory location
+          without side effects */
+       memory_read(dev->core, dev->mailbox - 4, &value);
+       if (value != 0x12345678) {
+               dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n");
+               return -1;
+       }
+
+       memory_read(dev->core, dev->mailbox, &flag);
+       if (flag) {
+               dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag);
+               return -1;
+       }
+
+       flag |= 1; /* tell 'em we're working on it */
+       memory_write(dev->core, dev->mailbox, flag);
+
+       /* write command + args + fill remaining with zeros */
+       memory_write(dev->core, dev->mailbox + 1, command); /* command code */
+       memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
+       for (i = 0; i < inputcnt ; i++) {
+               value = va_arg(args, int);
+               memory_write(dev->core, dev->mailbox + 4 + i, value);
+               dprintk(1, "API Input %d = %d\n", i, value);
+       }
+       for (; i < 16 ; i++)
+               memory_write(dev->core, dev->mailbox + 4 + i, 0);
+
+       flag |= 3; /* tell 'em we're done writing */
+       memory_write(dev->core, dev->mailbox, flag);
+
+       /* wait for firmware to handle the API command */
+       timeout = jiffies + msecs_to_jiffies(10);
+       for (;;) {
+               memory_read(dev->core, dev->mailbox, &flag);
+               if (0 == (flag & 4))
+                       break;
+               if (time_after(jiffies,timeout)) {
+                       dprintk(0, "ERROR: API Mailbox timeout\n");
+                       return -1;
+               }
+               udelay(10);
+       }
+
+       /* read output values */
+       for (i = 0; i < outputcnt ; i++) {
+               int *vptr = va_arg(args, int *);
+               memory_read(dev->core, dev->mailbox + 4 + i, vptr);
+               dprintk(1, "API Output %d = %d\n", i, *vptr);
+       }
+       va_end(args);
+
+       memory_read(dev->core, dev->mailbox + 2, &retval);
+       dprintk(1, "API result = %d\n",retval);
+
+       flag = 0;
+       memory_write(dev->core, dev->mailbox, flag);
+       return retval;
+}
+
+
+static int blackbird_find_mailbox(struct cx8802_dev *dev)
+{
+       u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456};
+       int signaturecnt=0;
+       u32 value;
+       int i;
+
+       for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
+               memory_read(dev->core, i, &value);
+               if (value == signature[signaturecnt])
+                       signaturecnt++;
+               else
+                       signaturecnt = 0;
+               if (4 == signaturecnt) {
+                       dprintk(1, "Mailbox signature found\n");
+                       return i;
+               }
+       }
+       dprintk(0, "Mailbox signature values not found!\n");
+       return -1;
+}
+
+static int blackbird_load_firmware(struct cx8802_dev *dev)
+{
+       static const unsigned char magic[8] = {
+               0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+       };
+       const struct firmware *firmware;
+       int i, retval = 0;
+       u32 value = 0;
+       u32 checksum = 0;
+       u32 *dataptr;
+
+       retval  = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
+        retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+        retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+        retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+       msleep(1);
+        retval |= register_write(dev->core, IVTV_REG_APU, 0);
+
+       if (retval < 0)
+               dprintk(0, "Error with register_write\n");
+
+       retval = request_firmware(&firmware, BLACKBIRD_FIRM_ENC_FILENAME,
+                                 &dev->pci->dev);
+       if (retval != 0) {
+               dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
+                       BLACKBIRD_FIRM_ENC_FILENAME);
+               dprintk(0, "Please fix your hotplug setup, the board will "
+                       "not work without firmware loaded!\n");
+               return -1;
+       }
+
+       if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+               dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+                       firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
+               return -1;
+       }
+
+       if (0 != memcmp(firmware->data, magic, 8)) {
+               dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
+               return -1;
+       }
+
+       /* transfer to the chip */
+       dprintk(1,"Loading firmware ...\n");
+       dataptr = (u32*)firmware->data;
+       for (i = 0; i < (firmware->size >> 2); i++) {
+               value = *dataptr;
+               checksum += ~value;
+               memory_write(dev->core, i, value);
+               dataptr++;
+       }
+
+       /* read back to verify with the checksum */
+       for (i--; i >= 0; i--) {
+               memory_read(dev->core, i, &value);
+               checksum -= ~value;
+       }
+       if (checksum) {
+               dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n");
+               return -1;
+       }
+       release_firmware(firmware);
+       dprintk(0, "Firmware upload successful.\n");
+
+        retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+        retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+        retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+       msleep(1);
+
+       retval |= register_read(dev->core, IVTV_REG_VPU, &value);
+        retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+       if (retval < 0)
+               dprintk(0, "Error with register_write\n");
+       return 0;
+}
+
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+       int bitrate_mode = 1;
+       int bitrate = 7500000;
+       int bitrate_peak = 7500000;
+
+       /* 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 */
+
+        /* assign output port */
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_OUTPUT_PORT, 1, 0, 1); /* 1 = Host */
+
+        /* assign framerate */
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0);
+
+        /* assign frame size */
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720);
+
+        /* assign aspect ratio */
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2);
+
+        /* assign bitrates */
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_BITRATES, 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));
+
+       /* assign gop closure */
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_CLOSURE, 1, 0, 0);
+
+        /* 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 props*/
+        blackbird_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_PROPS, 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 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 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)
+{
+       struct cx88_core *core = dev->core;
+       int version;
+       int retval;
+
+       dprintk(1,"Initialize codec\n");
+       retval = blackbird_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+       if (retval < 0) {
+               /* ping was not successful, reset and upload firmware */
+               cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
+               msleep(1);
+               cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
+               msleep(1);
+               retval = blackbird_load_firmware(dev);
+               if (retval < 0)
+                       return retval;
+
+               dev->mailbox = blackbird_find_mailbox(dev);
+               if (dev->mailbox < 0)
+                       return -1;
+
+               retval = blackbird_api_cmd(dev, IVTV_API_ENC_PING_FW, 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);
+               if (retval < 0) {
+                       dprintk(0, "ERROR: Firmware get encoder version failed!\n");
+                       return -1;
+               }
+               dprintk(0, "Firmware version is 0x%08x\n", version);
+       }
+       msleep(1);
+
+       cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
+       cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
+       cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */
+       cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
+
+#if 0 /* FIXME */
+       set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED);
+#endif
+       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_INITIALIZE_INPUT, 0, 0); /* initialize the video input */
+
+       msleep(1);
+
+        blackbird_api_cmd(dev, IVTV_API_MUTE_VIDEO, 1, 0, 0);
+       msleep(1);
+        blackbird_api_cmd(dev, IVTV_API_MUTE_AUDIO, 1, 0, 0);
+       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, IVTV_API_REFRESH_INPUT, 0,0);
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+                       unsigned int *count, unsigned int *size)
+{
+       struct cx8802_fh *fh = q->priv_data;
+
+       fh->dev->ts_packet_size  = 512;
+       fh->dev->ts_packet_count = 100;
+
+       *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
+       if (0 == *count)
+               *count = mpegbufs;
+       if (*count < 2)
+               *count = 2;
+       if (*count > 32)
+               *count = 32;
+       return 0;
+}
+
+static int
+bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+              enum v4l2_field field)
+{
+       struct cx8802_fh *fh = q->priv_data;
+       return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb);
+}
+
+static void
+bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct cx8802_fh *fh = q->priv_data;
+       cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb);
+}
+
+static void
+bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct cx8802_fh *fh = q->priv_data;
+       cx88_free_buffer(fh->dev->pci, (struct cx88_buffer*)vb);
+}
+
+static struct videobuf_queue_ops blackbird_qops = {
+       .buf_setup    = bb_buf_setup,
+       .buf_prepare  = bb_buf_prepare,
+       .buf_queue    = bb_buf_queue,
+       .buf_release  = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int mpeg_do_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, void *arg)
+{
+       struct cx8802_fh  *fh  = file->private_data;
+       struct cx8802_dev *dev = fh->dev;
+
+       if (debug > 1)
+               cx88_print_ioctl(dev->core->name,cmd);
+
+       switch (cmd) {
+
+       /* --- capture ioctls ---------------------------------------- */
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *f = arg;
+               int index;
+
+               index = f->index;
+               if (index != 0)
+                       return -EINVAL;
+
+               memset(f,0,sizeof(*f));
+               f->index = index;
+               strlcpy(f->description, "MPEG TS", sizeof(f->description));
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               f->pixelformat = V4L2_PIX_FMT_MPEG;
+               return 0;
+       }
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+       {
+               /* FIXME -- quick'n'dirty for exactly one size ... */
+               struct v4l2_format *f = arg;
+
+               memset(f,0,sizeof(*f));
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               f->fmt.pix.width        = 720;
+               f->fmt.pix.height       = 576;
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+               f->fmt.pix.sizeimage    = 1024 * 512 /* FIXME: BUFFER_SIZE */;
+       }
+
+       /* --- streaming capture ------------------------------------- */
+       case VIDIOC_REQBUFS:
+               return videobuf_reqbufs(&fh->mpegq, arg);
+
+       case VIDIOC_QUERYBUF:
+               return videobuf_querybuf(&fh->mpegq, arg);
+
+       case VIDIOC_QBUF:
+               return videobuf_qbuf(&fh->mpegq, arg);
+
+       case VIDIOC_DQBUF:
+               return videobuf_dqbuf(&fh->mpegq, arg,
+                                     file->f_flags & O_NONBLOCK);
+
+       case VIDIOC_STREAMON:
+               return videobuf_streamon(&fh->mpegq);
+
+       case VIDIOC_STREAMOFF:
+               return videobuf_streamoff(&fh->mpegq);
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int mpeg_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+}
+
+static int mpeg_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct cx8802_dev *h,*dev = NULL;
+       struct cx8802_fh *fh;
+       struct list_head *list;
+
+       list_for_each(list,&cx8802_devlist) {
+               h = list_entry(list, struct cx8802_dev, devlist);
+               if (h->mpeg_dev->minor == minor)
+                       dev = h;
+       }
+       if (NULL == dev)
+               return -ENODEV;
+
+       if (blackbird_initialize_codec(dev) < 0)
+               return -EINVAL;
+       dprintk(1,"open minor=%d\n",minor);
+
+       /* allocate + initialize per filehandle data */
+       fh = kmalloc(sizeof(*fh),GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+       memset(fh,0,sizeof(*fh));
+       file->private_data = fh;
+       fh->dev      = dev;
+
+       videobuf_queue_init(&fh->mpegq, &blackbird_qops,
+                           dev->pci, &dev->slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_TOP,
+                           sizeof(struct cx88_buffer),
+                           fh);
+       return 0;
+}
+
+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);
+
+       /* stop mpeg capture */
+       if (fh->mpegq.streaming)
+               videobuf_streamoff(&fh->mpegq);
+       if (fh->mpegq.reading)
+               videobuf_read_stop(&fh->mpegq);
+
+       file->private_data = NULL;
+       kfree(fh);
+       return 0;
+}
+
+static ssize_t
+mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+       struct cx8802_fh *fh = file->private_data;
+
+       return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+                                   file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int
+mpeg_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct cx8802_fh *fh = file->private_data;
+
+       return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int
+mpeg_mmap(struct file *file, struct vm_area_struct * vma)
+{
+       struct cx8802_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static struct file_operations mpeg_fops =
+{
+       .owner         = THIS_MODULE,
+       .open          = mpeg_open,
+       .release       = mpeg_release,
+       .read          = mpeg_read,
+       .poll          = mpeg_poll,
+       .mmap          = mpeg_mmap,
+       .ioctl         = mpeg_ioctl,
+       .llseek        = no_llseek,
+};
+
+static struct video_device cx8802_mpeg_template =
+{
+       .name          = "cx8802",
+       .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
+       .hardware      = 0,
+       .fops          = &mpeg_fops,
+       .minor         = -1,
+};
+
+/* ------------------------------------------------------------------ */
+
+static void blackbird_unregister_video(struct cx8802_dev *dev)
+{
+       if (dev->mpeg_dev) {
+               if (-1 != dev->mpeg_dev->minor)
+                       video_unregister_device(dev->mpeg_dev);
+               else
+                       video_device_release(dev->mpeg_dev);
+               dev->mpeg_dev = NULL;
+       }
+}
+
+static int blackbird_register_video(struct cx8802_dev *dev)
+{
+       int err;
+
+       dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci,
+                                      &cx8802_mpeg_template,"mpeg");
+       err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1);
+       if (err < 0) {
+               printk(KERN_INFO "%s/2: can't register mpeg device\n",
+                      dev->core->name);
+               return err;
+       }
+       printk(KERN_INFO "%s/2: registered device video%d [mpeg]\n",
+              dev->core->name,dev->mpeg_dev->minor & 0x1f);
+       return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+static int __devinit blackbird_probe(struct pci_dev *pci_dev,
+                                    const struct pci_device_id *pci_id)
+{
+       struct cx8802_dev *dev;
+       struct cx88_core  *core;
+       int err;
+
+       /* general setup */
+       core = cx88_core_get(pci_dev);
+       if (NULL == core)
+               return -EINVAL;
+
+       err = -ENODEV;
+       if (!cx88_boards[core->board].blackbird)
+               goto fail_core;
+
+       err = -ENOMEM;
+       dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+       if (NULL == dev)
+               goto fail_core;
+       memset(dev,0,sizeof(*dev));
+       dev->pci = pci_dev;
+       dev->core = core;
+
+       err = cx8802_init_common(dev);
+       if (0 != err)
+               goto fail_free;
+
+       /* blackbird stuff */
+       printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n",
+              core->name);
+       host_setup(dev->core);
+
+       list_add_tail(&dev->devlist,&cx8802_devlist);
+       blackbird_register_video(dev);
+       return 0;
+
+ fail_free:
+       kfree(dev);
+ fail_core:
+       cx88_core_put(core,pci_dev);
+       return err;
+}
+
+static void __devexit blackbird_remove(struct pci_dev *pci_dev)
+{
+        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+
+       /* blackbird */
+       blackbird_unregister_video(dev);
+       list_del(&dev->devlist);
+
+       /* common */
+       cx8802_fini_common(dev);
+}
+
+static struct pci_device_id cx8802_pci_tbl[] = {
+       {
+               .vendor       = 0x14f1,
+               .device       = 0x8802,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+       },{
+               /* --- end of list --- */
+       }
+};
+MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
+
+static struct pci_driver blackbird_pci_driver = {
+        .name     = "cx88-blackbird",
+        .id_table = cx8802_pci_tbl,
+        .probe    = blackbird_probe,
+        .remove   = __devexit_p(blackbird_remove),
+       .suspend  = cx8802_suspend_common,
+       .resume   = cx8802_resume_common,
+};
+
+static int blackbird_init(void)
+{
+       printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n",
+              (CX88_VERSION_CODE >> 16) & 0xff,
+              (CX88_VERSION_CODE >>  8) & 0xff,
+              CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+       return pci_module_init(&blackbird_pci_driver);
+}
+
+static void blackbird_fini(void)
+{
+       pci_unregister_driver(&blackbird_pci_driver);
+}
+
+module_init(blackbird_init);
+module_exit(blackbird_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
new file mode 100644 (file)
index 0000000..277a6d6
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * $Id: cx88-dvb.c,v 1.19 2004/11/07 14:44:59 kraxel Exp $
+ *
+ * device driver for Conexant 2388x based TV cards
+ * MPEG Transport Stream (DVB) routines
+ *
+ * (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx88.h"
+#include "cx22702.h"
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+
+MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+
+#define dprintk(level,fmt, arg...)     if (debug >= level) \
+       printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+                        unsigned int *count, unsigned int *size)
+{
+       struct cx8802_dev *dev = q->priv_data;
+
+       dev->ts_packet_size  = 188 * 4;
+       dev->ts_packet_count = 32;
+
+       *size  = dev->ts_packet_size * dev->ts_packet_count;
+       *count = 32;
+       return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+                          enum v4l2_field field)
+{
+       struct cx8802_dev *dev = q->priv_data;
+       return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct cx8802_dev *dev = q->priv_data;
+       cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+       struct cx8802_dev *dev = q->priv_data;
+       cx88_free_buffer(dev->pci, (struct cx88_buffer*)vb);
+}
+
+struct videobuf_queue_ops dvb_qops = {
+       .buf_setup    = dvb_buf_setup,
+       .buf_prepare  = dvb_buf_prepare,
+       .buf_queue    = dvb_buf_queue,
+       .buf_release  = dvb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
+{
+       static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x39 };
+       static u8 reset []         = { RESET,      0x80 };
+       static u8 adc_ctl_1_cfg [] = { ADC_CTL_1,  0x40 };
+       static u8 agc_cfg []       = { AGC_TARGET, 0x24, 0x20 };
+       static u8 gpp_ctl_cfg []   = { GPP_CTL,    0x33 };
+       static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+       mt352_write(fe, clock_config,   sizeof(clock_config));
+       udelay(200);
+       mt352_write(fe, reset,          sizeof(reset));
+       mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
+
+       mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
+       mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
+       mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+       return 0;
+}
+
+#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+
+static int lg_z201_pll_set(struct dvb_frontend* fe,
+                          struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+       u32 div;
+       unsigned char cp = 0;
+       unsigned char bs = 0;
+
+       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+       if (params->frequency < 542000000) cp = 0xbc;
+       else if (params->frequency < 830000000) cp = 0xf4;
+       else cp = 0xfc;
+
+       if (params->frequency == 0) bs = 0x03;
+       else if (params->frequency < 157500000) bs = 0x01;
+       else if (params->frequency < 443250000) bs = 0x02;
+       else bs = 0x04;
+
+       pllbuf[0] = 0xC2; /* Note: non-linux standard PLL I2C address */
+       pllbuf[1] = div >> 8;
+       pllbuf[2] = div & 0xff;
+       pllbuf[3] = cp;
+       pllbuf[4] = bs;
+
+       return 0;
+}
+
+static int thomson_dtt7579_pll_set(struct dvb_frontend* fe,
+                                  struct dvb_frontend_parameters* params,
+                                  u8* pllbuf)
+{
+       u32 div;
+       unsigned char cp = 0;
+       unsigned char bs = 0;
+
+       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+       if (params->frequency < 542000000) cp = 0xb4;
+       else if (params->frequency < 771000000) cp = 0xbc;
+       else cp = 0xf4;
+
+        if (params->frequency == 0) bs = 0x03;
+       else if (params->frequency < 443250000) bs = 0x02;
+       else bs = 0x08;
+
+       pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+       pllbuf[1] = div >> 8;
+       pllbuf[2] = div & 0xff;
+       pllbuf[3] = cp;
+       pllbuf[4] = bs;
+
+       return 0;
+}
+
+struct mt352_config dvico_fusionhdtv_dvbt1 = {
+       .demod_address = 0x0F,
+       .demod_init    = dvico_fusionhdtv_demod_init,
+       .pll_set       = lg_z201_pll_set,
+};
+
+struct mt352_config dvico_fusionhdtv_dvbt_plus = {
+       .demod_address = 0x0F,
+       .demod_init    = dvico_fusionhdtv_demod_init,
+       .pll_set       = thomson_dtt7579_pll_set,
+};
+
+static int dvb_register(struct cx8802_dev *dev)
+{
+       /* init struct videobuf_dvb */
+       dev->dvb.name = dev->core->name;
+
+       /* init frontend */
+       switch (dev->core->board) {
+       case CX88_BOARD_HAUPPAUGE_DVB_T1:
+       case CX88_BOARD_CONEXANT_DVB_T1:
+               dev->dvb.frontend = cx22702_create(&dev->core->i2c_adap,
+                                                  dev->core->pll_addr,
+                                                  dev->core->pll_type,
+                                                  dev->core->demod_addr);
+               break;
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
+               dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt1,
+                                                &dev->core->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops->info.frequency_min = 174000000;
+                       dev->dvb.frontend->ops->info.frequency_max = 862000000;
+               }
+               break;
+       case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
+               dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dvbt_plus,
+                                                &dev->core->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dev->dvb.frontend->ops->info.frequency_min = 174000000;
+                       dev->dvb.frontend->ops->info.frequency_max = 862000000;
+               }
+               break;
+       default:
+               printk("%s: FIXME: frontend handling not here yet ...\n",
+                      dev->core->name);
+               break;
+       }
+       if (NULL == dev->dvb.frontend)
+               return -1;
+
+       /* Copy the board name into the DVB structure */
+       strlcpy(dev->dvb.frontend->ops->info.name,
+               cx88_boards[dev->core->board].name,
+               sizeof(dev->dvb.frontend->ops->info.name));
+
+       /* register everything */
+       return videobuf_dvb_register(&dev->dvb);
+}
+
+/* ----------------------------------------------------------- */
+
+static int __devinit dvb_probe(struct pci_dev *pci_dev,
+                              const struct pci_device_id *pci_id)
+{
+       struct cx8802_dev *dev;
+       struct cx88_core  *core;
+       int err;
+
+       /* general setup */
+       core = cx88_core_get(pci_dev);
+       if (NULL == core)
+               return -EINVAL;
+
+       err = -ENODEV;
+       if (!cx88_boards[core->board].dvb)
+               goto fail_core;
+
+       err = -ENOMEM;
+       dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+       if (NULL == dev)
+               goto fail_core;
+       memset(dev,0,sizeof(*dev));
+       dev->pci = pci_dev;
+       dev->core = core;
+
+       err = cx8802_init_common(dev);
+       if (0 != err)
+               goto fail_free;
+
+       /* dvb stuff */
+       printk("%s/2: cx2388x based dvb card\n", core->name);
+       videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
+                           dev->pci, &dev->slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_TOP,
+                           sizeof(struct cx88_buffer),
+                           dev);
+       err = dvb_register(dev);
+       if (0 != err)
+               goto fail_free;
+       return 0;
+
+ fail_free:
+       kfree(dev);
+ fail_core:
+       cx88_core_put(core,pci_dev);
+       return err;
+}
+
+static void __devexit dvb_remove(struct pci_dev *pci_dev)
+{
+        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+
+       /* dvb */
+       videobuf_dvb_unregister(&dev->dvb);
+
+       /* common */
+       cx8802_fini_common(dev);
+       cx88_core_put(dev->core,dev->pci);
+       kfree(dev);
+}
+
+static struct pci_device_id cx8802_pci_tbl[] = {
+       {
+               .vendor       = 0x14f1,
+               .device       = 0x8802,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+       },{
+               /* --- end of list --- */
+       }
+};
+MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
+
+static struct pci_driver dvb_pci_driver = {
+        .name     = "cx88-dvb",
+        .id_table = cx8802_pci_tbl,
+        .probe    = dvb_probe,
+        .remove   = __devexit_p(dvb_remove),
+       .suspend  = cx8802_suspend_common,
+       .resume   = cx8802_resume_common,
+};
+
+static int dvb_init(void)
+{
+       printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n",
+              (CX88_VERSION_CODE >> 16) & 0xff,
+              (CX88_VERSION_CODE >>  8) & 0xff,
+              CX88_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
+              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+       return pci_module_init(&dvb_pci_driver);
+}
+
+static void dvb_fini(void)
+{
+       pci_unregister_driver(&dvb_pci_driver);
+}
+
+module_init(dvb_init);
+module_exit(dvb_fini);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
new file mode 100644 (file)
index 0000000..b538c83
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * $Id: cx88-mpeg.c,v 1.14 2004/10/25 11:26:36 kraxel Exp $
+ *
+ *  Support for the mpeg transport stream transfers
+ *  PCI function #2 of the cx2388x.
+ *
+ *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ *    (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <asm/delay.h>
+
+#include "cx88.h"
+
+/* ------------------------------------------------------------------ */
+
+MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
+MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
+
+#define dprintk(level,fmt, arg...)     if (debug >= level) \
+       printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int cx8802_start_dma(struct cx8802_dev    *dev,
+                           struct cx88_dmaqueue *q,
+                           struct cx88_buffer   *buf)
+{
+       struct cx88_core *core = dev->core;
+
+       dprintk(1, "cx8802_start_mpegport_dma %d\n", buf->vb.width);
+
+       /* setup fifo + format */
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
+                               dev->ts_packet_size, buf->risc.dma);
+
+       /* write TS length to chip */
+       cx_write(MO_TS_LNGTH, buf->vb.width);
+
+#if 1
+       /* FIXME: this needs a review.
+        * also: move to cx88-blackbird + cx88-dvb source files? */
+
+       if (cx88_boards[core->board].dvb) {
+               /* Setup TS portion of chip */
+               cx_write(TS_GEN_CNTRL, 0x0c);
+       }
+
+       if (cx88_boards[core->board].blackbird) {
+               cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
+
+               // cx_write(TS_F2_CMD_STAT_MM, 0x2900106); /* F2_CMD_STAT_MM defaults + master + memory space */
+               cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
+               udelay(100);
+
+               cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */
+               //cx_write(TS_HW_SOP_CNTRL, 0x2F0BC0); /* mpeg start byte ts: 0x2F0BC0 ? */
+               cx_write(TS_VALERR_CNTRL, 0x2000);
+
+               cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
+               udelay(100);
+       }
+#endif
+
+       /* reset counter */
+       cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET);
+       q->count = 1;
+
+       /* enable irqs */
+       cx_set(MO_PCI_INTMSK, 0x00fc04);
+       cx_write(MO_TS_INTMSK,  0x1f0011);
+
+       /* start dma */
+       cx_write(MO_DEV_CNTRL2, (1<<5)); /* FIXME: s/write/set/ ??? */
+       cx_write(MO_TS_DMACNTRL, 0x11);
+       return 0;
+}
+
+static int cx8802_stop_dma(struct cx8802_dev *dev)
+{
+       struct cx88_core *core = dev->core;
+
+       /* stop dma */
+       cx_clear(MO_TS_DMACNTRL, 0x11);
+
+       /* disable irqs */
+       cx_clear(MO_PCI_INTMSK, 0x000004);
+       cx_clear(MO_TS_INTMSK, 0x1f0011);
+
+       /* Reset the controller */
+       cx_write(TS_GEN_CNTRL, 0xcd);
+       return 0;
+}
+
+static int cx8802_restart_queue(struct cx8802_dev    *dev,
+                               struct cx88_dmaqueue *q)
+{
+       struct cx88_buffer *buf;
+       struct list_head *item;
+
+       if (list_empty(&q->active))
+               return 0;
+
+       buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+       dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+               buf, buf->vb.i);
+       cx8802_start_dma(dev, q, buf);
+       list_for_each(item,&q->active) {
+               buf = list_entry(item, struct cx88_buffer, vb.queue);
+               buf->count = q->count++;
+       }
+       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
+{
+       int size = dev->ts_packet_size * dev->ts_packet_count;
+       int rc;
+
+       dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+       if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+               return -EINVAL;
+
+       if (STATE_NEEDS_INIT == buf->vb.state) {
+               buf->vb.width  = dev->ts_packet_size;
+               buf->vb.height = dev->ts_packet_count;
+               buf->vb.size   = size;
+               buf->vb.field  = V4L2_FIELD_TOP;
+
+               if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
+                       goto fail;
+               cx88_risc_databuffer(dev->pci, &buf->risc,
+                                    buf->vb.dma.sglist,
+                                    buf->vb.width, buf->vb.height);
+       }
+       buf->vb.state = STATE_PREPARED;
+       return 0;
+
+ fail:
+       cx88_free_buffer(dev->pci,buf);
+       return rc;
+}
+
+void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
+{
+       struct cx88_buffer    *prev;
+       struct cx88_dmaqueue  *q    = &dev->mpegq;
+
+       /* 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)) {
+               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",
+                       buf, buf->vb.i, __FUNCTION__);
+
+       } else {
+               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",
+                       buf, buf->vb.i, __FUNCTION__);
+       }
+}
+
+/* ----------------------------------------------------------- */
+
+static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
+{
+       struct cx88_dmaqueue *q = &dev->mpegq;
+       struct cx88_buffer *buf;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->slock,flags);
+       while (!list_empty(&q->active)) {
+               buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+               list_del(&buf->vb.queue);
+               buf->vb.state = STATE_ERROR;
+               wake_up(&buf->vb.done);
+               dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
+                       buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+       }
+       if (restart)
+               cx8802_restart_queue(dev,q);
+       spin_unlock_irqrestore(&dev->slock,flags);
+}
+
+void cx8802_cancel_buffers(struct cx8802_dev *dev)
+{
+       struct cx88_dmaqueue *q = &dev->mpegq;
+
+       del_timer_sync(&q->timeout);
+       cx8802_stop_dma(dev);
+       do_cancel_buffers(dev,"cancel",0);
+}
+
+static void cx8802_timeout(unsigned long data)
+{
+       struct cx8802_dev *dev = (struct cx8802_dev*)data;
+
+       dprintk(1, "%s\n",__FUNCTION__);
+
+       if (debug)
+               cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
+       cx8802_stop_dma(dev);
+       do_cancel_buffers(dev,"timeout",1);
+}
+
+static void cx8802_mpeg_irq(struct cx8802_dev *dev)
+{
+       struct cx88_core *core = dev->core;
+       u32 status, mask, count;
+
+       status = cx_read(MO_TS_INTSTAT);
+       mask   = cx_read(MO_TS_INTMSK);
+       if (0 == (status & mask))
+               return;
+
+       cx_write(MO_TS_INTSTAT, status);
+       if (debug || (status & mask & ~0xff))
+               cx88_print_irqbits(core->name, "irq mpeg ",
+                                  cx88_mpeg_irqs, status, mask);
+
+       /* risc op code error */
+       if (status & (1 << 16)) {
+               printk(KERN_WARNING "%s: mpeg risc op code error\n",core->name);
+               cx_clear(MO_TS_DMACNTRL, 0x11);
+               cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
+       }
+
+       /* risc1 y */
+       if (status & 0x01) {
+               spin_lock(&dev->slock);
+               count = cx_read(MO_TS_GPCNT);
+               cx88_wakeup(dev->core, &dev->mpegq, count);
+               spin_unlock(&dev->slock);
+       }
+
+       /* risc2 y */
+       if (status & 0x10) {
+               spin_lock(&dev->slock);
+               cx8802_restart_queue(dev,&dev->mpegq);
+               spin_unlock(&dev->slock);
+       }
+
+        /* other general errors */
+        if (status & 0x1f0100) {
+                spin_lock(&dev->slock);
+               cx8802_stop_dma(dev);
+                cx8802_restart_queue(dev,&dev->mpegq);
+                spin_unlock(&dev->slock);
+        }
+}
+
+static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct cx8802_dev *dev = dev_id;
+       struct cx88_core *core = dev->core;
+       u32 status, mask;
+       int loop, handled = 0;
+
+       for (loop = 0; loop < 10; loop++) {
+               status = cx_read(MO_PCI_INTSTAT) & (~0x1f | 0x04);
+               mask   = cx_read(MO_PCI_INTMSK);
+               if (0 == (status & mask))
+                       goto out;
+               handled = 1;
+               cx_write(MO_PCI_INTSTAT, status);
+
+               if (status & mask & ~0x1f)
+                       cx88_irq(core,status,mask);
+               if (status & 0x04)
+                       cx8802_mpeg_irq(dev);
+       };
+       if (10 == loop) {
+               printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
+                      core->name);
+               cx_write(MO_PCI_INTMSK,0);
+       }
+
+ out:
+       return IRQ_RETVAL(handled);
+}
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+int cx8802_init_common(struct cx8802_dev *dev)
+{
+       int err;
+
+       /* pci init */
+       if (pci_enable_device(dev->pci))
+               return -EIO;
+       pci_set_master(dev->pci);
+       if (!pci_dma_supported(dev->pci,0xffffffff)) {
+               printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
+               return -EIO;
+       }
+
+       pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
+        pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
+        printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+              "latency: %d, mmio: 0x%lx\n", dev->core->name,
+              pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
+              dev->pci_lat,pci_resource_start(dev->pci,0));
+
+       /* initialize driver struct */
+        init_MUTEX(&dev->lock);
+       dev->slock = SPIN_LOCK_UNLOCKED;
+
+       /* init dma queue */
+       INIT_LIST_HEAD(&dev->mpegq.active);
+       INIT_LIST_HEAD(&dev->mpegq.queued);
+       dev->mpegq.timeout.function = cx8802_timeout;
+       dev->mpegq.timeout.data     = (unsigned long)dev;
+       init_timer(&dev->mpegq.timeout);
+       cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
+                         MO_TS_DMACNTRL,0x11,0x00);
+
+#if 0 /* FIXME */
+       /* initialize hardware */
+       cx8802_reset(dev);
+#endif
+
+       /* get irq */
+       err = request_irq(dev->pci->irq, cx8802_irq,
+                         SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev);
+       if (err < 0) {
+               printk(KERN_ERR "%s: can't get IRQ %d\n",
+                      dev->core->name, dev->pci->irq);
+               return err;
+       }
+
+#if 0 /* FIXME */
+       /* register i2c bus + load i2c helpers */
+       cx88_card_setup(dev);
+#endif
+
+       /* everything worked */
+       pci_set_drvdata(dev->pci,dev);
+       return 0;
+}
+
+void cx8802_fini_common(struct cx8802_dev *dev)
+{
+       cx8802_stop_dma(dev);
+       pci_disable_device(dev->pci);
+
+       /* unregister stuff */
+       free_irq(dev->pci->irq, dev);
+       pci_set_drvdata(dev->pci, NULL);
+
+       /* free memory */
+       btcx_riscmem_free(dev->pci,&dev->mpegq.stopper);
+}
+
+/* ----------------------------------------------------------- */
+
+int cx8802_suspend_common(struct pci_dev *pci_dev, u32 state)
+{
+        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx88_core *core = dev->core;
+
+       /* stop mpeg dma */
+       spin_lock(&dev->slock);
+       if (!list_empty(&dev->mpegq.active)) {
+               printk("%s: suspend mpeg\n", core->name);
+               cx8802_stop_dma(dev);
+               del_timer(&dev->mpegq.timeout);
+       }
+       spin_unlock(&dev->slock);
+
+#if 1
+       /* FIXME -- shutdown device */
+       cx88_shutdown(dev->core);
+#endif
+
+       pci_save_state(pci_dev);
+       if (0 != pci_set_power_state(pci_dev, state)) {
+               pci_disable_device(pci_dev);
+               dev->state.disabled = 1;
+       }
+       return 0;
+}
+
+int cx8802_resume_common(struct pci_dev *pci_dev)
+{
+        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx88_core *core = dev->core;
+
+       if (dev->state.disabled) {
+               pci_enable_device(pci_dev);
+               dev->state.disabled = 0;
+       }
+       pci_set_power_state(pci_dev, 0);
+       pci_restore_state(pci_dev);
+
+#if 1
+       /* FIXME: re-initialize hardware */
+       cx88_reset(dev->core);
+#endif
+
+       /* restart video+vbi capture */
+       spin_lock(&dev->slock);
+       if (!list_empty(&dev->mpegq.active)) {
+               printk("%s: resume mpeg\n", core->name);
+               cx8802_restart_queue(dev,&dev->mpegq);
+       }
+       spin_unlock(&dev->slock);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx8802_buf_prepare);
+EXPORT_SYMBOL(cx8802_buf_queue);
+EXPORT_SYMBOL(cx8802_cancel_buffers);
+
+EXPORT_SYMBOL(cx8802_init_common);
+EXPORT_SYMBOL(cx8802_fini_common);
+
+EXPORT_SYMBOL(cx8802_suspend_common);
+EXPORT_SYMBOL(cx8802_resume_common);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
new file mode 100644 (file)
index 0000000..b51f0ac
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * $Id: saa7134-dvb.c,v 1.4 2004/11/07 14:44:59 kraxel Exp $
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This 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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_init(struct saa7134_dev *dev)
+{
+       printk("%s: %s\n",dev->name,__FUNCTION__);
+
+       /* init struct videobuf_dvb */
+       dev->dvb.name = dev->name;
+       videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+                           dev->pci, &dev->slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_TOP,
+                           sizeof(struct saa7134_buf),
+                           dev);
+
+       /* TODO: init frontend */
+       if (NULL == dev->dvb.frontend)
+               return -1;
+
+       /* register everything else */
+       return videobuf_dvb_register(&dev->dvb);
+}
+
+static int dvb_fini(struct saa7134_dev *dev)
+{
+       printk("%s: %s\n",dev->name,__FUNCTION__);
+       videobuf_dvb_unregister(&dev->dvb);
+       return 0;
+}
+
+static struct saa7134_mpeg_ops dvb_ops = {
+       .type          = SAA7134_MPEG_DVB,
+       .init          = dvb_init,
+       .fini          = dvb_fini,
+};
+
+static int __init dvb_register(void)
+{
+       return saa7134_ts_register(&dvb_ops);
+}
+
+static void __exit dvb_unregister(void)
+{
+       saa7134_ts_unregister(&dvb_ops);
+}
+
+module_init(dvb_register);
+module_exit(dvb_unregister);
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
new file mode 100644 (file)
index 0000000..c2bca39
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * $Id: saa7134-empress.c,v 1.3 2004/11/07 13:17:15 kraxel Exp $
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ *  This 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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
+#include <media/saa6752hs.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+module_param_array(empress_nr, int, NULL, 0444);
+MODULE_PARM_DESC(empress_nr,"ts device number");
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+#define dprintk(fmt, arg...)   if (debug)                      \
+       printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static void ts_reset_encoder(struct saa7134_dev* dev)
+{
+       saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+       msleep(10);
+       saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+       msleep(100);
+}
+
+static int ts_init_encoder(struct saa7134_dev* dev, void* arg)
+{
+       ts_reset_encoder(dev);
+       saa7134_i2c_call_clients(dev, MPEG_SETPARAMS, arg);
+       return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int ts_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct saa7134_dev *h,*dev = NULL;
+       struct list_head *list;
+       int err;
+
+       list_for_each(list,&saa7134_devlist) {
+               h = list_entry(list, struct saa7134_dev, devlist);
+               if (h->empress_dev && h->empress_dev->minor == minor)
+                       dev = h;
+       }
+       if (NULL == dev)
+               return -ENODEV;
+
+       dprintk("open minor=%d\n",minor);
+       down(&dev->empress_tsq.lock);
+       err = -EBUSY;
+       if (dev->empress_users)
+               goto done;
+
+       dev->empress_users++;
+       file->private_data = dev;
+       ts_init_encoder(dev, NULL);
+       err = 0;
+
+ done:
+       up(&dev->empress_tsq.lock);
+       return err;
+}
+
+static int ts_release(struct inode *inode, struct file *file)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       if (dev->empress_tsq.streaming)
+               videobuf_streamoff(&dev->empress_tsq);
+       down(&dev->empress_tsq.lock);
+       if (dev->empress_tsq.reading)
+               videobuf_read_stop(&dev->empress_tsq);
+       dev->empress_users--;
+
+       /* stop the encoder */
+       ts_reset_encoder(dev);
+
+       up(&dev->empress_tsq.lock);
+       return 0;
+}
+
+static ssize_t
+ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       return videobuf_read_stream(&dev->empress_tsq,
+                                   data, count, ppos, 0,
+                                   file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int
+ts_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       return videobuf_poll_stream(file, &dev->empress_tsq, wait);
+}
+
+
+static int
+ts_mmap(struct file *file, struct vm_area_struct * vma)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       return videobuf_mmap_mapper(&dev->empress_tsq, vma);
+}
+
+/*
+ * This function is _not_ called directly, but from
+ * video_generic_ioctl (and maybe others).  userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int ts_do_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, void *arg)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       if (debug > 1)
+               saa7134_print_ioctl(dev->name,cmd);
+       switch (cmd) {
+       case VIDIOC_QUERYCAP:
+       {
+               struct v4l2_capability *cap = arg;
+
+               memset(cap,0,sizeof(*cap));
+                strcpy(cap->driver, "saa7134");
+               strlcpy(cap->card, saa7134_boards[dev->board].name,
+                       sizeof(cap->card));
+               sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+               cap->version = SAA7134_VERSION_CODE;
+               cap->capabilities =
+                       V4L2_CAP_VIDEO_CAPTURE |
+                       V4L2_CAP_READWRITE |
+                       V4L2_CAP_STREAMING;
+               return 0;
+       }
+
+       /* --- input switching --------------------------------------- */
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *i = arg;
+
+               if (i->index != 0)
+                       return -EINVAL;
+               i->type = V4L2_INPUT_TYPE_CAMERA;
+               strcpy(i->name,"CCIR656");
+               return 0;
+       }
+       case VIDIOC_G_INPUT:
+       {
+               int *i = arg;
+               *i = 0;
+               return 0;
+       }
+       case VIDIOC_S_INPUT:
+       {
+               int *i = arg;
+
+               if (*i != 0)
+                       return -EINVAL;
+               return 0;
+       }
+       /* --- capture ioctls ---------------------------------------- */
+
+       case VIDIOC_ENUM_FMT:
+       {
+               struct v4l2_fmtdesc *f = arg;
+               int index;
+
+               index = f->index;
+               if (index != 0)
+                       return -EINVAL;
+
+               memset(f,0,sizeof(*f));
+               f->index = index;
+               strlcpy(f->description, "MPEG TS", sizeof(f->description));
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               f->pixelformat = V4L2_PIX_FMT_MPEG;
+               return 0;
+       }
+
+       case VIDIOC_G_FMT:
+       {
+               struct v4l2_format *f = arg;
+
+               memset(f,0,sizeof(*f));
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+               /* FIXME: translate subsampling type EMPRESS into
+                *        width/height: */
+               f->fmt.pix.width        = 720; /* D1 */
+               f->fmt.pix.height       = 576;
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+               f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+               return 0;
+       }
+
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+
+               if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                   return -EINVAL;
+
+               /*
+                 FIXME: translate and round width/height into EMPRESS
+                 subsample type:
+
+                         type  |   PAL   |  NTSC
+                       ---------------------------
+                         SIF   | 352x288 | 352x240
+                        1/2 D1 | 352x576 | 352x480
+                        2/3 D1 | 480x576 | 480x480
+                         D1    | 720x576 | 720x480
+               */
+
+               f->fmt.pix.width        = 720; /* D1 */
+               f->fmt.pix.height       = 576;
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+               f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
+               return 0;
+       }
+
+       case VIDIOC_REQBUFS:
+               return videobuf_reqbufs(&dev->empress_tsq,arg);
+
+       case VIDIOC_QUERYBUF:
+               return videobuf_querybuf(&dev->empress_tsq,arg);
+
+       case VIDIOC_QBUF:
+               return videobuf_qbuf(&dev->empress_tsq,arg);
+
+       case VIDIOC_DQBUF:
+               return videobuf_dqbuf(&dev->empress_tsq,arg,
+                                     file->f_flags & O_NONBLOCK);
+
+       case VIDIOC_STREAMON:
+               return videobuf_streamon(&dev->empress_tsq);
+
+       case VIDIOC_STREAMOFF:
+               return videobuf_streamoff(&dev->empress_tsq);
+
+       case VIDIOC_QUERYCTRL:
+       case VIDIOC_G_CTRL:
+       case VIDIOC_S_CTRL:
+               return saa7134_common_ioctl(dev, cmd, arg);
+
+       case MPEG_SETPARAMS:
+               return ts_init_encoder(dev, arg);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int ts_ioctl(struct inode *inode, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
+}
+
+static struct file_operations ts_fops =
+{
+       .owner    = THIS_MODULE,
+       .open     = ts_open,
+       .release  = ts_release,
+       .read     = ts_read,
+       .poll     = ts_poll,
+       .mmap     = ts_mmap,
+       .ioctl    = ts_ioctl,
+       .llseek   = no_llseek,
+};
+
+/* ----------------------------------------------------------- */
+
+static struct video_device saa7134_empress_template =
+{
+       .name          = "saa7134-empress",
+       .type          = 0 /* FIXME */,
+       .type2         = 0 /* FIXME */,
+       .hardware      = 0,
+       .fops          = &ts_fops,
+       .minor         = -1,
+};
+
+static int empress_init(struct saa7134_dev *dev)
+{
+       int err;
+
+       dprintk("%s: %s\n",dev->name,__FUNCTION__);
+       dev->empress_dev = video_device_alloc();
+       if (NULL == dev->empress_dev)
+               return -ENOMEM;
+       *(dev->empress_dev) = saa7134_empress_template;
+       dev->empress_dev->dev     = &dev->pci->dev;
+       dev->empress_dev->release = video_device_release;
+       snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
+                "%s empress (%s)", dev->name,
+                saa7134_boards[dev->board].name);
+
+       err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
+                                   empress_nr[dev->nr]);
+       if (err < 0) {
+               printk(KERN_INFO "%s: can't register video device\n",
+                      dev->name);
+               video_device_release(dev->empress_dev);
+               dev->empress_dev = NULL;
+               return err;
+       }
+       printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+              dev->name,dev->empress_dev->minor & 0x1f);
+
+       videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops,
+                           dev->pci, &dev->slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_ALTERNATE,
+                           sizeof(struct saa7134_buf),
+                           dev);
+       return 0;
+}
+
+static int empress_fini(struct saa7134_dev *dev)
+{
+       dprintk("%s: %s\n",dev->name,__FUNCTION__);
+
+       if (NULL == dev->empress_dev)
+               return 0;
+       video_unregister_device(dev->empress_dev);
+       dev->empress_dev = NULL;
+       return 0;
+}
+
+static struct saa7134_mpeg_ops empress_ops = {
+       .type          = SAA7134_MPEG_EMPRESS,
+       .init          = empress_init,
+       .fini          = empress_fini,
+};
+
+static int __init empress_register(void)
+{
+       return saa7134_ts_register(&empress_ops);
+}
+
+static void __exit empress_unregister(void)
+{
+       saa7134_ts_unregister(&empress_ops);
+}
+
+module_init(empress_register);
+module_exit(empress_unregister);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
new file mode 100644 (file)
index 0000000..6f3d6ac
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * $Id: video-buf-dvb.c,v 1.5 2004/11/07 13:17:15 kraxel Exp $
+ *
+ * some helper function for simple DVB cards which simply DMA the
+ * complete transport stream and let the computer sort everything else
+ * (i.e. we are using the software demux, ...).  Also uses the
+ * video-buf to manage DMA buffers.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ *
+ * This 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/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include <media/video-buf.h>
+#include <media/video-buf-dvb.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+#define dprintk(fmt, arg...)   if (debug)                      \
+       printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name, ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int videobuf_dvb_thread(void *data)
+{
+       struct videobuf_dvb *dvb = data;
+       struct videobuf_buffer *buf;
+       unsigned long flags;
+       int err;
+
+       dprintk("dvb thread started\n");
+       videobuf_read_start(&dvb->dvbq);
+
+       for (;;) {
+               /* fetch next buffer */
+               buf = list_entry(dvb->dvbq.stream.next,
+                                struct videobuf_buffer, stream);
+               list_del(&buf->stream);
+               err = videobuf_waiton(buf,0,1);
+               BUG_ON(0 != err);
+
+               /* no more feeds left or stop_feed() asked us to quit */
+               if (0 == dvb->nfeeds)
+                       break;
+               if (kthread_should_stop())
+                       break;
+               if (current->flags & PF_FREEZE)
+                       refrigerator(PF_FREEZE);
+
+               /* feed buffer data to demux */
+               if (buf->state == STATE_DONE)
+                       dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc,
+                                        buf->size);
+
+               /* requeue buffer */
+               list_add_tail(&buf->stream,&dvb->dvbq.stream);
+               spin_lock_irqsave(dvb->dvbq.irqlock,flags);
+               dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf);
+               spin_unlock_irqrestore(dvb->dvbq.irqlock,flags);
+       }
+
+       videobuf_read_stop(&dvb->dvbq);
+       dprintk("dvb thread stopped\n");
+
+       /* Hmm, linux becomes *very* unhappy without this ... */
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+       }
+       return 0;
+}
+
+static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+       struct dvb_demux *demux  = feed->demux;
+       struct videobuf_dvb *dvb = demux->priv;
+       int rc;
+
+       if (!demux->dmx.frontend)
+               return -EINVAL;
+
+       down(&dvb->lock);
+       dvb->nfeeds++;
+       rc = dvb->nfeeds;
+
+       if (NULL != dvb->thread)
+               goto out;
+       dvb->thread = kthread_run(videobuf_dvb_thread,
+                                 dvb, "%s dvb", dvb->name);
+       if (IS_ERR(dvb->thread)) {
+               rc = PTR_ERR(dvb->thread);
+               dvb->thread = NULL;
+       }
+
+out:
+       up(&dvb->lock);
+       return rc;
+}
+
+static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+       struct dvb_demux *demux  = feed->demux;
+       struct videobuf_dvb *dvb = demux->priv;
+       int err = 0;
+
+       down(&dvb->lock);
+       dvb->nfeeds--;
+       if (0 == dvb->nfeeds  &&  NULL != dvb->thread) {
+               // FIXME: cx8802_cancel_buffers(dev);
+               err = kthread_stop(dvb->thread);
+               dvb->thread = NULL;
+       }
+       up(&dvb->lock);
+       return err;
+}
+
+/* ------------------------------------------------------------------ */
+
+int videobuf_dvb_register(struct videobuf_dvb *dvb)
+{
+       int result;
+
+       init_MUTEX(&dvb->lock);
+
+       /* register adapter */
+       result = dvb_register_adapter(&dvb->adapter, dvb->name, THIS_MODULE);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+                      dvb->name, result);
+               goto fail_adapter;
+       }
+
+       /* register frontend */
+       result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+                      dvb->name, result);
+               goto fail_frontend;
+       }
+
+       /* register demux stuff */
+       dvb->demux.dmx.capabilities =
+               DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+               DMX_MEMORY_BASED_FILTERING;
+       dvb->demux.priv       = dvb;
+       dvb->demux.filternum  = 256;
+       dvb->demux.feednum    = 256;
+       dvb->demux.start_feed = videobuf_dvb_start_feed;
+       dvb->demux.stop_feed  = videobuf_dvb_stop_feed;
+       result = dvb_dmx_init(&dvb->demux);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+                      dvb->name, result);
+               goto fail_dmx;
+       }
+
+       dvb->dmxdev.filternum    = 256;
+       dvb->dmxdev.demux        = &dvb->demux.dmx;
+       dvb->dmxdev.capabilities = 0;
+       result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+                      dvb->name, result);
+               goto fail_dmxdev;
+       }
+
+       dvb->fe_hw.source = DMX_FRONTEND_0;
+       result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+                      dvb->name, result);
+               goto fail_fe_hw;
+       }
+
+       dvb->fe_mem.source = DMX_MEMORY_FE;
+       result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+                      dvb->name, result);
+               goto fail_fe_mem;
+       }
+
+       result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+       if (result < 0) {
+               printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+                      dvb->name, result);
+               goto fail_fe_conn;
+       }
+
+       /* register network adapter */
+       dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+       return 0;
+
+fail_fe_conn:
+       dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+       dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+       dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+       dvb_dmx_release(&dvb->demux);
+fail_dmx:
+       dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+       dvb_unregister_adapter(dvb->adapter);
+fail_adapter:
+       return result;
+}
+
+void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
+{
+       dvb_net_release(&dvb->net);
+       dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+       dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+       dvb_dmxdev_release(&dvb->dmxdev);
+       dvb_dmx_release(&dvb->demux);
+       dvb_unregister_frontend(dvb->frontend);
+       dvb_unregister_adapter(dvb->adapter);
+}
+
+EXPORT_SYMBOL(videobuf_dvb_register);
+EXPORT_SYMBOL(videobuf_dvb_unregister);
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c
new file mode 100644 (file)
index 0000000..7227a8a
--- /dev/null
@@ -0,0 +1,571 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/i2o.h>
+
+static int verbose;
+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);
+void i2o_report_fail_status(u8 req_status, u32 * msg);
+void i2o_report_common_status(u8 req_status);
+static void i2o_report_common_dsc(u16 detailed_status);
+
+void i2o_dump_status_block(i2o_status_block * sb)
+{
+       pr_debug("Organization ID: %d\n", sb->org_id);
+       pr_debug("IOP ID:          %d\n", sb->iop_id);
+       pr_debug("Host Unit ID:    %d\n", sb->host_unit_id);
+       pr_debug("Segment Number:  %d\n", sb->segment_number);
+       pr_debug("I2O Version:     %d\n", sb->i2o_version);
+       pr_debug("IOP State:       %d\n", sb->iop_state);
+       pr_debug("Messanger Type:  %d\n", sb->msg_type);
+       pr_debug("Inbound Frame Size:      %d\n", sb->inbound_frame_size);
+       pr_debug("Init Code:               %d\n", sb->init_code);
+       pr_debug("Max Inbound MFrames:     %d\n", sb->max_inbound_frames);
+       pr_debug("Current Inbound MFrames: %d\n", sb->cur_inbound_frames);
+       pr_debug("Max Outbound MFrames:    %d\n", sb->max_outbound_frames);
+       pr_debug("Product ID String: %s\n", sb->product_id);
+       pr_debug("Expected LCT Size: %d\n", sb->expected_lct_size);
+       pr_debug("IOP Capabilities:  %d\n", sb->iop_capabilities);
+       pr_debug("Desired Private MemSize: %d\n", sb->desired_mem_size);
+       pr_debug("Current Private MemSize: %d\n", sb->current_mem_size);
+       pr_debug("Current Private MemBase: %d\n", sb->current_mem_base);
+       pr_debug("Desired Private IO Size: %d\n", sb->desired_io_size);
+       pr_debug("Current Private IO Size: %d\n", sb->current_io_size);
+       pr_debug("Current Private IO Base: %d\n", sb->current_io_base);
+};
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Report Cmd name, Request status, Detailed Status.
+ */
+void i2o_report_status(const char *severity, const char *str,
+                      struct i2o_message *m)
+{
+       u32 *msg = (u32 *) m;
+       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
+
+       printk("%s%s: ", severity, str);
+
+       if (cmd < 0x1F)         // Utility cmd
+               i2o_report_util_cmd(cmd);
+
+       else if (cmd >= 0xA0 && cmd <= 0xEF)    // Executive cmd
+               i2o_report_exec_cmd(cmd);
+       else
+               printk("Cmd = %0#2x, ", cmd);   // Other cmds
+
+       if (msg[0] & MSG_FAIL) {
+               i2o_report_fail_status(req_status, msg);
+               return;
+       }
+
+       i2o_report_common_status(req_status);
+
+       if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
+               i2o_report_common_dsc(detailed_status);
+       else
+               printk(" / DetailedStatus = %0#4x.\n", detailed_status);
+}
+
+/* Used to dump a message to syslog during debugging */
+void i2o_dump_message(struct i2o_message *m)
+{
+#ifdef DEBUG
+       u32 *msg = (u32 *) m;
+       int i;
+       printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
+              msg[0] >> 16 & 0xffff, msg);
+       for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++)
+               printk(KERN_INFO "  msg[%d] = %0#10x\n", i, msg[i]);
+#endif
+}
+
+/**
+ *     i2o_report_controller_unit - print information about a tid
+ *     @c: controller
+ *     @d: device
+ *
+ *     Dump an information block associated with a given unit (TID). The
+ *     tables are read and a block of text is output to printk that is
+ *     formatted intended for the user.
+ */
+
+void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d)
+{
+       char buf[64];
+       char str[22];
+       int ret;
+
+       if (verbose == 0)
+               return;
+
+       printk(KERN_INFO "Target ID %03x.\n", d->lct_data.tid);
+       if ((ret = i2o_parm_field_get(d, 0xF100, 3, buf, 16)) >= 0) {
+               buf[16] = 0;
+               printk(KERN_INFO "     Vendor: %s\n", buf);
+       }
+       if ((ret = i2o_parm_field_get(d, 0xF100, 4, buf, 16)) >= 0) {
+               buf[16] = 0;
+               printk(KERN_INFO "     Device: %s\n", buf);
+       }
+       if (i2o_parm_field_get(d, 0xF100, 5, buf, 16) >= 0) {
+               buf[16] = 0;
+               printk(KERN_INFO "     Description: %s\n", buf);
+       }
+       if ((ret = i2o_parm_field_get(d, 0xF100, 6, buf, 8)) >= 0) {
+               buf[8] = 0;
+               printk(KERN_INFO "        Rev: %s\n", buf);
+       }
+
+       printk(KERN_INFO "    Class: ");
+       //sprintf(str, "%-21s", i2o_get_class_name(d->lct_data.class_id));
+       printk("%s\n", str);
+
+       printk(KERN_INFO "  Subclass: 0x%04X\n", d->lct_data.sub_class);
+       printk(KERN_INFO "     Flags: ");
+
+       if (d->lct_data.device_flags & (1 << 0))
+               printk("C");    // ConfigDialog requested
+       if (d->lct_data.device_flags & (1 << 1))
+               printk("U");    // Multi-user capable
+       if (!(d->lct_data.device_flags & (1 << 4)))
+               printk("P");    // Peer service enabled!
+       if (!(d->lct_data.device_flags & (1 << 5)))
+               printk("M");    // Mgmt service enabled!
+       printk("\n");
+}
+
+/*
+MODULE_PARM(verbose, "i");
+MODULE_PARM_DESC(verbose, "Verbose diagnostics");
+*/
+/*
+ * Used for error reporting/debugging purposes.
+ * Following fail status are common to all classes.
+ * The preserved message must be handled in the reply handler.
+ */
+void i2o_report_fail_status(u8 req_status, u32 * msg)
+{
+       static char *FAIL_STATUS[] = {
+               "0x80",         /* not used */
+               "SERVICE_SUSPENDED",    /* 0x81 */
+               "SERVICE_TERMINATED",   /* 0x82 */
+               "CONGESTION",
+               "FAILURE",
+               "STATE_ERROR",
+               "TIME_OUT",
+               "ROUTING_FAILURE",
+               "INVALID_VERSION",
+               "INVALID_OFFSET",
+               "INVALID_MSG_FLAGS",
+               "FRAME_TOO_SMALL",
+               "FRAME_TOO_LARGE",
+               "INVALID_TARGET_ID",
+               "INVALID_INITIATOR_ID",
+               "INVALID_INITIATOR_CONTEX",     /* 0x8F */
+               "UNKNOWN_FAILURE"       /* 0xFF */
+       };
+
+       if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
+               printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.", req_status);
+       else
+               printk("TRANSPORT_%s.\n", FAIL_STATUS[req_status & 0x0F]);
+
+       /* Dump some details */
+
+       printk(KERN_ERR "  InitiatorId = %d, TargetId = %d\n",
+              (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
+       printk(KERN_ERR "  LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
+              (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+       printk(KERN_ERR "  FailingHostUnit = 0x%04X,  FailingIOP = 0x%03X\n",
+              msg[5] >> 16, msg[5] & 0xFFF);
+
+       printk(KERN_ERR "  Severity:  0x%02X ", (msg[4] >> 16) & 0xFF);
+       if (msg[4] & (1 << 16))
+               printk("(FormatError), "
+                      "this msg can never be delivered/processed.\n");
+       if (msg[4] & (1 << 17))
+               printk("(PathError), "
+                      "this msg can no longer be delivered/processed.\n");
+       if (msg[4] & (1 << 18))
+               printk("(PathState), "
+                      "the system state does not allow delivery.\n");
+       if (msg[4] & (1 << 19))
+               printk("(Congestion), resources temporarily not available;"
+                      "do not retry immediately.\n");
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following reply status are common to all classes.
+ */
+void i2o_report_common_status(u8 req_status)
+{
+       static char *REPLY_STATUS[] = {
+               "SUCCESS",
+               "ABORT_DIRTY",
+               "ABORT_NO_DATA_TRANSFER",
+               "ABORT_PARTIAL_TRANSFER",
+               "ERROR_DIRTY",
+               "ERROR_NO_DATA_TRANSFER",
+               "ERROR_PARTIAL_TRANSFER",
+               "PROCESS_ABORT_DIRTY",
+               "PROCESS_ABORT_NO_DATA_TRANSFER",
+               "PROCESS_ABORT_PARTIAL_TRANSFER",
+               "TRANSACTION_ERROR",
+               "PROGRESS_REPORT"
+       };
+
+       if (req_status >= ARRAY_SIZE(REPLY_STATUS))
+               printk("RequestStatus = %0#2x", req_status);
+       else
+               printk("%s", REPLY_STATUS[req_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following detailed status are valid  for executive class,
+ * utility class, DDM class and for transaction error replies.
+ */
+static void i2o_report_common_dsc(u16 detailed_status)
+{
+       static char *COMMON_DSC[] = {
+               "SUCCESS",
+               "0x01",         // not used
+               "BAD_KEY",
+               "TCL_ERROR",
+               "REPLY_BUFFER_FULL",
+               "NO_SUCH_PAGE",
+               "INSUFFICIENT_RESOURCE_SOFT",
+               "INSUFFICIENT_RESOURCE_HARD",
+               "0x08",         // not used
+               "CHAIN_BUFFER_TOO_LARGE",
+               "UNSUPPORTED_FUNCTION",
+               "DEVICE_LOCKED",
+               "DEVICE_RESET",
+               "INAPPROPRIATE_FUNCTION",
+               "INVALID_INITIATOR_ADDRESS",
+               "INVALID_MESSAGE_FLAGS",
+               "INVALID_OFFSET",
+               "INVALID_PARAMETER",
+               "INVALID_REQUEST",
+               "INVALID_TARGET_ADDRESS",
+               "MESSAGE_TOO_LARGE",
+               "MESSAGE_TOO_SMALL",
+               "MISSING_PARAMETER",
+               "TIMEOUT",
+               "UNKNOWN_ERROR",
+               "UNKNOWN_FUNCTION",
+               "UNSUPPORTED_VERSION",
+               "DEVICE_BUSY",
+               "DEVICE_NOT_AVAILABLE"
+       };
+
+       if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
+               printk(" / DetailedStatus = %0#4x.\n", detailed_status);
+       else
+               printk(" / %s.\n", COMMON_DSC[detailed_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_util_cmd(u8 cmd)
+{
+       switch (cmd) {
+       case I2O_CMD_UTIL_NOP:
+               printk("UTIL_NOP, ");
+               break;
+       case I2O_CMD_UTIL_ABORT:
+               printk("UTIL_ABORT, ");
+               break;
+       case I2O_CMD_UTIL_CLAIM:
+               printk("UTIL_CLAIM, ");
+               break;
+       case I2O_CMD_UTIL_RELEASE:
+               printk("UTIL_CLAIM_RELEASE, ");
+               break;
+       case I2O_CMD_UTIL_CONFIG_DIALOG:
+               printk("UTIL_CONFIG_DIALOG, ");
+               break;
+       case I2O_CMD_UTIL_DEVICE_RESERVE:
+               printk("UTIL_DEVICE_RESERVE, ");
+               break;
+       case I2O_CMD_UTIL_DEVICE_RELEASE:
+               printk("UTIL_DEVICE_RELEASE, ");
+               break;
+       case I2O_CMD_UTIL_EVT_ACK:
+               printk("UTIL_EVENT_ACKNOWLEDGE, ");
+               break;
+       case I2O_CMD_UTIL_EVT_REGISTER:
+               printk("UTIL_EVENT_REGISTER, ");
+               break;
+       case I2O_CMD_UTIL_LOCK:
+               printk("UTIL_LOCK, ");
+               break;
+       case I2O_CMD_UTIL_LOCK_RELEASE:
+               printk("UTIL_LOCK_RELEASE, ");
+               break;
+       case I2O_CMD_UTIL_PARAMS_GET:
+               printk("UTIL_PARAMS_GET, ");
+               break;
+       case I2O_CMD_UTIL_PARAMS_SET:
+               printk("UTIL_PARAMS_SET, ");
+               break;
+       case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
+               printk("UTIL_REPLY_FAULT_NOTIFY, ");
+               break;
+       default:
+               printk("Cmd = %0#2x, ", cmd);
+       }
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_exec_cmd(u8 cmd)
+{
+       switch (cmd) {
+       case I2O_CMD_ADAPTER_ASSIGN:
+               printk("EXEC_ADAPTER_ASSIGN, ");
+               break;
+       case I2O_CMD_ADAPTER_READ:
+               printk("EXEC_ADAPTER_READ, ");
+               break;
+       case I2O_CMD_ADAPTER_RELEASE:
+               printk("EXEC_ADAPTER_RELEASE, ");
+               break;
+       case I2O_CMD_BIOS_INFO_SET:
+               printk("EXEC_BIOS_INFO_SET, ");
+               break;
+       case I2O_CMD_BOOT_DEVICE_SET:
+               printk("EXEC_BOOT_DEVICE_SET, ");
+               break;
+       case I2O_CMD_CONFIG_VALIDATE:
+               printk("EXEC_CONFIG_VALIDATE, ");
+               break;
+       case I2O_CMD_CONN_SETUP:
+               printk("EXEC_CONN_SETUP, ");
+               break;
+       case I2O_CMD_DDM_DESTROY:
+               printk("EXEC_DDM_DESTROY, ");
+               break;
+       case I2O_CMD_DDM_ENABLE:
+               printk("EXEC_DDM_ENABLE, ");
+               break;
+       case I2O_CMD_DDM_QUIESCE:
+               printk("EXEC_DDM_QUIESCE, ");
+               break;
+       case I2O_CMD_DDM_RESET:
+               printk("EXEC_DDM_RESET, ");
+               break;
+       case I2O_CMD_DDM_SUSPEND:
+               printk("EXEC_DDM_SUSPEND, ");
+               break;
+       case I2O_CMD_DEVICE_ASSIGN:
+               printk("EXEC_DEVICE_ASSIGN, ");
+               break;
+       case I2O_CMD_DEVICE_RELEASE:
+               printk("EXEC_DEVICE_RELEASE, ");
+               break;
+       case I2O_CMD_HRT_GET:
+               printk("EXEC_HRT_GET, ");
+               break;
+       case I2O_CMD_ADAPTER_CLEAR:
+               printk("EXEC_IOP_CLEAR, ");
+               break;
+       case I2O_CMD_ADAPTER_CONNECT:
+               printk("EXEC_IOP_CONNECT, ");
+               break;
+       case I2O_CMD_ADAPTER_RESET:
+               printk("EXEC_IOP_RESET, ");
+               break;
+       case I2O_CMD_LCT_NOTIFY:
+               printk("EXEC_LCT_NOTIFY, ");
+               break;
+       case I2O_CMD_OUTBOUND_INIT:
+               printk("EXEC_OUTBOUND_INIT, ");
+               break;
+       case I2O_CMD_PATH_ENABLE:
+               printk("EXEC_PATH_ENABLE, ");
+               break;
+       case I2O_CMD_PATH_QUIESCE:
+               printk("EXEC_PATH_QUIESCE, ");
+               break;
+       case I2O_CMD_PATH_RESET:
+               printk("EXEC_PATH_RESET, ");
+               break;
+       case I2O_CMD_STATIC_MF_CREATE:
+               printk("EXEC_STATIC_MF_CREATE, ");
+               break;
+       case I2O_CMD_STATIC_MF_RELEASE:
+               printk("EXEC_STATIC_MF_RELEASE, ");
+               break;
+       case I2O_CMD_STATUS_GET:
+               printk("EXEC_STATUS_GET, ");
+               break;
+       case I2O_CMD_SW_DOWNLOAD:
+               printk("EXEC_SW_DOWNLOAD, ");
+               break;
+       case I2O_CMD_SW_UPLOAD:
+               printk("EXEC_SW_UPLOAD, ");
+               break;
+       case I2O_CMD_SW_REMOVE:
+               printk("EXEC_SW_REMOVE, ");
+               break;
+       case I2O_CMD_SYS_ENABLE:
+               printk("EXEC_SYS_ENABLE, ");
+               break;
+       case I2O_CMD_SYS_MODIFY:
+               printk("EXEC_SYS_MODIFY, ");
+               break;
+       case I2O_CMD_SYS_QUIESCE:
+               printk("EXEC_SYS_QUIESCE, ");
+               break;
+       case I2O_CMD_SYS_TAB_SET:
+               printk("EXEC_SYS_TAB_SET, ");
+               break;
+       default:
+               printk("Cmd = %#02x, ", cmd);
+       }
+}
+
+void i2o_debug_state(struct i2o_controller *c)
+{
+       printk(KERN_INFO "%s: State = ", c->name);
+       switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
+       case 0x01:
+               printk("INIT\n");
+               break;
+       case 0x02:
+               printk("RESET\n");
+               break;
+       case 0x04:
+               printk("HOLD\n");
+               break;
+       case 0x05:
+               printk("READY\n");
+               break;
+       case 0x08:
+               printk("OPERATIONAL\n");
+               break;
+       case 0x10:
+               printk("FAILED\n");
+               break;
+       case 0x11:
+               printk("FAULTED\n");
+               break;
+       default:
+               printk("%x (unknown !!)\n",
+                      ((i2o_status_block *) c->status_block.virt)->iop_state);
+       }
+};
+
+void i2o_systab_debug(struct i2o_sys_tbl *sys_tbl)
+{
+       u32 *table;
+       int count;
+       u32 size;
+
+       table = (u32 *) sys_tbl;
+       size = sizeof(struct i2o_sys_tbl) + sys_tbl->num_entries
+           * sizeof(struct i2o_sys_tbl_entry);
+
+       for (count = 0; count < (size >> 2); count++)
+               printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", count, table[count]);
+}
+
+void i2o_dump_hrt(struct i2o_controller *c)
+{
+       u32 *rows = (u32 *) c->hrt.virt;
+       u8 *p = (u8 *) c->hrt.virt;
+       u8 *d;
+       int count;
+       int length;
+       int i;
+       int state;
+
+       if (p[3] != 0) {
+               printk(KERN_ERR
+                      "%s: HRT table for controller is too new a version.\n",
+                      c->name);
+               return;
+       }
+
+       count = p[0] | (p[1] << 8);
+       length = p[2];
+
+       printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+              c->name, count, length << 2);
+
+       rows += 2;
+
+       for (i = 0; i < count; i++) {
+               printk(KERN_INFO "Adapter %08X: ", rows[0]);
+               p = (u8 *) (rows + 1);
+               d = (u8 *) (rows + 2);
+               state = p[1] << 8 | p[0];
+
+               printk("TID %04X:[", state & 0xFFF);
+               state >>= 12;
+               if (state & (1 << 0))
+                       printk("H");    /* Hidden */
+               if (state & (1 << 2)) {
+                       printk("P");    /* Present */
+                       if (state & (1 << 1))
+                               printk("C");    /* Controlled */
+               }
+               if (state > 9)
+                       printk("*");    /* Hard */
+
+               printk("]:");
+
+               switch (p[3] & 0xFFFF) {
+               case 0:
+                       /* Adapter private bus - easy */
+                       printk("Local bus %d: I/O at 0x%04X Mem 0x%08X",
+                              p[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
+                       break;
+               case 1:
+                       /* ISA bus */
+                       printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X",
+                              p[2], d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
+                       break;
+
+               case 2: /* EISA bus */
+                       printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+                              p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
+                       break;
+
+               case 3: /* MCA bus */
+                       printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+                              p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
+                       break;
+
+               case 4: /* PCI bus */
+                       printk("PCI %d: Bus %d Device %d Function %d",
+                              p[2], d[2], d[1], d[0]);
+                       break;
+
+               case 0x80:      /* Other */
+               default:
+                       printk("Unsupported bus type.");
+                       break;
+               }
+               printk("\n");
+               rows += length;
+       }
+}
+
+EXPORT_SYMBOL(i2o_dump_status_block);
+EXPORT_SYMBOL(i2o_dump_message);
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
new file mode 100644 (file)
index 0000000..ff4822e
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ *     Functions to handle I2O devices
+ *
+ *     Copyright (C) 2004      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>
+
+/* Exec OSM functions */
+extern struct bus_type i2o_bus_type;
+
+/**
+ *     i2o_device_issue_claim - claim or release a device
+ *     @dev: I2O device to claim or release
+ *     @cmd: claim or release command
+ *     @type: type of claim
+ *
+ *     Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent
+ *     is set by cmd. dev is the I2O device which should be claim or
+ *     released and the type is the claim type (see the I2O spec).
+ *
+ *     Returs 0 on success or negative error code on failure.
+ */
+static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
+                                        u32 type)
+{
+       struct i2o_message *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(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]);
+       writel(type, &msg->body[0]);
+
+       return i2o_msg_post_wait(dev->iop, m, 60);
+};
+
+/**
+ *     i2o_device_claim - claim a device for use by an OSM
+ *     @dev: I2O device to claim
+ *     @drv: I2O driver which wants to claim the device
+ *
+ *     Do the leg work to assign a device to a given OSM. If the claim succeed
+ *     the owner of the rimary. If the attempt fails a negative errno code
+ *     is returned. On success zero is returned.
+ */
+int i2o_device_claim(struct i2o_device *dev)
+{
+       int rc = 0;
+
+       down(&dev->lock);
+
+       rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
+       if (!rc)
+               pr_debug("claim of device %d succeded\n", dev->lct_data.tid);
+       else
+               pr_debug("claim of device %d failed %d\n", dev->lct_data.tid,
+                        rc);
+
+       up(&dev->lock);
+
+       return rc;
+};
+
+/**
+ *     i2o_device_claim_release - release a device that the OSM is using
+ *     @dev: device to release
+ *     @drv: driver which claimed the device
+ *
+ *     Drop a claim by an OSM on a given I2O device.
+ *
+ *     AC - some devices seem to want to refuse an unclaim until they have
+ *     finished internal processing. It makes sense since you don't want a
+ *     new device to go reconfiguring the entire system until you are done.
+ *     Thus we are prepared to wait briefly.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_claim_release(struct i2o_device *dev)
+{
+       int tries;
+       int rc = 0;
+
+       down(&dev->lock);
+
+       /*
+        *      If the controller takes a nonblocking approach to
+        *      releases we have to sleep/poll for a few times.
+        */
+       for (tries = 0; tries < 10; tries++) {
+               rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE,
+                                           I2O_CLAIM_PRIMARY);
+               if (!rc)
+                       break;
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(HZ);
+       }
+
+       if (!rc)
+               pr_debug("claim release of device %d succeded\n",
+                        dev->lct_data.tid);
+       else
+               pr_debug("claim release of device %d failed %d\n",
+                        dev->lct_data.tid, rc);
+
+       up(&dev->lock);
+
+       return rc;
+};
+
+/**
+ *     i2o_device_release - release the memory for a I2O device
+ *     @dev: I2O device which should be released
+ *
+ *     Release the allocated memory. This function is called if refcount of
+ *     device reaches 0 automatically.
+ */
+static void i2o_device_release(struct device *dev)
+{
+       struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+       pr_debug("Release I2O device %s\n", dev->bus_id);
+
+       kfree(i2o_dev);
+};
+
+/**
+ *     i2o_device_class_release - Remove I2O device attributes
+ *     @cd: I2O class device which is added to the I2O device class
+ *
+ *     Removes attributes from the I2O device again. Also search each device
+ *     on the controller for I2O devices which refert to this device as parent
+ *     or user and remove this links also.
+ */
+static void i2o_device_class_release(struct class_device *cd)
+{
+       struct i2o_device *i2o_dev, *tmp;
+       struct i2o_controller *c;
+
+       i2o_dev = to_i2o_device(cd->dev);
+       c = i2o_dev->iop;
+
+       sysfs_remove_link(&i2o_dev->device.kobj, "parent");
+       sysfs_remove_link(&i2o_dev->device.kobj, "user");
+
+       list_for_each_entry(tmp, &c->devices, list) {
+               if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+                       sysfs_remove_link(&tmp->device.kobj, "parent");
+               if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+                       sysfs_remove_link(&tmp->device.kobj, "user");
+       }
+};
+
+/* I2O device class */
+static struct class i2o_device_class = {
+       .name = "i2o_device",
+       .release = i2o_device_class_release
+};
+
+/**
+ *     i2o_device_alloc - Allocate a I2O device and initialize it
+ *
+ *     Allocate the memory for a I2O device and initialize locks and lists
+ *
+ *     Returns the allocated I2O device or a negative error code if the device
+ *     could not be allocated.
+ */
+static struct i2o_device *i2o_device_alloc(void)
+{
+       struct i2o_device *dev;
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       memset(dev, 0, sizeof(*dev));
+
+       INIT_LIST_HEAD(&dev->list);
+       init_MUTEX(&dev->lock);
+
+       dev->device.bus = &i2o_bus_type;
+       dev->device.release = &i2o_device_release;
+       dev->classdev.class = &i2o_device_class;
+       dev->classdev.dev = &dev->device;
+
+       return dev;
+};
+
+/**
+ *     i2o_device_add - allocate a new I2O device and add it to the IOP
+ *     @iop: I2O controller where the device is on
+ *     @entry: LCT entry of the I2O device
+ *
+ *     Allocate a new I2O device and initialize it with the LCT entry. The
+ *     device is appended to the device list of the controller.
+ *
+ *     Returns a pointer to the I2O device on success or negative error code
+ *     on failure.
+ */
+struct i2o_device *i2o_device_add(struct i2o_controller *c,
+                                 i2o_lct_entry * entry)
+{
+       struct i2o_device *dev;
+
+       dev = i2o_device_alloc();
+       if (IS_ERR(dev)) {
+               printk(KERN_ERR "i2o: unable to allocate i2o device\n");
+               return dev;
+       }
+
+       dev->lct_data = *entry;
+
+       snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit,
+                dev->lct_data.tid);
+
+       snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit,
+                dev->lct_data.tid);
+
+       dev->iop = c;
+       dev->device.parent = &c->device;
+
+       device_register(&dev->device);
+
+       list_add_tail(&dev->list, &c->devices);
+
+       class_device_register(&dev->classdev);
+
+       i2o_driver_notify_device_add_all(dev);
+
+       pr_debug("I2O device %s added\n", dev->device.bus_id);
+
+       return dev;
+};
+
+/**
+ *     i2o_device_remove - remove an I2O device from the I2O core
+ *     @dev: I2O device which should be released
+ *
+ *     Is used on I2O controller removal or LCT modification, when the device
+ *     is removed from the system. Note that the device could still hang
+ *     around until the refcount reaches 0.
+ */
+void i2o_device_remove(struct i2o_device *i2o_dev)
+{
+       i2o_driver_notify_device_remove_all(i2o_dev);
+       class_device_unregister(&i2o_dev->classdev);
+       list_del(&i2o_dev->list);
+       device_unregister(&i2o_dev->device);
+};
+
+/**
+ *     i2o_device_parse_lct - Parse a previously fetched LCT and create devices
+ *     @c: I2O controller from which the LCT should be parsed.
+ *
+ *     The Logical Configuration Table tells us what we can talk to on the
+ *     board. For every entry we create an I2O device, which is registered in
+ *     the I2O core.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_parse_lct(struct i2o_controller *c)
+{
+       struct i2o_device *dev, *tmp;
+       i2o_lct *lct;
+       int i;
+       int max;
+
+       down(&c->lct_lock);
+
+       if (c->lct)
+               kfree(c->lct);
+
+       lct = c->dlct.virt;
+
+       c->lct = kmalloc(lct->table_size * 4, GFP_KERNEL);
+       if (!c->lct) {
+               up(&c->lct_lock);
+               return -ENOMEM;
+       }
+
+       if (lct->table_size * 4 > c->dlct.len) {
+               memcpy_fromio(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);
+
+       lct = c->lct;
+
+       max = (lct->table_size - 3) / 9;
+
+       pr_debug("LCT has %d entries (LCT size: %d)\n", max, lct->table_size);
+
+       /* remove devices, which are not in the LCT anymore */
+       list_for_each_entry_safe(dev, tmp, &c->devices, list) {
+               int found = 0;
+
+               for (i = 0; i < max; i++) {
+                       if (lct->lct_entry[i].tid == dev->lct_data.tid) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       i2o_device_remove(dev);
+       }
+
+       /* add new devices, which are new in the LCT */
+       for (i = 0; i < max; i++) {
+               int found = 0;
+
+               list_for_each_entry_safe(dev, tmp, &c->devices, list) {
+                       if (lct->lct_entry[i].tid == dev->lct_data.tid) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       i2o_device_add(c, &lct->lct_entry[i]);
+       }
+       up(&c->lct_lock);
+
+       return 0;
+};
+
+/**
+ *     i2o_device_class_show_class_id - Displays class id of I2O device
+ *     @cd: class device of which the class id should be displayed
+ *     @buf: buffer into which the class id should be printed
+ *
+ *     Returns the number of bytes which are printed into the buffer.
+ */
+static ssize_t i2o_device_class_show_class_id(struct class_device *cd,
+                                             char *buf)
+{
+       struct i2o_device *dev = to_i2o_device(cd->dev);
+
+       sprintf(buf, "%03x\n", dev->lct_data.class_id);
+       return strlen(buf) + 1;
+};
+
+/**
+ *     i2o_device_class_show_tid - Displays TID of I2O device
+ *     @cd: class device of which the TID should be displayed
+ *     @buf: buffer into which the class id should be printed
+ *
+ *     Returns the number of bytes which are printed into the buffer.
+ */
+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);
+       return strlen(buf) + 1;
+};
+
+/* I2O device class attributes */
+static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id,
+                        NULL);
+static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL);
+
+/**
+ *     i2o_device_class_add - Adds attributes to the I2O device
+ *     @cd: I2O class device which is added to the I2O device class
+ *
+ *     This function get called when a I2O device is added to the class. It
+ *     creates the attributes for each device and creates user/parent symlink
+ *     if necessary.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_device_class_add(struct class_device *cd)
+{
+       struct i2o_device *i2o_dev, *tmp;
+       struct i2o_controller *c;
+
+       i2o_dev = to_i2o_device(cd->dev);
+       c = i2o_dev->iop;
+
+       class_device_create_file(cd, &class_device_attr_class_id);
+       class_device_create_file(cd, &class_device_attr_tid);
+
+       /* create user entries for this device */
+       tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
+       if (tmp)
+               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)
+               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)
+               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)
+               sysfs_create_link(&tmp->device.kobj,
+                                 &i2o_dev->device.kobj, "parent");
+
+       return 0;
+};
+
+/* I2O device class interface */
+static struct class_interface i2o_device_class_interface = {
+       .class = &i2o_device_class,
+       .add = i2o_device_class_add
+};
+
+/*
+ *     Run time support routines
+ */
+
+/*     Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *     This function can be used for all UtilParamsGet/Set operations.
+ *     The OperationList is given in oplist-buffer,
+ *     and results are returned in reslist-buffer.
+ *     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)
+{
+       struct i2o_message *msg;
+       u32 m;
+       u32 *res32 = (u32 *) reslist;
+       u32 *restmp = (u32 *) reslist;
+       int len = 0;
+       int i = 0;
+       int rc;
+       struct i2o_dma res;
+       struct i2o_controller *c = i2o_dev->iop;
+       struct device *dev = &c->pdev->dev;
+
+       res.virt = NULL;
+
+       if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL))
+               return -ENOMEM;
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY) {
+               i2o_dma_free(dev, &res);
+               return -ETIMEDOUT;
+       }
+
+       i = 0;
+       writel(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid,
+              &msg->u.head[1]);
+       writel(0, &msg->body[i++]);
+       writel(0x4C000000 | oplen, &msg->body[i++]);    /* OperationList */
+       memcpy_toio(&msg->body[i], oplist, oplen);
+       i += (oplen / 4 + (oplen % 4 ? 1 : 0));
+       writel(0xD0000000 | res.len, &msg->body[i++]);  /* ResultList */
+       writel(res.phys, &msg->body[i++]);
+
+       writel(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) |
+              SGL_OFFSET_5, &msg->u.head[0]);
+
+       rc = i2o_msg_post_wait_mem(c, m, 10, &res);
+
+       /* This only looks like a memory leak - don't "fix" it. */
+       if (rc == -ETIMEDOUT)
+               return rc;
+
+       memcpy_fromio(reslist, res.virt, res.len);
+       i2o_dma_free(dev, &res);
+
+       /* Query failed */
+       if (rc)
+               return rc;
+       /*
+        * Calculate number of bytes of Result LIST
+        * We need to loop through each Result BLOCK and grab the length
+        */
+       restmp = res32 + 1;
+       len = 1;
+       for (i = 0; i < (res32[0] & 0X0000FFFF); i++) {
+               if (restmp[0] & 0x00FF0000) {   /* BlockStatus != SUCCESS */
+                       printk(KERN_WARNING
+                              "%s - Error:\n  ErrorInfoSize = 0x%02x, "
+                              "BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+                              (cmd ==
+                               I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" :
+                              "PARAMS_GET", res32[1] >> 24,
+                              (res32[1] >> 16) & 0xFF, res32[1] & 0xFFFF);
+
+                       /*
+                        *      If this is the only request,than we return an error
+                        */
+                       if ((res32[0] & 0x0000FFFF) == 1) {
+                               return -((res32[1] >> 16) & 0xFF);      /* -BlockStatus */
+                       }
+               }
+               len += restmp[0] & 0x0000FFFF;  /* Length of res BLOCK */
+               restmp += restmp[0] & 0x0000FFFF;       /* Skip to next BLOCK */
+       }
+       return (len << 2);      /* bytes used by result list */
+}
+
+/*
+ *      Query one field group value or a whole scalar group.
+ */
+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 */
+       int size;
+
+       if (field == -1)        /* whole group */
+               opblk[4] = -1;
+
+       size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
+                             sizeof(opblk), resblk, sizeof(resblk));
+
+       memcpy(buf, resblk + 8, buflen);        /* cut off header */
+
+       if (size > buflen)
+               return buflen;
+
+       return size;
+}
+
+/*
+ *     Set a scalar group value or a whole group.
+ */
+int i2o_parm_field_set(struct i2o_device *i2o_dev, int group, int field,
+                      void *buf, int buflen)
+{
+       u16 *opblk;
+       u8 resblk[8 + buflen];  /* 8 bytes for header */
+       int size;
+
+       opblk = kmalloc(buflen + 64, GFP_KERNEL);
+       if (opblk == NULL) {
+               printk(KERN_ERR "i2o: no memory for operation buffer.\n");
+               return -ENOMEM;
+       }
+
+       opblk[0] = 1;           /* operation count */
+       opblk[1] = 0;           /* pad */
+       opblk[2] = I2O_PARAMS_FIELD_SET;
+       opblk[3] = group;
+
+       if (field == -1) {      /* whole group */
+               opblk[4] = -1;
+               memcpy(opblk + 5, buf, buflen);
+       } else {                /* single field */
+
+               opblk[4] = 1;
+               opblk[5] = field;
+               memcpy(opblk + 6, buf, buflen);
+       }
+
+       size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_SET, opblk,
+                             12 + buflen, resblk, sizeof(resblk));
+
+       kfree(opblk);
+       if (size > buflen)
+               return buflen;
+
+       return size;
+}
+
+/*
+ *     if oper == I2O_PARAMS_TABLE_GET, get from all rows
+ *             if fieldcount == -1 return all fields
+ *                     ibuf and ibuflen are unused (use NULL, 0)
+ *             else return specific fields
+ *                     ibuf contains fieldindexes
+ *
+ *     if oper == I2O_PARAMS_LIST_GET, get from specific rows
+ *             if fieldcount == -1 return all fields
+ *                     ibuf contains rowcount, keyvalues
+ *             else return specific fields
+ *                     fieldcount is # of fieldindexes
+ *                     ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ *     You could also use directly function i2o_issue_params().
+ */
+int i2o_parm_table_get(struct i2o_device *dev, int oper, int group,
+                      int fieldcount, void *ibuf, int ibuflen, void *resblk,
+                      int reslen)
+{
+       u16 *opblk;
+       int size;
+
+       size = 10 + ibuflen;
+       if (size % 4)
+               size += 4 - size % 4;
+
+       opblk = kmalloc(size, GFP_KERNEL);
+       if (opblk == NULL) {
+               printk(KERN_ERR "i2o: no memory for query buffer.\n");
+               return -ENOMEM;
+       }
+
+       opblk[0] = 1;           /* operation count */
+       opblk[1] = 0;           /* pad */
+       opblk[2] = oper;
+       opblk[3] = group;
+       opblk[4] = fieldcount;
+       memcpy(opblk + 5, ibuf, ibuflen);       /* other params */
+
+       size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
+                             size, resblk, reslen);
+
+       kfree(opblk);
+       if (size > reslen)
+               return reslen;
+
+       return size;
+}
+
+/**
+ *     i2o_device_init - Initialize I2O devices
+ *
+ *     Registers the I2O device class.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_init(void)
+{
+       int rc;
+
+       rc = class_register(&i2o_device_class);
+       if (rc)
+               return rc;
+
+       return class_interface_register(&i2o_device_class_interface);
+};
+
+/**
+ *     i2o_device_exit - I2O devices exit function
+ *
+ *     Unregisters the I2O device class.
+ */
+void i2o_device_exit(void)
+{
+       class_interface_register(&i2o_device_class_interface);
+       class_unregister(&i2o_device_class);
+};
+
+EXPORT_SYMBOL(i2o_device_claim);
+EXPORT_SYMBOL(i2o_device_claim_release);
+EXPORT_SYMBOL(i2o_parm_field_get);
+EXPORT_SYMBOL(i2o_parm_field_set);
+EXPORT_SYMBOL(i2o_parm_table_get);
+EXPORT_SYMBOL(i2o_parm_issue);
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c
new file mode 100644 (file)
index 0000000..bc69d66
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ *     Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs
+ *
+ *     Copyright (C) 2004      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/device.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/i2o.h>
+
+
+/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
+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");
+
+/* I2O drivers lock and array */
+static spinlock_t i2o_drivers_lock = SPIN_LOCK_UNLOCKED;
+static struct i2o_driver **i2o_drivers;
+
+/**
+ *     i2o_bus_match - Tell if a I2O device class id match the class ids of
+ *                     the I2O driver (OSM)
+ *
+ *     @dev: device which should be verified
+ *     @drv: the driver to match against
+ *
+ *     Used by the bus to check if the driver wants to handle the device.
+ *
+ *     Returns 1 if the class ids of the driver match the class id of the
+ *     device, otherwise 0.
+ */
+static int i2o_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct i2o_device *i2o_dev = to_i2o_device(dev);
+       struct i2o_driver *i2o_drv = to_i2o_driver(drv);
+       struct i2o_class_id *ids = i2o_drv->classes;
+
+       if (ids)
+               while (ids->class_id != I2O_CLASS_END) {
+                       if (ids->class_id == i2o_dev->lct_data.class_id)
+                               return 1;
+                       ids++;
+               }
+       return 0;
+};
+
+/* I2O bus type */
+struct bus_type i2o_bus_type = {
+       .name = "i2o",
+       .match = i2o_bus_match,
+};
+
+/**
+ *     i2o_driver_register - Register a I2O driver (OSM) in the I2O core
+ *     @drv: I2O driver which should be registered
+ *
+ *     Registers the OSM drv in the I2O core and creates an event queues if
+ *     necessary.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int i2o_driver_register(struct i2o_driver *drv)
+{
+       struct i2o_controller *c;
+       int i;
+       int rc = 0;
+       unsigned long flags;
+
+       pr_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);
+                       return -EFAULT;
+               }
+               pr_debug("Event queue initialized for driver %s\n", drv->name);
+       } else
+               drv->event_queue = NULL;
+
+       drv->driver.name = drv->name;
+       drv->driver.bus = &i2o_bus_type;
+
+       spin_lock_irqsave(&i2o_drivers_lock, flags);
+
+       for (i = 0; i2o_drivers[i]; i++)
+               if (i >= i2o_max_drivers) {
+                       printk(KERN_ERR "i2o: too many drivers registered, "
+                              "increase max_drivers\n");
+                       spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+                       return -EFAULT;
+               }
+
+       drv->context = i;
+       i2o_drivers[i] = drv;
+
+       spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+       pr_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);
+       }
+
+
+       rc = driver_register(&drv->driver);
+       if (rc)
+               destroy_workqueue(drv->event_queue);
+
+       return rc;
+};
+
+/**
+ *     i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core
+ *     @drv: I2O driver which should be unregistered
+ *
+ *     Unregisters the OSM drv from the I2O core and cleanup event queues if
+ *     necessary.
+ */
+void i2o_driver_unregister(struct i2o_driver *drv)
+{
+       struct i2o_controller *c;
+       unsigned long flags;
+
+       pr_debug("unregister driver %s\n", drv->name);
+
+       driver_unregister(&drv->driver);
+
+       list_for_each_entry(c, &i2o_controllers, list) {
+               struct i2o_device *i2o_dev;
+
+               list_for_each_entry(i2o_dev, &c->devices, list)
+                       i2o_driver_notify_device_remove(drv, i2o_dev);
+
+               i2o_driver_notify_controller_remove(drv, c);
+       }
+
+       spin_lock_irqsave(&i2o_drivers_lock, flags);
+       i2o_drivers[drv->context] = NULL;
+       spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+       if (drv->event_queue) {
+               destroy_workqueue(drv->event_queue);
+               drv->event_queue = NULL;
+               pr_debug("event queue removed for %s\n", drv->name);
+       }
+};
+
+/**
+ *     i2o_driver_dispatch - dispatch an I2O reply message
+ *     @c: I2O controller of the message
+ *     @m: I2O message number
+ *     @msg: I2O message to be delivered
+ *
+ *     The reply is delivered to the driver from which the original message
+ *     was. This function is only called from interrupt context.
+ *
+ *     Returns 0 on success and the message should not be flushed. Returns > 0
+ *     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 *msg)
+{
+       struct i2o_driver *drv;
+       u32 context = readl(&msg->u.s.icntxt);
+
+       if (likely(context < i2o_max_drivers)) {
+               spin_lock(&i2o_drivers_lock);
+               drv = i2o_drivers[context];
+               spin_unlock(&i2o_drivers_lock);
+
+               if (unlikely(!drv)) {
+                       printk(KERN_WARNING "i2o: Spurious reply to unknown "
+                              "driver %d\n", context);
+                       return -EIO;
+               }
+
+               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;
+
+                       tid = readl(&msg->u.head[1]) & 0x1fff;
+
+                       pr_debug("%s: event received from device %d\n", c->name,
+                                tid);
+
+                       /* cut of header from message size (in 32-bit words) */
+                       size = (readl(&msg->u.head[0]) >> 16) - 5;
+
+                       evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
+                       if (!evt)
+                               return -ENOMEM;
+                       memset(evt, 0, size * 4 + sizeof(*evt));
+
+                       evt->size = size;
+                       memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt,
+                                     (size + 2) * 4);
+
+                       list_for_each_entry_safe(dev, tmp, &c->devices, list)
+                           if (dev->lct_data.tid == tid) {
+                               evt->i2o_dev = dev;
+                               break;
+                       }
+
+                       INIT_WORK(&evt->work, (void (*)(void *))drv->event,
+                                 evt);
+                       queue_work(drv->event_queue, &evt->work);
+                       return 1;
+               }
+
+               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);
+               return -EIO;
+       } else
+               printk(KERN_WARNING "i2o: Spurious reply to unknown driver "
+                      "%d\n", readl(&msg->u.s.icntxt));
+       return -EIO;
+}
+
+/**
+ *     i2o_driver_notify_controller_add_all - Send notify of added controller
+ *                                            to all I2O drivers
+ *
+ *     Send notifications to all registered drivers that a new controller was
+ *     added.
+ */
+void i2o_driver_notify_controller_add_all(struct i2o_controller *c) {
+       int i;
+       struct i2o_driver *drv;
+
+       for(i = 0; i < I2O_MAX_DRIVERS; i ++) {
+               drv = i2o_drivers[i];
+
+               if(drv)
+                       i2o_driver_notify_controller_add(drv, c);
+       }
+}
+
+/**
+ *     i2o_driver_notify_controller_remove_all - Send notify of removed
+ *                                               controller to all I2O drivers
+ *
+ *     Send notifications to all registered drivers that a controller was
+ *     removed.
+ */
+void i2o_driver_notify_controller_remove_all(struct i2o_controller *c) {
+       int i;
+       struct i2o_driver *drv;
+
+       for(i = 0; i < I2O_MAX_DRIVERS; i ++) {
+               drv = i2o_drivers[i];
+
+               if(drv)
+                       i2o_driver_notify_controller_remove(drv, c);
+       }
+}
+
+/**
+ *     i2o_driver_notify_device_add_all - Send notify of added device to all
+ *                                        I2O drivers
+ *
+ *     Send notifications to all registered drivers that a device was added.
+ */
+void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev) {
+       int i;
+       struct i2o_driver *drv;
+
+       for(i = 0; i < I2O_MAX_DRIVERS; i ++) {
+               drv = i2o_drivers[i];
+
+               if(drv)
+                       i2o_driver_notify_device_add(drv, i2o_dev);
+       }
+}
+
+/**
+ *     i2o_driver_notify_device_remove_all - Send notify of removed device to
+ *                                           all I2O drivers
+ *
+ *     Send notifications to all registered drivers that a device was removed.
+ */
+void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev) {
+       int i;
+       struct i2o_driver *drv;
+
+       for(i = 0; i < I2O_MAX_DRIVERS; i ++) {
+               drv = i2o_drivers[i];
+
+               if(drv)
+                       i2o_driver_notify_device_remove(drv, i2o_dev);
+       }
+}
+
+/**
+ *     i2o_driver_init - initialize I2O drivers (OSMs)
+ *
+ *     Registers the I2O bus and allocate memory for the array of OSMs.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int __init i2o_driver_init(void)
+{
+       int rc = 0;
+
+       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);
+               i2o_max_drivers = I2O_MAX_DRIVERS;
+       }
+       printk(KERN_INFO "i2o: max_drivers=%d\n", i2o_max_drivers);
+
+       i2o_drivers =
+           kmalloc(i2o_max_drivers * sizeof(*i2o_drivers), GFP_KERNEL);
+       if (!i2o_drivers)
+               return -ENOMEM;
+
+       memset(i2o_drivers, 0, i2o_max_drivers * sizeof(*i2o_drivers));
+
+       rc = bus_register(&i2o_bus_type);
+
+       if (rc < 0)
+               kfree(i2o_drivers);
+
+       return rc;
+};
+
+/**
+ *     i2o_driver_exit - clean up I2O drivers (OSMs)
+ *
+ *     Unregisters the I2O bus and free driver array.
+ */
+void __exit i2o_driver_exit(void)
+{
+       bus_unregister(&i2o_bus_type);
+       kfree(i2o_drivers);
+};
+
+EXPORT_SYMBOL(i2o_driver_register);
+EXPORT_SYMBOL(i2o_driver_unregister);
+EXPORT_SYMBOL(i2o_driver_notify_controller_add_all);
+EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all);
+EXPORT_SYMBOL(i2o_driver_notify_device_add_all);
+EXPORT_SYMBOL(i2o_driver_notify_device_remove_all);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
new file mode 100644 (file)
index 0000000..117f261
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ *     Executive OSM
+ *
+ *     Copyright (C) 1999-2002 Red Hat Software
+ *
+ *     Written by Alan Cox, Building Number Three Ltd
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     A lot of the I2O message side code from this is taken from the Red
+ *     Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ *     Fixes/additions:
+ *             Philipp Rumpf
+ *             Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *             Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *             Deepak Saxena <deepak@plexity.net>
+ *             Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *             Alan Cox <alan@redhat.com>:
+ *                     Ported to Linux 2.5.
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *                     Minor fixes for 2.6.
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *                     Support for sysfs included.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+
+struct i2o_driver i2o_exec_driver;
+
+/* 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);
+
+/* Wait struct needed for POST WAIT */
+struct i2o_exec_wait {
+       wait_queue_head_t *wq;  /* Pointer to Wait queue */
+       struct i2o_dma dma;     /* DMA buffers to free on failure */
+       u32 tcntxt;             /* transaction context from reply */
+       int complete;           /* 1 if reply received otherwise 0 */
+       u32 m;                  /* message id */
+       struct i2o_message *msg;        /* pointer to the reply message */
+       struct list_head list;  /* node in global wait list */
+};
+
+/* Exec OSM class handling definition */
+static struct i2o_class_id i2o_exec_class_id[] = {
+       {I2O_CLASS_EXECUTIVE},
+       {I2O_CLASS_END}
+};
+
+/**
+ *     i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it
+ *
+ *     Allocate the i2o_exec_wait struct and initialize the wait.
+ *
+ *     Returns i2o_exec_wait pointer on success or negative error code on
+ *     failure.
+ */
+static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
+{
+       struct i2o_exec_wait *wait;
+
+       wait = kmalloc(sizeof(*wait), GFP_KERNEL);
+       if (!wait)
+               return ERR_PTR(-ENOMEM);
+
+       memset(wait, 0, sizeof(*wait));
+
+       INIT_LIST_HEAD(&wait->list);
+
+       return wait;
+};
+
+/**
+ *     i2o_exec_wait_free - Free a i2o_exec_wait struct
+ *     @i2o_exec_wait: I2O wait data which should be cleaned up
+ */
+static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
+{
+       kfree(wait);
+};
+
+/**
+ *     i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
+ *     @c: controller
+ *     @m: message to post
+ *     @timeout: time in seconds to wait
+ *     @dma: i2o_dma struct of the DMA buffer to free on failure
+ *
+ *     This API allows an OSM to post a message and then be told whether or
+ *     not the system received a successful reply. If the message times out
+ *     then the value '-ETIMEDOUT' is returned. This is a special case. In
+ *     this situation the message may (should) complete at an indefinite time
+ *     in the future. When it completes it will use the memory buffer
+ *     attached to the request. If -ETIMEDOUT is returned then the memory
+ *     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.
+ */
+int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
+                         timeout, struct i2o_dma *dma)
+{
+       DECLARE_WAIT_QUEUE_HEAD(wq);
+       DEFINE_WAIT(wait);
+       struct i2o_exec_wait *iwait;
+       static u32 tcntxt = 0x80000000;
+       struct i2o_message *msg = c->in_queue.virt + m;
+       int rc = 0;
+
+       iwait = i2o_exec_wait_alloc();
+       if (!iwait)
+               return -ENOMEM;
+
+       if (tcntxt == 0xffffffff)
+               tcntxt = 0x80000000;
+
+       if (dma)
+               iwait->dma = *dma;
+
+       /*
+        * Fill in the message initiator context and transaction context.
+        * We will only use transaction contexts >= 0x80000000 for POST WAIT,
+        * so we could find a POST WAIT reply easier in the reply handler.
+        */
+       writel(i2o_exec_driver.context, &msg->u.s.icntxt);
+       iwait->tcntxt = tcntxt++;
+       writel(iwait->tcntxt, &msg->u.s.tcntxt);
+
+       /*
+        * Post the message to the controller. At some point later it will
+        * return. If we time out before it returns then complete will be zero.
+        */
+       i2o_msg_post(c, m);
+
+       if (!iwait->complete) {
+               iwait->wq = &wq;
+               /*
+                * we add elements add the head, because if a entry in the list
+                * will never be removed, we have to iterate over it every time
+                */
+               list_add(&iwait->list, &i2o_exec_wait_list);
+
+               prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE);
+
+               if (!iwait->complete)
+                       schedule_timeout(timeout * HZ);
+
+               finish_wait(&wq, &wait);
+
+               iwait->wq = NULL;
+       }
+
+       barrier();
+
+       if (iwait->complete) {
+               if (readl(&iwait->msg->body[0]) >> 24)
+                       rc = readl(&iwait->msg->body[0]) & 0xff;
+               i2o_flush_reply(c, iwait->m);
+               i2o_exec_wait_free(iwait);
+       } else {
+               /*
+                * We cannot remove it now. This is important. When it does
+                * terminate (which it must do if the controller has not
+                * died...) then it will otherwise scribble on stuff.
+                *
+                * FIXME: try abort message
+                */
+               if (dma)
+                       dma->virt = NULL;
+
+               rc = -ETIMEDOUT;
+       }
+
+       return rc;
+};
+
+/**
+ *     i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP
+ *     @c: I2O controller which answers
+ *     @m: message id
+ *     @msg: pointer to the I2O reply message
+ *
+ *     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
+ *     and the task will be waked up. The task is now responsible for returning
+ *     the message m back to the controller! If the message reaches us after
+ *     the timeout clean up the i2o_exec_wait struct (including allocated
+ *     DMA buffer).
+ *
+ *     Return 0 on success and if the message m should not be given back to the
+ *     I2O controller, or >0 on success and if the message should be given back
+ *     afterwords. Returns negative error code on failure. In this case the
+ *     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 *msg)
+{
+       struct i2o_exec_wait *wait, *tmp;
+       static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+       int rc = 1;
+       u32 context;
+
+       context = readl(&msg->u.s.tcntxt);
+
+       /*
+        * We need to search through the i2o_exec_wait_list to see if the given
+        * message is still outstanding. If not, it means that the IOP took
+        * longer to respond to the message than we had allowed and timer has
+        * already expired. Not much we can do about that except log it for
+        * debug purposes, increase timeout, and recompile.
+        */
+       spin_lock(&lock);
+       list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
+               if (wait->tcntxt == context) {
+                       list_del(&wait->list);
+
+                       wait->m = m;
+                       wait->msg = msg;
+                       wait->complete = 1;
+
+                       barrier();
+
+                       if (wait->wq) {
+                               wake_up_interruptible(wait->wq);
+                               rc = 0;
+                       } else {
+                               struct device *dev;
+
+                               dev = &c->pdev->dev;
+
+                               pr_debug("timedout reply received!\n");
+                               i2o_dma_free(dev, &wait->dma);
+                               i2o_exec_wait_free(wait);
+                               rc = -1;
+                       }
+
+                       spin_unlock(&lock);
+
+                       return rc;
+               }
+       }
+
+       spin_unlock(&lock);
+
+       pr_debug("i2o: Bogus reply in POST WAIT (tr-context: %08x)!\n",
+                context);
+
+       return -1;
+};
+
+/**
+ *     i2o_exec_probe - Called if a new I2O device (executive class) appears
+ *     @dev: I2O device which should be probed
+ *
+ *     Registers event notification for every event from Executive device. The
+ *     return is always 0, because we want all devices of class Executive.
+ *
+ *     Returns 0 on success.
+ */
+static int i2o_exec_probe(struct device *dev)
+{
+       struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+       i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+
+       i2o_dev->iop->exec = i2o_dev;
+
+       return 0;
+};
+
+/**
+ *     i2o_exec_remove - Called on I2O device removal
+ *     @dev: I2O device which was removed
+ *
+ *     Unregisters event notification from Executive I2O device.
+ *
+ *     Returns 0 on success.
+ */
+static int i2o_exec_remove(struct device *dev)
+{
+       i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+
+       return 0;
+};
+
+/**
+ *     i2o_exec_lct_modified - Called on LCT NOTIFY reply
+ *     @c: I2O controller on which the LCT has modified
+ *
+ *     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.
+ */
+static void i2o_exec_lct_modified(struct i2o_controller *c)
+{
+       if (i2o_device_parse_lct(c) == -EAGAIN)
+               i2o_exec_lct_notify(c, 0);
+};
+
+/**
+ *     i2o_exec_reply -  I2O Executive reply handler
+ *     @c: I2O controller from which the reply comes
+ *     @m: message id
+ *     @msg: pointer to the I2O reply message
+ *
+ *     This function is always called from interrupt context. If a POST WAIT
+ *     reply was received, pass it to the complete function. If a LCT NOTIFY
+ *     reply was received, a new event is created to handle the update.
+ *
+ *     Returns 0 on success and if the reply should not be flushed or > 0
+ *     on success and if the reply should be flushed. Returns negative error
+ *     code on failure and if the reply should be flushed.
+ */
+static int i2o_exec_reply(struct i2o_controller *c, u32 m,
+                         struct i2o_message *msg)
+{
+       if (readl(&msg->u.head[0]) & MSG_FAIL) {        // Fail bit is set
+               struct i2o_message *pmsg;       /* preserved message */
+               u32 pm;
+
+               pm = readl(&msg->body[3]);
+
+               pmsg = c->in_queue.virt + pm;
+
+               i2o_report_status(KERN_INFO, "i2o_core", msg);
+
+               /* Release the preserved msg by resubmitting it as a NOP */
+               i2o_msg_nop(c, pm);
+
+               /* If reply to i2o_post_wait failed, return causes a timeout */
+               return -1;
+       }
+
+       if (readl(&msg->u.s.tcntxt) & 0x80000000)
+               return i2o_msg_post_wait_complete(c, m, msg);
+
+       if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
+               struct work_struct *work;
+
+               pr_debug("%s: LCT notify received\n", c->name);
+
+               work = kmalloc(sizeof(*work), GFP_ATOMIC);
+               if (!work)
+                       return -ENOMEM;
+
+               INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c);
+               queue_work(i2o_exec_driver.event_queue, work);
+               return 1;
+       }
+
+       /*
+        * If this happens, we want to dump the message to the syslog so
+        * it can be sent back to the card manufacturer by the end user
+        * to aid in debugging.
+        *
+        */
+       printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
+              "Message dumped to syslog\n", c->name);
+       i2o_dump_message(msg);
+
+       return -EFAULT;
+}
+
+/**
+ *     i2o_exec_event - Event handling function
+ *     @evt: Event which occurs
+ *
+ *     Handles events send by the Executive device. At the moment does not do
+ *     anything useful.
+ */
+static void i2o_exec_event(struct i2o_event *evt)
+{
+       printk(KERN_INFO "Event received from device: %d\n",
+              evt->i2o_dev->lct_data.tid);
+       kfree(evt);
+};
+
+/**
+ *     i2o_exec_lct_get - Get the IOP's Logical Configuration Table
+ *     @c: I2O controller from which the LCT should be fetched
+ *
+ *     Send a LCT NOTIFY request to the controller, and wait
+ *     I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is
+ *     to large, retry it.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int i2o_exec_lct_get(struct i2o_controller *c)
+{
+       struct i2o_message *msg;
+       u32 m;
+       int i = 0;
+       int rc = -EAGAIN;
+
+       for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {
+               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_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID,
+                      &msg->u.head[1]);
+               writel(0xffffffff, &msg->body[0]);
+               writel(0x00000000, &msg->body[1]);
+               writel(0xd0000000 | c->dlct.len, &msg->body[2]);
+               writel(c->dlct.phys, &msg->body[3]);
+
+               rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET);
+               if (rc < 0)
+                       break;
+
+               rc = i2o_device_parse_lct(c);
+               if (rc != -EAGAIN)
+                       break;
+       }
+
+       return rc;
+}
+
+/**
+ *     i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
+ *     @c: I2O controller to which the request should be send
+ *     @change_ind: change indicator
+ *
+ *     This function sends a LCT NOTIFY request to the I2O controller with
+ *     the change indicator change_ind. If the change_ind == 0 the controller
+ *     replies immediately after the request. If change_ind > 0 the reply is
+ *     send after change indicator of the LCT is > change_ind.
+ */
+int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
+{
+       i2o_status_block *sb = c->status_block.virt;
+       struct device *dev;
+       struct i2o_message *msg;
+       u32 m;
+
+       dev = &c->pdev->dev;
+
+       if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL))
+               return -ENOMEM;
+
+       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_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+       writel(i2o_exec_driver.context, &msg->u.s.icntxt);
+       writel(0, &msg->u.s.tcntxt);    /* FIXME */
+       writel(0xffffffff, &msg->body[0]);
+       writel(change_ind, &msg->body[1]);
+       writel(0xd0000000 | c->dlct.len, &msg->body[2]);
+       writel(c->dlct.phys, &msg->body[3]);
+
+       i2o_msg_post(c, m);
+
+       return 0;
+};
+
+/* Exec OSM driver struct */
+struct i2o_driver i2o_exec_driver = {
+       .name = "exec-osm",
+       .reply = i2o_exec_reply,
+       .event = i2o_exec_event,
+       .classes = i2o_exec_class_id,
+       .driver = {
+                  .probe = i2o_exec_probe,
+                  .remove = i2o_exec_remove,
+                  },
+};
+
+/**
+ *     i2o_exec_init - Registers the Exec OSM
+ *
+ *     Registers the Exec OSM in the I2O core.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+int __init i2o_exec_init(void)
+{
+       return i2o_driver_register(&i2o_exec_driver);
+};
+
+/**
+ *     i2o_exec_exit - Removes the Exec OSM
+ *
+ *     Unregisters the Exec OSM from the I2O core.
+ */
+void __exit i2o_exec_exit(void)
+{
+       i2o_driver_unregister(&i2o_exec_driver);
+};
+
+EXPORT_SYMBOL(i2o_msg_post_wait_mem);
+EXPORT_SYMBOL(i2o_exec_lct_get);
+EXPORT_SYMBOL(i2o_exec_lct_notify);
diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h
new file mode 100644 (file)
index 0000000..ddd9a15
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *     Block OSM structures/API
+ *
+ *     Copyright (C) 1999-2002 Red Hat Software
+ *
+ *     Written by Alan Cox, Building Number Three Ltd
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ *
+ *     For the purpose of avoiding doubt the preferred form of the work
+ *     for making modifications shall be a standards compliant form such
+ *     gzipped tar and not one requiring a proprietary or patent encumbered
+ *     tool to unpack.
+ *
+ *     Fixes/additions:
+ *             Steve Ralston:
+ *                     Multiple device handling error fixes,
+ *                     Added a queue depth.
+ *             Alan Cox:
+ *                     FC920 has an rmw bug. Dont or in the end marker.
+ *                     Removed queue walk, fixed for 64bitness.
+ *                     Rewrote much of the code over time
+ *                     Added indirect block lists
+ *                     Handle 64K limits on many controllers
+ *                     Don't use indirects on the Promise (breaks)
+ *                     Heavily chop down the queue depths
+ *             Deepak Saxena:
+ *                     Independent queues per IOP
+ *                     Support for dynamic device creation/deletion
+ *                     Code cleanup
+ *                     Support for larger I/Os through merge* functions
+ *                     (taken from DAC960 driver)
+ *             Boji T Kannanthanam:
+ *                     Set the I2O Block devices to be detected in increasing
+ *                     order of TIDs during boot.
+ *                     Search and set the I2O block device that we boot off
+ *                     from as the first device to be claimed (as /dev/i2o/hda)
+ *                     Properly attach/detach I2O gendisk structure from the
+ *                     system gendisk list. The I2O block devices now appear in
+ *                     /proc/partitions.
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *                     Minor bugfixes for 2.6.
+ */
+
+#ifndef I2O_BLOCK_OSM_H
+#define I2O_BLOCK_OSM_H
+
+#define I2O_BLOCK_RETRY_TIME HZ/4
+#define I2O_BLOCK_MAX_OPEN_REQUESTS 50
+
+/* I2O Block OSM mempool struct */
+struct i2o_block_mempool {
+       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 */
+       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 flags;
+       int power;                      /* power state */
+       int media_change_flag;          /* media changed flag */
+};
+
+/* I2O Block device request */
+struct i2o_block_request
+{
+       struct list_head queue;
+       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 */
+};
+
+/* I2O Block device delayed request */
+struct i2o_block_delayed_request
+{
+       struct work_struct work;
+       struct request_queue *queue;
+};
+
+#endif
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
new file mode 100644 (file)
index 0000000..699723e
--- /dev/null
@@ -0,0 +1,1258 @@
+/*
+ *     Functions to handle I2O controllers and I2O message handling
+ *
+ *     Copyright (C) 1999-2002 Red Hat Software
+ *
+ *     Written by Alan Cox, Building Number Three Ltd
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     A lot of the I2O message side code from this is taken from the
+ *     Red Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ *     Fixes/additions:
+ *             Philipp Rumpf
+ *             Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *             Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *             Deepak Saxena <deepak@plexity.net>
+ *             Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *             Alan Cox <alan@redhat.com>:
+ *                     Ported to Linux 2.5.
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *                     Minor fixes for 2.6.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+
+/* global I2O controller list */
+LIST_HEAD(i2o_controllers);
+
+/*
+ * global I2O System Table. Contains information about all the IOPs in the
+ * system. Used to inform IOPs about each others existence.
+ */
+static struct i2o_dma i2o_systab;
+
+/* 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
+ *     @m: message which should be returned
+ *
+ *     If you fetch a message via i2o_msg_get, and can't use it, you must
+ *     return the message with this function. Otherwise the message frame
+ *     is lost.
+ */
+void i2o_msg_nop(struct i2o_controller *c, u32 m)
+{
+       struct i2o_message *msg = c->in_queue.virt + m;
+
+       writel(THREE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+       writel(0, &msg->u.head[2]);
+       writel(0, &msg->u.head[3]);
+       i2o_msg_post(c, m);
+};
+
+/**
+ *     i2o_msg_get_wait - obtain an I2O message from the IOP
+ *     @c: I2O controller
+ *     @msg: pointer to a I2O message pointer
+ *     @wait: how long to wait until timeout
+ *
+ *     This function waits up to wait seconds for a message slot to be
+ *     available.
+ *
+ *     On a success the message is returned and the pointer to the message is
+ *     set in msg. The returned message is the physical page frame offset
+ *     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 **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);
+                       return I2O_QUEUE_EMPTY;
+               }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       }
+
+       return m;
+};
+
+#if BITS_PER_LONG == 64
+/**
+ *      i2o_cntxt_list_add - Append a pointer to context list and return a id
+ *     @c: controller to which the context list belong
+ *     @ptr: pointer to add to the context list
+ *
+ *     Because the context field in I2O is only 32-bit large, on 64-bit the
+ *     pointer is to large to fit in the context field. The i2o_cntxt_list
+ *     functions therefore map pointers to context fields.
+ *
+ *     Returns context id > 0 on success or 0 on failure.
+ */
+u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
+{
+       struct i2o_context_list_element *entry;
+       unsigned long flags;
+
+       if (!ptr)
+               printk(KERN_ERR "NULL pointer found!\n");
+
+       entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+       if (!entry) {
+               printk(KERN_ERR "i2o: Could not allocate memory for context "
+                      "list element\n");
+               return 0;
+       }
+
+       entry->ptr = ptr;
+       entry->timestamp = jiffies;
+       INIT_LIST_HEAD(&entry->list);
+
+       spin_lock_irqsave(&c->context_list_lock, flags);
+
+       if (unlikely(atomic_inc_and_test(&c->context_list_counter)))
+               atomic_inc(&c->context_list_counter);
+
+       entry->context = atomic_read(&c->context_list_counter);
+
+       list_add(&entry->list, &c->context_list);
+
+       spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+       pr_debug("Add context to list %p -> %d\n", ptr, context);
+
+       return entry->context;
+};
+
+/**
+ *      i2o_cntxt_list_remove - Remove a pointer from the context list
+ *     @c: controller to which the context list belong
+ *     @ptr: pointer which should be removed from the context list
+ *
+ *     Removes a previously added pointer from the context list and returns
+ *     the matching context id.
+ *
+ *     Returns context id on succes or 0 on failure.
+ */
+u32 i2o_cntxt_list_remove(struct i2o_controller *c, void *ptr)
+{
+       struct i2o_context_list_element *entry;
+       u32 context = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->context_list_lock, flags);
+       list_for_each_entry(entry, &c->context_list, list)
+           if (entry->ptr == ptr) {
+               list_del(&entry->list);
+               context = entry->context;
+               kfree(entry);
+               break;
+       }
+       spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+       if (!context)
+               printk(KERN_WARNING "i2o: Could not remove nonexistent ptr "
+                      "%p\n", ptr);
+
+       pr_debug("remove ptr from context list %d -> %p\n", context, ptr);
+
+       return context;
+};
+
+/**
+ *      i2o_cntxt_list_get - Get a pointer from the context list and remove it
+ *     @c: controller to which the context list belong
+ *     @context: context id to which the pointer belong
+ *
+ *     Returns pointer to the matching context id on success or NULL on
+ *     failure.
+ */
+void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
+{
+       struct i2o_context_list_element *entry;
+       unsigned long flags;
+       void *ptr = NULL;
+
+       spin_lock_irqsave(&c->context_list_lock, flags);
+       list_for_each_entry(entry, &c->context_list, list)
+           if (entry->context == context) {
+               list_del(&entry->list);
+               ptr = entry->ptr;
+               kfree(entry);
+               break;
+       }
+       spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+       if (!ptr)
+               printk(KERN_WARNING "i2o: context id %d not found\n", context);
+
+       pr_debug("get ptr from context list %d -> %p\n", context, ptr);
+
+       return ptr;
+};
+
+/**
+ *      i2o_cntxt_list_get_ptr - Get a context id from the context list
+ *     @c: controller to which the context list belong
+ *     @ptr: pointer to which the context id should be fetched
+ *
+ *     Returns context id which matches to the pointer on succes or 0 on
+ *     failure.
+ */
+u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
+{
+       struct i2o_context_list_element *entry;
+       u32 context = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->context_list_lock, flags);
+       list_for_each_entry(entry, &c->context_list, list)
+           if (entry->ptr == ptr) {
+               context = entry->context;
+               break;
+       }
+       spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+       if (!context)
+               printk(KERN_WARNING "i2o: Could not find nonexistent ptr "
+                      "%p\n", ptr);
+
+       pr_debug("get context id from context list %p -> %d\n", ptr, context);
+
+       return context;
+};
+#endif
+
+/**
+ *     i2o_iop_find - Find an I2O controller by id
+ *     @unit: unit number of the I2O controller to search for
+ *
+ *     Lookup the I2O controller on the controller list.
+ *
+ *     Returns pointer to the I2O controller on success or NULL if not found.
+ */
+struct i2o_controller *i2o_find_iop(int unit)
+{
+       struct i2o_controller *c;
+
+       list_for_each_entry(c, &i2o_controllers, list) {
+               if (c->unit == unit)
+                       return c;
+       }
+
+       return NULL;
+};
+
+/**
+ *     i2o_iop_find_device - Find a I2O device on an I2O controller
+ *     @c: I2O controller where the I2O device hangs on
+ *     @tid: TID of the I2O device to search for
+ *
+ *     Searches the devices of the I2O controller for a device with TID tid and
+ *     returns it.
+ *
+ *     Returns a pointer to the I2O device if found, otherwise NULL.
+ */
+struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid)
+{
+       struct i2o_device *dev;
+
+       list_for_each_entry(dev, &c->devices, list)
+           if (dev->lct_data.tid == tid)
+               return dev;
+
+       return NULL;
+};
+
+/**
+ *     i2o_quiesce_controller - quiesce controller
+ *     @c: controller
+ *
+ *     Quiesce an IOP. Causes IOP to make external operation quiescent
+ *     (i2o 'READY' state). Internal operation of the IOP continues normally.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_quiesce(struct i2o_controller *c)
+{
+       struct i2o_message *msg;
+       u32 m;
+       i2o_status_block *sb = c->status_block.virt;
+       int rc;
+
+       i2o_status_get(c);
+
+       /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+       if ((sb->iop_state != ADAPTER_STATE_READY) &&
+           (sb->iop_state != ADAPTER_STATE_OPERATIONAL))
+               return 0;
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+
+       /* 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);
+       else
+               pr_debug("%s: Quiesced.\n", c->name);
+
+       i2o_status_get(c);      // Entered READY state
+
+       return rc;
+};
+
+/**
+ *     i2o_iop_enable - move controller from ready to OPERATIONAL
+ *     @c: I2O controller
+ *
+ *     Enable IOP. This allows the IOP to resume external operations and
+ *     reverses the effect of a quiesce. Returns zero or an error code if
+ *     an error occurs.
+ */
+static int i2o_iop_enable(struct i2o_controller *c)
+{
+       struct i2o_message *msg;
+       u32 m;
+       i2o_status_block *sb = c->status_block.virt;
+       int rc;
+
+       i2o_status_get(c);
+
+       /* Enable only allowed on READY state */
+       if (sb->iop_state != ADAPTER_STATE_READY)
+               return -EINVAL;
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+
+       /* 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);
+       else
+               pr_debug("%s: Enabled.\n", c->name);
+
+       i2o_status_get(c);      // entered OPERATIONAL state
+
+       return rc;
+};
+
+/**
+ *     i2o_iop_quiesce_all - Quiesce all I2O controllers on the system
+ *
+ *     Quiesce all I2O controllers which are connected to the system.
+ */
+static inline void i2o_iop_quiesce_all(void)
+{
+       struct i2o_controller *c, *tmp;
+
+       list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
+               if (!c->no_quiesce)
+                       i2o_iop_quiesce(c);
+       }
+};
+
+/**
+ *     i2o_iop_enable_all - Enables all controllers on the system
+ *
+ *     Enables all I2O controllers which are connected to the system.
+ */
+static inline void i2o_iop_enable_all(void)
+{
+       struct i2o_controller *c, *tmp;
+
+       list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
+           i2o_iop_enable(c);
+};
+
+/**
+ *     i2o_clear_controller - Bring I2O controller into HOLD state
+ *     @c: controller
+ *
+ *     Clear an IOP to HOLD state, ie. terminate external operations, clear all
+ *     input queues and prepare for a system restart. IOP's internal operation
+ *     continues normally and the outbound queue is alive. The IOP is not
+ *     expected to rebuild its LCT.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_clear(struct i2o_controller *c)
+{
+       struct i2o_message *msg;
+       u32 m;
+       int rc;
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       /* Quiesce all IOPs first */
+       i2o_iop_quiesce_all();
+
+       writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &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);
+       else
+               pr_debug("%s: Cleared.\n", c->name);
+
+       /* Enable all IOPs */
+       i2o_iop_enable_all();
+
+       i2o_status_get(c);
+
+       return rc;
+}
+
+/**
+ *     i2o_iop_reset - reset an I2O controller
+ *     @c: controller to reset
+ *
+ *     Reset the IOP into INIT state and wait until IOP gets into RESET state.
+ *     Terminate all external operations, clear IOP's inbound and outbound
+ *     queues, terminate all DDMs, and reload the IOP's operating environment
+ *     and all local DDMs. The IOP rebuilds its LCT.
+ */
+static int i2o_iop_reset(struct i2o_controller *c)
+{
+       u8 *status = c->status.virt;
+       struct i2o_message *msg;
+       u32 m;
+       unsigned long timeout;
+       i2o_status_block *sb = c->status_block.virt;
+       int rc = 0;
+
+       pr_debug("Resetting controller\n");
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       memset(status, 0, 4);
+
+       /* Quiesce all IOPs first */
+       i2o_iop_quiesce_all();
+
+       writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+       writel(i2o_exec_driver.context, &msg->u.s.icntxt);
+       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]);
+
+       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 "IOP reset timeout.\n");
+                       rc = -ETIMEDOUT;
+                       goto exit;
+               }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+
+               rmb();
+       }
+
+       if (*status == 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.
+                */
+               pr_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 "IOP reset timeout.\n");
+                               rc = -ETIMEDOUT;
+                               goto exit;
+                       }
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(1);
+
+                       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;
+
+       /* 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);
+
+      exit:
+       /* Enable all IOPs */
+       i2o_iop_enable_all();
+
+       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.
+ */
+int i2o_iop_init_outbound_queue(struct i2o_controller *c)
+{
+       u8 *status = c->status.virt;
+       u32 m;
+       struct i2o_message *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);
+               m += MSG_FRAME_SIZE * 4;
+       }
+
+       return 0;
+}
+
+/**
+ *     i2o_iop_activate - Bring controller up to HOLD
+ *     @c: controller
+ *
+ *     This function brings an I2O controller into HOLD state. The adapter
+ *     is reset if necessary and then the queues and resource table are read.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_activate(struct i2o_controller *c)
+{
+       i2o_status_block *sb = c->status_block.virt;
+       int rc;
+       /* 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 "Unable to obtain status of %s, "
+                      "attempting a reset.\n", c->name);
+               if (i2o_iop_reset(c))
+                       return rc;
+       }
+
+       if (sb->i2o_version > I2OVER15) {
+               printk(KERN_ERR "%s: Not running vrs. 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;
+
+       case ADAPTER_STATE_READY:
+       case ADAPTER_STATE_OPERATIONAL:
+       case ADAPTER_STATE_HOLD:
+       case ADAPTER_STATE_FAILED:
+               pr_debug("already running, trying to reset...\n");
+               if (i2o_iop_reset(c))
+                       return -ENODEV;
+       }
+
+       rc = i2o_iop_init_outbound_queue(c);
+       if (rc)
+               return rc;
+
+       /* In HOLD state */
+
+       rc = i2o_hrt_get(c);
+       if (rc)
+               return rc;
+
+       return 0;
+};
+
+/**
+ *     i2o_iop_systab_set - Set the I2O System Table of the specified IOP
+ *     @c: I2O controller to which the system table should be send
+ *
+ *     Before the systab could be set i2o_systab_build() must be called.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_systab_set(struct i2o_controller *c)
+{
+       struct i2o_message *msg;
+       u32 m;
+       i2o_status_block *sb = c->status_block.virt;
+       struct device *dev = &c->pdev->dev;
+       struct resource *root;
+       int rc;
+
+       if (sb->current_mem_size < sb->desired_mem_size) {
+               struct resource *res = &c->mem_resource;
+               res->name = c->pdev->bus->name;
+               res->flags = IORESOURCE_MEM;
+               res->start = 0;
+               res->end = 0;
+               printk("%s: requires private memory resources.\n", c->name);
+               root = pci_find_parent_resource(c->pdev, res);
+               if (root == NULL)
+                       printk("Can't find parent resource!\n");
+               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);
+               }
+       }
+
+       if (sb->current_io_size < sb->desired_io_size) {
+               struct resource *res = &c->io_resource;
+               res->name = c->pdev->bus->name;
+               res->flags = IORESOURCE_IO;
+               res->start = 0;
+               res->end = 0;
+               printk("%s: requires private memory resources.\n", c->name);
+               root = pci_find_parent_resource(c->pdev, res);
+               if (root == NULL)
+                       printk("Can't find parent resource!\n");
+               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);
+               }
+       }
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len,
+                                        PCI_DMA_TODEVICE);
+       if (!i2o_systab.phys) {
+               i2o_msg_nop(c, m);
+               return -ENOMEM;
+       }
+
+       writel(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6, &msg->u.head[0]);
+       writel(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+
+       /*
+        * Provide three SGL-elements:
+        * System table (SysTab), Private memory space declaration and
+        * Private i/o space declaration
+        *
+        * FIXME: is this still true?
+        * Nasty one here. We can't use dma_alloc_coherent to send the
+        * same table to everyone. We have to go remap it for them all
+        */
+
+       writel(c->unit + 2, &msg->body[0]);
+       writel(0, &msg->body[1]);
+       writel(0x54000000 | i2o_systab.phys, &msg->body[2]);
+       writel(i2o_systab.phys, &msg->body[3]);
+       writel(0x54000000 | sb->current_mem_size, &msg->body[4]);
+       writel(sb->current_mem_base, &msg->body[5]);
+       writel(0xd4000000 | sb->current_io_size, &msg->body[6]);
+       writel(sb->current_io_base, &msg->body[6]);
+
+       rc = i2o_msg_post_wait(c, m, 120);
+
+       dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len,
+                        PCI_DMA_TODEVICE);
+
+       if (rc < 0)
+               printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n",
+                      c->name, -rc);
+       else
+               pr_debug("%s: SysTab set.\n", c->name);
+
+       i2o_status_get(c);      // Entered READY state
+
+       return rc;
+}
+
+/**
+ *     i2o_iop_online - Bring a controller online into OPERATIONAL state.
+ *     @c: I2O controller
+ *
+ *     Send the system table and enable the I2O controller.
+ *
+ *     Returns 0 on success or negativer error code on failure.
+ */
+static int i2o_iop_online(struct i2o_controller *c)
+{
+       int rc;
+
+       rc = i2o_iop_systab_set(c);
+       if (rc)
+               return rc;
+
+       /* In READY state */
+       pr_debug("%s: Attempting to enable...\n", c->name);
+       rc = i2o_iop_enable(c);
+       if (rc)
+               return rc;
+
+       return 0;
+};
+
+/**
+ *     i2o_iop_remove - Remove the I2O controller from the I2O core
+ *     @c: I2O controller
+ *
+ *     Remove the I2O controller from the I2O core. If devices are attached to
+ *     the controller remove these also and finally reset the controller.
+ */
+void i2o_iop_remove(struct i2o_controller *c)
+{
+       struct i2o_device *dev, *tmp;
+
+       pr_debug("Deleting controller %s\n", c->name);
+
+       i2o_driver_notify_controller_remove_all(c);
+
+       list_del(&c->list);
+
+       list_for_each_entry_safe(dev, tmp, &c->devices, list)
+           i2o_device_remove(dev);
+
+       /* Ask the IOP to switch to RESET state */
+       i2o_iop_reset(c);
+}
+
+/**
+ *     i2o_systab_build - Build system table
+ *
+ *     The system table contains information about all the IOPs in the system
+ *     (duh) and is used by the Executives on the IOPs to establish peer2peer
+ *     connections. We're not supporting peer2peer at the moment, but this
+ *     will be needed down the road for things like lan2lan forwarding.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_systab_build(void)
+{
+       struct i2o_controller *c, *tmp;
+       int num_controllers = 0;
+       u32 change_ind = 0;
+       int count = 0;
+       struct i2o_sys_tbl *systab = i2o_systab.virt;
+
+       list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
+           num_controllers++;
+
+       if (systab) {
+               change_ind = systab->change_ind;
+               kfree(i2o_systab.virt);
+       }
+
+       /* Header + IOPs */
+       i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers *
+           sizeof(struct i2o_sys_tbl_entry);
+
+       systab = i2o_systab.virt = kmalloc(i2o_systab.len, GFP_KERNEL);
+       if (!systab) {
+               printk(KERN_ERR "i2o: unable to allocate memory for System "
+                      "Table\n");
+               return -ENOMEM;
+       }
+       memset(systab, 0, i2o_systab.len);
+
+       systab->version = I2OVERSION;
+       systab->change_ind = change_ind + 1;
+
+       list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
+               i2o_status_block *sb;
+
+               if (count >= num_controllers) {
+                       printk(KERN_ERR "i2o: controller added while building "
+                              "system table\n");
+                       break;
+               }
+
+               sb = c->status_block.virt;
+
+               /*
+                * Get updated IOP state so we have the latest information
+                *
+                * We should delete the controller at this point if it
+                * doesn't respond since if it's not on the system table
+                * 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);
+                       i2o_iop_remove(c);
+                       continue;       // try the next one
+               }
+
+               systab->iops[count].org_id = sb->org_id;
+               systab->iops[count].iop_id = c->unit + 2;
+               systab->iops[count].seg_num = 0;
+               systab->iops[count].i2o_version = sb->i2o_version;
+               systab->iops[count].iop_state = sb->iop_state;
+               systab->iops[count].msg_type = sb->msg_type;
+               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);
+
+               count++;
+       }
+
+       systab->num_entries = count;
+
+       return 0;
+};
+
+/**
+ *     i2o_parse_hrt - Parse the hardware resource table.
+ *     @c: I2O controller
+ *
+ *     We don't do anything with it except dumping it (in debug mode).
+ *
+ *     Returns 0.
+ */
+static int i2o_parse_hrt(struct i2o_controller *c)
+{
+       i2o_dump_hrt(c);
+       return 0;
+};
+
+/**
+ *     i2o_status_get - Get the status block from the I2O controller
+ *     @c: I2O controller
+ *
+ *     Issue a status query on the controller. This updates the attached
+ *     status block. The status block could then be accessed through
+ *     c->status_block.
+ *
+ *     Returns 0 on sucess or negative error code on failure.
+ */
+int i2o_status_get(struct i2o_controller *c)
+{
+       struct i2o_message *msg;
+       u32 m;
+       u8 *status_block;
+       unsigned long timeout;
+
+       status_block = (u8 *) c->status_block.virt;
+       memset(status_block, 0, sizeof(i2o_status_block));
+
+       m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+       if (m == I2O_QUEUE_EMPTY)
+               return -ETIMEDOUT;
+
+       writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
+       writel(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 | ADAPTER_TID,
+              &msg->u.head[1]);
+       writel(i2o_exec_driver.context, &msg->u.s.icntxt);
+       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(sizeof(i2o_status_block), &msg->body[4]);        /* always 88 bytes */
+
+       i2o_msg_post(c, m);
+
+       /* Wait for a reply */
+       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);
+                       return -ETIMEDOUT;
+               }
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+
+               rmb();
+       }
+
+#ifdef DEBUG
+       i2o_debug_state(c);
+#endif
+
+       return 0;
+}
+
+/*
+ *     i2o_hrt_get - Get the Hardware Resource Table from the I2O controller
+ *     @c: I2O controller from which the HRT should be fetched
+ *
+ *     The HRT contains information about possible hidden devices but is
+ *     mostly useless to us.
+ *
+ *     Returns 0 on success or negativer error code on failure.
+ */
+int i2o_hrt_get(struct i2o_controller *c)
+{
+       int rc;
+       int i;
+       i2o_hrt *hrt = c->hrt.virt;
+       u32 size = sizeof(i2o_hrt);
+       struct device *dev = &c->pdev->dev;
+
+       for (i = 0; i < I2O_HRT_GET_TRIES; i++) {
+               struct i2o_message *msg;
+               u32 m;
+
+               m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+               if (m == I2O_QUEUE_EMPTY)
+                       return -ETIMEDOUT;
+
+               writel(SIX_WORD_MSG_SIZE | SGL_OFFSET_4, &msg->u.head[0]);
+               writel(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 | ADAPTER_TID,
+                      &msg->u.head[1]);
+               writel(0xd0000000 | c->hrt.len, &msg->body[0]);
+               writel(c->hrt.phys, &msg->body[1]);
+
+               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);
+                       return rc;
+               }
+
+               size = hrt->num_entries * hrt->entry_len << 2;
+               if (size > c->hrt.len) {
+                       if (i2o_dma_realloc(dev, &c->hrt, size, GFP_KERNEL))
+                               return -ENOMEM;
+                       else
+                               hrt = c->hrt.virt;
+               } else
+                       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);
+
+       return -EBUSY;
+}
+
+/**
+ *     i2o_iop_alloc - Allocate and initialize a i2o_controller struct
+ *
+ *     Allocate the necessary memory for a i2o_controller struct and
+ *     initialize the lists.
+ *
+ *     Returns a pointer to the I2O controller or a negative error code on
+ *     failure.
+ */
+struct i2o_controller *i2o_iop_alloc(void)
+{
+       static int unit = 0;    /* 0 and 1 are NULL IOP and Local Host */
+       struct i2o_controller *c;
+
+       c = kmalloc(sizeof(*c), GFP_KERNEL);
+       if (!c) {
+               printk(KERN_ERR "i2o: Insufficient memory to allocate the "
+                      "controller.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       memset(c, 0, sizeof(*c));
+
+       INIT_LIST_HEAD(&c->devices);
+       c->lock = SPIN_LOCK_UNLOCKED;
+       init_MUTEX(&c->lct_lock);
+       c->unit = unit++;
+       sprintf(c->name, "iop%d", c->unit);
+
+#if BITS_PER_LONG == 64
+       c->context_list_lock = SPIN_LOCK_UNLOCKED;
+       atomic_set(&c->context_list_counter, 0);
+       INIT_LIST_HEAD(&c->context_list);
+#endif
+
+       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
+ *
+ *     Initialize the I2O controller and if no error occurs add him to the I2O
+ *     core.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+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 = i2o_iop_activate(c))) {
+               printk(KERN_ERR "%s: controller could not activated\n",
+                      c->name);
+               i2o_iop_reset(c);
+               return rc;
+       }
+
+       pr_debug("building sys table %s...\n", c->name);
+
+       if ((rc = i2o_systab_build())) {
+               i2o_iop_reset(c);
+               return rc;
+       }
+
+       pr_debug("online controller %s...\n", c->name);
+
+       if ((rc = i2o_iop_online(c))) {
+               i2o_iop_reset(c);
+               return rc;
+       }
+
+       pr_debug("getting LCT %s...\n", c->name);
+
+       if ((rc = i2o_exec_lct_get(c))) {
+               i2o_iop_reset(c);
+               return rc;
+       }
+
+       list_add(&c->list, &i2o_controllers);
+
+       i2o_driver_notify_controller_add_all(c);
+
+       printk(KERN_INFO "%s: Controller added\n", c->name);
+
+       return 0;
+};
+
+/**
+ *     i2o_event_register - Turn on/off event notification for a I2O device
+ *     @dev: I2O device which should receive the event registration request
+ *     @drv: driver which want to get notified
+ *     @tcntxt: transaction context to use with this notifier
+ *     @evt_mask: mask of events
+ *
+ *     Create and posts an event registration message to the task. No reply
+ *     is waited for, or expected. If you do not want further notifications,
+ *     call the i2o_event_register again with a evt_mask of 0.
+ *
+ *     Returns 0 on success or -ETIMEDOUT if no message could be fetched for
+ *     sending the request.
+ */
+int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv,
+                      int tcntxt, u32 evt_mask)
+{
+       struct i2o_controller *c = dev->iop;
+       struct i2o_message *msg;
+       u32 m;
+
+       m = i2o_msg_get_wait(c, &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_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->lct_data.
+              tid, &msg->u.head[1]);
+       writel(drv->context, &msg->u.s.icntxt);
+       writel(tcntxt, &msg->u.s.tcntxt);
+       writel(evt_mask, &msg->body[0]);
+
+       i2o_msg_post(c, m);
+
+       return 0;
+};
+
+/**
+ *     i2o_iop_init - I2O main initialization function
+ *
+ *     Initialize the I2O drivers (OSM) functions, register the Executive OSM,
+ *     initialize the I2O PCI part and finally initialize I2O device stuff.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_iop_init(void)
+{
+       int rc = 0;
+
+       printk(KERN_INFO "I2O Core - (C) Copyright 1999 Red Hat Software\n");
+
+       rc = i2o_device_init();
+       if (rc)
+               goto exit;
+
+       rc = i2o_driver_init();
+       if (rc)
+               goto device_exit;
+
+       rc = i2o_exec_init();
+       if (rc)
+               goto driver_exit;
+
+       rc = i2o_pci_init();
+       if (rc < 0)
+               goto exec_exit;
+
+       return 0;
+
+      exec_exit:
+       i2o_exec_exit();
+
+      driver_exit:
+       i2o_driver_exit();
+
+      device_exit:
+       i2o_device_exit();
+
+      exit:
+       return rc;
+}
+
+/**
+ *     i2o_iop_exit - I2O main exit function
+ *
+ *     Removes I2O controllers from PCI subsystem and shut down OSMs.
+ */
+static void __exit i2o_iop_exit(void)
+{
+       i2o_pci_exit();
+       i2o_exec_exit();
+       i2o_driver_exit();
+       i2o_device_exit();
+};
+
+module_init(i2o_iop_init);
+module_exit(i2o_iop_exit);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_DESCRIPTION("I2O Core");
+MODULE_LICENSE("GPL");
+
+#if BITS_PER_LONG == 64
+EXPORT_SYMBOL(i2o_cntxt_list_add);
+EXPORT_SYMBOL(i2o_cntxt_list_get);
+EXPORT_SYMBOL(i2o_cntxt_list_remove);
+EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
+#endif
+EXPORT_SYMBOL(i2o_msg_get_wait);
+EXPORT_SYMBOL(i2o_msg_nop);
+EXPORT_SYMBOL(i2o_find_iop);
+EXPORT_SYMBOL(i2o_iop_find_device);
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_status_get);
+EXPORT_SYMBOL(i2o_hrt_get);
+EXPORT_SYMBOL(i2o_controllers);
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
new file mode 100644 (file)
index 0000000..9ee58b6
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ *     PCI handling of I2O controller
+ *
+ *     Copyright (C) 1999-2002 Red Hat Software
+ *
+ *     Written by Alan Cox, Building Number Three Ltd
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     A lot of the I2O message side code from this is taken from the Red
+ *     Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ *     Fixes/additions:
+ *             Philipp Rumpf
+ *             Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ *             Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ *             Deepak Saxena <deepak@plexity.net>
+ *             Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ *             Alan Cox <alan@redhat.com>:
+ *                     Ported to Linux 2.5.
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *                     Minor fixes for 2.6.
+ *             Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ *                     Support for sysfs included.
+ */
+
+#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 *);
+
+/* 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)},
+       {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
+ *
+ *     Remove all allocated DMA memory and unmap memory IO regions. If MTRR
+ *     is enabled, also remove it again.
+ */
+static void __devexit i2o_pci_free(struct i2o_controller *c)
+{
+       struct device *dev;
+
+       dev = &c->pdev->dev;
+
+       i2o_dma_free(dev, &c->out_queue);
+       i2o_dma_free(dev, &c->status_block);
+       if (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);
+
+       if (c->base.virt)
+               iounmap(c->base.virt);
+}
+
+/**
+ *     i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller
+ *     @c: I2O controller
+ *
+ *     Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All
+ *     IO mappings are also done here. If MTRR is enabled, also do add memory
+ *     regions here.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int __devinit i2o_pci_alloc(struct i2o_controller *c)
+{
+       struct pci_dev *pdev = c->pdev;
+       struct device *dev = &pdev->dev;
+       int i;
+
+       for (i = 0; i < 6; i++) {
+               /* Skip I/O spaces */
+               if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+                       if (!c->base.phys) {
+                               c->base.phys = pci_resource_start(pdev, i);
+                               c->base.len = pci_resource_len(pdev, i);
+
+                               /*
+                                * If we know what card it is, set the size
+                                * correctly. Code is taken from dpt_i2o.c
+                                */
+                               if(pdev->device == 0xa501) {
+                                       if(pdev->subsystem_device >= 0xc032 &&
+                                          pdev->subsystem_device <= 0xc03b) {
+                                               if(c->base.len > 0x400000)
+                                                       c->base.len = 0x400000;
+                                       } else {
+                                               if(c->base.len > 0x100000)
+                                                       c->base.len = 0x100000;
+                                       }
+                               }
+                               if (!c->raptor)
+                                       break;
+                       } else {
+                               c->in_queue.phys = pci_resource_start(pdev, i);
+                               c->in_queue.len = pci_resource_len(pdev, i);
+                               break;
+                       }
+               }
+       }
+
+       if (i == 6) {
+               printk(KERN_ERR "i2o: I2O controller has no memory regions"
+                      " defined.\n");
+               i2o_pci_free(c);
+               return -EINVAL;
+       }
+
+       /* Map the I2O controller */
+       if (c->raptor) {
+               printk(KERN_INFO "i2o: PCI I2O controller\n");
+               printk(KERN_INFO "     BAR0 at 0x%08lX size=%ld\n",
+                      (unsigned long)c->base.phys, (unsigned long)c->base.len);
+               printk(KERN_INFO "     BAR1 at 0x%08lX size=%ld\n",
+                      (unsigned long)c->in_queue.phys,
+                      (unsigned long)c->in_queue.len);
+       } else
+               printk(KERN_INFO "i2o: PCI I2O controller at %08lX size=%ld\n",
+                      (unsigned long)c->base.phys, (unsigned long)c->base.len);
+
+       c->base.virt = ioremap(c->base.phys, c->base.len);
+       if (!c->base.virt) {
+               printk(KERN_ERR "i2o: Unable to map controller.\n");
+               return -ENOMEM;
+       }
+
+       if (c->raptor) {
+               c->in_queue.virt = ioremap(c->in_queue.phys, c->in_queue.len);
+               if (!c->in_queue.virt) {
+                       printk(KERN_ERR "i2o: Unable to map controller.\n");
+                       i2o_pci_free(c);
+                       return -ENOMEM;
+               }
+       } 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 "i2o: could not enable write combining "
+                      "MTRR\n");
+       else
+               printk(KERN_INFO "i2o: using write combining MTRR\n");
+
+       /*
+        * 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 "i2o: MTRR workaround for Intel i960 processor"
+                      "\n");
+               c->mtrr_reg1 = mtrr_add(c->base.phys, 0x10000,
+                                       MTRR_TYPE_UNCACHABLE, 1);
+
+               if (c->mtrr_reg1 < 0) {
+                       printk(KERN_WARNING "i2o_pci: Error in setting "
+                              "MTRR_TYPE_UNCACHABLE\n");
+                       mtrr_del(c->mtrr_reg0, c->in_queue.phys,
+                                c->in_queue.len);
+                       c->mtrr_reg0 = -1;
+               }
+       }
+#endif
+
+       if (i2o_dma_alloc(dev, &c->status, 4, GFP_KERNEL)) {
+               i2o_pci_free(c);
+               return -ENOMEM;
+       }
+
+       if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) {
+               i2o_pci_free(c);
+               return -ENOMEM;
+       }
+
+       if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) {
+               i2o_pci_free(c);
+               return -ENOMEM;
+       }
+
+       if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block),
+                         GFP_KERNEL)) {
+               i2o_pci_free(c);
+               return -ENOMEM;
+       }
+
+       if (i2o_dma_alloc(dev, &c->out_queue, MSG_POOL_SIZE, GFP_KERNEL)) {
+               i2o_pci_free(c);
+               return -ENOMEM;
+       }
+
+       pci_set_drvdata(pdev, c);
+
+       return 0;
+}
+
+/**
+ *     i2o_pci_interrupt - Interrupt handler for I2O controller
+ *     @irq: interrupt line
+ *     @dev_id: pointer to the I2O controller
+ *     @r: pointer to registers
+ *
+ *     Handle an interrupt from a PCI based I2O controller. This turns out
+ *     to be rather simple. We keep the controller pointer in the cookie.
+ */
+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;
+       u32 *msg;
+
+       /*
+        * 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("960 bug detected\n");
+       }
+
+       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 = (struct i2o_message *)(mv -
+                                          (unsigned long)c->out_queue.phys +
+                                          (unsigned long)c->out_queue.virt);
+
+               msg = (u32 *) m;
+
+               /*
+                *      Ensure this message is seen coherently but cachably by
+                *      the processor
+                */
+               dma_sync_single_for_cpu(dev, c->out_queue.phys, MSG_FRAME_SIZE,
+                                       PCI_DMA_FROMDEVICE);
+
+               /* dispatch it */
+               if (i2o_driver_dispatch(c, mv, m))
+                       /* flush it if result != 0 */
+                       i2o_flush_reply(c, mv);
+
+               /*
+                * That 960 bug again...
+                */
+               mv = I2O_REPLY_READ32(c);
+               if (mv == I2O_QUEUE_EMPTY)
+                       mv = I2O_REPLY_READ32(c);
+       }
+       return IRQ_HANDLED;
+}
+
+/**
+ *     i2o_pci_irq_enable - Allocate interrupt for I2O controller
+ *
+ *     Allocate an interrupt for the I2O controller, and activate interrupts
+ *     on the I2O controller.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_irq_enable(struct i2o_controller *c)
+{
+       struct pci_dev *pdev = c->pdev;
+       int rc;
+
+       I2O_IRQ_WRITE32(c, 0xffffffff);
+
+       if (pdev->irq) {
+               rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ,
+                                c->name, c);
+               if (rc < 0) {
+                       printk(KERN_ERR "%s: unable to allocate interrupt %d."
+                              "\n", c->name, pdev->irq);
+                       return rc;
+               }
+       }
+
+       I2O_IRQ_WRITE32(c, 0x00000000);
+
+       printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
+
+       return 0;
+}
+
+/**
+ *     i2o_pci_irq_disable - Free interrupt for I2O controller
+ *     @c: I2O controller
+ *
+ *     Disable interrupts in I2O controller and then free interrupt.
+ */
+static void i2o_pci_irq_disable(struct i2o_controller *c)
+{
+       I2O_IRQ_WRITE32(c, 0xffffffff);
+
+       if (c->pdev->irq > 0)
+               free_irq(c->pdev->irq, c);
+}
+
+/**
+ *     i2o_pci_probe - Probe the PCI device for an I2O controller
+ *     @dev: PCI device to test
+ *     @id: id which matched with the PCI device id table
+ *
+ *     Probe the PCI device for any device which is a memory of the
+ *     Intelligent, I2O class or an Adaptec Zero Channel Controller. We
+ *     attempt to set up each such device and register it with the core.
+ *
+ *     Returns 0 on success or negative error code on failure.
+ */
+static int __devinit i2o_pci_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *id)
+{
+       struct i2o_controller *c;
+       int rc;
+
+       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");
+               return -ENODEV;
+       }
+
+       if ((rc = pci_enable_device(pdev))) {
+               printk(KERN_WARNING "i2o: I2O controller found but could not be"
+                      " enabled.\n");
+               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);
+               rc = -ENODEV;
+               goto disable;
+       }
+
+       pci_set_master(pdev);
+
+       c = i2o_iop_alloc();
+       if (IS_ERR(c)) {
+               printk(KERN_ERR "i2o: memory for I2O controller could not be "
+                      "allocated\n");
+               rc = PTR_ERR(c);
+               goto disable;
+       }
+
+       c->pdev = pdev;
+       c->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) {
+               c->short_req = 1;
+               printk(KERN_INFO "i2o: Symbios FC920 workarounds activated.\n");
+       }
+
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
+               c->promise = 1;
+               printk(KERN_INFO "i2o: Promise workarounds activated.\n");
+       }
+
+       /* 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 ((rc = i2o_pci_alloc(c))) {
+               printk(KERN_ERR "i2o: DMA / IO allocation for I2O controller "
+                      " failed\n");
+               goto free_controller;
+       }
+
+       if (i2o_pci_irq_enable(c)) {
+               printk(KERN_ERR "i2o: unable to enable interrupts for I2O "
+                      "controller\n");
+               goto free_pci;
+       }
+
+       if ((rc = i2o_iop_add(c)))
+               goto uninstall;
+
+       return 0;
+
+      uninstall:
+       i2o_pci_irq_disable(c);
+
+      free_pci:
+       i2o_pci_free(c);
+
+      free_controller:
+       i2o_iop_free(c);
+
+      disable:
+       pci_disable_device(pdev);
+
+       return rc;
+}
+
+/**
+ *     i2o_pci_remove - Removes a I2O controller from the system
+ *     pdev: I2O controller which should be removed
+ *
+ *     Reset the I2O controller, disable interrupts and remove all allocated
+ *     resources.
+ */
+static void __devexit i2o_pci_remove(struct pci_dev *pdev)
+{
+       struct i2o_controller *c;
+       c = pci_get_drvdata(pdev);
+
+       i2o_iop_remove(c);
+       i2o_pci_irq_disable(c);
+       i2o_pci_free(c);
+
+       printk(KERN_INFO "%s: Controller removed.\n", c->name);
+
+       i2o_iop_free(c);
+       pci_disable_device(pdev);
+};
+
+/* PCI driver for I2O controller */
+static struct pci_driver i2o_pci_driver = {
+       .name = "I2O controller",
+       .id_table = i2o_pci_ids,
+       .probe = i2o_pci_probe,
+       .remove = __devexit_p(i2o_pci_remove),
+};
+
+/**
+ *     i2o_pci_init - registers I2O PCI driver in PCI subsystem
+ *
+ *     Returns > 0 on success or negative error code on failure.
+ */
+int __init i2o_pci_init(void)
+{
+       return pci_register_driver(&i2o_pci_driver);
+};
+
+/**
+ *     i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem
+ */
+void __exit i2o_pci_exit(void)
+{
+       pci_unregister_driver(&i2o_pci_driver);
+};
+
+EXPORT_SYMBOL(i2o_dma_realloc);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
new file mode 100644 (file)
index 0000000..6b1b517
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# MMC subsystem configuration
+#
+
+menu "MMC/SD Card support"
+
+config MMC
+       tristate "MMC support"
+       help
+         MMC is the "multi-media card" bus protocol.
+
+         If you want MMC support, you should say Y here and also
+         to the specific driver for your MMC interface.
+
+config MMC_DEBUG
+       bool "MMC debugging"
+       depends on MMC != n
+       help
+         This is an option for use by developers; most people should
+         say N here.  This enables MMC core and driver debugging.
+
+config MMC_BLOCK
+       tristate "MMC block device driver"
+       depends on MMC
+       default y
+       help
+         Say Y here to enable the MMC block device driver support.
+         This provides a block device driver, which you can use to
+         mount the filesystem. Almost everyone wishing MMC support
+         should say Y or M here.
+
+config MMC_ARMMMCI
+       tristate "ARM AMBA Multimedia Card Interface support"
+       depends on ARM_AMBA && MMC
+       help
+         This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
+         Interface (PL180 and PL181) support.  If you have an ARM(R)
+         platform with a Multimedia Card slot, say Y or M here.
+
+         If unsure, say N.
+
+config MMC_PXA
+       tristate "Intel PXA255 Multimedia Card Interface support"
+       depends on ARCH_PXA && MMC
+       help
+         This selects the Intel(R) PXA(R) Multimedia card Interface.
+         If you have a PXA(R) platform with a Multimedia Card slot,
+         say Y or M here.
+
+         If unsure, say N.
+
+endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
new file mode 100644 (file)
index 0000000..def0111
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# Makefile for the kernel mmc device drivers.
+#
+
+#
+# Core
+#
+obj-$(CONFIG_MMC)              += mmc_core.o
+
+#
+# Media drivers
+#
+obj-$(CONFIG_MMC_BLOCK)                += mmc_block.o
+
+#
+# Host drivers
+#
+obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
+obj-$(CONFIG_MMC_PXA)          += pxamci.o
+
+mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
new file mode 100644 (file)
index 0000000..5c3d848
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+ *  linux/drivers/mmc/mmc.c
+ *
+ *  Copyright (C) 2003-2004 Russell King, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include "mmc.h"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...)      printk(KERN_DEBUG x)
+#else
+#define DBG(x...)      do { } while (0)
+#endif
+
+#define CMD_RETRIES    3
+
+/*
+ * OCR Bit positions to 10s of Vdd mV.
+ */
+static const unsigned short mmc_ocr_bit_to_vdd[] = {
+       150,    155,    160,    165,    170,    180,    190,    200,
+       210,    220,    230,    240,    250,    260,    270,    280,
+       290,    300,    310,    320,    330,    340,    350,    360
+};
+
+static const unsigned int tran_exp[] = {
+       10000,          100000,         1000000,        10000000,
+       0,              0,              0,              0
+};
+
+static const unsigned char tran_mant[] = {
+       0,      10,     12,     13,     15,     20,     25,     30,
+       35,     40,     45,     50,     55,     60,     70,     80,
+};
+
+static const unsigned int tacc_exp[] = {
+       1,      10,     100,    1000,   10000,  100000, 1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+       0,      10,     12,     13,     15,     20,     25,     30,
+       35,     40,     45,     50,     55,     60,     70,     80,
+};
+
+
+/**
+ *     mmc_request_done - finish processing an MMC command
+ *     @host: MMC host which completed command
+ *     @mrq: MMC request which completed
+ *
+ *     MMC drivers should call this function when they have completed
+ *     their processing of a command.  This should be called before the
+ *     data part of the command has completed.
+ */
+void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+       struct mmc_command *cmd = mrq->cmd;
+       int err = mrq->cmd->error;
+       DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode,
+           err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+       if (err && cmd->retries) {
+               cmd->retries--;
+               cmd->error = 0;
+               host->ops->request(host, mrq);
+       } else if (mrq->done) {
+               mrq->done(mrq);
+       }
+}
+
+EXPORT_SYMBOL(mmc_request_done);
+
+/**
+ *     mmc_start_request - start a command on a host
+ *     @host: MMC host to start command on
+ *     @mrq: MMC request to start
+ *
+ *     Queue a command on the specified host.  We expect the
+ *     caller to be holding the host lock with interrupts disabled.
+ */
+void
+mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+{
+       DBG("MMC: starting cmd %02x arg %08x flags %08x\n",
+           mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
+
+       WARN_ON(host->card_busy == NULL);
+
+       mrq->cmd->error = 0;
+       mrq->cmd->mrq = mrq;
+       if (mrq->data) {
+               mrq->cmd->data = mrq->data;
+               mrq->data->error = 0;
+               mrq->data->mrq = mrq;
+               if (mrq->stop) {
+                       mrq->data->stop = mrq->stop;
+                       mrq->stop->error = 0;
+                       mrq->stop->mrq = mrq;
+               }
+       }
+       host->ops->request(host, mrq);
+}
+
+EXPORT_SYMBOL(mmc_start_request);
+
+static void mmc_wait_done(struct mmc_request *mrq)
+{
+       complete(mrq->done_data);
+}
+
+int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+       DECLARE_COMPLETION(complete);
+
+       mrq->done_data = &complete;
+       mrq->done = mmc_wait_done;
+
+       mmc_start_request(host, mrq);
+
+       wait_for_completion(&complete);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_req);
+
+/**
+ *     mmc_wait_for_cmd - start a command and wait for completion
+ *     @host: MMC host to start command
+ *     @cmd: MMC command to start
+ *     @retries: maximum number of retries
+ *
+ *     Start a new MMC command for a host, and wait for the command
+ *     to complete.  Return any error that occurred while the command
+ *     was executing.  Do not attempt to parse the response.
+ */
+int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
+{
+       struct mmc_request mrq;
+
+       BUG_ON(host->card_busy == NULL);
+
+       memset(&mrq, 0, sizeof(struct mmc_request));
+
+       memset(cmd->resp, 0, sizeof(cmd->resp));
+       cmd->retries = retries;
+
+       mrq.cmd = cmd;
+       cmd->data = NULL;
+
+       mmc_wait_for_req(host, &mrq);
+
+       return cmd->error;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_cmd);
+
+
+
+/**
+ *     __mmc_claim_host - exclusively claim a host
+ *     @host: mmc host to claim
+ *     @card: mmc card to claim host for
+ *
+ *     Claim a host for a set of operations.  If a valid card
+ *     is passed and this wasn't the last card selected, select
+ *     the card before returning.
+ *
+ *     Note: you should use mmc_card_claim_host or mmc_claim_host.
+ */
+int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long flags;
+       int err = 0;
+
+       add_wait_queue(&host->wq, &wait);
+       spin_lock_irqsave(&host->lock, flags);
+       while (1) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (host->card_busy == NULL)
+                       break;
+               spin_unlock_irqrestore(&host->lock, flags);
+               schedule();
+               spin_lock_irqsave(&host->lock, flags);
+       }
+       set_current_state(TASK_RUNNING);
+       host->card_busy = card;
+       spin_unlock_irqrestore(&host->lock, flags);
+       remove_wait_queue(&host->wq, &wait);
+
+       if (card != (void *)-1 && host->card_selected != card) {
+               struct mmc_command cmd;
+
+               host->card_selected = card;
+
+               cmd.opcode = MMC_SELECT_CARD;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R1;
+
+               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+       }
+
+       return err;
+}
+
+EXPORT_SYMBOL(__mmc_claim_host);
+
+/**
+ *     mmc_release_host - release a host
+ *     @host: mmc host to release
+ *
+ *     Release a MMC host, allowing others to claim the host
+ *     for their operations.
+ */
+void mmc_release_host(struct mmc_host *host)
+{
+       unsigned long flags;
+
+       BUG_ON(host->card_busy == NULL);
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->card_busy = NULL;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       wake_up(&host->wq);
+}
+
+EXPORT_SYMBOL(mmc_release_host);
+
+/*
+ * Ensure that no card is selected.
+ */
+static void mmc_deselect_cards(struct mmc_host *host)
+{
+       struct mmc_command cmd;
+
+       if (host->card_selected) {
+               host->card_selected = NULL;
+
+               cmd.opcode = MMC_SELECT_CARD;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_NONE;
+
+               mmc_wait_for_cmd(host, &cmd, 0);
+       }
+}
+
+
+static inline void mmc_delay(unsigned int ms)
+{
+       if (ms < HZ / 1000) {
+               yield();
+               mdelay(ms);
+       } else {
+               msleep_interruptible (ms);
+       }
+}
+
+/*
+ * Mask off any voltages we don't support and select
+ * the lowest voltage
+ */
+static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+{
+       int bit;
+
+       ocr &= host->ocr_avail;
+
+       bit = ffs(ocr);
+       if (bit) {
+               bit -= 1;
+
+               ocr = 3 << bit;
+
+               host->ios.vdd = bit;
+               host->ops->set_ios(host, &host->ios);
+       } else {
+               ocr = 0;
+       }
+
+       return ocr;
+}
+
+#define UNSTUFF_BITS(resp,start,size)                                  \
+       ({                                                              \
+               const u32 __mask = (1 << (size)) - 1;                   \
+               const int __off = 3 - ((start) / 32);                   \
+               const int __shft = (start) & 31;                        \
+               u32 __res;                                              \
+                                                                       \
+               __res = resp[__off] >> __shft;                          \
+               if ((size) + __shft >= 32)                              \
+                       __res |= resp[__off-1] << (32 - __shft);        \
+               __res & __mask;                                         \
+       })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static void mmc_decode_cid(struct mmc_card *card)
+{
+       u32 *resp = card->raw_cid;
+
+       memset(&card->cid, 0, sizeof(struct mmc_cid));
+
+       /*
+        * The selection of the format here is guesswork based upon
+        * information people have sent to date.
+        */
+       switch (card->csd.mmca_vsn) {
+       case 0: /* MMC v1.? */
+       case 1: /* MMC v1.4 */
+               card->cid.manfid        = UNSTUFF_BITS(resp, 104, 24);
+               card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
+               card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
+               card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
+               card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
+               card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
+               card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
+               card->cid.prod_name[6]  = UNSTUFF_BITS(resp, 48, 8);
+               card->cid.hwrev         = UNSTUFF_BITS(resp, 44, 4);
+               card->cid.fwrev         = UNSTUFF_BITS(resp, 40, 4);
+               card->cid.serial        = UNSTUFF_BITS(resp, 16, 24);
+               card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
+               card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
+               break;
+
+       case 2: /* MMC v2.x ? */
+       case 3: /* MMC v3.x ? */
+               card->cid.manfid        = UNSTUFF_BITS(resp, 120, 8);
+               card->cid.oemid         = UNSTUFF_BITS(resp, 104, 16);
+               card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
+               card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
+               card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
+               card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
+               card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
+               card->cid.prod_name[5]  = UNSTUFF_BITS(resp, 56, 8);
+               card->cid.serial        = UNSTUFF_BITS(resp, 16, 32);
+               card->cid.month         = UNSTUFF_BITS(resp, 12, 4);
+               card->cid.year          = UNSTUFF_BITS(resp, 8, 4) + 1997;
+               break;
+
+       default:
+               printk("%s: card has unknown MMCA version %d\n",
+                       card->host->host_name, card->csd.mmca_vsn);
+               mmc_card_set_bad(card);
+               break;
+       }
+}
+
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
+static void mmc_decode_csd(struct mmc_card *card)
+{
+       struct mmc_csd *csd = &card->csd;
+       unsigned int e, m, csd_struct;
+       u32 *resp = card->raw_csd;
+
+       /*
+        * We only understand CSD structure v1.1 and v2.
+        * v2 has extra information in bits 15, 11 and 10.
+        */
+       csd_struct = UNSTUFF_BITS(resp, 126, 2);
+       if (csd_struct != 1 && csd_struct != 2) {
+               printk("%s: unrecognised CSD structure version %d\n",
+                       card->host->host_name, csd_struct);
+               mmc_card_set_bad(card);
+               return;
+       }
+
+       csd->mmca_vsn    = UNSTUFF_BITS(resp, 122, 4);
+       m = UNSTUFF_BITS(resp, 115, 4);
+       e = UNSTUFF_BITS(resp, 112, 3);
+       csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+       csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+       m = UNSTUFF_BITS(resp, 99, 4);
+       e = UNSTUFF_BITS(resp, 96, 3);
+       csd->max_dtr      = tran_exp[e] * tran_mant[m];
+       csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+
+       e = UNSTUFF_BITS(resp, 47, 3);
+       m = UNSTUFF_BITS(resp, 62, 12);
+       csd->capacity     = (1 + m) << (e + 2);
+
+       csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+}
+
+/*
+ * Locate a MMC card on this MMC host given a raw CID.
+ */
+static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid)
+{
+       struct mmc_card *card;
+
+       list_for_each_entry(card, &host->cards, node) {
+               if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0)
+                       return card;
+       }
+       return NULL;
+}
+
+/*
+ * Allocate a new MMC card, and assign a unique RCA.
+ */
+static struct mmc_card *
+mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
+{
+       struct mmc_card *card, *c;
+       unsigned int rca = *frca;
+
+       card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+       if (!card)
+               return ERR_PTR(-ENOMEM);
+
+       mmc_init_card(card, host);
+       memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));
+
+ again:
+       list_for_each_entry(c, &host->cards, node)
+               if (c->rca == rca) {
+                       rca++;
+                       goto again;
+               }
+
+       card->rca = rca;
+
+       *frca = rca;
+
+       return card;
+}
+
+/*
+ * Tell attached cards to go to IDLE state
+ */
+static void mmc_idle_cards(struct mmc_host *host)
+{
+       struct mmc_command cmd;
+
+       cmd.opcode = MMC_GO_IDLE_STATE;
+       cmd.arg = 0;
+       cmd.flags = MMC_RSP_NONE;
+
+       mmc_wait_for_cmd(host, &cmd, 0);
+
+       mmc_delay(1);
+}
+
+/*
+ * Apply power to the MMC stack.
+ */
+static void mmc_power_up(struct mmc_host *host)
+{
+       int bit = fls(host->ocr_avail) - 1;
+
+       host->ios.vdd = bit;
+       host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+       host->ios.power_mode = MMC_POWER_UP;
+       host->ops->set_ios(host, &host->ios);
+
+       mmc_delay(1);
+
+       host->ios.clock = host->f_min;
+       host->ios.power_mode = MMC_POWER_ON;
+       host->ops->set_ios(host, &host->ios);
+
+       mmc_delay(2);
+}
+
+static void mmc_power_off(struct mmc_host *host)
+{
+       host->ios.clock = 0;
+       host->ios.vdd = 0;
+       host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+       host->ios.power_mode = MMC_POWER_OFF;
+       host->ops->set_ios(host, &host->ios);
+}
+
+static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+       struct mmc_command cmd;
+       int i, err = 0;
+
+       cmd.opcode = MMC_SEND_OP_COND;
+       cmd.arg = ocr;
+       cmd.flags = MMC_RSP_R3;
+
+       for (i = 100; i; i--) {
+               err = mmc_wait_for_cmd(host, &cmd, 0);
+               if (err != MMC_ERR_NONE)
+                       break;
+
+               if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+                       break;
+
+               err = MMC_ERR_TIMEOUT;
+
+               mmc_delay(10);
+       }
+
+       if (rocr)
+               *rocr = cmd.resp[0];
+
+       return err;
+}
+
+/*
+ * Discover cards by requesting their CID.  If this command
+ * times out, it is not an error; there are no further cards
+ * to be discovered.  Add new cards to the list.
+ *
+ * Create a mmc_card entry for each discovered card, assigning
+ * it an RCA, and save the raw CID for decoding later.
+ */
+static void mmc_discover_cards(struct mmc_host *host)
+{
+       struct mmc_card *card;
+       unsigned int first_rca = 1, err;
+
+       while (1) {
+               struct mmc_command cmd;
+
+               cmd.opcode = MMC_ALL_SEND_CID;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R2;
+
+               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+               if (err == MMC_ERR_TIMEOUT) {
+                       err = MMC_ERR_NONE;
+                       break;
+               }
+               if (err != MMC_ERR_NONE) {
+                       printk(KERN_ERR "%s: error requesting CID: %d\n",
+                               host->host_name, err);
+                       break;
+               }
+
+               card = mmc_find_card(host, cmd.resp);
+               if (!card) {
+                       card = mmc_alloc_card(host, cmd.resp, &first_rca);
+                       if (IS_ERR(card)) {
+                               err = PTR_ERR(card);
+                               break;
+                       }
+                       list_add(&card->node, &host->cards);
+               }
+
+               card->state &= ~MMC_STATE_DEAD;
+
+               cmd.opcode = MMC_SET_RELATIVE_ADDR;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R1;
+
+               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+               if (err != MMC_ERR_NONE)
+                       mmc_card_set_dead(card);
+       }
+}
+
+static void mmc_read_csds(struct mmc_host *host)
+{
+       struct mmc_card *card;
+
+       list_for_each_entry(card, &host->cards, node) {
+               struct mmc_command cmd;
+               int err;
+
+               if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+                       continue;
+
+               cmd.opcode = MMC_SEND_CSD;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R2;
+
+               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+               if (err != MMC_ERR_NONE) {
+                       mmc_card_set_dead(card);
+                       continue;
+               }
+
+               memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd));
+
+               mmc_decode_csd(card);
+               mmc_decode_cid(card);
+       }
+}
+
+static unsigned int mmc_calculate_clock(struct mmc_host *host)
+{
+       struct mmc_card *card;
+       unsigned int max_dtr = host->f_max;
+
+       list_for_each_entry(card, &host->cards, node)
+               if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr)
+                       max_dtr = card->csd.max_dtr;
+
+       DBG("MMC: selected %d.%03dMHz transfer rate\n",
+           max_dtr / 1000000, (max_dtr / 1000) % 1000);
+
+       return max_dtr;
+}
+
+/*
+ * Check whether cards we already know about are still present.
+ * We do this by requesting status, and checking whether a card
+ * responds.
+ *
+ * A request for status does not cause a state change in data
+ * transfer mode.
+ */
+static void mmc_check_cards(struct mmc_host *host)
+{
+       struct list_head *l, *n;
+
+       mmc_deselect_cards(host);
+
+       list_for_each_safe(l, n, &host->cards) {
+               struct mmc_card *card = mmc_list_to_card(l);
+               struct mmc_command cmd;
+               int err;
+
+               cmd.opcode = MMC_SEND_STATUS;
+               cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_R1;
+
+               err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+               if (err == MMC_ERR_NONE)
+                       continue;
+
+               mmc_card_set_dead(card);
+       }
+}
+
+static void mmc_setup(struct mmc_host *host)
+{
+       if (host->ios.power_mode != MMC_POWER_ON) {
+               int err;
+               u32 ocr;
+
+               mmc_power_up(host);
+               mmc_idle_cards(host);
+
+               err = mmc_send_op_cond(host, 0, &ocr);
+               if (err != MMC_ERR_NONE)
+                       return;
+
+               host->ocr = mmc_select_voltage(host, ocr);
+
+               /*
+                * Since we're changing the OCR value, we seem to
+                * need to tell some cards to go back to the idle
+                * state.  We wait 1ms to give cards time to
+                * respond.
+                */
+               if (host->ocr)
+                       mmc_idle_cards(host);
+       } else {
+               host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+               host->ios.clock = host->f_min;
+               host->ops->set_ios(host, &host->ios);
+
+               /*
+                * We should remember the OCR mask from the existing
+                * cards, and detect the new cards OCR mask, combine
+                * the two and re-select the VDD.  However, if we do
+                * change VDD, we should do an idle, and then do a
+                * full re-initialisation.  We would need to notify
+                * drivers so that they can re-setup the cards as
+                * well, while keeping their queues at bay.
+                *
+                * For the moment, we take the easy way out - if the
+                * new cards don't like our currently selected VDD,
+                * they drop off the bus.
+                */
+       }
+
+       if (host->ocr == 0)
+               return;
+
+       /*
+        * Send the selected OCR multiple times... until the cards
+        * all get the idea that they should be ready for CMD2.
+        * (My SanDisk card seems to need this.)
+        */
+       mmc_send_op_cond(host, host->ocr, NULL);
+
+       mmc_discover_cards(host);
+
+       /*
+        * Ok, now switch to push-pull mode.
+        */
+       host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+       host->ops->set_ios(host, &host->ios);
+
+       mmc_read_csds(host);
+}
+
+
+/**
+ *     mmc_detect_change - process change of state on a MMC socket
+ *     @host: host which changed state.
+ *
+ *     All we know is that card(s) have been inserted or removed
+ *     from the socket(s).  We don't know which socket or cards.
+ */
+void mmc_detect_change(struct mmc_host *host)
+{
+       schedule_work(&host->detect);
+}
+
+EXPORT_SYMBOL(mmc_detect_change);
+
+
+static void mmc_rescan(void *data)
+{
+       struct mmc_host *host = data;
+       struct list_head *l, *n;
+
+       mmc_claim_host(host);
+
+       if (host->ios.power_mode == MMC_POWER_ON)
+               mmc_check_cards(host);
+
+       mmc_setup(host);
+
+       if (!list_empty(&host->cards)) {
+               /*
+                * (Re-)calculate the fastest clock rate which the
+                * attached cards and the host support.
+                */
+               host->ios.clock = mmc_calculate_clock(host);
+               host->ops->set_ios(host, &host->ios);
+       }
+
+       mmc_release_host(host);
+
+       list_for_each_safe(l, n, &host->cards) {
+               struct mmc_card *card = mmc_list_to_card(l);
+
+               /*
+                * If this is a new and good card, register it.
+                */
+               if (!mmc_card_present(card) && !mmc_card_dead(card)) {
+                       if (mmc_register_card(card))
+                               mmc_card_set_dead(card);
+                       else
+                               mmc_card_set_present(card);
+               }
+
+               /*
+                * If this card is dead, destroy it.
+                */
+               if (mmc_card_dead(card)) {
+                       list_del(&card->node);
+                       mmc_remove_card(card);
+               }
+       }
+
+       /*
+        * If we discover that there are no cards on the
+        * bus, turn off the clock and power down.
+        */
+       if (list_empty(&host->cards))
+               mmc_power_off(host);
+}
+
+
+/**
+ *     mmc_alloc_host - initialise the per-host structure.
+ *     @extra: sizeof private data structure
+ *     @dev: pointer to host device model structure
+ *
+ *     Initialise the per-host structure.
+ */
+struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+{
+       struct mmc_host *host;
+
+       host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+       if (host) {
+               memset(host, 0, sizeof(struct mmc_host) + extra);
+
+               spin_lock_init(&host->lock);
+               init_waitqueue_head(&host->wq);
+               INIT_LIST_HEAD(&host->cards);
+               INIT_WORK(&host->detect, mmc_rescan, host);
+
+               host->dev = dev;
+
+               /*
+                * By default, hosts do not support SGIO or large requests.
+                * They have to set these according to their abilities.
+                */
+               host->max_hw_segs = 1;
+               host->max_phys_segs = 1;
+               host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
+               host->max_seg_size = PAGE_CACHE_SIZE;
+       }
+
+       return host;
+}
+
+EXPORT_SYMBOL(mmc_alloc_host);
+
+/**
+ *     mmc_add_host - initialise host hardware
+ *     @host: mmc host
+ */
+int mmc_add_host(struct mmc_host *host)
+{
+       static unsigned int host_num;
+
+       snprintf(host->host_name, sizeof(host->host_name),
+                "mmc%d", host_num++);
+
+       mmc_power_off(host);
+       mmc_detect_change(host);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(mmc_add_host);
+
+/**
+ *     mmc_remove_host - remove host hardware
+ *     @host: mmc host
+ *
+ *     Unregister and remove all cards associated with this host,
+ *     and power down the MMC bus.
+ */
+void mmc_remove_host(struct mmc_host *host)
+{
+       struct list_head *l, *n;
+
+       list_for_each_safe(l, n, &host->cards) {
+               struct mmc_card *card = mmc_list_to_card(l);
+
+               mmc_remove_card(card);
+       }
+
+       mmc_power_off(host);
+}
+
+EXPORT_SYMBOL(mmc_remove_host);
+
+/**
+ *     mmc_free_host - free the host structure
+ *     @host: mmc host
+ *
+ *     Free the host once all references to it have been dropped.
+ */
+void mmc_free_host(struct mmc_host *host)
+{
+       flush_scheduled_work();
+       kfree(host);
+}
+
+EXPORT_SYMBOL(mmc_free_host);
+
+#ifdef CONFIG_PM
+
+/**
+ *     mmc_suspend_host - suspend a host
+ *     @host: mmc host
+ *     @state: suspend mode (PM_SUSPEND_xxx)
+ */
+int mmc_suspend_host(struct mmc_host *host, u32 state)
+{
+       mmc_claim_host(host);
+       mmc_deselect_cards(host);
+       mmc_power_off(host);
+       mmc_release_host(host);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(mmc_suspend_host);
+
+/**
+ *     mmc_resume_host - resume a previously suspended host
+ *     @host: mmc host
+ */
+int mmc_resume_host(struct mmc_host *host)
+{
+       mmc_detect_change(host);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(mmc_resume_host);
+
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
new file mode 100644 (file)
index 0000000..b498dff
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  linux/drivers/mmc/mmc.h
+ *
+ *  Copyright (C) 2003 Russell King, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _MMC_H
+#define _MMC_H
+/* core-internal functions */
+void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
+int mmc_register_card(struct mmc_card *card);
+void mmc_remove_card(struct mmc_card *card);
+#endif
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
new file mode 100644 (file)
index 0000000..f76673a
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * Block driver for media (i.e., flash cards)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author:  Andrew Christian
+ *          28 May 2002
+ */
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "mmc_queue.h"
+
+/*
+ * max 8 partitions per card
+ */
+#define MMC_SHIFT      3
+
+static int major;
+
+/*
+ * There is one mmc_blk_data per slot.
+ */
+struct mmc_blk_data {
+       spinlock_t      lock;
+       struct gendisk  *disk;
+       struct mmc_queue queue;
+
+       unsigned int    usage;
+       unsigned int    block_bits;
+};
+
+static DECLARE_MUTEX(open_lock);
+
+static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+{
+       struct mmc_blk_data *md;
+
+       down(&open_lock);
+       md = disk->private_data;
+       if (md && md->usage == 0)
+               md = NULL;
+       if (md)
+               md->usage++;
+       up(&open_lock);
+
+       return md;
+}
+
+static void mmc_blk_put(struct mmc_blk_data *md)
+{
+       down(&open_lock);
+       md->usage--;
+       if (md->usage == 0) {
+               put_disk(md->disk);
+               mmc_cleanup_queue(&md->queue);
+               kfree(md);
+       }
+       up(&open_lock);
+}
+
+static int mmc_blk_open(struct inode *inode, struct file *filp)
+{
+       struct mmc_blk_data *md;
+       int ret = -ENXIO;
+
+       md = mmc_blk_get(inode->i_bdev->bd_disk);
+       if (md) {
+               if (md->usage == 2)
+                       check_disk_change(inode->i_bdev);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int mmc_blk_release(struct inode *inode, struct file *filp)
+{
+       struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
+
+       mmc_blk_put(md);
+       return 0;
+}
+
+static int
+mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct block_device *bdev = inode->i_bdev;
+
+       if (cmd == HDIO_GETGEO) {
+               struct hd_geometry geo;
+
+               memset(&geo, 0, sizeof(struct hd_geometry));
+
+               geo.cylinders   = get_capacity(bdev->bd_disk) / (4 * 16);
+               geo.heads       = 4;
+               geo.sectors     = 16;
+               geo.start       = get_start_sect(bdev);
+
+               return copy_to_user((void __user *)arg, &geo, sizeof(geo))
+                       ? -EFAULT : 0;
+       }
+
+       return -ENOTTY;
+}
+
+static struct block_device_operations mmc_bdops = {
+       .open                   = mmc_blk_open,
+       .release                = mmc_blk_release,
+       .ioctl                  = mmc_blk_ioctl,
+       .owner                  = THIS_MODULE,
+};
+
+struct mmc_blk_request {
+       struct mmc_request      mrq;
+       struct mmc_command      cmd;
+       struct mmc_command      stop;
+       struct mmc_data         data;
+};
+
+static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
+{
+       struct mmc_blk_data *md = mq->data;
+       int stat = BLKPREP_OK;
+
+       /*
+        * If we have no device, we haven't finished initialising.
+        */
+       if (!md || !mq->card) {
+               printk(KERN_ERR "%s: killing request - no device/host\n",
+                      req->rq_disk->disk_name);
+               stat = BLKPREP_KILL;
+       }
+
+       return stat;
+}
+
+static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+{
+       struct mmc_blk_data *md = mq->data;
+       struct mmc_card *card = md->queue.card;
+       int ret;
+
+       if (mmc_card_claim_host(card))
+               goto cmd_err;
+
+       do {
+               struct mmc_blk_request brq;
+               struct mmc_command cmd;
+
+               memset(&brq, 0, sizeof(struct mmc_blk_request));
+               brq.mrq.cmd = &brq.cmd;
+               brq.mrq.data = &brq.data;
+
+               brq.cmd.arg = req->sector << 9;
+               brq.cmd.flags = MMC_RSP_R1;
+               brq.data.req = req;
+               brq.data.timeout_ns = card->csd.tacc_ns * 10;
+               brq.data.timeout_clks = card->csd.tacc_clks * 10;
+               brq.data.blksz_bits = md->block_bits;
+               brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+               brq.stop.opcode = MMC_STOP_TRANSMISSION;
+               brq.stop.arg = 0;
+               brq.stop.flags = MMC_RSP_R1B;
+
+               if (rq_data_dir(req) == READ) {
+                       brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
+                       brq.data.flags |= MMC_DATA_READ;
+               } else {
+                       brq.cmd.opcode = MMC_WRITE_BLOCK;
+                       brq.cmd.flags = MMC_RSP_R1B;
+                       brq.data.flags |= MMC_DATA_WRITE;
+                       brq.data.blocks = 1;
+               }
+               brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL;
+
+               mmc_wait_for_req(card->host, &brq.mrq);
+               if (brq.cmd.error) {
+                       printk(KERN_ERR "%s: error %d sending read/write command\n",
+                              req->rq_disk->disk_name, brq.cmd.error);
+                       goto cmd_err;
+               }
+
+               if (brq.data.error) {
+                       printk(KERN_ERR "%s: error %d transferring data\n",
+                              req->rq_disk->disk_name, brq.data.error);
+                       goto cmd_err;
+               }
+
+               if (brq.stop.error) {
+                       printk(KERN_ERR "%s: error %d sending stop command\n",
+                              req->rq_disk->disk_name, brq.stop.error);
+                       goto cmd_err;
+               }
+
+               do {
+                       int err;
+
+                       cmd.opcode = MMC_SEND_STATUS;
+                       cmd.arg = card->rca << 16;
+                       cmd.flags = MMC_RSP_R1;
+                       err = mmc_wait_for_cmd(card->host, &cmd, 5);
+                       if (err) {
+                               printk(KERN_ERR "%s: error %d requesting status\n",
+                                      req->rq_disk->disk_name, err);
+                               goto cmd_err;
+                       }
+               } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+#if 0
+               if (cmd.resp[0] & ~0x00000900)
+                       printk(KERN_ERR "%s: status = %08x\n",
+                              req->rq_disk->disk_name, cmd.resp[0]);
+               if (mmc_decode_status(cmd.resp))
+                       goto cmd_err;
+#endif
+
+               /*
+                * A block was successfully transferred.
+                */
+               spin_lock_irq(&md->lock);
+               ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+               if (!ret) {
+                       /*
+                        * The whole request completed successfully.
+                        */
+                       add_disk_randomness(req->rq_disk);
+                       blkdev_dequeue_request(req);
+                       end_that_request_last(req);
+               }
+               spin_unlock_irq(&md->lock);
+       } while (ret);
+
+       mmc_card_release_host(card);
+
+       return 1;
+
+ cmd_err:
+       mmc_card_release_host(card);
+
+       /*
+        * This is a little draconian, but until we get proper
+        * error handling sorted out here, its the best we can
+        * do - especially as some hosts have no idea how much
+        * data was transferred before the error occurred.
+        */
+       spin_lock_irq(&md->lock);
+       do {
+               ret = end_that_request_chunk(req, 0,
+                               req->current_nr_sectors << 9);
+       } while (ret);
+
+       add_disk_randomness(req->rq_disk);
+       blkdev_dequeue_request(req);
+       end_that_request_last(req);
+       spin_unlock_irq(&md->lock);
+
+       return 0;
+}
+
+#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
+
+static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+       struct mmc_blk_data *md;
+       int devidx, ret;
+
+       devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
+       if (devidx >= MMC_NUM_MINORS)
+               return ERR_PTR(-ENOSPC);
+       __set_bit(devidx, dev_use);
+
+       md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+       if (md) {
+               memset(md, 0, sizeof(struct mmc_blk_data));
+
+               md->disk = alloc_disk(1 << MMC_SHIFT);
+               if (md->disk == NULL) {
+                       kfree(md);
+                       md = ERR_PTR(-ENOMEM);
+                       goto out;
+               }
+
+               spin_lock_init(&md->lock);
+               md->usage = 1;
+
+               ret = mmc_init_queue(&md->queue, card, &md->lock);
+               if (ret) {
+                       put_disk(md->disk);
+                       kfree(md);
+                       md = ERR_PTR(ret);
+                       goto out;
+               }
+               md->queue.prep_fn = mmc_blk_prep_rq;
+               md->queue.issue_fn = mmc_blk_issue_rq;
+               md->queue.data = md;
+
+               md->disk->major = major;
+               md->disk->first_minor = devidx << MMC_SHIFT;
+               md->disk->fops = &mmc_bdops;
+               md->disk->private_data = md;
+               md->disk->queue = md->queue.queue;
+               md->disk->driverfs_dev = &card->dev;
+
+               sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+               sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
+
+               md->block_bits = card->csd.read_blkbits;
+
+               blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+               set_capacity(md->disk, card->csd.capacity);
+       }
+ out:
+       return md;
+}
+
+static int
+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
+{
+       struct mmc_command cmd;
+       int err;
+
+       mmc_card_claim_host(card);
+       cmd.opcode = MMC_SET_BLOCKLEN;
+       cmd.arg = 1 << card->csd.read_blkbits;
+       cmd.flags = MMC_RSP_R1;
+       err = mmc_wait_for_cmd(card->host, &cmd, 5);
+       mmc_card_release_host(card);
+
+       if (err) {
+               printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
+                       md->disk->disk_name, cmd.arg, err);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mmc_blk_probe(struct mmc_card *card)
+{
+       struct mmc_blk_data *md;
+       int err;
+
+       if (card->csd.cmdclass & ~0x1ff)
+               return -ENODEV;
+
+       if (card->csd.read_blkbits < 9) {
+               printk(KERN_WARNING "%s: read blocksize too small (%u)\n",
+                       mmc_card_id(card), 1 << card->csd.read_blkbits);
+               return -ENODEV;
+       }
+
+       md = mmc_blk_alloc(card);
+       if (IS_ERR(md))
+               return PTR_ERR(md);
+
+       err = mmc_blk_set_blksize(md, card);
+       if (err)
+               goto out;
+
+       printk(KERN_INFO "%s: %s %s %dKiB\n",
+               md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+               (card->csd.capacity << card->csd.read_blkbits) / 1024);
+
+       mmc_set_drvdata(card, md);
+       add_disk(md->disk);
+       return 0;
+
+ out:
+       mmc_blk_put(md);
+
+       return err;
+}
+
+static void mmc_blk_remove(struct mmc_card *card)
+{
+       struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+       if (md) {
+               int devidx;
+
+               del_gendisk(md->disk);
+
+               /*
+                * I think this is needed.
+                */
+               md->disk->queue = NULL;
+
+               devidx = md->disk->first_minor >> MMC_SHIFT;
+               __clear_bit(devidx, dev_use);
+
+               mmc_blk_put(md);
+       }
+       mmc_set_drvdata(card, NULL);
+}
+
+#ifdef CONFIG_PM
+static int mmc_blk_suspend(struct mmc_card *card, u32 state)
+{
+       struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+       if (md) {
+               mmc_queue_suspend(&md->queue);
+       }
+       return 0;
+}
+
+static int mmc_blk_resume(struct mmc_card *card)
+{
+       struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+       if (md) {
+               mmc_blk_set_blksize(md, card);
+               mmc_queue_resume(&md->queue);
+       }
+       return 0;
+}
+#else
+#define        mmc_blk_suspend NULL
+#define mmc_blk_resume NULL
+#endif
+
+static struct mmc_driver mmc_driver = {
+       .drv            = {
+               .name   = "mmcblk",
+       },
+       .probe          = mmc_blk_probe,
+       .remove         = mmc_blk_remove,
+       .suspend        = mmc_blk_suspend,
+       .resume         = mmc_blk_resume,
+};
+
+static int __init mmc_blk_init(void)
+{
+       int res = -ENOMEM;
+
+       res = register_blkdev(major, "mmc");
+       if (res < 0) {
+               printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
+                      major, res);
+               goto out;
+       }
+       if (major == 0)
+               major = res;
+
+       devfs_mk_dir("mmc");
+       return mmc_register_driver(&mmc_driver);
+
+ out:
+       return res;
+}
+
+static void __exit mmc_blk_exit(void)
+{
+       mmc_unregister_driver(&mmc_driver);
+       devfs_remove("mmc");
+       unregister_blkdev(major, "mmc");
+}
+
+module_init(mmc_blk_init);
+module_exit(mmc_blk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
+
+module_param(major, int, 0444);
+MODULE_PARM_DESC(major, "specify the major device number for MMC block driver");
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
new file mode 100644 (file)
index 0000000..e818b92
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *  linux/drivers/mmc/mmc_queue.c
+ *
+ *  Copyright (C) 2003 Russell King, 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include "mmc_queue.h"
+
+#define MMC_QUEUE_EXIT         (1 << 0)
+#define MMC_QUEUE_SUSPENDED    (1 << 1)
+
+/*
+ * Prepare a MMC request.  Essentially, this means passing the
+ * preparation off to the media driver.  The media driver will
+ * create a mmc_io_request in req->special.
+ */
+static int mmc_prep_request(struct request_queue *q, struct request *req)
+{
+       struct mmc_queue *mq = q->queuedata;
+       int ret = BLKPREP_KILL;
+
+       if (req->flags & REQ_SPECIAL) {
+               /*
+                * Special commands already have the command
+                * blocks already setup in req->special.
+                */
+               BUG_ON(!req->special);
+
+               ret = BLKPREP_OK;
+       } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+               /*
+                * Block I/O requests need translating according
+                * to the protocol.
+                */
+               ret = mq->prep_fn(mq, req);
+       } else {
+               /*
+                * Everything else is invalid.
+                */
+               blk_dump_rq_flags(req, "MMC bad request");
+       }
+
+       if (ret == BLKPREP_OK)
+               req->flags |= REQ_DONTPREP;
+
+       return ret;
+}
+
+static int mmc_queue_thread(void *d)
+{
+       struct mmc_queue *mq = d;
+       struct request_queue *q = mq->queue;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /*
+        * Set iothread to ensure that we aren't put to sleep by
+        * the process freezing.  We handle suspension ourselves.
+        */
+       current->flags |= PF_MEMALLOC|PF_NOFREEZE;
+
+       daemonize("mmcqd");
+
+       complete(&mq->thread_complete);
+
+       down(&mq->thread_sem);
+       add_wait_queue(&mq->thread_wq, &wait);
+       do {
+               struct request *req = NULL;
+
+               spin_lock_irq(q->queue_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!blk_queue_plugged(q))
+                       mq->req = req = elv_next_request(q);
+               spin_unlock(q->queue_lock);
+
+               if (!req) {
+                       if (mq->flags & MMC_QUEUE_EXIT)
+                               break;
+                       up(&mq->thread_sem);
+                       schedule();
+                       down(&mq->thread_sem);
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+
+               mq->issue_fn(mq, req);
+       } while (1);
+       remove_wait_queue(&mq->thread_wq, &wait);
+       up(&mq->thread_sem);
+
+       complete_and_exit(&mq->thread_complete, 0);
+       return 0;
+}
+
+/*
+ * Generic MMC request handler.  This is called for any queue on a
+ * particular host.  When the host is not busy, we look for a request
+ * on any queue on this host, and attempt to issue it.  This may
+ * not be the queue we were asked to process.
+ */
+static void mmc_request(request_queue_t *q)
+{
+       struct mmc_queue *mq = q->queuedata;
+
+       if (!mq->req)
+               wake_up(&mq->thread_wq);
+}
+
+/**
+ * mmc_init_queue - initialise a queue structure.
+ * @mq: mmc queue
+ * @card: mmc card to attach this queue
+ * @lock: queue lock
+ *
+ * Initialise a MMC card request queue.
+ */
+int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
+{
+       struct mmc_host *host = card->host;
+       u64 limit = BLK_BOUNCE_HIGH;
+       int ret;
+
+       if (host->dev->dma_mask && *host->dev->dma_mask)
+               limit = *host->dev->dma_mask;
+
+       mq->card = card;
+       mq->queue = blk_init_queue(mmc_request, lock);
+       if (!mq->queue)
+               return -ENOMEM;
+
+       blk_queue_prep_rq(mq->queue, mmc_prep_request);
+       blk_queue_bounce_limit(mq->queue, limit);
+       blk_queue_max_sectors(mq->queue, host->max_sectors);
+       blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
+       blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
+       blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+
+       mq->queue->queuedata = mq;
+       mq->req = NULL;
+
+       init_completion(&mq->thread_complete);
+       init_waitqueue_head(&mq->thread_wq);
+       init_MUTEX(&mq->thread_sem);
+
+       ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
+       if (ret < 0) {
+               blk_cleanup_queue(mq->queue);
+       } else {
+               wait_for_completion(&mq->thread_complete);
+               init_completion(&mq->thread_complete);
+               ret = 0;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(mmc_init_queue);
+
+void mmc_cleanup_queue(struct mmc_queue *mq)
+{
+       mq->flags |= MMC_QUEUE_EXIT;
+       wake_up(&mq->thread_wq);
+       wait_for_completion(&mq->thread_complete);
+       blk_cleanup_queue(mq->queue);
+
+       mq->card = NULL;
+}
+EXPORT_SYMBOL(mmc_cleanup_queue);
+
+/**
+ * mmc_queue_suspend - suspend a MMC request queue
+ * @mq: MMC queue to suspend
+ *
+ * Stop the block request queue, and wait for our thread to
+ * complete any outstanding requests.  This ensures that we
+ * won't suspend while a request is being processed.
+ */
+void mmc_queue_suspend(struct mmc_queue *mq)
+{
+       request_queue_t *q = mq->queue;
+       unsigned long flags;
+
+       if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
+               mq->flags |= MMC_QUEUE_SUSPENDED;
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_stop_queue(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+
+               down(&mq->thread_sem);
+       }
+}
+EXPORT_SYMBOL(mmc_queue_suspend);
+
+/**
+ * mmc_queue_resume - resume a previously suspended MMC request queue
+ * @mq: MMC queue to resume
+ */
+void mmc_queue_resume(struct mmc_queue *mq)
+{
+       request_queue_t *q = mq->queue;
+       unsigned long flags;
+
+       if (mq->flags & MMC_QUEUE_SUSPENDED) {
+               mq->flags &= ~MMC_QUEUE_SUSPENDED;
+
+               up(&mq->thread_sem);
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_start_queue(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+       }
+}
+EXPORT_SYMBOL(mmc_queue_resume);
diff --git a/drivers/mmc/mmc_queue.h b/drivers/mmc/mmc_queue.h
new file mode 100644 (file)
index 0000000..6bef900
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef MMC_QUEUE_H
+#define MMC_QUEUE_H
+
+struct request;
+struct task_struct;
+
+struct mmc_queue {
+       struct mmc_card         *card;
+       struct completion       thread_complete;
+       wait_queue_head_t       thread_wq;
+       struct semaphore        thread_sem;
+       unsigned int            flags;
+       struct request          *req;
+       int                     (*prep_fn)(struct mmc_queue *, struct request *);
+       int                     (*issue_fn)(struct mmc_queue *, struct request *);
+       void                    *data;
+       struct request_queue    *queue;
+};
+
+struct mmc_io_request {
+       struct request          *rq;
+       int                     num;
+       struct mmc_command      selcmd;         /* mmc_queue private */
+       struct mmc_command      cmd[4];         /* max 4 commands */
+};
+
+extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
+extern void mmc_cleanup_queue(struct mmc_queue *);
+extern void mmc_queue_suspend(struct mmc_queue *);
+extern void mmc_queue_resume(struct mmc_queue *);
+
+#endif
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
new file mode 100644 (file)
index 0000000..2b7ebda
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *  linux/drivers/mmc/mmc_sysfs.c
+ *
+ *  Copyright (C) 2003 Russell King, 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  MMC sysfs/driver model support.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include "mmc.h"
+
+#define dev_to_mmc_card(d)     container_of(d, struct mmc_card, dev)
+#define to_mmc_driver(d)       container_of(d, struct mmc_driver, drv)
+
+static void mmc_release_card(struct device *dev)
+{
+       struct mmc_card *card = dev_to_mmc_card(dev);
+
+       kfree(card);
+}
+
+/*
+ * This currently matches any MMC driver to any MMC card - drivers
+ * themselves make the decision whether to drive this card in their
+ * probe method.  However, we force "bad" cards to fail.
+ */
+static int mmc_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct mmc_card *card = dev_to_mmc_card(dev);
+       return !mmc_card_bad(card);
+}
+
+static int
+mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
+               int buf_size)
+{
+       struct mmc_card *card = dev_to_mmc_card(dev);
+       char ccc[13];
+       int i = 0;
+
+#define add_env(fmt,val)                                               \
+       ({                                                              \
+               int len, ret = -ENOMEM;                                 \
+               if (i < num_envp) {                                     \
+                       envp[i++] = buf;                                \
+                       len = snprintf(buf, buf_size, fmt, val) + 1;    \
+                       buf_size -= len;                                \
+                       buf += len;                                     \
+                       if (buf_size >= 0)                              \
+                               ret = 0;                                \
+               }                                                       \
+               ret;                                                    \
+       })
+
+       for (i = 0; i < 12; i++)
+               ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
+       ccc[12] = '\0';
+
+       i = 0;
+       add_env("MMC_CCC=%s", ccc);
+       add_env("MMC_MANFID=%06x", card->cid.manfid);
+       add_env("MMC_NAME=%s", mmc_card_name(card));
+       add_env("MMC_OEMID=%04x", card->cid.oemid);
+
+       return 0;
+}
+
+static int mmc_bus_suspend(struct device *dev, u32 state)
+{
+       struct mmc_driver *drv = to_mmc_driver(dev->driver);
+       struct mmc_card *card = dev_to_mmc_card(dev);
+       int ret = 0;
+
+       if (dev->driver && drv->suspend)
+               ret = drv->suspend(card, state);
+       return ret;
+}
+
+static int mmc_bus_resume(struct device *dev)
+{
+       struct mmc_driver *drv = to_mmc_driver(dev->driver);
+       struct mmc_card *card = dev_to_mmc_card(dev);
+       int ret = 0;
+
+       if (dev->driver && drv->resume)
+               ret = drv->resume(card);
+       return ret;
+}
+
+static struct bus_type mmc_bus_type = {
+       .name           = "mmc",
+       .match          = mmc_bus_match,
+       .hotplug        = mmc_bus_hotplug,
+       .suspend        = mmc_bus_suspend,
+       .resume         = mmc_bus_resume,
+};
+
+
+static int mmc_drv_probe(struct device *dev)
+{
+       struct mmc_driver *drv = to_mmc_driver(dev->driver);
+       struct mmc_card *card = dev_to_mmc_card(dev);
+
+       return drv->probe(card);
+}
+
+static int mmc_drv_remove(struct device *dev)
+{
+       struct mmc_driver *drv = to_mmc_driver(dev->driver);
+       struct mmc_card *card = dev_to_mmc_card(dev);
+
+       drv->remove(card);
+
+       return 0;
+}
+
+
+/**
+ *     mmc_register_driver - register a media driver
+ *     @drv: MMC media driver
+ */
+int mmc_register_driver(struct mmc_driver *drv)
+{
+       drv->drv.bus = &mmc_bus_type;
+       drv->drv.probe = mmc_drv_probe;
+       drv->drv.remove = mmc_drv_remove;
+       return driver_register(&drv->drv);
+}
+
+EXPORT_SYMBOL(mmc_register_driver);
+
+/**
+ *     mmc_unregister_driver - unregister a media driver
+ *     @drv: MMC media driver
+ */
+void mmc_unregister_driver(struct mmc_driver *drv)
+{
+       drv->drv.bus = &mmc_bus_type;
+       driver_unregister(&drv->drv);
+}
+
+EXPORT_SYMBOL(mmc_unregister_driver);
+
+
+#define MMC_ATTR(name, fmt, args...)                                   \
+static ssize_t mmc_dev_show_##name (struct device *dev, char *buf)     \
+{                                                                      \
+       struct mmc_card *card = dev_to_mmc_card(dev);                   \
+       return sprintf(buf, fmt, args);                                 \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)
+
+MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
+       card->raw_cid[2], card->raw_cid[3]);
+MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
+       card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
+MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
+MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
+MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
+MMC_ATTR(name, "%s\n", card->cid.prod_name);
+MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
+MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
+
+static struct device_attribute *mmc_dev_attributes[] = {
+       &dev_attr_cid,
+       &dev_attr_csd,
+       &dev_attr_date,
+       &dev_attr_fwrev,
+       &dev_attr_hwrev,
+       &dev_attr_manfid,
+       &dev_attr_name,
+       &dev_attr_oemid,
+       &dev_attr_serial,
+};
+
+/*
+ * Internal function.  Initialise a MMC card structure.
+ */
+void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
+{
+       memset(card, 0, sizeof(struct mmc_card));
+       card->host = host;
+       device_initialize(&card->dev);
+       card->dev.parent = card->host->dev;
+       card->dev.bus = &mmc_bus_type;
+       card->dev.release = mmc_release_card;
+}
+
+/*
+ * Internal function.  Register a new MMC card with the driver model.
+ */
+int mmc_register_card(struct mmc_card *card)
+{
+       int ret, i;
+
+       snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
+                "%s:%04x", card->host->host_name, card->rca);
+
+       ret = device_add(&card->dev);
+       if (ret == 0)
+               for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++)
+                       device_create_file(&card->dev, mmc_dev_attributes[i]);
+
+       return ret;
+}
+
+/*
+ * Internal function.  Unregister a new MMC card with the
+ * driver model, and (eventually) free it.
+ */
+void mmc_remove_card(struct mmc_card *card)
+{
+       if (mmc_card_present(card))
+               device_del(&card->dev);
+
+       put_device(&card->dev);
+}
+
+
+static int __init mmc_init(void)
+{
+       return bus_register(&mmc_bus_type);
+}
+
+static void __exit mmc_exit(void)
+{
+       bus_unregister(&mmc_bus_type);
+}
+
+module_init(mmc_init);
+module_exit(mmc_exit);
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
new file mode 100644 (file)
index 0000000..47e1636
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ *  linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware/amba.h>
+#include <asm/hardware/clock.h>
+#include <asm/mach/mmc.h>
+
+#include "mmci.h"
+
+#define DRIVER_NAME "mmci-pl18x"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(host,fmt,args...)  \
+       pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args)
+#else
+#define DBG(host,fmt,args...)  do { } while (0)
+#endif
+
+static unsigned int fmax = 515633;
+
+static void
+mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
+{
+       writel(0, host->base + MMCICOMMAND);
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+
+       if (mrq->data)
+               mrq->data->bytes_xfered = host->data_xfered;
+
+       /*
+        * Need to drop the host lock here; mmc_request_done may call
+        * back into the driver...
+        */
+       spin_unlock(&host->lock);
+       mmc_request_done(host->mmc, mrq);
+       spin_lock(&host->lock);
+}
+
+static void mmci_stop_data(struct mmci_host *host)
+{
+       writel(0, host->base + MMCIDATACTRL);
+       writel(0, host->base + MMCIMASK1);
+       host->data = NULL;
+}
+
+static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
+{
+       unsigned int datactrl, timeout, irqmask;
+       void *base;
+
+       DBG(host, "blksz %04x blks %04x flags %08x\n",
+           1 << data->blksz_bits, data->blocks, data->flags);
+
+       host->data = data;
+       host->size = data->blocks << data->blksz_bits;
+       host->data_xfered = 0;
+
+       mmci_init_sg(host, data);
+
+       timeout = data->timeout_clks +
+                 ((unsigned long long)data->timeout_ns * host->cclk) /
+                  1000000000ULL;
+
+       base = host->base;
+       writel(timeout, base + MMCIDATATIMER);
+       writel(host->size, base + MMCIDATALENGTH);
+
+       datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
+       if (data->flags & MMC_DATA_READ) {
+               datactrl |= MCI_DPSM_DIRECTION;
+               irqmask = MCI_RXFIFOHALFFULLMASK;
+       } else {
+               /*
+                * We don't actually need to include "FIFO empty" here
+                * since its implicit in "FIFO half empty".
+                */
+               irqmask = MCI_TXFIFOHALFEMPTYMASK;
+       }
+
+       writel(datactrl, base + MMCIDATACTRL);
+       writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
+       writel(irqmask, base + MMCIMASK1);
+}
+
+static void
+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
+{
+       void *base = host->base;
+
+       DBG(host, "op %02x arg %08x flags %08x\n",
+           cmd->opcode, cmd->arg, cmd->flags);
+
+       if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+               writel(0, base + MMCICOMMAND);
+               udelay(1);
+       }
+
+       c |= cmd->opcode | MCI_CPSM_ENABLE;
+       switch (cmd->flags & MMC_RSP_MASK) {
+       case MMC_RSP_NONE:
+       default:
+               break;
+       case MMC_RSP_LONG:
+               c |= MCI_CPSM_LONGRSP;
+       case MMC_RSP_SHORT:
+               c |= MCI_CPSM_RESPONSE;
+               break;
+       }
+       if (/*interrupt*/0)
+               c |= MCI_CPSM_INTERRUPT;
+
+       host->cmd = cmd;
+
+       writel(cmd->arg, base + MMCIARGUMENT);
+       writel(c, base + MMCICOMMAND);
+}
+
+static void
+mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
+             unsigned int status)
+{
+       if (status & MCI_DATABLOCKEND) {
+               host->data_xfered += 1 << data->blksz_bits;
+       }
+       if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+               if (status & MCI_DATACRCFAIL)
+                       data->error = MMC_ERR_BADCRC;
+               else if (status & MCI_DATATIMEOUT)
+                       data->error = MMC_ERR_TIMEOUT;
+               else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
+                       data->error = MMC_ERR_FIFO;
+               status |= MCI_DATAEND;
+       }
+       if (status & MCI_DATAEND) {
+               mmci_stop_data(host);
+
+               if (!data->stop) {
+                       mmci_request_end(host, data->mrq);
+               } else {
+                       mmci_start_command(host, data->stop, 0);
+               }
+       }
+}
+
+static void
+mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
+            unsigned int status)
+{
+       void *base = host->base;
+
+       host->cmd = NULL;
+
+       cmd->resp[0] = readl(base + MMCIRESPONSE0);
+       cmd->resp[1] = readl(base + MMCIRESPONSE1);
+       cmd->resp[2] = readl(base + MMCIRESPONSE2);
+       cmd->resp[3] = readl(base + MMCIRESPONSE3);
+
+       if (status & MCI_CMDTIMEOUT) {
+               cmd->error = MMC_ERR_TIMEOUT;
+       } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
+               cmd->error = MMC_ERR_BADCRC;
+       }
+
+       if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+               mmci_request_end(host, cmd->mrq);
+       } else if (!(cmd->data->flags & MMC_DATA_READ)) {
+               mmci_start_data(host, cmd->data);
+       }
+}
+
+static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
+{
+       void *base = host->base;
+       char *ptr = buffer;
+       u32 status;
+
+       do {
+               int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+
+               if (count > remain)
+                       count = remain;
+
+               if (count <= 0)
+                       break;
+
+               readsl(base + MMCIFIFO, ptr, count >> 2);
+
+               ptr += count;
+               remain -= count;
+
+               if (remain == 0)
+                       break;
+
+               status = readl(base + MMCISTATUS);
+       } while (status & MCI_RXDATAAVLBL);
+
+       return ptr - buffer;
+}
+
+static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
+{
+       void *base = host->base;
+       char *ptr = buffer;
+
+       do {
+               unsigned int count, maxcnt;
+
+               maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+               count = min(remain, maxcnt);
+
+               writesl(base + MMCIFIFO, ptr, count >> 2);
+
+               ptr += count;
+               remain -= count;
+
+               if (remain == 0)
+                       break;
+
+               status = readl(base + MMCISTATUS);
+       } while (status & MCI_TXFIFOHALFEMPTY);
+
+       return ptr - buffer;
+}
+
+/*
+ * PIO data transfer IRQ handler.
+ */
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct mmci_host *host = dev_id;
+       void *base = host->base;
+       u32 status;
+
+       status = readl(base + MMCISTATUS);
+
+       DBG(host, "irq1 %08x\n", status);
+
+       do {
+               unsigned long flags;
+               unsigned int remain, len;
+               char *buffer;
+
+               /*
+                * For write, we only need to test the half-empty flag
+                * here - if the FIFO is completely empty, then by
+                * definition it is more than half empty.
+                *
+                * For read, check for data available.
+                */
+               if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
+                       break;
+
+               /*
+                * Map the current scatter buffer.
+                */
+               buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
+               remain = host->sg_ptr->length - host->sg_off;
+
+               len = 0;
+               if (status & MCI_RXACTIVE)
+                       len = mmci_pio_read(host, buffer, remain);
+               if (status & MCI_TXACTIVE)
+                       len = mmci_pio_write(host, buffer, remain, status);
+
+               /*
+                * Unmap the buffer.
+                */
+               mmci_kunmap_atomic(host, &flags);
+
+               host->sg_off += len;
+               host->size -= len;
+               remain -= len;
+
+               if (remain)
+                       break;
+
+               if (!mmci_next_sg(host))
+                       break;
+
+               status = readl(base + MMCISTATUS);
+       } while (1);
+
+       /*
+        * If we're nearing the end of the read, switch to
+        * "any data available" mode.
+        */
+       if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
+               writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
+
+       /*
+        * If we run out of data, disable the data IRQs; this
+        * prevents a race where the FIFO becomes empty before
+        * the chip itself has disabled the data path, and
+        * stops us racing with our data end IRQ.
+        */
+       if (host->size == 0) {
+               writel(0, base + MMCIMASK1);
+               writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Handle completion of command and data transfers.
+ */
+static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct mmci_host *host = dev_id;
+       u32 status;
+       int ret = 0;
+
+       spin_lock(&host->lock);
+
+       do {
+               struct mmc_command *cmd;
+               struct mmc_data *data;
+
+               status = readl(host->base + MMCISTATUS);
+               status &= readl(host->base + MMCIMASK0);
+               writel(status, host->base + MMCICLEAR);
+
+               DBG(host, "irq0 %08x\n", status);
+
+               data = host->data;
+               if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
+                             MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
+                       mmci_data_irq(host, data, status);
+
+               cmd = host->cmd;
+               if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
+                       mmci_cmd_irq(host, cmd, status);
+
+               ret = 1;
+       } while (status);
+
+       spin_unlock(&host->lock);
+
+       return IRQ_RETVAL(ret);
+}
+
+static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+
+       WARN_ON(host->mrq != NULL);
+
+       spin_lock_irq(&host->lock);
+
+       host->mrq = mrq;
+
+       if (mrq->data && mrq->data->flags & MMC_DATA_READ)
+               mmci_start_data(host, mrq->data);
+
+       mmci_start_command(host, mrq->cmd, 0);
+
+       spin_unlock_irq(&host->lock);
+}
+
+static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+       u32 clk = 0, pwr = 0;
+
+       DBG(host, "clock %uHz busmode %u powermode %u Vdd %u\n",
+           ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+
+       if (ios->clock) {
+               if (ios->clock >= host->mclk) {
+                       clk = MCI_CLK_BYPASS;
+                       host->cclk = host->mclk;
+               } else {
+                       clk = host->mclk / (2 * ios->clock) - 1;
+                       if (clk > 256)
+                               clk = 255;
+                       host->cclk = host->mclk / (2 * (clk + 1));
+               }
+               clk |= MCI_CLK_ENABLE;
+       }
+
+       if (host->plat->translate_vdd)
+               pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
+
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               break;
+       case MMC_POWER_UP:
+               pwr |= MCI_PWR_UP;
+               break;
+       case MMC_POWER_ON:
+               pwr |= MCI_PWR_ON;
+               break;
+       }
+
+       if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+               pwr |= MCI_ROD;
+
+       writel(clk, host->base + MMCICLOCK);
+
+       if (host->pwr != pwr) {
+               host->pwr = pwr;
+               writel(pwr, host->base + MMCIPOWER);
+       }
+}
+
+static struct mmc_host_ops mmci_ops = {
+       .request        = mmci_request,
+       .set_ios        = mmci_set_ios,
+};
+
+static void mmci_check_status(unsigned long data)
+{
+       struct mmci_host *host = (struct mmci_host *)data;
+       unsigned int status;
+
+       status = host->plat->status(mmc_dev(host->mmc));
+       if (status ^ host->oldstat)
+               mmc_detect_change(host->mmc);
+
+       host->oldstat = status;
+       mod_timer(&host->timer, jiffies + HZ);
+}
+
+static int mmci_probe(struct amba_device *dev, void *id)
+{
+       struct mmc_platform_data *plat = dev->dev.platform_data;
+       struct mmci_host *host;
+       struct mmc_host *mmc;
+       int ret;
+
+       /* must have platform data */
+       if (!plat) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = amba_request_regions(dev, DRIVER_NAME);
+       if (ret)
+               goto out;
+
+       mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto rel_regions;
+       }
+
+       host = mmc_priv(mmc);
+       host->clk = clk_get(&dev->dev, "MCLK");
+       if (IS_ERR(host->clk)) {
+               ret = PTR_ERR(host->clk);
+               host->clk = NULL;
+               goto host_free;
+       }
+
+       ret = clk_use(host->clk);
+       if (ret)
+               goto clk_free;
+
+       ret = clk_enable(host->clk);
+       if (ret)
+               goto clk_unuse;
+
+       host->plat = plat;
+       host->mclk = clk_get_rate(host->clk);
+       host->mmc = mmc;
+       host->base = ioremap(dev->res.start, SZ_4K);
+       if (!host->base) {
+               ret = -ENOMEM;
+               goto clk_disable;
+       }
+
+       mmc->ops = &mmci_ops;
+       mmc->f_min = (host->mclk + 511) / 512;
+       mmc->f_max = min(host->mclk, fmax);
+       mmc->ocr_avail = plat->ocr_mask;
+
+       /*
+        * We can do SGIO
+        */
+       mmc->max_hw_segs = 16;
+       mmc->max_phys_segs = 16;
+
+       /*
+        * Since we only have a 16-bit data length register, we must
+        * ensure that we don't exceed 2^16-1 bytes in a single request.
+        * Choose 64 (512-byte) sectors as the limit.
+        */
+       mmc->max_sectors = 64;
+
+       /*
+        * Set the maximum segment size.  Since we aren't doing DMA
+        * (yet) we are only limited by the data length register.
+        */
+       mmc->max_seg_size = mmc->max_sectors << 9;
+
+       spin_lock_init(&host->lock);
+
+       writel(0, host->base + MMCIMASK0);
+       writel(0, host->base + MMCIMASK1);
+       writel(0xfff, host->base + MMCICLEAR);
+
+       ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host);
+       if (ret)
+               goto unmap;
+
+       ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host);
+       if (ret)
+               goto irq0_free;
+
+       writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+
+       amba_set_drvdata(dev, mmc);
+
+       mmc_add_host(mmc);
+
+       printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
+               mmc->host_name, amba_rev(dev), amba_config(dev),
+               dev->res.start, dev->irq[0], dev->irq[1]);
+
+       init_timer(&host->timer);
+       host->timer.data = (unsigned long)host;
+       host->timer.function = mmci_check_status;
+       host->timer.expires = jiffies + HZ;
+       add_timer(&host->timer);
+
+       return 0;
+
+ irq0_free:
+       free_irq(dev->irq[0], host);
+ unmap:
+       iounmap(host->base);
+ clk_disable:
+       clk_disable(host->clk);
+ clk_unuse:
+       clk_unuse(host->clk);
+ clk_free:
+       clk_put(host->clk);
+ host_free:
+       mmc_free_host(mmc);
+ rel_regions:
+       amba_release_regions(dev);
+ out:
+       return ret;
+}
+
+static int mmci_remove(struct amba_device *dev)
+{
+       struct mmc_host *mmc = amba_get_drvdata(dev);
+
+       amba_set_drvdata(dev, NULL);
+
+       if (mmc) {
+               struct mmci_host *host = mmc_priv(mmc);
+
+               del_timer_sync(&host->timer);
+
+               mmc_remove_host(mmc);
+
+               writel(0, host->base + MMCIMASK0);
+               writel(0, host->base + MMCIMASK1);
+
+               writel(0, host->base + MMCICOMMAND);
+               writel(0, host->base + MMCIDATACTRL);
+
+               free_irq(dev->irq[0], host);
+               free_irq(dev->irq[1], host);
+
+               iounmap(host->base);
+               clk_disable(host->clk);
+               clk_unuse(host->clk);
+               clk_put(host->clk);
+
+               mmc_free_host(mmc);
+
+               amba_release_regions(dev);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmci_suspend(struct amba_device *dev, u32 state)
+{
+       struct mmc_host *mmc = amba_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc) {
+               struct mmci_host *host = mmc_priv(mmc);
+
+               ret = mmc_suspend_host(mmc, state);
+               if (ret == 0)
+                       writel(0, host->base + MMCIMASK0);
+       }
+
+       return ret;
+}
+
+static int mmci_resume(struct amba_device *dev)
+{
+       struct mmc_host *mmc = amba_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc) {
+               struct mmci_host *host = mmc_priv(mmc);
+
+               writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+
+               ret = mmc_resume_host(mmc);
+       }
+
+       return ret;
+}
+#else
+#define mmci_suspend   NULL
+#define mmci_resume    NULL
+#endif
+
+static struct amba_id mmci_ids[] = {
+       {
+               .id     = 0x00041180,
+               .mask   = 0x000fffff,
+       },
+       {
+               .id     = 0x00041181,
+               .mask   = 0x000fffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver mmci_driver = {
+       .drv            = {
+               .name   = DRIVER_NAME,
+       },
+       .probe          = mmci_probe,
+       .remove         = mmci_remove,
+       .suspend        = mmci_suspend,
+       .resume         = mmci_resume,
+       .id_table       = mmci_ids,
+};
+
+static int __init mmci_init(void)
+{
+       return amba_driver_register(&mmci_driver);
+}
+
+static void __exit mmci_exit(void)
+{
+       amba_driver_unregister(&mmci_driver);
+}
+
+module_init(mmci_init);
+module_exit(mmci_exit);
+module_param(fmax, uint, 0444);
+
+MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h
new file mode 100644 (file)
index 0000000..ce3a026
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *  linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#define MMCIPOWER              0x000
+#define MCI_PWR_OFF            0x00
+#define MCI_PWR_UP             0x02
+#define MCI_PWR_ON             0x03
+#define MCI_OD                 (1 << 6)
+#define MCI_ROD                        (1 << 7)
+
+#define MMCICLOCK              0x004
+#define MCI_CLK_ENABLE         (1 << 8)
+#define MCI_CLK_PWRSAVE                (1 << 9)
+#define MCI_CLK_BYPASS         (1 << 10)
+
+#define MMCIARGUMENT           0x008
+#define MMCICOMMAND            0x00c
+#define MCI_CPSM_RESPONSE      (1 << 6)
+#define MCI_CPSM_LONGRSP       (1 << 7)
+#define MCI_CPSM_INTERRUPT     (1 << 8)
+#define MCI_CPSM_PENDING       (1 << 9)
+#define MCI_CPSM_ENABLE                (1 << 10)
+
+#define MMCIRESPCMD            0x010
+#define MMCIRESPONSE0          0x014
+#define MMCIRESPONSE1          0x018
+#define MMCIRESPONSE2          0x01c
+#define MMCIRESPONSE3          0x020
+#define MMCIDATATIMER          0x024
+#define MMCIDATALENGTH         0x028
+#define MMCIDATACTRL           0x02c
+#define MCI_DPSM_ENABLE                (1 << 0)
+#define MCI_DPSM_DIRECTION     (1 << 1)
+#define MCI_DPSM_MODE          (1 << 2)
+#define MCI_DPSM_DMAENABLE     (1 << 3)
+
+#define MMCIDATACNT            0x030
+#define MMCISTATUS             0x034
+#define MCI_CMDCRCFAIL         (1 << 0)
+#define MCI_DATACRCFAIL                (1 << 1)
+#define MCI_CMDTIMEOUT         (1 << 2)
+#define MCI_DATATIMEOUT                (1 << 3)
+#define MCI_TXUNDERRUN         (1 << 4)
+#define MCI_RXOVERRUN          (1 << 5)
+#define MCI_CMDRESPEND         (1 << 6)
+#define MCI_CMDSENT            (1 << 7)
+#define MCI_DATAEND            (1 << 8)
+#define MCI_DATABLOCKEND       (1 << 10)
+#define MCI_CMDACTIVE          (1 << 11)
+#define MCI_TXACTIVE           (1 << 12)
+#define MCI_RXACTIVE           (1 << 13)
+#define MCI_TXFIFOHALFEMPTY    (1 << 14)
+#define MCI_RXFIFOHALFFULL     (1 << 15)
+#define MCI_TXFIFOFULL         (1 << 16)
+#define MCI_RXFIFOFULL         (1 << 17)
+#define MCI_TXFIFOEMPTY                (1 << 18)
+#define MCI_RXFIFOEMPTY                (1 << 19)
+#define MCI_TXDATAAVLBL                (1 << 20)
+#define MCI_RXDATAAVLBL                (1 << 21)
+
+#define MMCICLEAR              0x038
+#define MCI_CMDCRCFAILCLR      (1 << 0)
+#define MCI_DATACRCFAILCLR     (1 << 1)
+#define MCI_CMDTIMEOUTCLR      (1 << 2)
+#define MCI_DATATIMEOUTCLR     (1 << 3)
+#define MCI_TXUNDERRUNCLR      (1 << 4)
+#define MCI_RXOVERRUNCLR       (1 << 5)
+#define MCI_CMDRESPENDCLR      (1 << 6)
+#define MCI_CMDSENTCLR         (1 << 7)
+#define MCI_DATAENDCLR         (1 << 8)
+#define MCI_DATABLOCKENDCLR    (1 << 10)
+
+#define MMCIMASK0              0x03c
+#define MCI_CMDCRCFAILMASK     (1 << 0)
+#define MCI_DATACRCFAILMASK    (1 << 1)
+#define MCI_CMDTIMEOUTMASK     (1 << 2)
+#define MCI_DATATIMEOUTMASK    (1 << 3)
+#define MCI_TXUNDERRUNMASK     (1 << 4)
+#define MCI_RXOVERRUNMASK      (1 << 5)
+#define MCI_CMDRESPENDMASK     (1 << 6)
+#define MCI_CMDSENTMASK                (1 << 7)
+#define MCI_DATAENDMASK                (1 << 8)
+#define MCI_DATABLOCKENDMASK   (1 << 10)
+#define MCI_CMDACTIVEMASK      (1 << 11)
+#define MCI_TXACTIVEMASK       (1 << 12)
+#define MCI_RXACTIVEMASK       (1 << 13)
+#define MCI_TXFIFOHALFEMPTYMASK        (1 << 14)
+#define MCI_RXFIFOHALFFULLMASK (1 << 15)
+#define MCI_TXFIFOFULLMASK     (1 << 16)
+#define MCI_RXFIFOFULLMASK     (1 << 17)
+#define MCI_TXFIFOEMPTYMASK    (1 << 18)
+#define MCI_RXFIFOEMPTYMASK    (1 << 19)
+#define MCI_TXDATAAVLBLMASK    (1 << 20)
+#define MCI_RXDATAAVLBLMASK    (1 << 21)
+
+#define MMCIMASK1              0x040
+#define MMCIFIFOCNT            0x048
+#define MMCIFIFO               0x080 /* to 0x0bc */
+
+#define MCI_IRQENABLE  \
+       (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|     \
+       MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
+       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
+
+/*
+ * The size of the FIFO in bytes.
+ */
+#define MCI_FIFOSIZE   (16*4)
+       
+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
+
+#define NR_SG          16
+
+struct clk;
+
+struct mmci_host {
+       void                    *base;
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+       struct mmc_host         *mmc;
+       struct clk              *clk;
+
+       unsigned int            data_xfered;
+
+       spinlock_t              lock;
+
+       unsigned int            mclk;
+       unsigned int            cclk;
+       u32                     pwr;
+       struct mmc_platform_data *plat;
+
+       struct timer_list       timer;
+       unsigned int            oldstat;
+
+       struct scatterlist      sg[NR_SG];
+       unsigned int            sg_len;
+
+       /* pio stuff */
+       struct scatterlist      *sg_ptr;
+       unsigned int            sg_off;
+       unsigned int            size;
+};
+
+static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+       struct scatterlist *sg = host->sg;
+       struct request *req = data->req;
+
+       /*
+        * Ideally, we want the higher levels to pass us a scatter list.
+        */
+       host->sg_len = blk_rq_map_sg(req->q, req, sg);
+       host->sg_ptr = sg;
+       host->sg_off = 0;
+}
+
+static inline int mmci_next_sg(struct mmci_host *host)
+{
+       host->sg_ptr++;
+       host->sg_off = 0;
+       return --host->sg_len;
+}
+
+static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
+{
+       struct scatterlist *sg = host->sg_ptr;
+
+       local_irq_save(*flags);
+       return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+}
+
+static inline void mmci_kunmap_atomic(struct mmci_host *host, unsigned long *flags)
+{
+       kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ);
+       local_irq_restore(*flags);
+}
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
new file mode 100644 (file)
index 0000000..23a5091
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ *  linux/drivers/mmc/pxa.c - PXA MMCI driver
+ *
+ *  Copyright (C) 2003 Russell King, 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This hardware is really sick:
+ *   - No way to clear interrupts.
+ *   - Have to turn off the clock whenever we touch the device.
+ *   - Doesn't tell you how many data blocks were transferred.
+ *  Yuck!
+ *
+ *     1 and 3 byte data transfers not supported
+ *     max block length up to 1023
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mmc.h>
+
+#include "pxamci.h"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...)      printk(KERN_DEBUG x)
+#else
+#define DBG(x...)      do { } while (0)
+#endif
+
+struct pxamci_host {
+       struct mmc_host         *mmc;
+       spinlock_t              lock;
+       struct resource         *res;
+       void                    *base;
+       int                     irq;
+       int                     dma;
+       unsigned int            clkrt;
+       unsigned int            cmdat;
+       unsigned int            imask;
+       unsigned int            power_mode;
+       struct pxamci_platform_data *pdata;
+
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+
+       dma_addr_t              sg_dma;
+       struct pxa_dma_desc     *sg_cpu;
+
+       dma_addr_t              dma_buf;
+       unsigned int            dma_size;
+       unsigned int            dma_dir;
+};
+
+/*
+ * The base MMC clock rate
+ */
+#define CLOCKRATE      20000000
+
+static inline unsigned int ns_to_clocks(unsigned int ns)
+{
+       return (ns * (CLOCKRATE / 1000000) + 999) / 1000;
+}
+
+static void pxamci_stop_clock(struct pxamci_host *host)
+{
+       if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
+               unsigned long timeout = 10000;
+               unsigned int v;
+
+               writel(STOP_CLOCK, host->base + MMC_STRPCL);
+
+               do {
+                       v = readl(host->base + MMC_STAT);
+                       if (!(v & STAT_CLK_EN))
+                               break;
+                       udelay(1);
+               } while (timeout--);
+
+               if (v & STAT_CLK_EN)
+                       dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
+       }
+}
+
+static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->imask &= ~mask;
+       writel(host->imask, host->base + MMC_I_MASK);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->imask |= mask;
+       writel(host->imask, host->base + MMC_I_MASK);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
+{
+       unsigned int nob = data->blocks;
+       unsigned int timeout, size;
+       dma_addr_t dma;
+       u32 dcmd;
+       int i;
+
+       host->data = data;
+
+       if (data->flags & MMC_DATA_STREAM)
+               nob = 0xffff;
+
+       writel(nob, host->base + MMC_NOB);
+       writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
+
+       timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks;
+       writel((timeout + 255) / 256, host->base + MMC_RDTO);
+
+       if (data->flags & MMC_DATA_READ) {
+               host->dma_dir = DMA_FROM_DEVICE;
+               dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
+               DRCMRTXMMC = 0;
+               DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
+       } else {
+               host->dma_dir = DMA_TO_DEVICE;
+               dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
+               DRCMRRXMMC = 0;
+               DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
+       }
+
+       dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
+
+       host->dma_size = data->blocks << data->blksz_bits;
+       host->dma_buf = dma_map_single(mmc_dev(host->mmc), data->req->buffer,
+                                      host->dma_size, host->dma_dir);
+
+       for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) {
+               u32 len = size;
+
+               if (len > DCMD_LENGTH)
+                       len = 0x1000;
+
+               if (data->flags & MMC_DATA_READ) {
+                       host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
+                       host->sg_cpu[i].dtadr = dma;
+               } else {
+                       host->sg_cpu[i].dsadr = dma;
+                       host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
+               }
+               host->sg_cpu[i].dcmd = dcmd | len;
+
+               dma += len;
+               size -= len;
+
+               if (size) {
+                       host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
+                                                sizeof(struct pxa_dma_desc);
+               } else {
+                       host->sg_cpu[i].ddadr = DDADR_STOP;
+               }
+       }
+       wmb();
+
+       DDADR(host->dma) = host->sg_dma;
+       DCSR(host->dma) = DCSR_RUN;
+}
+
+static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+       WARN_ON(host->cmd != NULL);
+       host->cmd = cmd;
+
+       if (cmd->flags & MMC_RSP_BUSY)
+               cmdat |= CMDAT_BUSY;
+
+       switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) {
+       case MMC_RSP_SHORT | MMC_RSP_CRC:
+               cmdat |= CMDAT_RESP_SHORT;
+               break;
+       case MMC_RSP_SHORT:
+               cmdat |= CMDAT_RESP_R3;
+               break;
+       case MMC_RSP_LONG | MMC_RSP_CRC:
+               cmdat |= CMDAT_RESP_R2;
+               break;
+       default:
+               break;
+       }
+
+       writel(cmd->opcode, host->base + MMC_CMD);
+       writel(cmd->arg >> 16, host->base + MMC_ARGH);
+       writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
+       writel(cmdat, host->base + MMC_CMDAT);
+       writel(host->clkrt, host->base + MMC_CLKRT);
+
+       writel(START_CLOCK, host->base + MMC_STRPCL);
+
+       pxamci_enable_irq(host, END_CMD_RES);
+}
+
+static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
+{
+       DBG("PXAMCI: request done\n");
+       host->mrq = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
+static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
+{
+       struct mmc_command *cmd = host->cmd;
+       int i;
+       u32 v;
+
+       if (!cmd)
+               return 0;
+
+       host->cmd = NULL;
+
+       /*
+        * Did I mention this is Sick.  We always need to
+        * discard the upper 8 bits of the first 16-bit word.
+        */
+       v = readl(host->base + MMC_RES) & 0xffff;
+       for (i = 0; i < 4; i++) {
+               u32 w1 = readl(host->base + MMC_RES) & 0xffff;
+               u32 w2 = readl(host->base + MMC_RES) & 0xffff;
+               cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
+               v = w2;
+       }
+
+       if (stat & STAT_TIME_OUT_RESPONSE) {
+               cmd->error = MMC_ERR_TIMEOUT;
+       } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+               cmd->error = MMC_ERR_BADCRC;
+       }
+
+       pxamci_disable_irq(host, END_CMD_RES);
+       if (host->data && cmd->error == MMC_ERR_NONE) {
+               pxamci_enable_irq(host, DATA_TRAN_DONE);
+       } else {
+               pxamci_finish_request(host, host->mrq);
+       }
+
+       return 1;
+}
+
+static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
+{
+       struct mmc_data *data = host->data;
+
+       if (!data)
+               return 0;
+
+       DCSR(host->dma) = 0;
+       dma_unmap_single(mmc_dev(host->mmc), host->dma_buf, host->dma_size,
+                        host->dma_dir);
+
+       if (stat & STAT_READ_TIME_OUT)
+               data->error = MMC_ERR_TIMEOUT;
+       else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
+               data->error = MMC_ERR_BADCRC;
+
+       /*
+        * There appears to be a hardware design bug here.  There seems to
+        * be no way to find out how much data was transferred to the card.
+        * This means that if there was an error on any block, we mark all
+        * data blocks as being in error.
+        */
+       if (data->error == MMC_ERR_NONE)
+               data->bytes_xfered = data->blocks << data->blksz_bits;
+       else
+               data->bytes_xfered = 0;
+
+       pxamci_disable_irq(host, DATA_TRAN_DONE);
+
+       host->data = NULL;
+       if (host->mrq->stop && data->error == MMC_ERR_NONE) {
+               pxamci_stop_clock(host);
+               pxamci_start_cmd(host, host->mrq->stop, 0);
+       } else {
+               pxamci_finish_request(host, host->mrq);
+       }
+
+       return 1;
+}
+
+static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
+{
+       struct pxamci_host *host = devid;
+       unsigned int ireg;
+       int handled = 0;
+
+       ireg = readl(host->base + MMC_I_REG);
+
+       DBG("PXAMCI: irq %08x\n", ireg);
+
+       if (ireg) {
+               unsigned stat = readl(host->base + MMC_STAT);
+
+               DBG("PXAMCI: stat %08x\n", stat);
+
+               if (ireg & END_CMD_RES)
+                       handled |= pxamci_cmd_done(host, stat);
+               if (ireg & DATA_TRAN_DONE)
+                       handled |= pxamci_data_done(host, stat);
+       }
+
+       return IRQ_RETVAL(handled);
+}
+
+static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct pxamci_host *host = mmc_priv(mmc);
+       unsigned int cmdat;
+
+       WARN_ON(host->mrq != NULL);
+
+       host->mrq = mrq;
+
+       pxamci_stop_clock(host);
+
+       cmdat = host->cmdat;
+       host->cmdat &= ~CMDAT_INIT;
+
+       if (mrq->data) {
+               pxamci_setup_data(host, mrq->data);
+
+               cmdat &= ~CMDAT_BUSY;
+               cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
+               if (mrq->data->flags & MMC_DATA_WRITE)
+                       cmdat |= CMDAT_WRITE;
+
+               if (mrq->data->flags & MMC_DATA_STREAM)
+                       cmdat |= CMDAT_STREAM;
+       }
+
+       pxamci_start_cmd(host, mrq->cmd, cmdat);
+}
+
+static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct pxamci_host *host = mmc_priv(mmc);
+
+       DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n",
+           ios->clock, ios->power_mode, ios->vdd / 100,
+           ios->vdd % 100);
+
+       if (ios->clock) {
+               unsigned int clk = CLOCKRATE / ios->clock;
+               if (CLOCKRATE / clk > ios->clock)
+                       clk <<= 1;
+               host->clkrt = fls(clk) - 1;
+
+               /*
+                * we write clkrt on the next command
+                */
+       } else if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
+               /*
+                * Ensure that the clock is off.
+                */
+               writel(STOP_CLOCK, host->base + MMC_STRPCL);
+       }
+
+       if (host->power_mode != ios->power_mode) {
+               host->power_mode = ios->power_mode;
+
+               if (host->pdata && host->pdata->setpower)
+                       host->pdata->setpower(mmc->dev, ios->vdd);
+
+               if (ios->power_mode == MMC_POWER_ON)
+                       host->cmdat |= CMDAT_INIT;
+       }
+
+       DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n",
+           host->clkrt, host->cmdat);
+}
+
+static struct mmc_host_ops pxamci_ops = {
+       .request        = pxamci_request,
+       .set_ios        = pxamci_set_ios,
+};
+
+static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+{
+       printk(KERN_ERR "DMA%d: IRQ???\n", dma);
+       DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+}
+
+static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs)
+{
+       mmc_detect_change(devid);
+       return IRQ_HANDLED;
+}
+
+static int pxamci_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct mmc_host *mmc;
+       struct pxamci_host *host = NULL;
+       struct resource *r;
+       int ret, irq;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!r || irq == NO_IRQ)
+               return -ENXIO;
+
+       r = request_mem_region(r->start, SZ_4K, "PXAMCI");
+       if (!r)
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mmc->ops = &pxamci_ops;
+       mmc->f_min = 312500;
+       mmc->f_max = 20000000;
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->dma = -1;
+       host->pdata = pdev->dev.platform_data;
+       mmc->ocr_avail = host->pdata ?
+                        host->pdata->ocr_mask :
+                        MMC_VDD_32_33|MMC_VDD_33_34;
+
+       host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
+       if (!host->sg_cpu) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       spin_lock_init(&host->lock);
+       host->res = r;
+       host->irq = irq;
+       host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+                     END_CMD_RES|PRG_DONE|DATA_TRAN_DONE;
+
+       host->base = ioremap(r->start, SZ_4K);
+       if (!host->base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * Ensure that the host controller is shut down, and setup
+        * with our defaults.
+        */
+       pxamci_stop_clock(host);
+       writel(0, host->base + MMC_SPI);
+       writel(64, host->base + MMC_RESTO);
+       writel(host->imask, host->base + MMC_I_MASK);
+
+       pxa_gpio_mode(GPIO6_MMCCLK_MD);
+       pxa_gpio_mode(GPIO8_MMCCS0_MD);
+       pxa_set_cken(CKEN12_MMC, 1);
+
+       host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host);
+       if (host->dma < 0) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host);
+       if (ret)
+               goto out;
+
+       dev_set_drvdata(dev, mmc);
+
+       if (host->pdata && host->pdata->init)
+               host->pdata->init(dev, pxamci_detect_irq, mmc);
+
+       mmc_add_host(mmc);
+
+       return 0;
+
+ out:
+       if (host) {
+               if (host->dma >= 0)
+                       pxa_free_dma(host->dma);
+               if (host->base)
+                       iounmap(host->base);
+               if (host->sg_cpu)
+                       dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+       }
+       if (mmc)
+               mmc_free_host(mmc);
+       release_resource(r);
+       return ret;
+}
+
+static int pxamci_remove(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+       if (mmc) {
+               struct pxamci_host *host = mmc_priv(mmc);
+
+               if (host->pdata && host->pdata->exit)
+                       host->pdata->exit(dev, mmc);
+
+               mmc_remove_host(mmc);
+
+               pxamci_stop_clock(host);
+               writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+                      END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
+                      host->base + MMC_I_MASK);
+
+               pxa_set_cken(CKEN12_MMC, 0);
+
+               free_irq(host->irq, host);
+               pxa_free_dma(host->dma);
+               iounmap(host->base);
+               dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+
+               pxa_set_cken(CKEN12_MMC, 0);
+
+               release_resource(host->res);
+
+               mmc_free_host(mmc);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxamci_suspend(struct device *dev, u32 state, u32 level)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc && level == SUSPEND_DISABLE)
+               ret = mmc_suspend_host(mmc, state);
+
+       return ret;
+}
+
+static int pxamci_resume(struct device *dev, u32 level)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (mmc && level == RESUME_ENABLE)
+               ret = mmc_resume_host(mmc);
+
+       return ret;
+}
+#else
+#define pxamci_suspend NULL
+#define pxamci_resume  NULL
+#endif
+
+static struct device_driver pxamci_driver = {
+       .name           = "pxa2xx-mci",
+       .bus            = &platform_bus_type,
+       .probe          = pxamci_probe,
+       .remove         = pxamci_remove,
+       .suspend        = pxamci_suspend,
+       .resume         = pxamci_resume,
+};
+
+static int __init pxamci_init(void)
+{
+       return driver_register(&pxamci_driver);
+}
+
+static void __exit pxamci_exit(void)
+{
+       driver_unregister(&pxamci_driver);
+}
+
+module_init(pxamci_init);
+module_exit(pxamci_exit);
+
+MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/pxamci.h
new file mode 100644 (file)
index 0000000..a80b24d
--- /dev/null
@@ -0,0 +1,94 @@
+#undef MMC_STRPCL
+#undef MMC_STAT
+#undef MMC_CLKRT
+#undef MMC_SPI
+#undef MMC_CMDAT
+#undef MMC_RESTO
+#undef MMC_RDTO
+#undef MMC_BLKLEN
+#undef MMC_NOB
+#undef MMC_PRTBUF
+#undef MMC_I_MASK
+#undef END_CMD_RES
+#undef PRG_DONE
+#undef DATA_TRAN_DONE
+#undef MMC_I_REG
+#undef MMC_CMD
+#undef MMC_ARGH
+#undef MMC_ARGL
+#undef MMC_RES
+#undef MMC_RXFIFO
+#undef MMC_TXFIFO
+
+#define MMC_STRPCL     0x0000
+#define STOP_CLOCK             (1 << 0)
+#define START_CLOCK            (2 << 0)
+
+#define MMC_STAT       0x0004
+#define STAT_END_CMD_RES               (1 << 13)
+#define STAT_PRG_DONE                  (1 << 12)
+#define STAT_DATA_TRAN_DONE            (1 << 11)
+#define STAT_CLK_EN                    (1 << 8)
+#define STAT_RECV_FIFO_FULL            (1 << 7)
+#define STAT_XMIT_FIFO_EMPTY           (1 << 6)
+#define STAT_RES_CRC_ERR               (1 << 5)
+#define STAT_SPI_READ_ERROR_TOKEN      (1 << 4)
+#define STAT_CRC_READ_ERROR            (1 << 3)
+#define STAT_CRC_WRITE_ERROR           (1 << 2)
+#define STAT_TIME_OUT_RESPONSE         (1 << 1)
+#define STAT_READ_TIME_OUT             (1 << 0)
+
+#define MMC_CLKRT      0x0008          /* 3 bit */
+
+#define MMC_SPI                0x000c
+#define SPI_CS_ADDRESS         (1 << 3)
+#define SPI_CS_EN              (1 << 2)
+#define CRC_ON                 (1 << 1)
+#define SPI_EN                 (1 << 0)
+
+#define MMC_CMDAT      0x0010
+#define CMDAT_DMAEN            (1 << 7)
+#define CMDAT_INIT             (1 << 6)
+#define CMDAT_BUSY             (1 << 5)
+#define CMDAT_STREAM           (1 << 4)        /* 1 = stream */
+#define CMDAT_WRITE            (1 << 3)        /* 1 = write */
+#define CMDAT_DATAEN           (1 << 2)
+#define CMDAT_RESP_NONE                (0 << 0)
+#define CMDAT_RESP_SHORT       (1 << 0)
+#define CMDAT_RESP_R2          (2 << 0)
+#define CMDAT_RESP_R3          (3 << 0)
+
+#define MMC_RESTO      0x0014  /* 7 bit */
+
+#define MMC_RDTO       0x0018  /* 16 bit */
+
+#define MMC_BLKLEN     0x001c  /* 10 bit */
+
+#define MMC_NOB                0x0020  /* 16 bit */
+
+#define MMC_PRTBUF     0x0024
+#define BUF_PART_FULL          (1 << 0)
+
+#define MMC_I_MASK     0x0028
+#define TXFIFO_WR_REQ          (1 << 6)
+#define RXFIFO_RD_REQ          (1 << 5)
+#define CLK_IS_OFF             (1 << 4)
+#define STOP_CMD               (1 << 3)
+#define END_CMD_RES            (1 << 2)
+#define PRG_DONE               (1 << 1)
+#define DATA_TRAN_DONE         (1 << 0)
+
+#define MMC_I_REG      0x002c
+/* same as MMC_I_MASK */
+
+#define MMC_CMD                0x0030
+
+#define MMC_ARGH       0x0034  /* 16 bit */
+
+#define MMC_ARGL       0x0038  /* 16 bit */
+
+#define MMC_RES                0x003c  /* 16 bit */
+
+#define MMC_RXFIFO     0x0040  /* 8 bit */
+
+#define MMC_TXFIFO     0x0044  /* 8 bit */
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
new file mode 100644 (file)
index 0000000..0871134
--- /dev/null
@@ -0,0 +1,1596 @@
+/*
+ *  linux/drivers/mmc/wbsd.c
+ *
+ *  Copyright (C) 2004 Pierre Ossman, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "wbsd.h"
+
+#define DRIVER_NAME "wbsd"
+#define DRIVER_VERSION "1.0"
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...) \
+       printk(KERN_DEBUG DRIVER_NAME ": " x)
+#define DBGF(f, x...) \
+       printk(KERN_DEBUG DRIVER_NAME " [%s()]: " f, __func__, ##x)
+#else
+#define DBG(x...)      do { } while (0)
+#define DBGF(x...)     do { } while (0)
+#endif
+
+static unsigned int io = 0x248;
+static unsigned int irq = 6;
+static int dma = 2;
+
+#ifdef CONFIG_MMC_DEBUG
+void DBG_REG(int reg, u8 value)
+{
+       int i;
+       
+       printk(KERN_DEBUG "wbsd: Register %d: 0x%02X %3d '%c' ",
+               reg, (int)value, (int)value, (value < 0x20)?'.':value);
+       
+       for (i = 7;i >= 0;i--)
+       {
+               if (value & (1 << i))
+                       printk("x");
+               else
+                       printk(".");
+       }
+       
+       printk("\n");
+}
+#else
+#define DBG_REG(r, v) do {}  while (0)
+#endif
+
+/*
+ * Basic functions
+ */
+
+static inline void wbsd_unlock_config(struct wbsd_host* host)
+{
+       outb(host->unlock_code, host->config);
+       outb(host->unlock_code, host->config);
+}
+
+static inline void wbsd_lock_config(struct wbsd_host* host)
+{
+       outb(LOCK_CODE, host->config);
+}
+
+static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
+{
+       outb(reg, host->config);
+       outb(value, host->config + 1);
+}
+
+static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
+{
+       outb(reg, host->config);
+       return inb(host->config + 1);
+}
+
+static inline void wbsd_write_index(struct wbsd_host* host, u8 index, u8 value)
+{
+       outb(index, host->base + WBSD_IDXR);
+       outb(value, host->base + WBSD_DATAR);
+}
+
+static inline u8 wbsd_read_index(struct wbsd_host* host, u8 index)
+{
+       outb(index, host->base + WBSD_IDXR);
+       return inb(host->base + WBSD_DATAR);
+}
+
+/*
+ * Common routines
+ */
+
+static void wbsd_init_device(struct wbsd_host* host)
+{
+       u8 setup, ier;
+       
+       /*
+        * Reset chip (SD/MMC part) and fifo.
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+       
+       /*
+        * Read back default clock.
+        */
+       host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
+
+       /*
+        * Power down port.
+        */
+       outb(WBSD_POWER_N, host->base + WBSD_CSR);
+       
+       /*
+        * Set maximum timeout.
+        */
+       wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
+       
+       /*
+        * Enable interesting interrupts.
+        */
+       ier = 0;
+       ier |= WBSD_EINT_CARD;
+       ier |= WBSD_EINT_FIFO_THRE;
+       ier |= WBSD_EINT_CCRC;
+       ier |= WBSD_EINT_TIMEOUT;
+       ier |= WBSD_EINT_CRC;
+       ier |= WBSD_EINT_TC;
+
+       outb(ier, host->base + WBSD_EIR);
+
+       /*
+        * Clear interrupts.
+        */
+       inb(host->base + WBSD_ISR);
+}
+
+static void wbsd_reset(struct wbsd_host* host)
+{
+       u8 setup;
+       
+       printk(KERN_ERR DRIVER_NAME ": Resetting chip\n");
+       
+       /*
+        * Soft reset of chip (SD/MMC part).
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       setup |= WBSD_SOFT_RESET;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+}
+
+static void wbsd_request_end(struct wbsd_host* host, struct mmc_request* mrq)
+{
+       unsigned long dmaflags;
+       
+       DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
+       
+       if (host->dma >= 0)
+       {
+               /*
+                * Release ISA DMA controller.
+                */
+               dmaflags = claim_dma_lock();
+               disable_dma(host->dma);
+               clear_dma_ff(host->dma);
+               release_dma_lock(dmaflags);
+
+               /*
+                * Disable DMA on host.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, 0);
+       }
+       
+       host->mrq = NULL;
+
+       /*
+        * MMC layer might call back into the driver so first unlock.
+        */
+       spin_unlock(&host->lock);
+       mmc_request_done(host->mmc, mrq);
+       spin_lock(&host->lock);
+}
+
+/*
+ * Scatter/gather functions
+ */
+
+static inline void wbsd_init_sg(struct wbsd_host* host, struct mmc_data* data)
+{
+       struct request* req = data->req;
+       
+       /*
+        * Get info. about SG list from data structure.
+        */
+       host->cur_sg = data->sg;
+       host->num_sg = data->sg_len;
+
+       host->offset = 0;
+       host->remain = host->cur_sg->length;
+}
+
+static inline int wbsd_next_sg(struct wbsd_host* host)
+{
+       /*
+        * Skip to next SG entry.
+        */
+       host->cur_sg++;
+       host->num_sg--;
+
+       /*
+        * Any entries left?
+        */
+       if (host->num_sg > 0)
+         {
+           host->offset = 0;
+           host->remain = host->cur_sg->length;
+         }
+       
+       return host->num_sg;
+}
+
+static inline char* wbsd_kmap_sg(struct wbsd_host* host)
+{
+       return kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
+               host->cur_sg->offset;
+}
+
+static inline void wbsd_kunmap_sg(struct wbsd_host* host)
+{
+       kunmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
+}
+
+static inline void wbsd_sg_to_dma(struct wbsd_host* host, struct mmc_data* data)
+{
+       unsigned int len, i, size;
+       struct scatterlist* sg;
+       char* dmabuf = host->dma_buffer;
+       char* sgbuf;
+       
+       size = host->size;
+       
+       sg = data->sg;
+       len = data->sg_len;
+       
+       /*
+        * Just loop through all entries. Size might not
+        * be the entire list though so make sure that
+        * we do not transfer too much.
+        */
+       for (i = 0;i < len;i++)
+       {
+               sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+               if (size < sg[i].length)
+                       memcpy(dmabuf, sgbuf, size);
+               else
+                       memcpy(dmabuf, sgbuf, sg[i].length);
+               kunmap_atomic(sg[i].page, KM_BIO_SRC_IRQ);
+               dmabuf += sg[i].length;
+               
+               if (size < sg[i].length)
+                       size = 0;
+               else
+                       size -= sg[i].length;
+       
+               if (size == 0)
+                       break;
+       }
+       
+       /*
+        * Check that we didn't get a request to transfer
+        * more data than can fit into the SG list.
+        */
+       
+       BUG_ON(size != 0);
+       
+       host->size -= size;
+}
+
+static inline void wbsd_dma_to_sg(struct wbsd_host* host, struct mmc_data* data)
+{
+       unsigned int len, i, size;
+       struct scatterlist* sg;
+       char* dmabuf = host->dma_buffer;
+       char* sgbuf;
+       
+       size = host->size;
+       
+       sg = data->sg;
+       len = data->sg_len;
+       
+       /*
+        * Just loop through all entries. Size might not
+        * be the entire list though so make sure that
+        * we do not transfer too much.
+        */
+       for (i = 0;i < len;i++)
+       {
+               sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+               if (size < sg[i].length)
+                       memcpy(sgbuf, dmabuf, size);
+               else
+                       memcpy(sgbuf, dmabuf, sg[i].length);
+               kunmap_atomic(sg[i].page, KM_BIO_SRC_IRQ);
+               dmabuf += sg[i].length;
+               
+               if (size < sg[i].length)
+                       size = 0;
+               else
+                       size -= sg[i].length;
+               
+               if (size == 0)
+                       break;
+       }
+       
+       /*
+        * Check that we didn't get a request to transfer
+        * more data than can fit into the SG list.
+        */
+       
+       BUG_ON(size != 0);
+       
+       host->size -= size;
+}
+
+/*
+ * Command handling
+ */
+static inline void wbsd_get_short_reply(struct wbsd_host* host,
+       struct mmc_command* cmd)
+{
+       /*
+        * Correct response type?
+        */
+       if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT)
+       {
+               cmd->error = MMC_ERR_INVALID;
+               return;
+       }
+       
+       cmd->resp[0] =
+               wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
+       cmd->resp[0] |=
+               wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
+       cmd->resp[0] |=
+               wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
+       cmd->resp[0] |=
+               wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
+       cmd->resp[1] =
+               wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
+}
+
+static inline void wbsd_get_long_reply(struct wbsd_host* host,
+       struct mmc_command* cmd)
+{
+       int i;
+       
+       /*
+        * Correct response type?
+        */
+       if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG)
+       {
+               cmd->error = MMC_ERR_INVALID;
+               return;
+       }
+       
+       for (i = 0;i < 4;i++)
+       {
+               cmd->resp[i] =
+                       wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
+               cmd->resp[i] |=
+                       wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
+               cmd->resp[i] |=
+                       wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
+               cmd->resp[i] |=
+                       wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
+       }
+}
+
+static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs);
+
+static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
+{
+       int i;
+       u8 status, eir, isr;
+       
+       DBGF("Sending cmd (%x)\n", cmd->opcode);
+
+       /*
+        * Disable interrupts as the interrupt routine
+        * will destroy the contents of ISR.
+        */
+       eir = inb(host->base + WBSD_EIR);
+       outb(0, host->base + WBSD_EIR);
+       
+       /*
+        * Send the command (CRC calculated by host).
+        */
+       outb(cmd->opcode, host->base + WBSD_CMDR);
+       for (i = 3;i >= 0;i--)
+               outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
+       
+       cmd->error = MMC_ERR_NONE;
+       
+       /*
+        * Wait for the request to complete.
+        */
+       do {
+               status = wbsd_read_index(host, WBSD_IDX_STATUS);
+       } while (status & WBSD_CARDTRAFFIC);
+
+       /*
+        * Do we expect a reply?
+        */
+       if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE)
+       {
+               /*
+                * Read back status.
+                */
+               isr = inb(host->base + WBSD_ISR);
+               
+               /* Card removed? */
+               if (isr & WBSD_INT_CARD)
+                       cmd->error = MMC_ERR_TIMEOUT;
+               /* Timeout? */
+               else if (isr & WBSD_INT_TIMEOUT)
+                       cmd->error = MMC_ERR_TIMEOUT;
+               /* CRC? */
+               else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
+                       cmd->error = MMC_ERR_BADCRC;
+               /* All ok */
+               else
+               {
+                       if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT)
+                               wbsd_get_short_reply(host, cmd);
+                       else
+                               wbsd_get_long_reply(host, cmd);
+               }
+       }
+
+       /*
+        * Restore interrupt mask to previous value.
+        */
+       outb(eir, host->base + WBSD_EIR);
+       
+       /*
+        * Call the interrupt routine to jump start
+        * interrupts.
+        */
+       wbsd_irq(0, host, NULL);
+
+       DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
+}
+
+/*
+ * Data functions
+ */
+
+static void wbsd_empty_fifo(struct wbsd_host* host)
+{
+       struct mmc_data* data = host->mrq->cmd->data;
+       char* buffer;
+       
+       /*
+        * Handle excessive data.
+        */
+       if (data->bytes_xfered == host->size)
+               return;
+       
+       buffer = wbsd_kmap_sg(host) + host->offset;
+
+       /*
+        * Drain the fifo. This has a tendency to loop longer
+        * than the FIFO length (usually one block).
+        */
+       while (!(inb(host->base + WBSD_FSR) & WBSD_FIFO_EMPTY))
+       {
+               *buffer = inb(host->base + WBSD_DFR);
+               buffer++;
+               host->offset++;
+               host->remain--;
+
+               data->bytes_xfered++;
+               
+               /*
+                * Transfer done?
+                */
+               if (data->bytes_xfered == host->size)
+               {
+                       wbsd_kunmap_sg(host);                           
+                       return;
+               }
+               
+               /*
+                * End of scatter list entry?
+                */
+               if (host->remain == 0)
+               {
+                       wbsd_kunmap_sg(host);
+                       
+                       /*
+                        * Get next entry. Check if last.
+                        */
+                       if (!wbsd_next_sg(host))
+                       {
+                               /*
+                                * We should never reach this point.
+                                * It means that we're trying to
+                                * transfer more blocks than can fit
+                                * into the scatter list.
+                                */
+                               BUG_ON(1);
+                               
+                               host->size = data->bytes_xfered;
+                               
+                               return;
+                       }
+                       
+                       buffer = wbsd_kmap_sg(host);
+               }
+       }
+       
+       wbsd_kunmap_sg(host);
+}
+
+static void wbsd_fill_fifo(struct wbsd_host* host)
+{
+       struct mmc_data* data = host->mrq->cmd->data;
+       char* buffer;
+       
+       /*
+        * Check that we aren't being called after the
+        * entire buffer has been transfered.
+        */
+       if (data->bytes_xfered == host->size)
+               return;
+
+       buffer = wbsd_kmap_sg(host) + host->offset;
+
+       /*
+        * Fill the fifo. This has a tendency to loop longer
+        * than the FIFO length (usually one block).
+        */
+       while (!(inb(host->base + WBSD_FSR) & WBSD_FIFO_FULL))
+       {
+               outb(*buffer, host->base + WBSD_DFR);
+               buffer++;
+               host->offset++;
+               host->remain--;
+               
+               data->bytes_xfered++;
+               
+               /*
+                * Transfer done?
+                */
+               if (data->bytes_xfered == host->size)
+               {
+                       wbsd_kunmap_sg(host);
+                       return;
+               }
+
+               /*
+                * End of scatter list entry?
+                */
+               if (host->remain == 0)
+               {
+                       wbsd_kunmap_sg(host);
+                       
+                       /*
+                        * Get next entry. Check if last.
+                        */
+                       if (!wbsd_next_sg(host))
+                       {
+                               /*
+                                * We should never reach this point.
+                                * It means that we're trying to
+                                * transfer more blocks than can fit
+                                * into the scatter list.
+                                */
+                               BUG_ON(1);
+                               
+                               host->size = data->bytes_xfered;
+                               
+                               return;
+                       }
+                       
+                       buffer = wbsd_kmap_sg(host);
+               }
+       }
+       
+       wbsd_kunmap_sg(host);
+}
+
+static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
+{
+       u16 blksize;
+       u8 setup;
+       unsigned long dmaflags;
+
+       DBGF("blksz %04x blks %04x flags %08x\n",
+               1 << data->blksz_bits, data->blocks, data->flags);
+       DBGF("tsac %d ms nsac %d clk\n",
+               data->timeout_ns / 1000000, data->timeout_clks);
+       
+       /*
+        * Calculate size.
+        */
+       host->size = data->blocks << data->blksz_bits;
+
+       /*
+        * Check timeout values for overflow.
+        * (Yes, some cards cause this value to overflow).
+        */
+       if (data->timeout_ns > 127000000)
+               wbsd_write_index(host, WBSD_IDX_TAAC, 127);
+       else
+               wbsd_write_index(host, WBSD_IDX_TAAC, data->timeout_ns/1000000);
+       
+       if (data->timeout_clks > 255)
+               wbsd_write_index(host, WBSD_IDX_NSAC, 255);
+       else
+               wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
+       
+       /*
+        * Inform the chip of how large blocks will be
+        * sent. It needs this to determine when to
+        * calculate CRC.
+        *
+        * Space for CRC must be included in the size.
+        */
+       blksize = (1 << data->blksz_bits) + 2;
+       
+       wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+       wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+
+       /*
+        * Clear the FIFO. This is needed even for DMA
+        * transfers since the chip still uses the FIFO
+        * internally.
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       setup |= WBSD_FIFO_RESET;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+       
+       /*
+        * DMA transfer?
+        */
+       if (host->dma >= 0)
+       {       
+               /*
+                * The buffer for DMA is only 64 kB.
+                */
+               BUG_ON(host->size > 0x10000);
+               if (host->size > 0x10000)
+               {
+                       data->error = MMC_ERR_INVALID;
+                       return;
+               }
+               
+               /*
+                * Transfer data from the SG list to
+                * the DMA buffer.
+                */
+               if (data->flags & MMC_DATA_WRITE)
+                       wbsd_sg_to_dma(host, data);
+               
+               /*
+                * Initialise the ISA DMA controller.
+                */     
+               dmaflags = claim_dma_lock();
+               disable_dma(host->dma);
+               clear_dma_ff(host->dma);
+               if (data->flags & MMC_DATA_READ)
+                       set_dma_mode(host->dma, DMA_MODE_READ);
+               else
+                       set_dma_mode(host->dma, DMA_MODE_WRITE);
+               set_dma_addr(host->dma, host->dma_addr);
+               set_dma_count(host->dma, host->size);
+
+               enable_dma(host->dma);
+               release_dma_lock(dmaflags);
+
+               /*
+                * Enable DMA on the host.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA,
+                       WBSD_DMA_SINGLE | WBSD_DMA_ENABLE);
+       }
+       else
+       {
+               /*
+                * This flag is used to keep printk
+                * output to a minimum.
+                */
+               host->firsterr = 1;
+               
+               /*
+                * Initialise the SG list.
+                */
+               wbsd_init_sg(host, data);
+       
+               /*
+                * Turn off DMA.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, 0);
+       
+               /*
+                * Set up FIFO threshold levels (and fill
+                * buffer if doing a write).
+                */
+               if (data->flags & MMC_DATA_READ)
+               {
+                       wbsd_write_index(host, WBSD_IDX_FIFOEN,
+                               WBSD_FIFOEN_FULL | 8);
+               }
+               else
+               {
+                       wbsd_write_index(host, WBSD_IDX_FIFOEN,
+                               WBSD_FIFOEN_EMPTY | 8);
+                       wbsd_fill_fifo(host);
+               }
+       }       
+               
+       data->error = MMC_ERR_NONE;
+}
+
+static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
+{
+       unsigned long dmaflags;
+       int count;
+       
+       WARN_ON(host->mrq == NULL);
+
+       /*
+        * Send a stop command if needed.
+        */
+       if (data->stop)
+               wbsd_send_command(host, data->stop);
+       
+       /*
+        * DMA transfer?
+        */
+       if (host->dma >= 0)
+       {
+               /*
+                * Disable DMA on the host.
+                */
+               wbsd_write_index(host, WBSD_IDX_DMA, 0);
+               
+               /*
+                * Turn of ISA DMA controller.
+                */
+               dmaflags = claim_dma_lock();
+               disable_dma(host->dma);
+               clear_dma_ff(host->dma);
+               count = get_dma_residue(host->dma);
+               release_dma_lock(dmaflags);
+               
+               /*
+                * Any leftover data?
+                */
+               if (count)
+               {
+                       printk(KERN_ERR DRIVER_NAME ": Incomplete DMA "
+                               "transfer. %d bytes left.\n", count);
+                       
+                       data->error = MMC_ERR_FAILED;
+               }
+               else
+               {
+                       /*
+                        * Transfer data from DMA buffer to
+                        * SG list.
+                        */
+                       if (data->flags & MMC_DATA_READ)
+                               wbsd_dma_to_sg(host, data);
+                       
+                       data->bytes_xfered = host->size;
+               }
+       }
+       
+       DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
+       
+       wbsd_request_end(host, host->mrq);
+}
+
+/*
+ * MMC Callbacks
+ */
+
+static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
+{
+       struct wbsd_host* host = mmc_priv(mmc);
+       struct mmc_command* cmd;
+
+       /*
+        * Disable tasklets to avoid a deadlock.
+        */
+       spin_lock_bh(&host->lock);
+
+       BUG_ON(host->mrq != NULL);
+
+       cmd = mrq->cmd;
+
+       host->mrq = mrq;
+       
+       /*
+        * If there is no card in the slot then
+        * timeout immediatly.
+        */
+       if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT))
+       {
+               cmd->error = MMC_ERR_TIMEOUT;
+               goto done;
+       }
+
+       /*
+        * Does the request include data?
+        */
+       if (cmd->data)
+       {
+               wbsd_prepare_data(host, cmd->data);
+               
+               if (cmd->data->error != MMC_ERR_NONE)
+                       goto done;
+       }
+       
+       wbsd_send_command(host, cmd);
+
+       /*
+        * If this is a data transfer the request
+        * will be finished after the data has
+        * transfered.
+        */     
+       if (cmd->data && (cmd->error == MMC_ERR_NONE))
+       {               
+               spin_unlock_bh(&host->lock);
+
+               return;
+       }
+               
+done:
+       wbsd_request_end(host, mrq);
+
+       spin_unlock_bh(&host->lock);
+}
+
+static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
+{
+       struct wbsd_host* host = mmc_priv(mmc);
+       u8 clk, setup, pwr;
+       
+       DBGF("clock %uHz busmode %u powermode %u Vdd %u\n",
+               ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+
+       spin_lock_bh(&host->lock);
+
+       /*
+        * Reset the chip on each power off.
+        * Should clear out any weird states.
+        */
+       if (ios->power_mode == MMC_POWER_OFF)
+               wbsd_init_device(host);
+       
+       if (ios->clock >= 24000000)
+               clk = WBSD_CLK_24M;
+       else if (ios->clock >= 16000000)
+               clk = WBSD_CLK_16M;
+       else if (ios->clock >= 12000000)
+               clk = WBSD_CLK_12M;
+       else
+               clk = WBSD_CLK_375K;
+
+       /*
+        * Only write to the clock register when
+        * there is an actual change.
+        */
+       if (clk != host->clk)
+       {
+               wbsd_write_index(host, WBSD_IDX_CLK, clk);
+               host->clk = clk;
+       }
+
+       if (ios->power_mode != MMC_POWER_OFF)
+       {
+               /*
+                * Power up card.
+                */
+               pwr = inb(host->base + WBSD_CSR);
+               pwr &= ~WBSD_POWER_N;
+               outb(pwr, host->base + WBSD_CSR);
+
+               /*
+                * This behaviour is stolen from the
+                * Windows driver. Don't know why, but
+                * it is needed.
+                */
+               setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+               if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+                       setup |= WBSD_DAT3_H;
+               else
+                       setup &= ~WBSD_DAT3_H;
+               wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+               mdelay(1);
+       }
+
+       spin_unlock_bh(&host->lock);
+}
+
+/*
+ * Tasklets
+ */
+
+inline static struct mmc_data* wbsd_get_data(struct wbsd_host* host)
+{
+       WARN_ON(!host->mrq);
+       if (!host->mrq)
+               return NULL;
+
+       WARN_ON(!host->mrq->cmd);
+       if (!host->mrq->cmd)
+               return NULL;
+
+       WARN_ON(!host->mrq->cmd->data);
+       if (!host->mrq->cmd->data)
+               return NULL;
+       
+       return host->mrq->cmd->data;
+}
+
+static void wbsd_tasklet_card(unsigned long param)
+{
+       struct wbsd_host* host = (struct wbsd_host*)param;
+       u8 csr;
+       
+       spin_lock(&host->lock);
+       
+       csr = inb(host->base + WBSD_CSR);
+       WARN_ON(csr == 0xff);
+       
+       if (csr & WBSD_CARDPRESENT)
+               DBG("Card inserted\n");
+       else
+       {
+               DBG("Card removed\n");
+               
+               if (host->mrq)
+               {
+                       printk(KERN_ERR DRIVER_NAME
+                               ": Card removed during transfer!\n");
+                       wbsd_reset(host);
+                       
+                       host->mrq->cmd->error = MMC_ERR_FAILED;
+                       tasklet_schedule(&host->finish_tasklet);
+               }
+       }
+       
+       /*
+        * Unlock first since we might get a call back.
+        */
+       spin_unlock(&host->lock);
+
+       mmc_detect_change(host->mmc);
+}
+
+static void wbsd_tasklet_fifo(unsigned long param)
+{
+       struct wbsd_host* host = (struct wbsd_host*)param;
+       struct mmc_data* data;
+       
+       spin_lock(&host->lock);
+               
+       if (!host->mrq)
+               goto end;
+       
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+
+       if (data->flags & MMC_DATA_WRITE)
+               wbsd_fill_fifo(host);
+       else
+               wbsd_empty_fifo(host);
+
+       /*
+        * Done?
+        */
+       if (host->size == data->bytes_xfered)
+       {
+               wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
+               tasklet_schedule(&host->finish_tasklet);
+       }
+
+end:   
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_crc(unsigned long param)
+{
+       struct wbsd_host* host = (struct wbsd_host*)param;
+       struct mmc_data* data;
+       
+       spin_lock(&host->lock);
+       
+       WARN_ON(!host->mrq);
+       if (!host->mrq)
+               goto end;
+       
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+       
+       DBGF("CRC error\n");
+
+       data->error = MMC_ERR_BADCRC;
+       
+       tasklet_schedule(&host->finish_tasklet);
+
+end:           
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_timeout(unsigned long param)
+{
+       struct wbsd_host* host = (struct wbsd_host*)param;
+       struct mmc_data* data;
+       
+       spin_lock(&host->lock);
+       
+       WARN_ON(!host->mrq);
+       if (!host->mrq)
+               goto end;
+       
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+       
+       DBGF("Timeout\n");
+
+       data->error = MMC_ERR_TIMEOUT;
+       
+       tasklet_schedule(&host->finish_tasklet);
+
+end:   
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_finish(unsigned long param)
+{
+       struct wbsd_host* host = (struct wbsd_host*)param;
+       struct mmc_data* data;
+       
+       spin_lock(&host->lock);
+       
+       WARN_ON(!host->mrq);
+       if (!host->mrq)
+               goto end;
+       
+       data = wbsd_get_data(host);
+       if (!data)
+               goto end;
+
+       wbsd_finish_data(host, data);
+       
+end:   
+       spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_block(unsigned long param)
+{
+       struct wbsd_host* host = (struct wbsd_host*)param;
+       struct mmc_data* data;
+       
+       spin_lock(&host->lock);
+
+       if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) !=
+               WBSD_CRC_OK)
+       {
+               data = wbsd_get_data(host);
+               if (!data)
+                       goto end;
+               
+               DBGF("CRC error\n");
+
+               data->error = MMC_ERR_BADCRC;
+       
+               tasklet_schedule(&host->finish_tasklet);
+       }
+
+end:   
+       spin_unlock(&host->lock);
+}
+
+/*
+ * Interrupt handling
+ */
+
+static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct wbsd_host* host = dev_id;
+       int isr;
+       
+       isr = inb(host->base + WBSD_ISR);
+
+       /*
+        * Was it actually our hardware that caused the interrupt?
+        */
+       if (isr == 0xff || isr == 0x00)
+               return IRQ_NONE;
+
+       /*
+        * Schedule tasklets as needed.
+        */
+       if (isr & WBSD_INT_CARD)
+               tasklet_schedule(&host->card_tasklet);
+       if (isr & WBSD_INT_FIFO_THRE)
+               tasklet_hi_schedule(&host->fifo_tasklet);
+       if (isr & WBSD_INT_CRC)
+               tasklet_hi_schedule(&host->crc_tasklet);
+       if (isr & WBSD_INT_TIMEOUT)
+               tasklet_hi_schedule(&host->timeout_tasklet);
+       if (isr & WBSD_INT_BUSYEND)
+               tasklet_hi_schedule(&host->block_tasklet);
+       if (isr & WBSD_INT_TC)
+               tasklet_schedule(&host->finish_tasklet);
+       
+       return IRQ_HANDLED;
+}
+
+/*
+ * Support functions for probe
+ */
+
+static int wbsd_scan(struct wbsd_host* host)
+{
+       int i, j, k;
+       int id;
+       
+       /*
+        * Iterate through all ports, all codes to
+        * find hardware that is in our known list.
+        */
+       for (i = 0;i < sizeof(config_ports)/sizeof(int);i++)
+       {
+               if (!request_region(config_ports[i], 2, DRIVER_NAME))
+                       continue;
+                       
+               for (j = 0;j < sizeof(unlock_codes)/sizeof(int);j++)
+               {
+                       id = 0xFFFF;
+                       
+                       outb(unlock_codes[j], config_ports[i]);
+                       outb(unlock_codes[j], config_ports[i]);
+                       
+                       outb(WBSD_CONF_ID_HI, config_ports[i]);
+                       id = inb(config_ports[i] + 1) << 8;
+
+                       outb(WBSD_CONF_ID_LO, config_ports[i]);
+                       id |= inb(config_ports[i] + 1);
+                       
+                       for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++)
+                       {
+                               if (id == valid_ids[k])
+                               {                               
+                                       host->chip_id = id;
+                                       host->config = config_ports[i];
+                                       host->unlock_code = unlock_codes[i];
+                               
+                                       return 0;
+                               }
+                       }
+                       
+                       if (id != 0xFFFF)
+                       {
+                               DBG("Unknown hardware (id %x) found at %x\n",
+                                       id, config_ports[i]);
+                       }
+
+                       outb(LOCK_CODE, config_ports[i]);
+               }
+               
+               release_region(config_ports[i], 2);
+       }
+       
+       return -ENODEV;
+}
+
+static int wbsd_request_regions(struct wbsd_host* host)
+{
+       if (io & 0x7)
+               return -EINVAL;
+       
+       if (!request_region(io, 8, DRIVER_NAME))
+               return -EIO;
+       
+       host->base = io;
+               
+       return 0;
+}
+
+static void wbsd_release_regions(struct wbsd_host* host)
+{
+       if (host->base)
+               release_region(host->base, 8);
+
+       if (host->config)
+               release_region(host->config, 2);
+}
+
+static void wbsd_init_dma(struct wbsd_host* host)
+{
+       host->dma = -1;
+       
+       if (dma < 0)
+               return;
+       
+       if (request_dma(dma, DRIVER_NAME))
+               goto err;
+       
+       /*
+        * We need to allocate a special buffer in
+        * order for ISA to be able to DMA to it.
+        */
+       host->dma_buffer = kmalloc(65536,
+               GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
+       if (!host->dma_buffer)
+               goto free;
+
+       /*
+        * Translate the address to a physical address.
+        */
+       host->dma_addr = isa_virt_to_bus(host->dma_buffer);
+                       
+       /*
+        * ISA DMA must be aligned on a 64k basis.
+        */
+       if ((host->dma_addr & 0xffff) != 0)
+               goto kfree;
+       /*
+        * ISA cannot access memory above 16 MB.
+        */
+       else if (host->dma_addr >= 0x1000000)
+               goto kfree;
+
+       host->dma = dma;
+       
+       return;
+       
+kfree:
+       /*
+        * If we've gotten here then there is some kind of alignment bug
+        */
+       BUG_ON(1);
+       
+       kfree(host->dma_buffer);
+       host->dma_buffer = NULL;
+
+free:
+       free_dma(dma);
+
+err:
+       printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "
+               "Falling back on FIFO.\n", dma);
+}
+
+static struct mmc_host_ops wbsd_ops = {
+       .request        = wbsd_request,
+       .set_ios        = wbsd_set_ios,
+};
+
+/*
+ * Device probe
+ */
+
+static int wbsd_probe(struct device* dev)
+{
+       struct wbsd_host* host = NULL;
+       struct mmc_host* mmc = NULL;
+       int ret;
+       
+       /*
+        * Allocate MMC structure.
+        */
+       mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
+       if (!mmc)
+               return -ENOMEM;
+       
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       
+       /*
+        * Scan for hardware.
+        */
+       ret = wbsd_scan(host);
+       if (ret)
+               goto freemmc;
+
+       /*
+        * Reset the chip.
+        */     
+       wbsd_write_config(host, WBSD_CONF_SWRST, 1);
+       wbsd_write_config(host, WBSD_CONF_SWRST, 0);
+
+       /*
+        * Allocate I/O ports.
+        */
+       ret = wbsd_request_regions(host);
+       if (ret)
+               goto release;
+
+       /*
+        * Set host parameters.
+        */
+       mmc->ops = &wbsd_ops;
+       mmc->f_min = 375000;
+       mmc->f_max = 24000000;
+       mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+       
+       spin_lock_init(&host->lock);
+
+       /*
+        * Select SD/MMC function.
+        */
+       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+       
+       /*
+        * Set up card detection.
+        */
+       wbsd_write_config(host, WBSD_CONF_PINS, 0x02);
+       
+       /*
+        * Configure I/O port.
+        */
+       wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
+       wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
+
+       /*
+        * Allocate interrupt.
+        */
+       ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
+       if (ret)
+               goto release;
+       
+       host->irq = irq;
+       
+       /*
+        * Set up tasklets.
+        */
+       tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
+       tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
+       tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
+       tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
+       tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
+       tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
+       
+       /*
+        * Configure interrupt.
+        */
+       wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
+       
+       /*
+        * Allocate DMA.
+        */
+       wbsd_init_dma(host);
+       
+       /*
+        * If all went well, then configure DMA.
+        */
+       if (host->dma >= 0)
+               wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
+       
+       /*
+        * Maximum number of segments. Worst case is one sector per segment
+        * so this will be 64kB/512.
+        */
+       mmc->max_hw_segs = NR_SG;
+       mmc->max_phys_segs = NR_SG;
+       
+       /*
+        * Maximum number of sectors in one transfer. Also limited by 64kB
+        * buffer.
+        */
+       mmc->max_sectors = 128;
+       
+       /*
+        * Maximum segment size. Could be one segment with the maximum number
+        * of segments.
+        */
+       mmc->max_seg_size = mmc->max_sectors * 512;
+       
+       /*
+        * Enable chip.
+        */
+       wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+       
+       /*
+        * Power up chip.
+        */
+       wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+       
+       /*
+        * Power Management stuff. No idea how this works.
+        * Not tested.
+        */
+#ifdef CONFIG_PM
+       wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
+#endif
+
+       /*
+        * Reset the chip into a known state.
+        */
+       wbsd_init_device(host);
+       
+       dev_set_drvdata(dev, mmc);
+       
+       /*
+        * Add host to MMC layer.
+        */
+       mmc_add_host(mmc);
+
+       printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n",
+               mmc->host_name, (int)host->chip_id, (int)host->base,
+               (int)host->irq, (int)host->dma);
+
+       return 0;
+
+release:
+       wbsd_release_regions(host);
+
+freemmc:
+       mmc_free_host(mmc);
+
+       return ret;
+}
+
+/*
+ * Device remove
+ */
+
+static int wbsd_remove(struct device* dev)
+{
+       struct mmc_host* mmc = dev_get_drvdata(dev);
+       struct wbsd_host* host;
+       
+       if (!mmc)
+               return 0;
+
+       host = mmc_priv(mmc);
+       
+       /*
+        * Unregister host with MMC layer.
+        */
+       mmc_remove_host(mmc);
+
+       /*
+        * Power down the SD/MMC function.
+        */
+       wbsd_unlock_config(host);
+       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+       wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
+       wbsd_lock_config(host);
+       
+       /*
+        * Free resources.
+        */
+       if (host->dma_buffer)
+               kfree(host->dma_buffer);
+       
+       if (host->dma >= 0)
+               free_dma(host->dma);
+
+       free_irq(host->irq, host);
+       
+       tasklet_kill(&host->card_tasklet);
+       tasklet_kill(&host->fifo_tasklet);
+       tasklet_kill(&host->crc_tasklet);
+       tasklet_kill(&host->timeout_tasklet);
+       tasklet_kill(&host->finish_tasklet);
+       tasklet_kill(&host->block_tasklet);
+       
+       wbsd_release_regions(host);
+       
+       mmc_free_host(mmc);
+
+       return 0;
+}
+
+/*
+ * Power management
+ */
+
+#ifdef CONFIG_PM
+static int wbsd_suspend(struct device *dev, u32 state, u32 level)
+{
+       DBGF("Not yet supported\n");
+
+       return 0;
+}
+
+static int wbsd_resume(struct device *dev, u32 level)
+{
+       DBGF("Not yet supported\n");
+
+       return 0;
+}
+#else
+#define wbsd_suspend NULL
+#define wbsd_resume NULL
+#endif
+
+static void wbsd_release(struct device *dev)
+{
+}
+
+static struct platform_device wbsd_device = {
+       .name           = DRIVER_NAME,
+       .id                     = -1,
+       .dev            = {
+               .release = wbsd_release,
+       },
+};
+
+static struct device_driver wbsd_driver = {
+       .name           = DRIVER_NAME,
+       .bus            = &platform_bus_type,
+       .probe          = wbsd_probe,
+       .remove         = wbsd_remove,
+       
+       .suspend        = wbsd_suspend,
+       .resume         = wbsd_resume,
+};
+
+/*
+ * Module loading/unloading
+ */
+
+static int __init wbsd_drv_init(void)
+{
+       int result;
+       
+       printk(KERN_INFO DRIVER_NAME
+               ": Winbond W83L51xD SD/MMC card interface driver, "
+               DRIVER_VERSION "\n");
+       printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+       
+       result = driver_register(&wbsd_driver);
+       if (result < 0)
+               return result;
+
+       result = platform_device_register(&wbsd_device);
+       if (result < 0)
+               return result;
+
+       return 0;
+}
+
+static void __exit wbsd_drv_exit(void)
+{
+       platform_device_unregister(&wbsd_device);
+       
+       driver_unregister(&wbsd_driver);
+
+       DBG("unloaded\n");
+}
+
+module_init(wbsd_drv_init);
+module_exit(wbsd_drv_exit);
+module_param(io, uint, 0444);
+module_param(irq, uint, 0444);
+module_param(dma, int, 0444);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
+
+MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
+MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
+MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
new file mode 100644 (file)
index 0000000..51652c3
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *  linux/drivers/mmc/wbsd.h
+ *
+ *  Copyright (C) 2004 Pierre Ossman, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const int config_ports[] = { 0x2E, 0x4E };
+const int unlock_codes[] = { 0x83, 0x87 };
+
+const int valid_ids[] = {
+       0x7112,
+       };
+
+#define LOCK_CODE              0xAA
+
+#define WBSD_CONF_SWRST                0x02
+#define WBSD_CONF_DEVICE       0x07
+#define WBSD_CONF_ID_HI                0x20
+#define WBSD_CONF_ID_LO                0x21
+#define WBSD_CONF_POWER                0x22
+#define WBSD_CONF_PME          0x23
+#define WBSD_CONF_PMES         0x24
+
+#define WBSD_CONF_ENABLE       0x30
+#define WBSD_CONF_PORT_HI      0x60
+#define WBSD_CONF_PORT_LO      0x61
+#define WBSD_CONF_IRQ          0x70
+#define WBSD_CONF_DRQ          0x74
+
+#define WBSD_CONF_PINS         0xF0
+
+#define DEVICE_SD              0x03
+
+#define WBSD_CMDR              0x00
+#define WBSD_DFR               0x01
+#define WBSD_EIR               0x02
+#define WBSD_ISR               0x03
+#define WBSD_FSR               0x04
+#define WBSD_IDXR              0x05
+#define WBSD_DATAR             0x06
+#define WBSD_CSR               0x07
+
+#define WBSD_EINT_CARD         0x40
+#define WBSD_EINT_FIFO_THRE    0x20
+#define WBSD_EINT_CCRC         0x10
+#define WBSD_EINT_TIMEOUT      0x08
+#define WBSD_EINT_PROGEND      0x04
+#define WBSD_EINT_CRC          0x02
+#define WBSD_EINT_TC           0x01
+
+#define WBSD_INT_PENDING       0x80
+#define WBSD_INT_CARD          0x40
+#define WBSD_INT_FIFO_THRE     0x20
+#define WBSD_INT_CRC           0x10
+#define WBSD_INT_TIMEOUT       0x08
+#define WBSD_INT_PROGEND       0x04
+#define WBSD_INT_BUSYEND       0x02
+#define WBSD_INT_TC            0x01
+
+#define WBSD_FIFO_EMPTY                0x80
+#define WBSD_FIFO_FULL         0x40
+#define WBSD_FIFO_EMTHRE       0x20
+#define WBSD_FIFO_FUTHRE       0x10
+#define WBSD_FIFO_SZMASK       0x0F
+
+#define WBSD_MSLED             0x20
+#define WBSD_POWER_N           0x10
+#define WBSD_WRPT              0x04
+#define WBSD_CARDPRESENT       0x01
+
+#define WBSD_IDX_CLK           0x01
+#define WBSD_IDX_PBSMSB                0x02
+#define WBSD_IDX_TAAC          0x03
+#define WBSD_IDX_NSAC          0x04
+#define WBSD_IDX_PBSLSB                0x05
+#define WBSD_IDX_SETUP         0x06
+#define WBSD_IDX_DMA           0x07
+#define WBSD_IDX_FIFOEN                0x08
+#define WBSD_IDX_STATUS                0x10
+#define WBSD_IDX_RSPLEN                0x1E
+#define WBSD_IDX_RESP0         0x1F
+#define WBSD_IDX_RESP1         0x20
+#define WBSD_IDX_RESP2         0x21
+#define WBSD_IDX_RESP3         0x22
+#define WBSD_IDX_RESP4         0x23
+#define WBSD_IDX_RESP5         0x24
+#define WBSD_IDX_RESP6         0x25
+#define WBSD_IDX_RESP7         0x26
+#define WBSD_IDX_RESP8         0x27
+#define WBSD_IDX_RESP9         0x28
+#define WBSD_IDX_RESP10                0x29
+#define WBSD_IDX_RESP11                0x2A
+#define WBSD_IDX_RESP12                0x2B
+#define WBSD_IDX_RESP13                0x2C
+#define WBSD_IDX_RESP14                0x2D
+#define WBSD_IDX_RESP15                0x2E
+#define WBSD_IDX_RESP16                0x2F
+#define WBSD_IDX_CRCSTATUS     0x30
+#define WBSD_IDX_ISR           0x3F
+
+#define WBSD_CLK_375K          0x00
+#define WBSD_CLK_12M           0x01
+#define WBSD_CLK_16M           0x02
+#define WBSD_CLK_24M           0x03
+
+#define WBSD_DAT3_H            0x08
+#define WBSD_FIFO_RESET                0x04
+#define WBSD_SOFT_RESET                0x02
+#define WBSD_INC_INDEX         0x01
+
+#define WBSD_DMA_SINGLE                0x02
+#define WBSD_DMA_ENABLE                0x01
+
+#define WBSD_FIFOEN_EMPTY      0x20
+#define WBSD_FIFOEN_FULL       0x10
+#define WBSD_FIFO_THREMASK     0x0F
+
+#define WBSD_BUSY              0x20
+#define WBSD_CARDTRAFFIC       0x04
+#define WBSD_SENDCMD           0x02
+#define WBSD_RECVRES           0x01
+
+#define WBSD_RSP_SHORT         0x00
+#define WBSD_RSP_LONG          0x01
+
+#define WBSD_CRC_MASK          0x1F
+#define WBSD_CRC_OK            0x05 /* S010E (00101) */
+#define WBSD_CRC_FAIL          0x0B /* S101E (01011) */
+
+
+/* 64kB / 512 */
+#define NR_SG                  128
+
+struct wbsd_host
+{
+       struct mmc_host*        mmc;            /* MMC structure */
+       
+       spinlock_t              lock;           /* Mutex */
+
+       struct mmc_request*     mrq;            /* Current request */
+       
+       struct scatterlist      sg[NR_SG];      /* SG list */
+       struct scatterlist*     cur_sg;         /* Current SG entry */
+       unsigned int            num_sg;         /* Number of entries left */
+       
+       unsigned int            offset;         /* Offset into current entry */
+       unsigned int            remain;         /* Data left in curren entry */
+
+       int                     size;           /* Total size of transfer */
+       
+       char*                   dma_buffer;     /* ISA DMA buffer */
+       dma_addr_t              dma_addr;       /* Physical address for same */
+
+       int                     firsterr;       /* See fifo functions */
+       
+       u8                      clk;            /* Current clock speed */
+       
+       int                     config;         /* Config port */
+       u8                      unlock_code;    /* Code to unlock config */
+
+       int                     chip_id;        /* ID of controller */
+       
+       int                     base;           /* I/O port base */
+       int                     irq;            /* Interrupt */
+       int                     dma;            /* DMA channel */
+       
+       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
+       struct tasklet_struct   fifo_tasklet;
+       struct tasklet_struct   crc_tasklet;
+       struct tasklet_struct   timeout_tasklet;
+       struct tasklet_struct   finish_tasklet;
+       struct tasklet_struct   block_tasklet;
+};
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
new file mode 100644 (file)
index 0000000..fbf4470
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef FWH_LOCK_H
+#define FWH_LOCK_H
+
+
+enum fwh_lock_state {
+        FWH_UNLOCKED   = 0,
+       FWH_DENY_WRITE = 1,
+       FWH_IMMUTABLE  = 2,
+       FWH_DENY_READ  = 4,
+};
+
+struct fwh_xxlock_thunk {
+       enum fwh_lock_state val;
+       flstate_t state;
+};
+
+
+#define FWH_XXLOCK_ONEBLOCK_LOCK   ((struct fwh_xxlock_thunk){ FWH_DENY_WRITE, FL_LOCKING})
+#define FWH_XXLOCK_ONEBLOCK_UNLOCK ((struct fwh_xxlock_thunk){ FWH_UNLOCKED,   FL_UNLOCKING})
+
+/*
+ * This locking/unlock is specific to firmware hub parts.  Only one
+ * is known that supports the Intel command set.    Firmware
+ * hub parts cannot be interleaved as they are on the LPC bus
+ * so this code has not been tested with interleaved chips,
+ * and will likely fail in that context.
+ */
+static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, 
+       unsigned long adr, int len, void *thunk)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct fwh_xxlock_thunk *xxlt = (struct fwh_xxlock_thunk *)thunk;
+       int ret;
+
+       /* Refuse the operation if the we cannot look behind the chip */
+       if (chip->start < 0x400000) {
+               DEBUG( MTD_DEBUG_LEVEL3,
+                       "MTD %s(): chip->start: %lx wanted >= 0x400000\n",
+                       __func__, chip->start );
+               return -EIO;
+       }
+       /*
+        * lock block registers:
+        * - on 64k boundariesand
+        * - bit 1 set high
+        * - block lock registers are 4MiB lower - overflow subtract (danger)
+        * 
+        * The address manipulation is first done on the logical address
+        * which is 0 at the start of the chip, and then the offset of
+        * the individual chip is addted to it.  Any other order a weird
+        * map offset could cause problems.
+        */
+       adr = (adr & ~0xffffUL) | 0x2;
+       adr += chip->start - 0x400000;
+
+       /*
+        * This is easy because these are writes to registers and not writes
+        * to flash memory - that means that we don't have to check status
+        * and timeout.
+        */
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, adr, FL_LOCKING);
+       if (ret) {
+               cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
+
+       chip->state = xxlt->state;
+       map_write(map, CMD(xxlt->val), adr);
+
+       /* Done and happy. */
+       chip->state = FL_READY;
+       put_chip(map, chip, adr);
+       cfi_spin_unlock(chip->mutex);
+       return 0;
+}
+
+
+static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       int ret;
+
+       ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
+               (void *)&FWH_XXLOCK_ONEBLOCK_LOCK);
+
+       return ret;
+}
+
+
+static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       int ret;
+
+       ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
+               (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK);
+       
+       return ret;
+}
+
+static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param)
+{
+       printk(KERN_NOTICE "using fwh lock/unlock method\n");
+       /* Setup for the chips with the fwh lock method */
+       mtd->lock   = fwh_lock_varsize;
+       mtd->unlock = fwh_unlock_varsize;
+}
+#endif /* FWH_LOCK_H */
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
new file mode 100644 (file)
index 0000000..44de3a8
--- /dev/null
@@ -0,0 +1,227 @@
+/* linux/drivers/mtd/maps/bast_flash.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Bast (EB2410ITX) NOR MTD Mapping driver
+ *
+ * Changelog:
+ *     20-Sep-2004  BJD  Initial version
+ *
+ * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $
+ *
+ * This 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/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+
+#include <asm/arch/map.h>
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-cpld.h>
+
+#ifdef CONFIG_MTD_BAST_MAXSIZE
+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024))
+#else
+#define AREA_MAXSIZE (32*1024*1024)
+#endif
+
+#define PFX "bast-flash: "
+
+struct bast_flash_info {
+       struct mtd_info         *mtd;
+       struct map_info          map;
+       struct mtd_partition    *partitions;
+       struct resource         *area;
+};
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+static struct bast_flash_info *to_bast_info(struct device *dev)
+{
+       return (struct bast_flash_info *)dev_get_drvdata(dev);
+}
+
+static void bast_flash_setrw(int to)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       val = __raw_readb(BAST_VA_CTRL3);
+       
+       if (to)
+               val |= BAST_CPLD_CTRL3_ROMWEN;
+       else
+               val &= ~BAST_CPLD_CTRL3_ROMWEN;
+
+       pr_debug("new cpld ctrl3=%02x\n", val);
+
+       __raw_writeb(val, BAST_VA_CTRL3);
+       local_irq_restore(flags);
+}
+
+static int bast_flash_remove(struct device *dev)
+{
+       struct bast_flash_info *info = to_bast_info(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+       if (info == NULL) 
+               return 0;
+
+       if (info->map.virt != NULL)
+               iounmap(info->map.virt);
+
+       if (info->mtd) {
+               del_mtd_partitions(info->mtd);
+               map_destroy(info->mtd);
+       }
+
+       if (info->partitions)
+               kfree(info->partitions);
+
+       if (info->area) {
+               release_resource(info->area);
+               kfree(info->area);
+       }
+       
+       kfree(info);
+
+       return 0;
+}
+
+static int bast_flash_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bast_flash_info *info;
+       struct resource *res;
+       int err = 0;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL) {
+               printk(KERN_ERR PFX "no memory for flash info\n");
+               err = -ENOMEM;
+               goto exit_error;
+       }
+
+       memzero(info, sizeof(*info));
+       dev_set_drvdata(dev, info);
+
+       res = pdev->resource;  /* assume that the flash has one resource */
+
+       info->map.phys = res->start;
+       info->map.size = res->end - res->start + 1;
+       info->map.name = dev->bus_id;   
+       info->map.bankwidth = 2;
+       
+       if (info->map.size > AREA_MAXSIZE)
+               info->map.size = AREA_MAXSIZE;
+
+       pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__,
+                info->map.phys, info->map.size);
+       
+       info->area = request_mem_region(res->start, info->map.size,
+                                       pdev->name);
+       if (info->area == NULL) {
+               printk(KERN_ERR PFX "cannot reserve flash memory region\n");
+               err = -ENOENT;
+               goto exit_error;
+       }
+
+       info->map.virt = ioremap(res->start, info->map.size);
+       pr_debug("%s: virt at %08x\n", __FUNCTION__, (int)info->map.virt);
+
+       if (info->map.virt == 0) {
+               printk(KERN_ERR PFX "failed to ioremap() region\n");
+               err = -EIO;
+               goto exit_error;
+       }
+       simple_map_init(&info->map);
+
+       /* enable the write to the flash area */
+
+       bast_flash_setrw(1);
+
+       /* probe for the device(s) */
+
+       info->mtd = do_map_probe("jedec_probe", &info->map);
+       if (info->mtd == NULL)
+               info->mtd = do_map_probe("cfi_probe", &info->map);
+
+       if (info->mtd == NULL) {
+               printk(KERN_ERR PFX "map_probe() failed\n");
+               err = -ENXIO;
+               goto exit_error;
+       }
+
+       /* mark ourselves as the owner */
+       info->mtd->owner = THIS_MODULE;
+
+       err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
+       if (err > 0) {
+               err = add_mtd_partitions(info->mtd, info->partitions, err);
+               if (err) 
+                       printk(KERN_ERR PFX "cannot add/parse partitions\n");
+       }
+
+       if (err == 0)
+               return 0;
+
+       /* fall through to exit error */
+
+ exit_error:
+       bast_flash_remove(dev);
+       return err;
+}
+
+static struct device_driver bast_flash_driver = {
+       .name           = "bast-nor",
+       .bus            = &platform_bus_type,
+       .probe          = bast_flash_probe,
+       .remove         = bast_flash_remove,
+};
+
+static int __init bast_flash_init(void)
+{
+       printk("BAST NOR-Flash Driver, (c) 2004 Simtec Electronics\n");
+       return driver_register(&bast_flash_driver);
+}
+
+static void __exit bast_flash_exit(void)
+{
+       driver_unregister(&bast_flash_driver);
+}
+
+module_init(bast_flash_init);
+module_exit(bast_flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("BAST MTD Map driver");
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c
new file mode 100644 (file)
index 0000000..914c0f5
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
+ * 
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
+ * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
+ * 
+ * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/page.h>
+#include <asm/mach-types.h>
+#include <asm/system.h>
+#include <asm/errno.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#ifdef CONFIG_MTD_CONCAT
+#include <linux/mtd/concat.h>
+#endif
+
+#include <asm/hardware.h>
+#include <asm/arch-sa1100/h3600.h>
+#include <asm/io.h>
+
+
+#ifndef CONFIG_IPAQ_HANDHELD
+#error This is for iPAQ Handhelds only
+#endif
+#ifdef CONFIG_SA1100_JORNADA56X
+
+static void jornada56x_set_vpp(struct map_info *map, int vpp)
+{
+       if (vpp)
+               GPSR = GPIO_GPIO26;
+       else
+               GPCR = GPIO_GPIO26;
+       GPDR |= GPIO_GPIO26;
+}
+
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+
+static void jornada720_set_vpp(struct map_info *map, int vpp)
+{
+       if (vpp)
+               PPSR |= 0x80;
+       else
+               PPSR &= ~0x80;
+       PPDR |= 0x80;
+}
+
+#endif
+
+#define MAX_IPAQ_CS 2          /* Number of CS we are going to test */
+
+#define IPAQ_MAP_INIT(X) \
+       { \
+               name:           "IPAQ flash " X, \
+       }
+
+
+static struct map_info ipaq_map[MAX_IPAQ_CS] = {
+       IPAQ_MAP_INIT("bank 1"),
+       IPAQ_MAP_INIT("bank 2")
+};
+
+static struct mtd_info *my_sub_mtd[MAX_IPAQ_CS] = {
+       NULL,
+       NULL
+};
+
+/*
+ * Here are partition information for all known IPAQ-based devices.
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * The *_max_flash_size is the maximum possible mapped flash size which
+ * is not necessarily the actual flash size.  It must be no more than
+ * the value specified in the "struct map_desc *_io_desc" mapping
+ * definition for the corresponding machine.
+ *
+ * Please keep these in alphabetical order, and formatted as per existing
+ * entries.  Thanks.
+ */
+
+#ifdef CONFIG_IPAQ_HANDHELD
+static unsigned long h3xxx_max_flash_size = 0x04000000;
+static struct mtd_partition h3xxx_partitions[] = {
+       {
+               name:           "H3XXX boot firmware",
+#ifndef CONFIG_LAB
+               size:           0x00040000,
+#else
+               size:           0x00080000,
+#endif
+               offset:         0,
+#ifndef CONFIG_LAB
+               mask_flags:     MTD_WRITEABLE,  /* force read-only */
+#endif
+       }, 
+       {
+               name:           "H3XXX root jffs2",
+#ifndef CONFIG_LAB
+               size:           0x2000000 - 2*0x40000, /* Warning, this is fixed later */
+               offset:         0x00040000,
+#else
+               size:           0x2000000 - 0x40000 - 0x80000, /* Warning, this is fixed later */
+               offset:         0x00080000,
+#endif
+       },
+       {
+               name:           "asset",
+               size:           0x40000,
+               offset:         0x2000000 - 0x40000, /* Warning, this is fixed later */
+               mask_flags:     MTD_WRITEABLE,  /* force read-only */
+       }
+};
+
+#ifndef CONFIG_MTD_CONCAT
+static struct mtd_partition h3xxx_partitions_bank2[] = {
+       /* this is used only on 2 CS machines when concat is not present */
+       {
+               name:           "second H3XXX root jffs2",
+               size:           0x1000000 - 0x40000, /* Warning, this is fixed later */
+               offset:         0x00000000,
+       },
+       {
+               name:           "second asset",
+               size:           0x40000,
+               offset:         0x1000000 - 0x40000, /* Warning, this is fixed later */
+               mask_flags:     MTD_WRITEABLE,  /* force read-only */
+       }
+};
+#endif
+
+static spinlock_t ipaq_vpp_lock = SPIN_LOCK_UNLOCKED;
+
+static void h3xxx_set_vpp(struct map_info *map, int vpp)
+{
+       static int nest = 0;
+       
+       spin_lock(&ipaq_vpp_lock);
+       if (vpp)
+               nest++;
+       else
+               nest--;
+       if (nest)
+               assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 1);
+       else
+               assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 0);
+       spin_unlock(&ipaq_vpp_lock);
+}
+
+#endif
+
+#if defined(CONFIG_SA1100_JORNADA56X) || defined(CONFIG_SA1100_JORNADA720)
+static unsigned long jornada_max_flash_size = 0x02000000;
+static struct mtd_partition jornada_partitions[] = {
+       {
+               name:           "Jornada boot firmware",
+               size:           0x00040000,
+               offset:         0,
+               mask_flags:     MTD_WRITEABLE,  /* force read-only */
+       }, {
+               name:           "Jornada root jffs2",
+               size:           MTDPART_SIZ_FULL,
+               offset:         0x00040000,
+       }
+};
+#endif
+
+
+static struct mtd_partition *parsed_parts;
+static struct mtd_info *mymtd;
+
+static unsigned long cs_phys[] = {
+#ifdef CONFIG_ARCH_SA1100
+       SA1100_CS0_PHYS,
+       SA1100_CS1_PHYS,
+       SA1100_CS2_PHYS,
+       SA1100_CS3_PHYS,
+       SA1100_CS4_PHYS,
+       SA1100_CS5_PHYS,
+#else 
+       PXA_CS0_PHYS,
+       PXA_CS1_PHYS,
+       PXA_CS2_PHYS,
+       PXA_CS3_PHYS,
+       PXA_CS4_PHYS,
+       PXA_CS5_PHYS,
+#endif
+};
+
+static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
+
+static int __init h1900_special_case(void);
+
+int __init ipaq_mtd_init(void)
+{
+       struct mtd_partition *parts = NULL;
+       int nb_parts = 0;
+       int parsed_nr_parts = 0;
+       const char *part_type;
+       int i; /* used when we have >1 flash chips */
+       unsigned long tot_flashsize = 0; /* used when we have >1 flash chips */
+
+       /* Default flash bankwidth */
+       // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
+       
+       if (machine_is_h1900())
+       {
+               /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */
+               return h1900_special_case();
+       }
+
+       if (machine_is_h3100() || machine_is_h1900())
+               for(i=0; i<MAX_IPAQ_CS; i++)
+                       ipaq_map[i].bankwidth = 2;
+       else
+               for(i=0; i<MAX_IPAQ_CS; i++)
+                       ipaq_map[i].bankwidth = 4;
+                       
+       /*
+        * Static partition definition selection
+        */
+       part_type = "static";
+
+       simple_map_init(&ipaq_map[0]);
+       simple_map_init(&ipaq_map[1]);
+
+#ifdef CONFIG_IPAQ_HANDHELD
+       if (machine_is_ipaq()) {
+               parts = h3xxx_partitions;
+               nb_parts = ARRAY_SIZE(h3xxx_partitions);
+               for(i=0; i<MAX_IPAQ_CS; i++) {
+                       ipaq_map[i].size = h3xxx_max_flash_size;
+                       ipaq_map[i].set_vpp = h3xxx_set_vpp;
+                       ipaq_map[i].phys = cs_phys[i];
+                       ipaq_map[i].virt = __ioremap(cs_phys[i], 0x04000000, 0, 1);
+                       if (machine_is_h3100 () || machine_is_h1900())
+                               ipaq_map[i].bankwidth = 2;
+               }
+               if (machine_is_h3600()) {
+                       /* No asset partition here */
+                       h3xxx_partitions[1].size += 0x40000;
+                       nb_parts--;
+               }
+       }
+#endif
+#ifdef CONFIG_ARCH_H5400
+       if (machine_is_h5400()) {
+               ipaq_map[0].size = 0x02000000;
+               ipaq_map[1].size = 0x02000000;
+               ipaq_map[1].phys = 0x02000000;
+               ipaq_map[1].virt = ipaq_map[0].virt + 0x02000000;
+       }
+#endif
+#ifdef CONFIG_ARCH_H1900
+       if (machine_is_h1900()) {
+               ipaq_map[0].size = 0x00400000;
+               ipaq_map[1].size = 0x02000000;
+               ipaq_map[1].phys = 0x00080000;
+               ipaq_map[1].virt = ipaq_map[0].virt + 0x00080000;
+       }
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA56X
+       if (machine_is_jornada56x()) {
+               parts = jornada_partitions;
+               nb_parts = ARRAY_SIZE(jornada_partitions);
+               ipaq_map[0].size = jornada_max_flash_size;
+               ipaq_map[0].set_vpp = jornada56x_set_vpp;
+               ipaq_map[0].virt = (__u32)__ioremap(0x0, 0x04000000, 0, 1);
+       }
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+       if (machine_is_jornada720()) {
+               parts = jornada_partitions;
+               nb_parts = ARRAY_SIZE(jornada_partitions);
+               ipaq_map[0].size = jornada_max_flash_size;
+               ipaq_map[0].set_vpp = jornada720_set_vpp;
+       }
+#endif
+
+
+       if (machine_is_ipaq()) { /* for iPAQs only */
+               for(i=0; i<MAX_IPAQ_CS; i++) {
+                       printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with CFI.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
+                       my_sub_mtd[i] = do_map_probe("cfi_probe", &ipaq_map[i]);
+                       if (!my_sub_mtd[i]) {
+                               printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
+                               my_sub_mtd[i] = do_map_probe("jedec_probe", &ipaq_map[i]);
+                       }
+                       if (!my_sub_mtd[i]) {
+                               printk(KERN_NOTICE "iPAQ flash: failed to find flash.\n");
+                               if (i)
+                                       break;
+                               else
+                                       return -ENXIO;
+                       } else
+                               printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);
+                       
+                       /* do we really need this debugging? --joshua 20030703 */
+                       // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);
+                       my_sub_mtd[i]->owner = THIS_MODULE;
+                       tot_flashsize += my_sub_mtd[i]->size;
+               }
+#ifdef CONFIG_MTD_CONCAT
+               /* fix the asset location */
+#      ifdef CONFIG_LAB
+               h3xxx_partitions[1].size = tot_flashsize - 0x40000 - 0x80000 /* extra big boot block */;
+#      else
+               h3xxx_partitions[1].size = tot_flashsize - 2 * 0x40000;
+#      endif
+               h3xxx_partitions[2].offset = tot_flashsize - 0x40000;
+               /* and concat the devices */
+               mymtd = mtd_concat_create(&my_sub_mtd[0], i,
+                                         "ipaq");
+               if (!mymtd) {
+                       printk("Cannot create iPAQ concat device\n");
+                       return -ENXIO;
+               }
+#else
+               mymtd = my_sub_mtd[0];
+
+               /* 
+                *In the very near future, command line partition parsing
+                * will use the device name as 'mtd-id' instead of a value
+                * passed to the parse_cmdline_partitions() routine. Since
+                * the bootldr says 'ipaq', make sure it continues to work. 
+                */
+               mymtd->name = "ipaq";
+
+               if ((machine_is_h3600())) {
+#      ifdef CONFIG_LAB
+                       h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x80000;
+#      else
+                       h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000;
+#      endif
+                       nb_parts = 2;
+               } else {
+#      ifdef CONFIG_LAB
+                       h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000 - 0x80000; /* extra big boot block */
+#      else
+                       h3xxx_partitions[1].size = my_sub_mtd[0]->size - 2*0x40000;
+#      endif
+                       h3xxx_partitions[2].offset = my_sub_mtd[0]->size - 0x40000;
+               }
+
+               if (my_sub_mtd[1]) {
+#      ifdef CONFIG_LAB
+                       h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x80000;
+#      else
+                       h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x40000;
+#      endif
+                       h3xxx_partitions_bank2[1].offset = my_sub_mtd[1]->size - 0x40000;
+               }
+#endif
+       }
+       else {
+               /*
+                * Now let's probe for the actual flash.  Do it here since
+                * specific machine settings might have been set above.
+                */
+               printk(KERN_NOTICE "IPAQ flash: probing %d-bit flash bus, window=%lx\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
+               mymtd = do_map_probe("cfi_probe", &ipaq_map[0]);
+               if (!mymtd)
+                       return -ENXIO;
+               mymtd->owner = THIS_MODULE;
+       }
+
+
+       /*
+        * Dynamic partition selection stuff (might override the static ones)
+        */
+
+        i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);
+                       
+        if (i > 0) {
+                nb_parts = parsed_nr_parts = i;
+                parts = parsed_parts;
+                part_type = "dynamic";
+        }
+
+        if (!parts) {
+                printk(KERN_NOTICE "IPAQ flash: no partition info available, registering whole flash at once\n");
+                add_mtd_device(mymtd);
+#ifndef CONFIG_MTD_CONCAT
+                if (my_sub_mtd[1])
+                        add_mtd_device(my_sub_mtd[1]);
+#endif
+        } else {
+                printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+                add_mtd_partitions(mymtd, parts, nb_parts);
+#ifndef CONFIG_MTD_CONCAT
+                if (my_sub_mtd[1])
+                        add_mtd_partitions(my_sub_mtd[1], h3xxx_partitions_bank2, ARRAY_SIZE(h3xxx_partitions_bank2));
+#endif
+        }
+
+        return 0;
+}
+
+static void __exit ipaq_mtd_cleanup(void)
+{
+       int i;
+
+       if (mymtd) {
+               del_mtd_partitions(mymtd);
+#ifndef CONFIG_MTD_CONCAT
+               if (my_sub_mtd[1])
+                       del_mtd_partitions(my_sub_mtd[1]);
+#endif
+               map_destroy(mymtd);
+#ifdef CONFIG_MTD_CONCAT
+               for(i=0; i<MAX_IPAQ_CS; i++) 
+#else
+                       for(i=1; i<MAX_IPAQ_CS; i++) 
+#endif           
+                       {
+                               if (my_sub_mtd[i])
+                                       map_destroy(my_sub_mtd[i]);
+                       }
+               if (parsed_parts)
+                       kfree(parsed_parts);
+       }
+}
+
+static int __init h1900_special_case(void)
+{
+       /* The iPAQ h1900 is a special case - it has weird ROM. */
+       simple_map_init(&ipaq_map[0]);
+       ipaq_map[0].size = 0x80000;
+       ipaq_map[0].set_vpp = h3xxx_set_vpp;
+       ipaq_map[0].phys = 0x0;
+       ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1);
+       ipaq_map[0].bankwidth = 2;
+       
+       printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
+       mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);
+       if (!mymtd)
+               return -ENODEV;
+       add_mtd_device(mymtd);
+       printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");
+       
+       return 0;
+}
+
+module_init(ipaq_mtd_init);
+module_exit(ipaq_mtd_cleanup);
+
+MODULE_AUTHOR("Jamey Hicks");
+MODULE_DESCRIPTION("IPAQ CFI map driver");
+MODULE_LICENSE("MIT");
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
new file mode 100644 (file)
index 0000000..104488c
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * $Id: ixp2000.c,v 1.1 2004/09/02 00:13:41 dsaxena Exp $
+ *
+ * drivers/mtd/maps/ixp2000.c
+ *
+ * Mapping for the Intel XScale IXP2000 based systems
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+
+#include <linux/reboot.h>
+
+struct ixp2000_flash_info {
+       struct          mtd_info *mtd;
+       struct          map_info map;
+       struct          mtd_partition *partitions;
+       struct          resource *res;
+       int             nr_banks;
+};
+
+static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
+{
+       unsigned long (*set_bank)(unsigned long) =
+               (unsigned long(*)(unsigned long))map->map_priv_2;
+
+       return (set_bank ? set_bank(ofs) : ofs);
+}
+
+#ifdef __ARMEB__
+/*
+ * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which
+ * causes the lower address bits to be XORed with 0x11 on 8 bit accesses
+ * and XORed with 0x10 on 16 bit accesses. See the spec update, erratta 44.
+ */
+static int errata44_workaround = 0;
+
+static inline unsigned long address_fix8_write(unsigned long addr)
+{
+       if (errata44_workaround) {
+               return (addr ^ 3);
+       }
+       return addr;
+}
+#else
+
+#define address_fix8_write(x)  (x)
+#endif
+
+static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs)
+{
+       map_word val;
+
+       val.x[0] =  *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs)));
+       return val;
+}
+
+/*
+ * We can't use the standard memcpy due to the broken SlowPort
+ * address translation on rev A0 and A1 silicon and the fact that
+ * we have banked flash.
+ */
+static void ixp2000_flash_copy_from(struct map_info *map, void *to,
+                             unsigned long from, ssize_t len)
+{
+       from = flash_bank_setup(map, from);
+       while(len--)
+               *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
+}
+
+static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs)
+{
+       *(__u8 *) (address_fix8_write(map->map_priv_1 +
+                                     flash_bank_setup(map, ofs))) = d.x[0];
+}
+
+static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to,
+                           const void *from, ssize_t len)
+{
+       to = flash_bank_setup(map, to);
+       while(len--) {
+               unsigned long tmp = address_fix8_write(map->map_priv_1 + to++);
+               *(__u8 *)(tmp) = *(__u8 *)(from++);
+       }
+}
+
+
+static int ixp2000_flash_remove(struct device *_dev)
+{
+       struct platform_device *dev = to_platform_device(_dev);
+       struct flash_platform_data *plat = dev->dev.platform_data;
+       struct ixp2000_flash_info *info = dev_get_drvdata(&dev->dev);
+
+       dev_set_drvdata(&dev->dev, NULL);
+
+       if(!info)
+               return 0;
+
+       if (info->mtd) {
+               del_mtd_partitions(info->mtd);
+               map_destroy(info->mtd);
+       }
+       if (info->map.map_priv_1)
+               iounmap((void *) info->map.map_priv_1);
+
+       if (info->partitions)
+               kfree(info->partitions);
+
+       if (info->res) {
+               release_resource(info->res);
+               kfree(info->res);
+       }
+
+       if (plat->exit)
+               plat->exit();
+
+       return 0;
+}
+
+
+static int ixp2000_flash_probe(struct device *_dev)
+{
+       static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+       struct platform_device *dev = to_platform_device(_dev);
+       struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
+       struct flash_platform_data *plat;
+       struct ixp2000_flash_info *info;
+       unsigned long window_size;
+       int err = -1;
+
+       if (!ixp_data)
+               return -ENODEV;
+
+       plat = ixp_data->platform_data;
+       if (!plat)
+               return -ENODEV;
+
+       window_size = dev->resource->end - dev->resource->start + 1;
+       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dM)\n",
+                       ixp_data->nr_banks, ((u32)window_size >> 20));
+
+       if (plat->width != 1) {
+               dev_err(_dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n",
+                               plat->width * 8);
+               return -EIO;
+       }
+
+       info = kmalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL);
+       if(!info) {
+               err = -ENOMEM;
+               goto Error;
+       }
+       memzero(info, sizeof(struct ixp2000_flash_info));
+
+       dev_set_drvdata(&dev->dev, info);
+
+       /*
+        * Tell the MTD layer we're not 1:1 mapped so that it does
+        * not attempt to do a direct access on us.
+        */
+       info->map.phys = NO_XIP;
+
+       info->nr_banks = ixp_data->nr_banks;
+       info->map.size = ixp_data->nr_banks * window_size;
+       info->map.bankwidth = 1;
+
+       /*
+        * map_priv_2 is used to store a ptr to to the bank_setup routine
+        */
+       info->map.map_priv_2 = (u32) ixp_data->bank_setup;
+
+       info->map.name = dev->dev.bus_id;
+       info->map.read = ixp2000_flash_read8;
+       info->map.write = ixp2000_flash_write8;
+       info->map.copy_from = ixp2000_flash_copy_from;
+       info->map.copy_to = ixp2000_flash_copy_to;
+
+       info->res = request_mem_region(dev->resource->start,
+                       dev->resource->end - dev->resource->start + 1,
+                       dev->dev.bus_id);
+       if (!info->res) {
+               dev_err(_dev, "Could not reserve memory region\n");
+               err = -ENOMEM;
+               goto Error;
+       }
+
+       info->map.map_priv_1 =
+           (unsigned long) ioremap(dev->resource->start,
+                                   dev->resource->end - dev->resource->start + 1);
+       if (!info->map.map_priv_1) {
+               dev_err(_dev, "Failed to ioremap flash region\n");
+               err = -EIO;
+               goto Error;
+       }
+
+       /*
+        * Setup read mode for FLASH
+        */
+       *IXP2000_SLOWPORT_FRM = 1;
+
+#if defined(__ARMEB__)
+       /*
+        * Enable errata 44 workaround for NPUs with broken slowport
+        */
+
+       errata44_workaround = ixp2000_has_broken_slowport();
+       dev_info(_dev, "Errata 44 workaround %s\n",
+              errata44_workaround ? "enabled" : "disabled");
+#endif
+
+       info->mtd = do_map_probe(plat->map_name, &info->map);
+       if (!info->mtd) {
+               dev_err(_dev, "map_probe failed\n");
+               err = -ENXIO;
+               goto Error;
+       }
+       info->mtd->owner = THIS_MODULE;
+
+       err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
+       if (err > 0) {
+               err = add_mtd_partitions(info->mtd, info->partitions, err);
+               if(err)
+                       dev_err(_dev, "Could not parse partitions\n");
+       }
+
+       if (err)
+               goto Error;
+
+       return 0;
+
+Error:
+       ixp2000_flash_remove(_dev);
+       return err;
+}
+
+static struct device_driver ixp2000_flash_driver = {
+       .name           = "IXP2000-Flash",
+       .bus            = &platform_bus_type,
+       .probe          = &ixp2000_flash_probe,
+       .remove         = &ixp2000_flash_remove
+};
+
+static int __init ixp2000_flash_init(void)
+{
+       return driver_register(&ixp2000_flash_driver);
+}
+
+static void __exit ixp2000_flash_exit(void)
+{
+       driver_unregister(&ixp2000_flash_driver);
+}
+
+module_init(ixp2000_flash_init);
+module_exit(ixp2000_flash_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
new file mode 100644 (file)
index 0000000..6e559bc
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Mapping for Ocotea user flash
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright 2002-2004 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <asm/ibm44x.h>
+#include <platforms/4xx/ocotea.h>
+
+static struct mtd_info *flash;
+
+static struct map_info ocotea_small_map = {
+       .name =         "Ocotea small flash",
+       .size =         OCOTEA_SMALL_FLASH_SIZE,
+       .buswidth =     1,
+};
+
+static struct map_info ocotea_large_map = {
+       .name =         "Ocotea large flash",
+       .size =         OCOTEA_LARGE_FLASH_SIZE,
+       .buswidth =     1,
+};
+
+static struct mtd_partition ocotea_small_partitions[] = {
+       {
+               .name =   "pibs",
+               .offset = 0x0,
+               .size =   0x100000,
+       }
+};
+
+static struct mtd_partition ocotea_large_partitions[] = {
+       {
+               .name =   "fs",
+               .offset = 0,
+               .size =   0x300000,
+       },
+       {
+               .name =   "firmware",
+               .offset = 0x300000,
+               .size =   0x100000,
+       }
+};
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+int __init init_ocotea(void)
+{
+       u8 fpga0_reg;
+       u8 *fpga0_adr;
+       unsigned long long small_flash_base, large_flash_base;
+
+       fpga0_adr = ioremap64(OCOTEA_FPGA_ADDR, 16);
+       if (!fpga0_adr)
+               return -ENOMEM;
+
+       fpga0_reg = readb((unsigned long)fpga0_adr);
+       iounmap(fpga0_adr);
+
+       if (OCOTEA_BOOT_LARGE_FLASH(fpga0_reg)) {
+               small_flash_base = OCOTEA_SMALL_FLASH_HIGH;
+               large_flash_base = OCOTEA_LARGE_FLASH_LOW;
+       }
+       else {
+               small_flash_base = OCOTEA_SMALL_FLASH_LOW;
+               large_flash_base = OCOTEA_LARGE_FLASH_HIGH;
+       }
+
+       ocotea_small_map.phys = small_flash_base;
+       ocotea_small_map.virt = ioremap64(small_flash_base,
+                                        ocotea_small_map.size);
+
+       if (!ocotea_small_map.virt) {
+               printk("Failed to ioremap flash\n");
+               return -EIO;
+       }
+
+       simple_map_init(&ocotea_small_map);
+
+       flash = do_map_probe("map_rom", &ocotea_small_map);
+       if (flash) {
+               flash->owner = THIS_MODULE;
+               add_mtd_partitions(flash, ocotea_small_partitions,
+                                       NB_OF(ocotea_small_partitions));
+       } else {
+               printk("map probe failed for flash\n");
+               return -ENXIO;
+       }
+
+       ocotea_large_map.phys = large_flash_base;
+       ocotea_large_map.virt = ioremap64(large_flash_base,
+                                        ocotea_large_map.size);
+
+       if (!ocotea_large_map.virt) {
+               printk("Failed to ioremap flash\n");
+               return -EIO;
+       }
+
+       simple_map_init(&ocotea_large_map);
+
+       flash = do_map_probe("cfi_probe", &ocotea_large_map);
+       if (flash) {
+               flash->owner = THIS_MODULE;
+               add_mtd_partitions(flash, ocotea_large_partitions,
+                                       NB_OF(ocotea_large_partitions));
+       } else {
+               printk("map probe failed for flash\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static void __exit cleanup_ocotea(void)
+{
+       if (flash) {
+               del_mtd_partitions(flash);
+               map_destroy(flash);
+       }
+
+       if (ocotea_small_map.virt) {
+               iounmap((void *)ocotea_small_map.virt);
+               ocotea_small_map.virt = 0;
+       }
+
+       if (ocotea_large_map.virt) {
+               iounmap((void *)ocotea_large_map.virt);
+               ocotea_large_map.virt = 0;
+       }
+}
+
+module_init(init_ocotea);
+module_exit(cleanup_ocotea);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GX Ocotea boards");
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c
new file mode 100644 (file)
index 0000000..f90998b
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * ts5500_flash.c -- MTD map driver for Technology Systems TS-5500 board
+ *
+ * Copyright (C) 2004 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Note:
+ * - In order for detection to work, jumper 3 must be set.
+ * - Drive A and B use a proprietary FTL from General Software which isn't 
+ *   supported as of yet so standard drives can't be mounted; you can create 
+ *   your own (e.g. jffs) file system.
+ * - If you have created your own jffs file system and the bios overwrites 
+ *   it during boot, try disabling Drive A: and B: in the boot order.
+ *
+ * $Id: ts5500_flash.c,v 1.1 2004/09/20 15:33:26 sean Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR    0x09400000
+#define WINDOW_SIZE    0x00200000
+
+static struct map_info ts5500_map = {
+       .name = "TS-5500 Flash",
+       .size = WINDOW_SIZE,
+       .bankwidth = 1,
+       .phys = WINDOW_ADDR
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition ts5500_partitions[] = {
+       {
+               .name = "Drive A",
+               .offset = 0,
+               .size = 0x0e0000
+       },
+       {
+               .name = "BIOS",
+               .offset = 0x0e0000,
+               .size = 0x020000,
+       },
+       {
+               .name = "Drive B",
+               .offset = 0x100000,
+               .size = 0x100000
+       }
+};
+
+#define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition))
+
+#endif
+
+static struct mtd_info *mymtd;
+
+static int __init init_ts5500_map(void)
+{
+       int rc = 0;
+
+       ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size);
+
+       if(!ts5500_map.virt) {
+               printk(KERN_ERR "Failed to ioremap_nocache\n");
+               rc = -EIO;
+               goto err_out_ioremap;
+       }
+
+       simple_map_init(&ts5500_map);
+
+       mymtd = do_map_probe("jedec_probe", &ts5500_map);
+       if(!mymtd)
+               mymtd = do_map_probe("map_rom", &ts5500_map);
+
+       if(!mymtd) {
+               rc = -ENXIO;
+               goto err_out_map;
+       }
+
+       mymtd->owner = THIS_MODULE;
+#ifdef CONFIG_MTD_PARTITIONS
+       add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS);
+#else  
+       add_mtd_device(mymtd);
+#endif
+
+       return 0;
+
+err_out_map:
+       map_destroy(mymtd);
+err_out_ioremap:
+       iounmap(ts5500_map.virt);
+
+       return rc;
+}
+
+static void __exit cleanup_ts5500_map(void)
+{
+       if (mymtd) {
+#ifdef CONFIG_MTD_PARTITIONS
+               del_mtd_partitions(mymtd);
+#else
+               del_mtd_device(mymtd);
+#endif
+               map_destroy(mymtd);
+       }
+
+       if (ts5500_map.virt) {
+               iounmap(ts5500_map.virt);
+               ts5500_map.virt = NULL;
+       }
+}
+
+module_init(init_ts5500_map);
+module_exit(cleanup_ts5500_map);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_DESCRIPTION("MTD map driver for Techology Systems TS-5500 board");
+
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c
new file mode 100644 (file)
index 0000000..3825a7a
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  drivers/mtd/nand/h1910.c
+ *
+ *  Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com)
+ *
+ *  Derived from drivers/mtd/nand/edb7312.c
+ *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner Exp $
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is
+ *   a 128Mibit (16MiB x 8 bits) NAND flash device.
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <asm/sizes.h>
+#include <asm/arch/h1900-gpio.h>
+#include <asm/arch/ipaq.h>
+
+/*
+ * MTD structure for EDB7312 board
+ */
+static struct mtd_info *h1910_nand_mtd = NULL;
+
+/*
+ * Module stuff
+ */
+
+#ifdef CONFIG_MTD_PARTITIONS
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info[] = {
+       { name: "h1910 NAND Flash",
+                 offset: 0,
+                 size: 16*1024*1024 }
+};
+#define NUM_PARTITIONS 1
+
+#endif
+
+
+/* 
+ *     hardware specific access to control-lines
+ */
+static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) 
+{
+       struct nand_chip* this = (struct nand_chip *) (mtd->priv);
+       
+       switch(cmd) {
+               
+       case NAND_CTL_SETCLE: 
+               this->IO_ADDR_R |= (1 << 2);
+               this->IO_ADDR_W |= (1 << 2);
+               break;
+       case NAND_CTL_CLRCLE: 
+               this->IO_ADDR_R &= ~(1 << 2);
+               this->IO_ADDR_W &= ~(1 << 2);
+               break;
+               
+       case NAND_CTL_SETALE:
+               this->IO_ADDR_R |= (1 << 3);
+               this->IO_ADDR_W |= (1 << 3);
+               break;
+       case NAND_CTL_CLRALE:
+               this->IO_ADDR_R &= ~(1 << 3);
+               this->IO_ADDR_W &= ~(1 << 3);
+               break;
+               
+       case NAND_CTL_SETNCE:
+               break;
+       case NAND_CTL_CLRNCE:
+               break;
+       }
+}
+
+/*
+ *     read device ready pin
+ */
+#if 0
+static int h1910_device_ready(struct mtd_info *mtd)
+{
+       return (GPLR(55) & GPIO_bit(55));
+}
+#endif
+
+/*
+ * Main initialization routine
+ */
+static int __init h1910_init (void)
+{
+       struct nand_chip *this;
+       const char *part_type = 0;
+       int mtd_parts_nb = 0;
+       struct mtd_partition *mtd_parts = 0;
+       void __iomem *nandaddr;
+       
+       if (!machine_is_h1900())
+               return -ENODEV;
+               
+       nandaddr = __ioremap(0x08000000, 0x1000, 0, 1);
+       if (!nandaddr) {
+               printk("Failed to ioremap nand flash.\n");
+               return -ENOMEM;
+       }
+       
+       /* Allocate memory for MTD device structure and private data */
+       h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + 
+                            sizeof(struct nand_chip),
+                            GFP_KERNEL);
+       if (!h1910_nand_mtd) {
+               printk("Unable to allocate h1910 NAND MTD device structure.\n");
+               iounmap ((void *) nandaddr);
+               return -ENOMEM;
+       }
+       
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&h1910_nand_mtd[1]);
+       
+       /* Initialize structures */
+       memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+       
+       /* Link the private data with the MTD structure */
+       h1910_nand_mtd->priv = this;
+       
+       /*
+        * Enable VPEN
+        */
+       GPSR(37) = GPIO_bit(37);
+       
+       /* insert callbacks */
+       this->IO_ADDR_R = nandaddr;
+       this->IO_ADDR_W = nandaddr;
+       this->hwcontrol = h1910_hwcontrol;
+       this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
+       /* 15 us command delay time */
+       this->chip_delay = 50;
+       this->eccmode = NAND_ECC_SOFT;
+       this->options = NAND_NO_AUTOINCR;
+       
+       /* Scan to find existence of the device */
+       if (nand_scan (h1910_nand_mtd, 1)) {
+               printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
+               kfree (h1910_nand_mtd);
+               iounmap ((void *) nandaddr);
+               return -ENXIO;
+       }
+       
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+       mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, 
+                                               "h1910-nand");
+       if (mtd_parts_nb > 0)
+         part_type = "command line";
+       else
+         mtd_parts_nb = 0;
+#endif
+       if (mtd_parts_nb == 0)
+       {
+               mtd_parts = partition_info;
+               mtd_parts_nb = NUM_PARTITIONS;
+               part_type = "static";
+       }
+       
+       /* Register the partitions */
+       printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+       add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
+       
+       /* Return happy */
+       return 0;
+}
+module_init(h1910_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit h1910_cleanup (void)
+{
+       struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
+       
+       /* Release resources, unregister device */
+       nand_release (h1910_nand_mtd);
+
+       /* Release io resource */
+       iounmap ((void *) this->IO_ADDR_W);
+
+       /* Free the MTD device structure */
+       kfree (h1910_nand_mtd);
+}
+module_exit(h1910_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joshua Wise <joshua at joshuawise dot com>");
+MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910");
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
new file mode 100644 (file)
index 0000000..02305a2
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ *  drivers/mtd/nand/rtc_from4.c
+ *
+ *  Copyright (C) 2004  Red Hat, Inc.
+ * 
+ *  Derived from drivers/mtd/nand/spia.c
+ *       Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *
+ * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $
+ *
+ * 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.
+ *
+ * Overview:
+ *   This is a device driver for the AG-AND flash device found on the
+ *   Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), 
+ *   which utilizes the Renesas HN29V1G91T-30 part. 
+ *   This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/rslib.h>
+#include <linux/module.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+
+/*
+ * MTD structure for Renesas board
+ */
+static struct mtd_info *rtc_from4_mtd = NULL;
+
+#define RTC_FROM4_MAX_CHIPS    2
+
+/* HS77x9 processor register defines */
+#define SH77X9_BCR1    ((volatile unsigned short *)(0xFFFFFF60))
+#define SH77X9_BCR2    ((volatile unsigned short *)(0xFFFFFF62))
+#define SH77X9_WCR1    ((volatile unsigned short *)(0xFFFFFF64))
+#define SH77X9_WCR2    ((volatile unsigned short *)(0xFFFFFF66))
+#define SH77X9_MCR     ((volatile unsigned short *)(0xFFFFFF68))
+#define SH77X9_PCR     ((volatile unsigned short *)(0xFFFFFF6C))
+#define SH77X9_FRQCR   ((volatile unsigned short *)(0xFFFFFF80))
+
+/*
+ * Values specific to the Renesas Technology Corp. FROM_BOARD4 (used with HS77x9 processor)
+ */
+/* Address where flash is mapped */
+#define RTC_FROM4_FIO_BASE     0x14000000
+
+/* CLE and ALE are tied to address lines 5 & 4, respectively */
+#define RTC_FROM4_CLE          (1 << 5)
+#define RTC_FROM4_ALE          (1 << 4)
+
+/* address lines A24-A22 used for chip selection */
+#define RTC_FROM4_NAND_ADDR_SLOT3      (0x00800000)
+#define RTC_FROM4_NAND_ADDR_SLOT4      (0x00C00000)
+#define RTC_FROM4_NAND_ADDR_FPGA       (0x01000000)
+/* mask address lines A24-A22 used for chip selection */
+#define RTC_FROM4_NAND_ADDR_MASK       (RTC_FROM4_NAND_ADDR_SLOT3 | RTC_FROM4_NAND_ADDR_SLOT4 | RTC_FROM4_NAND_ADDR_FPGA)
+
+/* FPGA status register for checking device ready (bit zero) */
+#define RTC_FROM4_FPGA_SR              (RTC_FROM4_NAND_ADDR_FPGA | 0x00000002)
+#define RTC_FROM4_DEVICE_READY         0x0001
+
+/* FPGA Reed-Solomon ECC Control register */
+
+#define RTC_FROM4_RS_ECC_CTL           (RTC_FROM4_NAND_ADDR_FPGA | 0x00000050)
+#define RTC_FROM4_RS_ECC_CTL_CLR       (1 << 7)
+#define RTC_FROM4_RS_ECC_CTL_GEN       (1 << 6)
+#define RTC_FROM4_RS_ECC_CTL_FD_E      (1 << 5)
+
+/* FPGA Reed-Solomon ECC code base */
+#define RTC_FROM4_RS_ECC               (RTC_FROM4_NAND_ADDR_FPGA | 0x00000060)
+#define RTC_FROM4_RS_ECCN              (RTC_FROM4_NAND_ADDR_FPGA | 0x00000080)
+
+/* FPGA Reed-Solomon ECC check register */
+#define RTC_FROM4_RS_ECC_CHK           (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
+#define RTC_FROM4_RS_ECC_CHK_ERROR     (1 << 7)
+
+/* Undefine for software ECC */
+#define RTC_FROM4_HWECC        1
+
+/*
+ * Module stuff
+ */
+static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE);
+
+const static struct mtd_partition partition_info[] = {
+        {
+                .name   = "Renesas flash partition 1",
+                .offset = 0,
+                .size   = MTDPART_SIZ_FULL
+        },
+};
+#define NUM_PARTITIONS 1
+
+/* 
+ *     hardware specific flash bbt decriptors
+ *     Note: this is to allow debugging by disabling 
+ *             NAND_BBT_CREATE and/or NAND_BBT_WRITE
+ *
+ */
+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr rtc_from4_bbt_main_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+       .offs = 40,
+       .len = 4,
+       .veroffs = 44,
+       .maxblocks = 4,
+       .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+       .offs = 40,
+       .len = 4,
+       .veroffs = 44,
+       .maxblocks = 4,
+       .pattern = mirror_pattern
+};
+
+
+
+#ifdef RTC_FROM4_HWECC
+
+/* the Reed Solomon control structure */
+static struct rs_control *rs_decoder;
+
+/* 
+ *      hardware specific Out Of Band information
+ */
+static struct nand_oobinfo rtc_from4_nand_oobinfo = {
+       .useecc = MTD_NANDECC_AUTOPLACE,
+       .eccbytes = 32,
+       .eccpos = {
+                0,  1,  2,  3,  4,  5,  6,  7,
+                8,  9, 10, 11, 12, 13, 14, 15,
+               16, 17, 18, 19, 20, 21, 22, 23,
+               24, 25, 26, 27, 28, 29, 30, 31},
+       .oobfree = { {32, 32} }
+};
+
+/* Aargh. I missed the reversed bit order, when I
+ * was talking to Renesas about the FPGA.
+ *
+ * The table is used for bit reordering and inversion
+ * of the ecc byte which we get from the FPGA
+ */
+static uint8_t revbits[256] = {
+        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+#endif
+
+
+
+/* 
+ * rtc_from4_hwcontrol - hardware specific access to control-lines
+ * @mtd:       MTD device structure
+ * @cmd:       hardware control command
+ *
+ * Address lines (A5 and A4) are used to control Command and Address Latch 
+ * Enable on this board, so set the read/write address appropriately.
+ *
+ * Chip Enable is also controlled by the Chip Select (CS5) and 
+ * Address lines (A24-A22), so no action is required here.
+ *
+ */
+static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+       struct nand_chip* this = (struct nand_chip *) (mtd->priv);
+       
+       switch(cmd) {
+               
+       case NAND_CTL_SETCLE: 
+               this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE);
+               break;
+       case NAND_CTL_CLRCLE: 
+               this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
+               break;
+               
+       case NAND_CTL_SETALE:
+               this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
+               break;
+       case NAND_CTL_CLRALE:
+               this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
+               break;
+               
+       case NAND_CTL_SETNCE:
+               break;
+       case NAND_CTL_CLRNCE:
+               break;
+
+       }
+}
+
+
+/*
+ * rtc_from4_nand_select_chip - hardware specific chip select
+ * @mtd:       MTD device structure
+ * @chip:      Chip to select (0 == slot 3, 1 == slot 4)
+ *
+ * The chip select is based on address lines A24-A22.
+ * This driver uses flash slots 3 and 4 (A23-A22).
+ *
+ */
+static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+        struct nand_chip *this = mtd->priv;
+
+       this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R & ~RTC_FROM4_NAND_ADDR_MASK);
+       this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_NAND_ADDR_MASK);
+
+        switch(chip) {
+
+        case 0:                /* select slot 3 chip */
+               this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT3);
+               this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT3);
+                break;
+        case 1:                /* select slot 4 chip */
+               this->IO_ADDR_R = (void __iomem *)((unsigned long)this->IO_ADDR_R | RTC_FROM4_NAND_ADDR_SLOT4);
+               this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_NAND_ADDR_SLOT4);
+                break;
+
+        }
+}
+
+
+
+/*
+ * rtc_from4_nand_device_ready - hardware specific ready/busy check
+ * @mtd:       MTD device structure
+ *
+ * This board provides the Ready/Busy state in the status register
+ * of the FPGA.  Bit zero indicates the RDY(1)/BSY(0) signal.
+ *
+ */
+static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
+{
+       unsigned short status;
+
+       status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_FPGA_SR));
+
+       return (status & RTC_FROM4_DEVICE_READY);
+
+}
+
+#ifdef RTC_FROM4_HWECC
+/*
+ * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
+ * @mtd:       MTD device structure
+ * @mode:      I/O mode; read or write
+ *
+ * enable hardware ECC for data read or write 
+ *
+ */
+static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       volatile unsigned short * rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL);
+       unsigned short status;
+
+       switch (mode) {
+           case NAND_ECC_READ :
+               status =  RTC_FROM4_RS_ECC_CTL_CLR 
+                       | RTC_FROM4_RS_ECC_CTL_FD_E;
+
+               *rs_ecc_ctl = status;
+               break;
+
+           case NAND_ECC_READSYN :
+               status =  0x00;
+
+               *rs_ecc_ctl = status;
+               break;
+
+           case NAND_ECC_WRITE :
+               status =  RTC_FROM4_RS_ECC_CTL_CLR 
+                       | RTC_FROM4_RS_ECC_CTL_GEN 
+                       | RTC_FROM4_RS_ECC_CTL_FD_E;
+
+               *rs_ecc_ctl = status;
+               break;
+
+           default:
+               BUG();
+               break;
+       }
+
+}
+
+/*
+ * rtc_from4_calculate_ecc - hardware specific code to read ECC code
+ * @mtd:       MTD device structure
+ * @dat:       buffer containing the data to generate ECC codes
+ * @ecc_code   ECC codes calculated
+ *
+ * The ECC code is calculated by the FPGA.  All we have to do is read the values
+ * from the FPGA registers.
+ *
+ * Note: We read from the inverted registers, since data is inverted before
+ * the code is calculated. So all 0xff data (blank page) results in all 0xff rs code
+ *
+ */
+static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+       volatile unsigned short * rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN);
+       unsigned short value;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               value = *rs_eccn;
+               ecc_code[i] = (unsigned char)value;
+               rs_eccn++;
+       }
+       ecc_code[7] |= 0x0f;    /* set the last four bits (not used) */
+}
+
+/*
+ * rtc_from4_correct_data - hardware specific code to correct data using ECC code
+ * @mtd:       MTD device structure
+ * @buf:       buffer containing the data to generate ECC codes
+ * @ecc1       ECC codes read
+ * @ecc2       ECC codes calculated
+ *
+ * The FPGA tells us fast, if there's an error or not. If no, we go back happy
+ * else we read the ecc results from the fpga and call the rs library to decode
+ * and hopefully correct the error
+ *
+ * For now I use the code, which we read from the FLASH to use the RS lib,
+ * as the syndrom conversion has a unresolved issue.
+ */
+static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
+{
+       int i, j, res;
+       unsigned short status; 
+       uint16_t par[6], syn[6], tmp;
+       uint8_t ecc[8];
+        volatile unsigned short *rs_ecc;
+
+       status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK));
+
+       if (!(status & RTC_FROM4_RS_ECC_CHK_ERROR)) {
+               return 0;
+       }
+
+       /* Read the syndrom pattern from the FPGA and correct the bitorder */
+       rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);
+        for (i = 0; i < 8; i++) {
+                ecc[i] = revbits[(*rs_ecc) & 0xFF];
+                rs_ecc++;
+        }
+
+       /* convert into 6 10bit syndrome fields */
+       par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | 
+                                     (((uint16_t)ecc[1] << 8) & 0x300)];
+       par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) |
+                                     (((uint16_t)ecc[2] << 6) & 0x3c0)];
+       par[3] = rs_decoder->index_of[(((uint16_t)ecc[2] >> 4) & 0x00f) |
+                                     (((uint16_t)ecc[3] << 4) & 0x3f0)];
+       par[2] = rs_decoder->index_of[(((uint16_t)ecc[3] >> 6) & 0x003) |
+                                     (((uint16_t)ecc[4] << 2) & 0x3fc)];
+       par[1] = rs_decoder->index_of[(((uint16_t)ecc[5] >> 0) & 0x0ff) |
+                                     (((uint16_t)ecc[6] << 8) & 0x300)];
+       par[0] = (((uint16_t)ecc[6] >> 2) & 0x03f) | (((uint16_t)ecc[7] << 6) & 0x3c0);
+
+       /* Convert to computable syndrome */
+       for (i = 0; i < 6; i++) {
+               syn[i] = par[0];
+               for (j = 1; j < 6; j++)
+                       if (par[j] != rs_decoder->nn)
+                               syn[i] ^= rs_decoder->alpha_to[rs_modnn(rs_decoder, par[j] + i * j)];
+
+               /* Convert to index form */
+               syn[i] = rs_decoder->index_of[syn[i]];
+       }
+
+       /* Let the library code do its magic.*/
+       res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL);
+       if (res > 0) {
+               DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " 
+                       "ECC corrected %d errors on read\n", res);
+       }
+       return res;
+}
+#endif
+
+/*
+ * Main initialization routine
+ */
+int __init rtc_from4_init (void)
+{
+       struct nand_chip *this;
+       unsigned short bcr1, bcr2, wcr2;
+
+       /* Allocate memory for MTD device structure and private data */
+       rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
+                               GFP_KERNEL);
+       if (!rtc_from4_mtd) {
+               printk ("Unable to allocate Renesas NAND MTD device structure.\n");
+               return -ENOMEM;
+       }
+
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&rtc_from4_mtd[1]);
+
+       /* Initialize structures */
+       memset((char *) rtc_from4_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+
+       /* Link the private data with the MTD structure */
+       rtc_from4_mtd->priv = this;
+
+       /* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */
+       bcr1 = *SH77X9_BCR1 & ~0x0002;
+       bcr1 |= 0x0002;
+       *SH77X9_BCR1 = bcr1;
+
+       /* set */
+       bcr2 = *SH77X9_BCR2 & ~0x0c00;
+       bcr2 |= 0x0800;
+       *SH77X9_BCR2 = bcr2;
+
+       /* set area 5 wait states */
+       wcr2 = *SH77X9_WCR2 & ~0x1c00;
+       wcr2 |= 0x1c00;
+       *SH77X9_WCR2 = wcr2;
+
+       /* Set address of NAND IO lines */
+       this->IO_ADDR_R = rtc_from4_fio_base;
+       this->IO_ADDR_W = rtc_from4_fio_base;
+       /* Set address of hardware control function */
+       this->hwcontrol = rtc_from4_hwcontrol;
+       /* Set address of chip select function */
+        this->select_chip = rtc_from4_nand_select_chip;
+       /* command delay time (in us) */
+       this->chip_delay = 100;
+       /* return the status of the Ready/Busy line */
+       this->dev_ready = rtc_from4_nand_device_ready;
+
+#ifdef RTC_FROM4_HWECC
+       printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
+
+        this->eccmode = NAND_ECC_HW8_512;
+       this->options |= NAND_HWECC_SYNDROME;
+       /* set the nand_oobinfo to support FPGA H/W error detection */
+       this->autooob = &rtc_from4_nand_oobinfo;
+       this->enable_hwecc = rtc_from4_enable_hwecc;
+       this->calculate_ecc = rtc_from4_calculate_ecc;
+       this->correct_data = rtc_from4_correct_data;
+#else
+       printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
+
+       this->eccmode = NAND_ECC_SOFT;
+#endif
+
+       /* set the bad block tables to support debugging */
+       this->bbt_td = &rtc_from4_bbt_main_descr;
+       this->bbt_md = &rtc_from4_bbt_mirror_descr;
+
+       /* Scan to find existence of the device */
+       if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) {
+               kfree(rtc_from4_mtd);
+               return -ENXIO;
+       }
+
+       /* Register the partitions */
+       add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
+
+#ifdef RTC_FROM4_HWECC
+       /* We could create the decoder on demand, if memory is a concern.
+        * This way we have it handy, if an error happens 
+        *
+        * Symbolsize is 10 (bits)
+        * Primitve polynomial is x^10+x^3+1
+        * first consecutive root is 0
+        * primitve element to generate roots = 1
+        * generator polinomial degree = 6
+        */
+       rs_decoder = init_rs(10, 0x409, 0, 1, 6);
+       if (!rs_decoder) {
+               printk (KERN_ERR "Could not create a RS decoder\n");
+               nand_release(rtc_from4_mtd);
+               kfree(rtc_from4_mtd);
+               return -ENOMEM;
+       }
+#endif
+       /* Return happy */
+       return 0;
+}
+module_init(rtc_from4_init);
+
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit rtc_from4_cleanup (void)
+{
+       /* Release resource, unregister partitions */
+       nand_release(rtc_from4_mtd);
+
+       /* Free the MTD device structure */
+       kfree (rtc_from4_mtd);
+
+#ifdef RTC_FROM4_HWECC
+       /* Free the reed solomon resources */
+       if (rs_decoder) {
+               free_rs(rs_decoder);
+       }
+#endif
+}
+module_exit(rtc_from4_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("d.marlin <dmarlin@redhat.com");
+MODULE_DESCRIPTION("Board-specific glue layer for AG-AND flash on Renesas FROM_BOARD4");
+
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
new file mode 100644 (file)
index 0000000..d11fe47
--- /dev/null
@@ -0,0 +1,704 @@
+/* linux/drivers/mtd/nand/s3c2410.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2410 NAND driver
+ *
+ * Changelog:
+ *     21-Sep-2004  BJD  Initial version
+ *     23-Sep-2004  BJD  Mulitple device support
+ *     28-Sep-2004  BJD  Fixed ECC placement for Hardware mode
+ *     12-Oct-2004  BJD  Fixed errors in use of platform data
+ *
+ * $Id: s3c2410.c,v 1.5 2004/10/12 10:10:15 bjd Exp $
+ *
+ * This 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 <config/mtd/nand/s3c2410/hwecc.h>
+#include <config/mtd/nand/s3c2410/debug.h>
+
+#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/arch/regs-nand.h>
+#include <asm/arch/nand.h>
+
+#define PFX "s3c2410-nand: "
+
+#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
+static int hardware_ecc = 1;
+#else
+static int hardware_ecc = 0;
+#endif
+
+/* new oob placement block for use with hardware ecc generation
+ */
+
+static struct nand_oobinfo nand_hw_eccoob = {
+       .useecc = MTD_NANDECC_AUTOPLACE,
+       .eccbytes = 3,
+       .eccpos = {0, 1, 2 },
+       .oobfree = { {8, 8} }
+};
+
+/* controller and mtd information */
+
+struct s3c2410_nand_info;
+
+struct s3c2410_nand_mtd {
+       struct mtd_info                 mtd;
+       struct nand_chip                chip;
+       struct s3c2410_nand_set         *set;
+       struct s3c2410_nand_info        *info;
+       int                             scan_res;
+};
+
+/* overview of the s3c2410 nand state */
+
+struct s3c2410_nand_info {
+       /* mtd info */
+       struct nand_hw_control          controller;
+       struct s3c2410_nand_mtd         *mtds;
+       struct s3c2410_platform_nand    *platform;
+
+       /* device info */
+       struct device                   *device;
+       struct resource                 *area;
+       struct clk                      *clk;
+       void                            *regs;
+       int                             mtd_count;
+};
+
+/* conversion functions */
+
+static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd)
+{
+       return container_of(mtd, struct s3c2410_nand_mtd, mtd);
+}
+
+static struct s3c2410_nand_info *s3c2410_nand_mtd_toinfo(struct mtd_info *mtd)
+{
+       return s3c2410_nand_mtd_toours(mtd)->info;
+}
+
+static struct s3c2410_nand_info *to_nand_info(struct device *dev)
+{
+       return (struct s3c2410_nand_info *)dev_get_drvdata(dev);
+}
+
+static struct s3c2410_platform_nand *to_nand_plat(struct device *dev)
+{
+       return (struct s3c2410_platform_nand *)dev->platform_data;
+}
+
+/* timing calculations */
+
+#define NS_IN_KHZ 10000000
+
+static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
+{
+       int result;
+
+       result = (wanted * NS_IN_KHZ) / clk;
+       result++;
+
+       pr_debug("result %d from %ld, %d\n", result, clk, wanted);
+
+       if (result > max) {
+               printk("%d ns is too big for current clock rate %ld\n",
+                      wanted, clk);
+               return -1;
+       }
+
+       if (result < 1)
+               result = 1;
+
+       return result;
+}
+
+#define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ)
+
+/* controller setup */
+
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, 
+                              struct device *dev)
+{
+       struct s3c2410_platform_nand *plat = to_nand_plat(dev);
+       unsigned int tacls, twrph0, twrph1;
+       unsigned long clkrate = clk_get_rate(info->clk);
+       unsigned long cfg;
+
+       /* calculate the timing information for the controller */
+
+       if (plat != NULL) {
+               tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8);
+               twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
+               twrph1 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
+       } else {
+               /* default timings */
+               tacls = 8;
+               twrph0 = 8;
+               twrph1 = 8;
+       }
+       
+       if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
+               printk(KERN_ERR PFX "cannot get timings suitable for board\n");
+               return -EINVAL;
+       }
+
+       printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n",
+              to_ns(tacls, clkrate),
+              to_ns(twrph0, clkrate),
+              to_ns(twrph1, clkrate));
+
+       cfg  = S3C2410_NFCONF_EN;
+       cfg |= S3C2410_NFCONF_TACLS(tacls-1);
+       cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1);
+       cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1);
+
+       pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
+
+       writel(cfg, info->regs + S3C2410_NFCONF);
+       return 0;
+}
+
+/* select chip */
+
+static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct s3c2410_nand_info *info;
+       struct s3c2410_nand_mtd *nmtd; 
+       struct nand_chip *this = mtd->priv;
+       unsigned long cur;
+
+       nmtd = (struct s3c2410_nand_mtd *)this->priv;
+       info = nmtd->info;
+
+       cur = readl(info->regs + S3C2410_NFCONF);
+
+       if (chip == -1) {
+               cur |= S3C2410_NFCONF_nFCE;
+       } else {
+               if (chip > nmtd->set->nr_chips) {
+                       printk(KERN_ERR PFX "chip %d out of range\n", chip);
+                       return;
+               }
+
+               if (info->platform != NULL) {
+                       if (info->platform->select_chip != NULL)
+                               (info->platform->select_chip)(nmtd->set, chip);
+               }
+
+               cur &= ~S3C2410_NFCONF_nFCE;
+       }
+
+       writel(cur, info->regs + S3C2410_NFCONF);
+}
+
+/* command and control functions */
+
+static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       unsigned long cur;
+
+       switch (cmd) {
+       case NAND_CTL_SETNCE:
+               cur = readl(info->regs + S3C2410_NFCONF);
+               cur &= ~S3C2410_NFCONF_nFCE;
+               writel(cur, info->regs + S3C2410_NFCONF);
+               break;
+
+       case NAND_CTL_CLRNCE:
+               cur = readl(info->regs + S3C2410_NFCONF);
+               cur |= S3C2410_NFCONF_nFCE;
+               writel(cur, info->regs + S3C2410_NFCONF);
+               break;
+
+               /* we don't need to implement these */
+       case NAND_CTL_SETCLE:
+       case NAND_CTL_CLRCLE:
+       case NAND_CTL_SETALE:
+       case NAND_CTL_CLRALE:
+               pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd);
+               break;
+       }
+}
+
+/* s3c2410_nand_command
+ *
+ * This function implements sending commands and the relevant address
+ * information to the chip, via the hardware controller. Since the
+ * S3C2410 generates the correct ALE/CLE signaling automatically, we
+ * do not need to use hwcontrol.
+*/
+
+static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command,
+                                 int column, int page_addr)
+{
+       register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       register struct nand_chip *this = mtd->priv;
+
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->oobblock) {
+                       /* OOB area */
+                       column -= mtd->oobblock;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               
+               writeb(readcmd, info->regs + S3C2410_NFCMD);
+       }
+       writeb(command, info->regs + S3C2410_NFCMD);
+
+       /* Set ALE and clear CLE to start address cycle */
+
+       if (column != -1 || page_addr != -1) {
+
+               /* Serially input address */
+               if (column != -1) {
+                       /* Adjust columns for 16 bit buswidth */
+                       if (this->options & NAND_BUSWIDTH_16)
+                               column >>= 1;
+                       writeb(column, info->regs + S3C2410_NFADDR);
+               }
+               if (page_addr != -1) {
+                       writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR);
+                       writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR);
+                       /* One more address cycle for higher density devices */
+                       if (this->chipsize & 0x0c000000) 
+                               writeb((unsigned char) ((page_addr >> 16) & 0x0f),
+                                      info->regs + S3C2410_NFADDR);
+               }
+               /* Latch in address */
+       }
+       
+       /* 
+        * program and erase have their own busy handlers 
+        * status and sequential in needs no delay
+       */
+       switch (command) {
+                       
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_STATUS:
+               return;
+
+       case NAND_CMD_RESET:
+               if (this->dev_ready)    
+                       break;
+
+               udelay(this->chip_delay);
+               writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD);
+
+               while ( !(this->read_byte(mtd) & 0x40));
+               return;
+
+       /* This applies to read commands */     
+       default:
+               /* 
+                * If we don't have access to the busy pin, we apply the given
+                * command delay
+               */
+               if (!this->dev_ready) {
+                       udelay (this->chip_delay);
+                       return;
+               }       
+       }
+       
+       /* Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine. */
+       ndelay (100);
+       /* wait until command is processed */
+       while (!this->dev_ready(mtd));
+}
+
+
+/* s3c2410_nand_devready()
+ *
+ * returns 0 if the nand is busy, 1 if it is ready
+*/
+
+static int s3c2410_nand_devready(struct mtd_info *mtd)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       
+       return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
+}
+
+/* ECC handling functions */
+
+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+                                    u_char *read_ecc, u_char *calc_ecc)
+{
+       pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n",
+                mtd, dat, read_ecc, calc_ecc);
+
+       pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n",
+                read_ecc[0], read_ecc[1], read_ecc[2],
+                calc_ecc[0], calc_ecc[1], calc_ecc[2]);
+
+       if (read_ecc[0] == calc_ecc[0] &&
+           read_ecc[1] == calc_ecc[1] &&
+           read_ecc[2] == calc_ecc[2]) 
+               return 0;
+
+       /* we curently have no method for correcting the error */
+
+       return -1;
+}
+
+static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       unsigned long ctrl;
+
+       ctrl = readl(info->regs + S3C2410_NFCONF);
+       ctrl |= S3C2410_NFCONF_INITECC;
+       writel(ctrl, info->regs + S3C2410_NFCONF);
+}
+
+static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
+                                     const u_char *dat, u_char *ecc_code)
+{
+       struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+
+       ecc_code[0] = readb(info->regs + S3C2410_NFECC + 0);
+       ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
+       ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
+
+       pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",
+                ecc_code[0], ecc_code[1], ecc_code[2]);
+
+       return 0;
+}
+
+
+/* over-ride the standard functions for a little more speed? */
+
+static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct nand_chip *this = (struct nand_chip *)mtd->priv;
+       readsb(this->IO_ADDR_R, buf, len);
+}
+
+static void s3c2410_nand_write_buf(struct mtd_info *mtd,
+                                  const u_char *buf, int len)
+{
+       struct nand_chip *this = (struct nand_chip *)mtd->priv;
+       writesb(this->IO_ADDR_W, buf, len);
+}
+
+/* device management functions */
+
+static int s3c2410_nand_remove(struct device *dev)
+{
+       struct s3c2410_nand_info *info = to_nand_info(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+       if (info == NULL) 
+               return 0;
+
+       /* first thing we need to do is release all our mtds
+        * and their partitions, then go through freeing the
+        * resources used 
+        */
+       
+       if (info->mtds != NULL) {
+               struct s3c2410_nand_mtd *ptr = info->mtds;
+               int mtdno;
+
+               for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {
+                       pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);
+                       nand_release(&ptr->mtd);
+               }
+
+               kfree(info->mtds);
+       }
+
+       /* free the common resources */
+
+       if (info->clk != NULL && !IS_ERR(info->clk)) {
+               clk_disable(info->clk);
+               clk_unuse(info->clk);
+               clk_put(info->clk);
+       }
+
+       if (info->regs != NULL) {
+               iounmap(info->regs);
+               info->regs = NULL;
+       }
+
+       if (info->area != NULL) {
+               release_resource(info->area);
+               kfree(info->area);
+               info->area = NULL;
+       }
+
+       kfree(info);
+
+       return 0;
+}
+
+#ifdef CONFIG_MTD_PARTITIONS
+static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
+                                     struct s3c2410_nand_mtd *mtd,
+                                     struct s3c2410_nand_set *set)
+{
+       if (set == NULL)
+               return add_mtd_device(&mtd->mtd);
+
+       if (set->nr_partitions > 0 && set->partitions != NULL) {
+               return add_mtd_partitions(&mtd->mtd,
+                                         set->partitions,
+                                         set->nr_partitions);
+       }
+
+       return add_mtd_device(&mtd->mtd);
+}
+#else
+static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
+                                     struct s3c2410_nand_mtd *mtd,
+                                     struct s3c2410_nand_set *set)
+{
+       return add_mtd_device(&mtd->mtd);
+}
+#endif
+
+/* s3c2410_nand_init_chip
+ *
+ * init a single instance of an chip 
+*/
+
+static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
+                                  struct s3c2410_nand_mtd *nmtd,
+                                  struct s3c2410_nand_set *set)
+{
+       struct nand_chip *chip = &nmtd->chip;
+
+       chip->IO_ADDR_R    = (char *)info->regs + S3C2410_NFDATA;
+       chip->IO_ADDR_W    = (char *)info->regs + S3C2410_NFDATA;
+       chip->hwcontrol    = s3c2410_nand_hwcontrol;
+       chip->dev_ready    = s3c2410_nand_devready;
+       chip->cmdfunc      = s3c2410_nand_command;
+       chip->write_buf    = s3c2410_nand_write_buf;
+       chip->read_buf     = s3c2410_nand_read_buf;
+       chip->select_chip  = s3c2410_nand_select_chip;
+       chip->chip_delay   = 50;
+       chip->priv         = nmtd;
+       chip->options      = 0;
+       chip->controller   = &info->controller;
+
+       nmtd->info         = info;
+       nmtd->mtd.priv     = chip;
+       nmtd->set          = set;
+
+       if (hardware_ecc) {
+               chip->correct_data  = s3c2410_nand_correct_data;
+               chip->enable_hwecc  = s3c2410_nand_enable_hwecc;
+               chip->calculate_ecc = s3c2410_nand_calculate_ecc;
+               chip->eccmode       = NAND_ECC_HW3_512;
+               chip->autooob       = &nand_hw_eccoob;
+       } else {
+               chip->eccmode       = NAND_ECC_SOFT;
+       }
+}
+
+/* s3c2410_nand_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices
+*/
+
+static int s3c2410_nand_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s3c2410_platform_nand *plat = to_nand_plat(dev);
+       struct s3c2410_nand_info *info;
+       struct s3c2410_nand_mtd *nmtd;
+       struct s3c2410_nand_set *sets;
+       struct resource *res;
+       int err = 0;
+       int size;
+       int nr_sets;
+       int setno;
+
+       pr_debug("s3c2410_nand_probe(%p)\n", dev);
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL) {
+               printk(KERN_ERR PFX "no memory for flash info\n");
+               err = -ENOMEM;
+               goto exit_error;
+       }
+
+       memzero(info, sizeof(*info));
+       dev_set_drvdata(dev, info);
+
+       spin_lock_init(&info->controller.lock);
+
+       /* get the clock source and enable it */
+
+       info->clk = clk_get(dev, "nand");
+       if (IS_ERR(info->clk)) {
+               printk(KERN_ERR PFX "failed to get clock");
+               err = -ENOENT;
+               goto exit_error;
+       }
+
+       clk_use(info->clk);
+       clk_enable(info->clk);
+
+       /* allocate and map the resource */
+
+       res = pdev->resource;  /* assume that the flash has one resource */
+       size = res->end - res->start + 1;
+
+       info->area = request_mem_region(res->start, size, pdev->name);
+
+       if (info->area == NULL) {
+               printk(KERN_ERR PFX "cannot reserve register region\n");
+               err = -ENOENT;
+               goto exit_error;
+       }
+
+       info->device = dev;
+       info->platform = plat;
+       info->regs = ioremap(res->start, size);
+
+       if (info->regs == NULL) {
+               printk(KERN_ERR PFX "cannot reserve register region\n");
+               err = -EIO;
+               goto exit_error;
+       }               
+
+       printk(KERN_INFO PFX "mapped registers at %p\n", info->regs);
+
+       /* initialise the hardware */
+
+       err = s3c2410_nand_inithw(info, dev);
+       if (err != 0)
+               goto exit_error;
+
+       sets = (plat != NULL) ? plat->sets : NULL;
+       nr_sets = (plat != NULL) ? plat->nr_sets : 1;
+
+       info->mtd_count = nr_sets;
+
+       /* allocate our information */
+
+       size = nr_sets * sizeof(*info->mtds);
+       info->mtds = kmalloc(size, GFP_KERNEL);
+       if (info->mtds == NULL) {
+               printk(KERN_ERR PFX "failed to allocate mtd storage\n");
+               err = -ENOMEM;
+               goto exit_error;
+       }
+
+       memzero(info->mtds, size);
+
+       /* initialise all possible chips */
+
+       nmtd = info->mtds;
+
+       for (setno = 0; setno < nr_sets; setno++, nmtd++) {
+               pr_debug("initialising set %d (%p, info %p)\n",
+                        setno, nmtd, info);
+               
+               s3c2410_nand_init_chip(info, nmtd, sets);
+
+               nmtd->scan_res = nand_scan(&nmtd->mtd,
+                                          (sets) ? sets->nr_chips : 1);
+
+               if (nmtd->scan_res == 0) {
+                       s3c2410_nand_add_partition(info, nmtd, sets);
+               }
+
+               if (sets != NULL)
+                       sets++;
+       }
+       
+       pr_debug("initialised ok\n");
+       return 0;
+
+ exit_error:
+       s3c2410_nand_remove(dev);
+
+       if (err == 0)
+               err = -EINVAL;
+       return err;
+}
+
+static struct device_driver s3c2410_nand_driver = {
+       .name           = "s3c2410-nand",
+       .bus            = &platform_bus_type,
+       .probe          = s3c2410_nand_probe,
+       .remove         = s3c2410_nand_remove,
+};
+
+static int __init s3c2410_nand_init(void)
+{
+       printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n");
+       return driver_register(&s3c2410_nand_driver);
+}
+
+static void __exit s3c2410_nand_exit(void)
+{
+       driver_unregister(&s3c2410_nand_driver);
+}
+
+module_init(s3c2410_nand_init);
+module_exit(s3c2410_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C2410 MTD NAND driver");
diff --git a/drivers/net/cris/Makefile b/drivers/net/cris/Makefile
new file mode 100644 (file)
index 0000000..b4e8932
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_ETRAX_ARCH_V10) += eth_v10.o
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
new file mode 100644 (file)
index 0000000..4426708
--- /dev/null
@@ -0,0 +1,1836 @@
+/* $Id: ethernet.c,v 1.31 2004/10/18 14:49:03 starvik Exp $
+ *
+ * e100net.c: A network driver for the ETRAX 100LX network controller.
+ *
+ * Copyright (c) 1998-2002 Axis Communications AB.
+ *
+ * The outline of this driver comes from skeleton.c.
+ *
+ * $Log: ethernet.c,v $
+ * Revision 1.31  2004/10/18 14:49:03  starvik
+ * Use RX interrupt as random source
+ *
+ * Revision 1.30  2004/09/29 10:44:04  starvik
+ * Enabed MAC-address output again
+ *
+ * Revision 1.29  2004/08/24 07:14:05  starvik
+ * Make use of generic MDIO interface and constants.
+ *
+ * Revision 1.28  2004/08/20 09:37:11  starvik
+ * Added support for Intel LXT972A. Creds to Randy Scarborough.
+ *
+ * Revision 1.27  2004/08/16 12:37:22  starvik
+ * Merge of Linux 2.6.8
+ *
+ * Revision 1.25  2004/06/21 10:29:57  starvik
+ * Merge of Linux 2.6.7
+ *
+ * Revision 1.23  2004/06/09 05:29:22  starvik
+ * Avoid any race where R_DMA_CH1_FIRST is NULL (may trigger cache bug).
+ *
+ * Revision 1.22  2004/05/14 07:58:03  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.20  2004/03/11 11:38:40  starvik
+ * Merge of Linux 2.6.4
+ *
+ * Revision 1.18  2003/12/03 13:45:46  starvik
+ * Use hardware pad for short packets to prevent information leakage.
+ *
+ * Revision 1.17  2003/07/04 08:27:37  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.16  2003/04/24 08:28:22  starvik
+ * New LED behaviour: LED off when no link
+ *
+ * Revision 1.15  2003/04/09 05:20:47  starvik
+ * Merge of Linux 2.5.67
+ *
+ * Revision 1.13  2003/03/06 16:11:01  henriken
+ * Off by one error in group address register setting.
+ *
+ * Revision 1.12  2003/02/27 17:24:19  starvik
+ * Corrected Rev to Revision
+ *
+ * Revision 1.11  2003/01/24 09:53:21  starvik
+ * Oops. Initialize GA to 0, not to 1
+ *
+ * Revision 1.10  2003/01/24 09:50:55  starvik
+ * Initialize GA_0 and GA_1 to 0 to avoid matching of unwanted packets
+ *
+ * Revision 1.9  2002/12/13 07:40:58  starvik
+ * Added basic ethtool interface
+ * Handled out of memory when allocating new buffers
+ *
+ * Revision 1.8  2002/12/11 13:13:57  starvik
+ * Added arch/ to v10 specific includes
+ * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+ *
+ * Revision 1.7  2002/11/26 09:41:42  starvik
+ * Added e100_set_config (standard interface to set media type)
+ * Added protection against preemptive scheduling
+ * Added standard MII ioctls
+ *
+ * Revision 1.6  2002/11/21 07:18:18  starvik
+ * Timers must be initialized in 2.5.48
+ *
+ * Revision 1.5  2002/11/20 11:56:11  starvik
+ * Merge of Linux 2.5.48
+ *
+ * Revision 1.4  2002/11/18 07:26:46  starvik
+ * Linux 2.5 port of latest Linux 2.4 ethernet driver
+ *
+ * Revision 1.33  2002/10/02 20:16:17  hp
+ * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
+ *
+ * Revision 1.32  2002/09/16 06:05:58  starvik
+ * Align memory returned by dev_alloc_skb
+ * Moved handling of sent packets to interrupt to avoid reference counting problem
+ *
+ * Revision 1.31  2002/09/10 13:28:23  larsv
+ * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
+ * for supported functionality by issuing special ioctls, i.e. wireless
+ * extensions.
+ *
+ * Revision 1.30  2002/05/07 18:50:08  johana
+ * Correct spelling in comments.
+ *
+ * Revision 1.29  2002/05/06 05:38:49  starvik
+ * Performance improvements:
+ *    Large packets are not copied (breakpoint set to 256 bytes)
+ *    The cache bug workaround is delayed until half of the receive list
+ *      has been used
+ *    Added transmit list
+ *    Transmit interrupts are only enabled when transmit queue is full
+ *
+ * Revision 1.28.2.1  2002/04/30 08:15:51  starvik
+ * Performance improvements:
+ *   Large packets are not copied (breakpoint set to 256 bytes)
+ *   The cache bug workaround is delayed until half of the receive list
+ *     has been used.
+ *   Added transmit list
+ *   Transmit interrupts are only enabled when transmit queue is full
+ *
+ * Revision 1.28  2002/04/22 11:47:21  johana
+ * Fix according to 2.4.19-pre7. time_after/time_before and
+ * missing end of comment.
+ * The patch has a typo for ethernet.c in e100_clear_network_leds(),
+ *  that is fixed here.
+ *
+ * Revision 1.27  2002/04/12 11:55:11  bjornw
+ * Added TODO
+ *
+ * Revision 1.26  2002/03/15 17:11:02  bjornw
+ * Use prepare_rx_descriptor after the CPU has touched the receiving descs
+ *
+ * Revision 1.25  2002/03/08 13:07:53  bjornw
+ * Unnecessary spinlock removed
+ *
+ * Revision 1.24  2002/02/20 12:57:43  fredriks
+ * Replaced MIN() with min().
+ *
+ * Revision 1.23  2002/02/20 10:58:14  fredriks
+ * Strip the Ethernet checksum (4 bytes) before forwarding a frame to upper layers.
+ *
+ * Revision 1.22  2002/01/30 07:48:22  matsfg
+ * Initiate R_NETWORK_TR_CTRL
+ *
+ * Revision 1.21  2001/11/23 11:54:49  starvik
+ * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list
+ * Removed compiler warnings
+ *
+ * Revision 1.20  2001/11/12 19:26:00  pkj
+ * * Corrected e100_negotiate() to not assign half to current_duplex when
+ *   it was supposed to compare them...
+ * * Cleaned up failure handling in e100_open().
+ * * Fixed compiler warnings.
+ *
+ * Revision 1.19  2001/11/09 07:43:09  starvik
+ * Added full duplex support
+ * Added ioctl to set speed and duplex
+ * Clear LED timer only runs when LED is lit
+ *
+ * Revision 1.18  2001/10/03 14:40:43  jonashg
+ * Update rx_bytes counter.
+ *
+ * Revision 1.17  2001/06/11 12:43:46  olof
+ * Modified defines for network LED behavior
+ *
+ * Revision 1.16  2001/05/30 06:12:46  markusl
+ * TxDesc.next should not be set to NULL
+ *
+ * Revision 1.15  2001/05/29 10:27:04  markusl
+ * Updated after review remarks:
+ * +Use IO_EXTRACT
+ * +Handle underrun
+ *
+ * Revision 1.14  2001/05/29 09:20:14  jonashg
+ * Use driver name on printk output so one can tell which driver that complains.
+ *
+ * Revision 1.13  2001/05/09 12:35:59  johana
+ * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
+ *
+ * Revision 1.12  2001/04/05 11:43:11  tobiasa
+ * Check dev before panic.
+ *
+ * Revision 1.11  2001/04/04 11:21:05  markusl
+ * Updated according to review remarks
+ *
+ * Revision 1.10  2001/03/26 16:03:06  bjornw
+ * Needs linux/config.h
+ *
+ * Revision 1.9  2001/03/19 14:47:48  pkj
+ * * Make sure there is always a pause after the network LEDs are
+ *   changed so they will not look constantly lit during heavy traffic.
+ * * Always use HZ when setting times relative to jiffies.
+ * * Use LED_NETWORK_SET() when setting the network LEDs.
+ *
+ * Revision 1.8  2001/02/27 13:52:48  bjornw
+ * malloc.h -> slab.h
+ *
+ * Revision 1.7  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.6  2001/01/26 15:21:04  starvik
+ * Don't disable interrupts while reading MDIO registers (MDIO is slow)
+ * Corrected promiscuous mode
+ * Improved deallocation of IRQs ("ifconfig eth0 down" now works)
+ *
+ * Revision 1.5  2000/11/29 17:22:22  bjornw
+ * Get rid of the udword types legacy stuff
+ *
+ * Revision 1.4  2000/11/22 16:36:09  bjornw
+ * Please marketing by using the correct case when spelling Etrax.
+ *
+ * Revision 1.3  2000/11/21 16:43:04  bjornw
+ * Minor short->int change
+ *
+ * Revision 1.2  2000/11/08 14:27:57  bjornw
+ * 2.4 port
+ *
+ * Revision 1.1  2000/11/06 13:56:00  bjornw
+ * Verbatim copy of the 1.24 version of e100net.c from elinux
+ *
+ * Revision 1.24  2000/10/04 15:55:23  bjornw
+ * * Use virt_to_phys etc. for DMA addresses
+ * * Removed bogus CHECKSUM_UNNECESSARY
+ *
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/if.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+
+#include <asm/arch/svinto.h>/* DMA and register descriptions */
+#include <asm/io.h>         /* LED_* I/O functions */
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/ethernet.h>
+#include <asm/cache.h>
+
+//#define ETHDEBUG
+#define D(x)
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+
+static const char* cardname = "ETRAX 100LX built-in ethernet controller";
+
+/* A default ethernet address. Highlevel SW will set the real one later */
+
+static struct sockaddr default_mac = {
+       0,
+       { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
+};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+       struct net_device_stats stats;
+       struct mii_if_info mii_if;
+
+       /* Tx control lock.  This protects the transmit buffer ring
+        * state along with the "tx full" state of the driver.  This
+        * means all netif_queue flow control actions are protected
+        * by this lock as well.
+        */
+       spinlock_t lock;
+};
+
+typedef struct etrax_eth_descr
+{
+       etrax_dma_descr descr;
+       struct sk_buff* skb;
+} etrax_eth_descr;
+
+/* Some transceivers requires special handling */
+struct transceiver_ops
+{
+       unsigned int oui;
+       void (*check_speed)(struct net_device* dev);
+       void (*check_duplex)(struct net_device* dev);
+};
+
+struct transceiver_ops* transceiver;
+
+/* Duplex settings */
+enum duplex
+{
+       half,
+       full,
+       autoneg
+};
+
+/* Dma descriptors etc. */
+
+#define MAX_MEDIA_DATA_SIZE 1518
+
+#define MIN_PACKET_LEN      46
+#define ETHER_HEAD_LEN      14
+
+/*
+** MDIO constants.
+*/
+#define MDIO_START                          0x1
+#define MDIO_READ                           0x2
+#define MDIO_WRITE                          0x1
+#define MDIO_PREAMBLE              0xfffffffful
+
+/* Broadcom specific */
+#define MDIO_AUX_CTRL_STATUS_REG           0x18
+#define MDIO_BC_FULL_DUPLEX_IND             0x1
+#define MDIO_BC_SPEED                       0x2
+
+/* TDK specific */
+#define MDIO_TDK_DIAGNOSTIC_REG              18
+#define MDIO_TDK_DIAGNOSTIC_RATE          0x400
+#define MDIO_TDK_DIAGNOSTIC_DPLX          0x800
+
+/*Intel LXT972A specific*/
+#define MDIO_INT_STATUS_REG_2                  0x0011
+#define MDIO_INT_FULL_DUPLEX_IND               ( 1 << 9 )
+#define MDIO_INT_SPEED                         ( 1 << 14 )
+
+/* Network flash constants */
+#define NET_FLASH_TIME                  (HZ/50) /* 20 ms */
+#define NET_FLASH_PAUSE                (HZ/100) /* 10 ms */
+#define NET_LINK_UP_CHECK_INTERVAL       (2*HZ) /* 2 s   */
+#define NET_DUPLEX_CHECK_INTERVAL        (2*HZ) /* 2 s   */
+
+#define NO_NETWORK_ACTIVITY 0
+#define NETWORK_ACTIVITY    1
+
+#define NBR_OF_RX_DESC     64
+#define NBR_OF_TX_DESC     256
+
+/* Large packets are sent directly to upper layers while small packets are */
+/* copied (to reduce memory waste). The following constant decides the breakpoint */
+#define RX_COPYBREAK 256
+
+/* Due to a chip bug we need to flush the cache when descriptors are returned */
+/* to the DMA. To decrease performance impact we return descriptors in chunks. */
+/* The following constant determines the number of descriptors to return. */
+#define RX_QUEUE_THRESHOLD  NBR_OF_RX_DESC/2
+
+#define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
+
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+                                         IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+                                         IO_STATE_(reg##_, field##_, _##val)
+
+static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
+                                          to be processed */
+static etrax_eth_descr *myLastRxDesc;  /* The last processed descriptor */
+static etrax_eth_descr *myPrevRxDesc;  /* The descriptor right before myNextRxDesc */
+
+static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
+
+static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */
+static etrax_eth_descr* myLastTxDesc;  /* End of send queue */
+static etrax_eth_descr* myNextTxDesc;  /* Next descriptor to use */
+static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
+
+static unsigned int network_rec_config_shadow = 0;
+static unsigned int mdio_phy_addr; /* Transciever address */
+
+static unsigned int network_tr_ctrl_shadow = 0;
+
+/* Network speed indication. */
+static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static int current_speed; /* Speed read from transceiver */
+static int current_speed_selection; /* Speed selected by user */
+static unsigned long led_next_time;
+static int led_active;
+static int rx_queue_len;
+
+/* Duplex */
+static struct timer_list duplex_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static int full_duplex;
+static enum duplex current_duplex;
+
+/* Index to functions, as function prototypes. */
+
+static int etrax_ethernet_init(void);
+
+static int e100_open(struct net_device *dev);
+static int e100_set_mac_address(struct net_device *dev, void *addr);
+static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100_rx(struct net_device *dev);
+static int e100_close(struct net_device *dev);
+static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
+static int e100_set_config(struct net_device* dev, struct ifmap* map);
+static void e100_tx_timeout(struct net_device *dev);
+static struct net_device_stats *e100_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void e100_hardware_send_packet(char *buf, int length);
+static void update_rx_stats(struct net_device_stats *);
+static void update_tx_stats(struct net_device_stats *);
+static int e100_probe_transceiver(struct net_device* dev);
+
+static void e100_check_speed(unsigned long priv);
+static void e100_set_speed(struct net_device* dev, unsigned long speed);
+static void e100_check_duplex(unsigned long priv);
+static void e100_set_duplex(struct net_device* dev, enum duplex);
+static void e100_negotiate(struct net_device* dev);
+
+static int e100_get_mdio_reg(struct net_device *dev, int phy_id, int location);
+static void e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value);
+
+static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
+static void e100_send_mdio_bit(unsigned char bit);
+static unsigned char e100_receive_mdio_bit(void);
+static void e100_reset_transceiver(struct net_device* net);
+
+static void e100_clear_network_leds(unsigned long dummy);
+static void e100_set_network_leds(int active);
+
+static void broadcom_check_speed(struct net_device* dev);
+static void broadcom_check_duplex(struct net_device* dev);
+static void tdk_check_speed(struct net_device* dev);
+static void tdk_check_duplex(struct net_device* dev);
+static void intel_check_speed(struct net_device* dev);
+static void intel_check_duplex(struct net_device* dev);
+static void generic_check_speed(struct net_device* dev);
+static void generic_check_duplex(struct net_device* dev);
+
+struct transceiver_ops transceivers[] =
+{
+       {0x1018, broadcom_check_speed, broadcom_check_duplex},  /* Broadcom */
+       {0xC039, tdk_check_speed, tdk_check_duplex},            /* TDK 2120 */
+       {0x039C, tdk_check_speed, tdk_check_duplex},            /* TDK 2120C */
+        {0x04de, intel_check_speed, intel_check_duplex},       /* Intel LXT972A*/
+       {0x0000, generic_check_speed, generic_check_duplex}     /* Generic, must be last */
+};
+
+#define tx_done(dev) (*R_DMA_CH0_CMD == 0)
+
+/*
+ * Check for a network adaptor of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, allocate space for the device and return success
+ * (detachable devices only).
+ */
+
+static int __init
+etrax_ethernet_init(void)
+{
+       struct net_device *dev;
+        struct net_local* np;
+       int i, err;
+
+       printk(KERN_INFO
+              "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
+
+       dev = alloc_etherdev(sizeof(struct net_local));
+       np = dev->priv;
+
+       if (!dev)
+               return -ENOMEM;
+
+       dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
+
+       /* now setup our etrax specific stuff */
+
+       dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */
+       dev->dma = NETWORK_RX_DMA_NBR;
+
+       /* fill in our handlers so the network layer can talk to us in the future */
+
+       dev->open               = e100_open;
+       dev->hard_start_xmit    = e100_send_packet;
+       dev->stop               = e100_close;
+       dev->get_stats          = e100_get_stats;
+       dev->set_multicast_list = set_multicast_list;
+       dev->set_mac_address    = e100_set_mac_address;
+       dev->do_ioctl           = e100_ioctl;
+       dev->set_config         = e100_set_config;
+       dev->tx_timeout         = e100_tx_timeout;
+
+       /* Initialise the list of Etrax DMA-descriptors */
+
+       /* Initialise receive descriptors */
+
+       for (i = 0; i < NBR_OF_RX_DESC; i++) {
+               /* Allocate two extra cachelines to make sure that buffer used by DMA
+                * does not share cacheline with any other data (to avoid cache bug)
+                */
+               RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+               RxDescList[i].descr.ctrl   = 0;
+               RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
+               RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
+               RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
+               RxDescList[i].descr.status = 0;
+               RxDescList[i].descr.hw_len = 0;
+               prepare_rx_descriptor(&RxDescList[i].descr);
+       }
+
+       RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl   = d_eol;
+       RxDescList[NBR_OF_RX_DESC - 1].descr.next   = virt_to_phys(&RxDescList[0]);
+       rx_queue_len = 0;
+
+       /* Initialize transmit descriptors */
+       for (i = 0; i < NBR_OF_TX_DESC; i++) {
+               TxDescList[i].descr.ctrl   = 0;
+               TxDescList[i].descr.sw_len = 0;
+               TxDescList[i].descr.next   = virt_to_phys(&TxDescList[i + 1].descr);
+               TxDescList[i].descr.buf    = 0;
+               TxDescList[i].descr.status = 0;
+               TxDescList[i].descr.hw_len = 0;
+               TxDescList[i].skb = 0;
+       }
+
+       TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl   = d_eol;
+       TxDescList[NBR_OF_TX_DESC - 1].descr.next   = virt_to_phys(&TxDescList[0].descr);
+
+       /* Initialise initial pointers */
+
+       myNextRxDesc  = &RxDescList[0];
+       myLastRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
+       myPrevRxDesc  = &RxDescList[NBR_OF_RX_DESC - 1];
+       myFirstTxDesc = &TxDescList[0];
+       myNextTxDesc  = &TxDescList[0];
+       myLastTxDesc  = &TxDescList[NBR_OF_TX_DESC - 1];
+
+       /* Register device */
+       err = register_netdev(dev);
+       if (err) {
+               free_netdev(dev);
+               return err;
+       }
+
+       /* set the default MAC address */
+
+       e100_set_mac_address(dev, &default_mac);
+
+       /* Initialize speed indicator stuff. */
+
+       current_speed = 10;
+       current_speed_selection = 0; /* Auto */
+       speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+        duplex_timer.data = (unsigned long)dev;
+       speed_timer.function = e100_check_speed;
+
+       clear_led_timer.function = e100_clear_network_leds;
+
+       full_duplex = 0;
+       current_duplex = autoneg;
+       duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+        duplex_timer.data = (unsigned long)dev;
+       duplex_timer.function = e100_check_duplex;
+
+        /* Initialize mii interface */
+       np->mii_if.phy_id = mdio_phy_addr;
+       np->mii_if.phy_id_mask = 0x1f;
+       np->mii_if.reg_num_mask = 0x1f;
+       np->mii_if.dev = dev;
+       np->mii_if.mdio_read = e100_get_mdio_reg;
+       np->mii_if.mdio_write = e100_set_mdio_reg;
+
+       /* Initialize group address registers to make sure that no */
+       /* unwanted addresses are matched */
+       *R_NETWORK_GA_0 = 0x00000000;
+       *R_NETWORK_GA_1 = 0x00000000;
+       return 0;
+}
+
+/* set MAC address of the interface. called from the core after a
+ * SIOCSIFADDR ioctl, and from the bootup above.
+ */
+
+static int
+e100_set_mac_address(struct net_device *dev, void *p)
+{
+       struct net_local *np = (struct net_local *)dev->priv;
+       struct sockaddr *addr = p;
+       int i;
+
+       spin_lock(&np->lock); /* preemption protection */
+
+       /* remember it */
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       /* Write it to the hardware.
+        * Note the way the address is wrapped:
+        * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24);
+        * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8);
+        */
+
+       *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+               (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+       *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
+       *R_NETWORK_SA_2 = 0;
+
+       /* show it in the log as well */
+
+       printk(KERN_INFO "%s: changed MAC to ", dev->name);
+
+       for (i = 0; i < 5; i++)
+               printk("%02X:", dev->dev_addr[i]);
+
+       printk("%02X\n", dev->dev_addr[i]);
+
+       spin_unlock(&np->lock);
+
+       return 0;
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+static int
+e100_open(struct net_device *dev)
+{
+       unsigned long flags;
+
+       /* enable the MDIO output pin */
+
+       *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable);
+
+       *R_IRQ_MASK0_CLR =
+               IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
+               IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
+               IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
+
+       /* clear dma0 and 1 eop and descr irq masks */
+       *R_IRQ_MASK2_CLR =
+               IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
+               IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+               IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
+               IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+
+       /* Reset and wait for the DMA channels */
+
+       RESET_DMA(NETWORK_TX_DMA_NBR);
+       RESET_DMA(NETWORK_RX_DMA_NBR);
+       WAIT_DMA(NETWORK_TX_DMA_NBR);
+       WAIT_DMA(NETWORK_RX_DMA_NBR);
+
+       /* Initialise the etrax network controller */
+
+       /* allocate the irq corresponding to the receiving DMA */
+
+       if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt,
+                       SA_SAMPLE_RANDOM, cardname, (void *)dev)) {
+               goto grace_exit0;
+       }
+
+       /* allocate the irq corresponding to the transmitting DMA */
+
+       if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
+                       cardname, (void *)dev)) {
+               goto grace_exit1;
+       }
+
+       /* allocate the irq corresponding to the network errors etc */
+
+       if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0,
+                       cardname, (void *)dev)) {
+               goto grace_exit2;
+       }
+
+       /* give the HW an idea of what MAC address we want */
+
+       *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+               (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+       *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
+       *R_NETWORK_SA_2 = 0;
+
+#if 0
+       /* use promiscuous mode for testing */
+       *R_NETWORK_GA_0 = 0xffffffff;
+       *R_NETWORK_GA_1 = 0xffffffff;
+
+       *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
+#else
+       SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
+       SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
+       SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+       *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+#endif
+
+       *R_NETWORK_GEN_CONFIG =
+               IO_STATE(R_NETWORK_GEN_CONFIG, phy,    mii_clk) |
+               IO_STATE(R_NETWORK_GEN_CONFIG, enable, on);
+
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none);
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont);
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable);
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable);
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable);
+       SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
+       *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+
+       save_flags(flags);
+       cli();
+
+       /* enable the irq's for ethernet DMA */
+
+       *R_IRQ_MASK2_SET =
+               IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
+               IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
+
+       *R_IRQ_MASK0_SET =
+               IO_STATE(R_IRQ_MASK0_SET, overrun,       set) |
+               IO_STATE(R_IRQ_MASK0_SET, underrun,      set) |
+               IO_STATE(R_IRQ_MASK0_SET, excessive_col, set);
+
+       /* make sure the irqs are cleared */
+
+       *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+       *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
+
+       /* make sure the rec and transmit error counters are cleared */
+
+       (void)*R_REC_COUNTERS;  /* dummy read */
+       (void)*R_TR_COUNTERS;   /* dummy read */
+
+       /* start the receiving DMA channel so we can receive packets from now on */
+
+       *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc);
+       *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start);
+
+       /* Set up transmit DMA channel so it can be restarted later */
+
+       *R_DMA_CH0_FIRST = 0;
+       *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+
+       restore_flags(flags);
+
+       /* Probe for transceiver */
+       if (e100_probe_transceiver(dev))
+               goto grace_exit3;
+
+       /* Start duplex/speed timers */
+       add_timer(&speed_timer);
+       add_timer(&duplex_timer);
+
+       /* We are now ready to accept transmit requeusts from
+        * the queueing layer of the networking.
+        */
+       netif_start_queue(dev);
+
+       return 0;
+
+grace_exit3:
+       free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+grace_exit2:
+       free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+grace_exit1:
+       free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+grace_exit0:
+       return -EAGAIN;
+}
+
+
+static void
+generic_check_speed(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+       if ((data & ADVERTISE_100FULL) ||
+           (data & ADVERTISE_100HALF))
+               current_speed = 100;
+       else
+               current_speed = 10;
+}
+
+static void
+tdk_check_speed(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+       current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
+}
+
+static void
+broadcom_check_speed(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+       current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
+}
+
+static void
+intel_check_speed(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+       current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
+}
+
+static void
+e100_check_speed(unsigned long priv)
+{
+       struct net_device* dev = (struct net_device*)priv;
+       static int led_initiated = 0;
+       unsigned long data;
+       int old_speed = current_speed;
+
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR);
+       if (!(data & BMSR_LSTATUS)) {
+               current_speed = 0;
+       } else {
+               transceiver->check_speed(dev);
+       }
+
+       if ((old_speed != current_speed) || !led_initiated) {
+               led_initiated = 1;
+               e100_set_network_leds(NO_NETWORK_ACTIVITY);
+       }
+
+       /* Reinitialize the timer. */
+       speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+       add_timer(&speed_timer);
+}
+
+static void
+e100_negotiate(struct net_device* dev)
+{
+       unsigned short data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+
+       /* Discard old speed and duplex settings */
+       data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL |
+                 ADVERTISE_10HALF | ADVERTISE_10FULL);
+
+       switch (current_speed_selection) {
+               case 10 :
+                       if (current_duplex == full)
+                               data |= ADVERTISE_10FULL;
+                       else if (current_duplex == half)
+                               data |= ADVERTISE_10HALF;
+                       else
+                               data |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+                       break;
+
+               case 100 :
+                        if (current_duplex == full)
+                               data |= ADVERTISE_100FULL;
+                       else if (current_duplex == half)
+                               data |= ADVERTISE_100HALF;
+                       else
+                               data |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+                       break;
+
+               case 0 : /* Auto */
+                        if (current_duplex == full)
+                               data |= ADVERTISE_100FULL | ADVERTISE_10FULL;
+                       else if (current_duplex == half)
+                               data |= ADVERTISE_100HALF | ADVERTISE_10HALF;
+                       else
+                               data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
+                                 ADVERTISE_100HALF | ADVERTISE_100FULL;
+                       break;
+
+               default : /* assume autoneg speed and duplex */
+                       data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
+                                 ADVERTISE_100HALF | ADVERTISE_100FULL;
+       }
+
+       e100_set_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE, data);
+
+       /* Renegotiate with link partner */
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+       data |= BMCR_ANENABLE | BMCR_ANRESTART;
+
+       e100_set_mdio_reg(dev, mdio_phy_addr, MII_BMCR, data);
+}
+
+static void
+e100_set_speed(struct net_device* dev, unsigned long speed)
+{
+       if (speed != current_speed_selection) {
+               current_speed_selection = speed;
+               e100_negotiate(dev);
+       }
+}
+
+static void
+e100_check_duplex(unsigned long priv)
+{
+       struct net_device *dev = (struct net_device *)priv;
+       struct net_local *np = (struct net_local *)dev->priv;
+       int old_duplex = full_duplex;
+       transceiver->check_duplex(dev);
+       if (old_duplex != full_duplex) {
+               /* Duplex changed */
+               SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
+               *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+       }
+
+       /* Reinitialize the timer. */
+       duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
+       add_timer(&duplex_timer);
+       np->mii_if.full_duplex = full_duplex;
+}
+
+static void
+generic_check_duplex(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+       if ((data & ADVERTISE_10FULL) ||
+           (data & ADVERTISE_100FULL))
+               full_duplex = 1;
+       else
+               full_duplex = 0;
+}
+
+static void
+tdk_check_duplex(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+       full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
+}
+
+static void
+broadcom_check_duplex(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+       full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
+}
+
+static void
+intel_check_duplex(struct net_device* dev)
+{
+       unsigned long data;
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+       full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;
+}
+
+static void
+e100_set_duplex(struct net_device* dev, enum duplex new_duplex)
+{
+       if (new_duplex != current_duplex) {
+               current_duplex = new_duplex;
+               e100_negotiate(dev);
+       }
+}
+
+static int
+e100_probe_transceiver(struct net_device* dev)
+{
+       unsigned int phyid_high;
+       unsigned int phyid_low;
+       unsigned int oui;
+       struct transceiver_ops* ops = NULL;
+
+       /* Probe MDIO physical address */
+       for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
+               if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 0xffff)
+                       break;
+       }
+       if (mdio_phy_addr == 32)
+                return -ENODEV;
+
+       /* Get manufacturer */
+       phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);
+       phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2);
+       oui = (phyid_high << 6) | (phyid_low >> 10);
+
+       for (ops = &transceivers[0]; ops->oui; ops++) {
+               if (ops->oui == oui)
+                       break;
+       }
+       transceiver = ops;
+
+       return 0;
+}
+
+static int
+e100_get_mdio_reg(struct net_device *dev, int phy_id, int location)
+{
+       unsigned short cmd;    /* Data to be sent on MDIO port */
+       int data;   /* Data read from MDIO */
+       int bitCounter;
+
+       /* Start of frame, OP Code, Physical Address, Register Address */
+       cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) |
+               (location << 2);
+
+       e100_send_mdio_cmd(cmd, 0);
+
+       data = 0;
+
+       /* Data... */
+       for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+               data |= (e100_receive_mdio_bit() << bitCounter);
+       }
+
+       return data;
+}
+
+static void
+e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value)
+{
+       int bitCounter;
+       unsigned short cmd;
+
+       cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) |
+             (location << 2);
+
+       e100_send_mdio_cmd(cmd, 1);
+
+       /* Data... */
+       for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+               e100_send_mdio_bit(GET_BIT(bitCounter, value));
+       }
+
+}
+
+static void
+e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
+{
+       int bitCounter;
+       unsigned char data = 0x2;
+
+       /* Preamble */
+       for (bitCounter = 31; bitCounter>= 0; bitCounter--)
+               e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));
+
+       for (bitCounter = 15; bitCounter >= 2; bitCounter--)
+               e100_send_mdio_bit(GET_BIT(bitCounter, cmd));
+
+       /* Turnaround */
+       for (bitCounter = 1; bitCounter >= 0 ; bitCounter--)
+               if (write_cmd)
+                       e100_send_mdio_bit(GET_BIT(bitCounter, data));
+               else
+                       e100_receive_mdio_bit();
+}
+
+static void
+e100_send_mdio_bit(unsigned char bit)
+{
+       *R_NETWORK_MGM_CTRL =
+               IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
+               IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
+       udelay(1);
+       *R_NETWORK_MGM_CTRL =
+               IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
+               IO_MASK(R_NETWORK_MGM_CTRL, mdck) |
+               IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
+       udelay(1);
+}
+
+static unsigned char
+e100_receive_mdio_bit()
+{
+       unsigned char bit;
+       *R_NETWORK_MGM_CTRL = 0;
+       bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT);
+       udelay(1);
+       *R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck);
+       udelay(1);
+       return bit;
+}
+
+static void
+e100_reset_transceiver(struct net_device* dev)
+{
+       unsigned short cmd;
+       unsigned short data;
+       int bitCounter;
+
+       data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+
+       cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2);
+
+       e100_send_mdio_cmd(cmd, 1);
+
+       data |= 0x8000;
+
+       for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
+               e100_send_mdio_bit(GET_BIT(bitCounter, data));
+       }
+}
+
+/* Called by upper layers if they decide it took too long to complete
+ * sending a packet - we need to reset and stuff.
+ */
+
+static void
+e100_tx_timeout(struct net_device *dev)
+{
+       struct net_local *np = (struct net_local *)dev->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&np->lock, flags);
+
+       printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+              tx_done(dev) ? "IRQ problem" : "network cable problem");
+
+       /* remember we got an error */
+
+       np->stats.tx_errors++;
+
+       /* reset the TX DMA in case it has hung on something */
+
+       RESET_DMA(NETWORK_TX_DMA_NBR);
+       WAIT_DMA(NETWORK_TX_DMA_NBR);
+
+       /* Reset the transceiver. */
+
+       e100_reset_transceiver(dev);
+
+       /* and get rid of the packets that never got an interrupt */
+       while (myFirstTxDesc != myNextTxDesc)
+       {
+               dev_kfree_skb(myFirstTxDesc->skb);
+               myFirstTxDesc->skb = 0;
+               myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+       }
+
+       /* Set up transmit DMA channel so it can be restarted later */
+       *R_DMA_CH0_FIRST = 0;
+       *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+
+       /* tell the upper layers we're ok again */
+
+       netif_wake_queue(dev);
+       spin_unlock_irqrestore(&np->lock, flags);
+}
+
+
+/* This will only be invoked if the driver is _not_ in XOFF state.
+ * What this means is that we need not check it, and that this
+ * invariant will hold if we make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+
+static int
+e100_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+       struct net_local *np = (struct net_local *)dev->priv;
+       unsigned char *buf = skb->data;
+       unsigned long flags;
+
+#ifdef ETHDEBUG
+       printk("send packet len %d\n", length);
+#endif
+       spin_lock_irqsave(&np->lock, flags);  /* protect from tx_interrupt and ourself */
+
+       myNextTxDesc->skb = skb;
+
+       dev->trans_start = jiffies;
+
+       e100_hardware_send_packet(buf, skb->len);
+
+       myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
+
+       /* Stop queue if full */
+       if (myNextTxDesc == myFirstTxDesc) {
+               netif_stop_queue(dev);
+       }
+
+       spin_unlock_irqrestore(&np->lock, flags);
+
+       return 0;
+}
+
+/*
+ * The typical workload of the driver:
+ *   Handle the network interface interrupts.
+ */
+
+static irqreturn_t
+e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct net_local *np = (struct net_local *)dev->priv;
+       unsigned long irqbits = *R_IRQ_MASK2_RD;
+
+       /* Disable RX/TX IRQs to avoid reentrancy */
+       *R_IRQ_MASK2_CLR =
+         IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+         IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+
+       /* Handle received packets */
+       if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
+               /* acknowledge the eop interrupt */
+
+               *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
+
+               /* check if one or more complete packets were indeed received */
+
+               while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) &&
+                      (myNextRxDesc != myLastRxDesc)) {
+                       /* Take out the buffer and give it to the OS, then
+                        * allocate a new buffer to put a packet in.
+                        */
+                       e100_rx(dev);
+                       ((struct net_local *)dev->priv)->stats.rx_packets++;
+                       /* restart/continue on the channel, for safety */
+                       *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
+                       /* clear dma channel 1 eop/descr irq bits */
+                       *R_DMA_CH1_CLR_INTR =
+                               IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) |
+                               IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do);
+
+                       /* now, we might have gotten another packet
+                          so we have to loop back and check if so */
+               }
+       }
+
+       /* Report any packets that have been sent */
+       while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+              myFirstTxDesc != myNextTxDesc)
+       {
+               np->stats.tx_bytes += myFirstTxDesc->skb->len;
+               np->stats.tx_packets++;
+
+               /* dma is ready with the transmission of the data in tx_skb, so now
+                  we can release the skb memory */
+               dev_kfree_skb_irq(myFirstTxDesc->skb);
+               myFirstTxDesc->skb = 0;
+               myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+       }
+
+       if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
+               /* acknowledge the eop interrupt and wake up queue */
+               *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+               netif_wake_queue(dev);
+       }
+
+       /* Enable RX/TX IRQs again */
+       *R_IRQ_MASK2_SET =
+         IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
+         IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct net_local *np = (struct net_local *)dev->priv;
+       unsigned long irqbits = *R_IRQ_MASK0_RD;
+
+       /* check for underrun irq */
+       if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) {
+               SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
+               *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+               SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
+               np->stats.tx_errors++;
+               D(printk("ethernet receiver underrun!\n"));
+       }
+
+       /* check for overrun irq */
+       if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {
+               update_rx_stats(&np->stats); /* this will ack the irq */
+               D(printk("ethernet receiver overrun!\n"));
+       }
+       /* check for excessive collision irq */
+       if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) {
+               SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
+               *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
+               SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
+               *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
+               np->stats.tx_errors++;
+               D(printk("ethernet excessive collisions!\n"));
+       }
+       return IRQ_HANDLED;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+e100_rx(struct net_device *dev)
+{
+       struct sk_buff *skb;
+       int length = 0;
+       struct net_local *np = (struct net_local *)dev->priv;
+       unsigned char *skb_data_ptr;
+#ifdef ETHDEBUG
+       int i;
+#endif
+
+       if (!led_active && time_after(jiffies, led_next_time)) {
+               /* light the network leds depending on the current speed. */
+               e100_set_network_leds(NETWORK_ACTIVITY);
+
+               /* Set the earliest time we may clear the LED */
+               led_next_time = jiffies + NET_FLASH_TIME;
+               led_active = 1;
+               mod_timer(&clear_led_timer, jiffies + HZ/10);
+       }
+
+       length = myNextRxDesc->descr.hw_len - 4;
+       ((struct net_local *)dev->priv)->stats.rx_bytes += length;
+
+#ifdef ETHDEBUG
+       printk("Got a packet of length %d:\n", length);
+       /* dump the first bytes in the packet */
+       skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf);
+       for (i = 0; i < 8; i++) {
+               printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
+                      skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
+                      skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
+               skb_data_ptr += 8;
+       }
+#endif
+
+       if (length < RX_COPYBREAK) {
+               /* Small packet, copy data */
+               skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
+               if (!skb) {
+                       np->stats.rx_errors++;
+                       printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+                       return;
+               }
+
+               skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
+               skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
+
+#ifdef ETHDEBUG
+               printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
+                 skb->head, skb->data, skb->tail, skb->end);
+               printk("copying packet to 0x%x.\n", skb_data_ptr);
+#endif
+
+               memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
+       }
+       else {
+               /* Large packet, send directly to upper layers and allocate new
+                * memory (aligned to cache line boundary to avoid bug).
+                * Before sending the skb to upper layers we must make sure that
+                * skb->data points to the aligned start of the packet.
+                */
+               int align;
+               struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+               if (!new_skb) {
+                       np->stats.rx_errors++;
+                       printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+                       return;
+               }
+               skb = myNextRxDesc->skb;
+               align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;
+               skb_put(skb, length + align);
+               skb_pull(skb, align); /* Remove alignment bytes */
+               myNextRxDesc->skb = new_skb;
+               myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
+       }
+
+       skb->dev = dev;
+       skb->protocol = eth_type_trans(skb, dev);
+
+       /* Send the packet to the upper layers */
+       netif_rx(skb);
+
+       /* Prepare for next packet */
+       myNextRxDesc->descr.status = 0;
+       myPrevRxDesc = myNextRxDesc;
+       myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
+
+       rx_queue_len++;
+
+       /* Check if descriptors should be returned */
+       if (rx_queue_len == RX_QUEUE_THRESHOLD) {
+               flush_etrax_cache();
+               myPrevRxDesc->descr.ctrl |= d_eol;
+               myLastRxDesc->descr.ctrl &= ~d_eol;
+               myLastRxDesc = myPrevRxDesc;
+               rx_queue_len = 0;
+       }
+}
+
+/* The inverse routine to net_open(). */
+static int
+e100_close(struct net_device *dev)
+{
+       struct net_local *np = (struct net_local *)dev->priv;
+
+       printk(KERN_INFO "Closing %s.\n", dev->name);
+
+       netif_stop_queue(dev);
+
+       *R_IRQ_MASK0_CLR =
+               IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
+               IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
+               IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
+
+       *R_IRQ_MASK2_CLR =
+               IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
+               IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+               IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
+               IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+
+       /* Stop the receiver and the transmitter */
+
+       RESET_DMA(NETWORK_TX_DMA_NBR);
+       RESET_DMA(NETWORK_RX_DMA_NBR);
+
+       /* Flush the Tx and disable Rx here. */
+
+       free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev);
+       free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
+       free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+
+       /* Update the statistics here. */
+
+       update_rx_stats(&np->stats);
+       update_tx_stats(&np->stats);
+
+       /* Stop speed/duplex timers */
+       del_timer(&speed_timer);
+       del_timer(&duplex_timer);
+
+       return 0;
+}
+
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct mii_ioctl_data *data = if_mii(ifr);
+       struct net_local *np = netdev_priv(dev);
+
+       spin_lock(&np->lock); /* Preempt protection */
+       switch (cmd) {
+               case SIOCETHTOOL:
+                       return e100_ethtool_ioctl(dev,ifr);
+               case SIOCGMIIPHY: /* Get PHY address */
+                       data->phy_id = mdio_phy_addr;
+                       break;
+               case SIOCGMIIREG: /* Read MII register */
+                       data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num);
+                       break;
+               case SIOCSMIIREG: /* Write MII register */
+                       e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in);
+                       break;
+               /* The ioctls below should be considered obsolete but are */
+               /* still present for compatability with old scripts/apps  */
+               case SET_ETH_SPEED_10:                  /* 10 Mbps */
+                       e100_set_speed(dev, 10);
+                       break;
+               case SET_ETH_SPEED_100:                /* 100 Mbps */
+                       e100_set_speed(dev, 100);
+                       break;
+               case SET_ETH_SPEED_AUTO:              /* Auto negotiate speed */
+                       e100_set_speed(dev, 0);
+                       break;
+               case SET_ETH_DUPLEX_HALF:              /* Half duplex. */
+                       e100_set_duplex(dev, half);
+                       break;
+               case SET_ETH_DUPLEX_FULL:              /* Full duplex. */
+                       e100_set_duplex(dev, full);
+                       break;
+               case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
+                       e100_set_duplex(dev, autoneg);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       spin_unlock(&np->lock);
+       return 0;
+}
+
+static int
+e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+       struct ethtool_cmd ecmd;
+
+       if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+               return -EFAULT;
+
+       switch (ecmd.cmd) {
+               case ETHTOOL_GSET:
+               {
+                       memset((void *) &ecmd, 0, sizeof (ecmd));
+                       ecmd.supported =
+                         SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+                         SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+                         SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+                       ecmd.port = PORT_TP;
+                       ecmd.transceiver = XCVR_EXTERNAL;
+                       ecmd.phy_address = mdio_phy_addr;
+                       ecmd.speed = current_speed;
+                       ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+                       ecmd.advertising = ADVERTISED_TP;
+                       if (current_duplex == autoneg && current_speed_selection == 0)
+                               ecmd.advertising |= ADVERTISED_Autoneg;
+                       else {
+                               ecmd.advertising |=
+                                 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+                                 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+                               if (current_speed_selection == 10)
+                                       ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+                               else if (current_speed_selection == 100)
+                                       ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+                               if (current_duplex == half)
+                                       ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+                               else if (current_duplex == full)
+                                       ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+                       }
+                       ecmd.autoneg = AUTONEG_ENABLE;
+                       if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+                               return -EFAULT;
+               }
+               break;
+               case ETHTOOL_SSET:
+               {
+                       if (!capable(CAP_NET_ADMIN)) {
+                               return -EPERM;
+                       }
+                       if (ecmd.autoneg == AUTONEG_ENABLE) {
+                               e100_set_duplex(dev, autoneg);
+                               e100_set_speed(dev, 0);
+                       } else {
+                               e100_set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
+                               e100_set_speed(dev, ecmd.speed == SPEED_10 ? 10: 100);
+                       }
+               }
+               break;
+               case ETHTOOL_GDRVINFO:
+               {
+                       struct ethtool_drvinfo info;
+                       memset((void *) &info, 0, sizeof (info));
+                       strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
+                       strncpy(info.version, "$Revision: 1.31 $", sizeof(info.version) - 1);
+                       strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+                       strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+                       info.regdump_len = 0;
+                       info.eedump_len = 0;
+                       info.testinfo_len = 0;
+                       if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+                               return -EFAULT;
+               }
+               break;
+               case ETHTOOL_NWAY_RST:
+                       if (current_duplex == autoneg && current_speed_selection == 0)
+                               e100_negotiate(dev);
+               break;
+               default:
+                       return -EOPNOTSUPP;
+               break;
+       }
+       return 0;
+}
+
+static int
+e100_set_config(struct net_device *dev, struct ifmap *map)
+{
+       struct net_local *np = (struct net_local *)dev->priv;
+       spin_lock(&np->lock); /* Preempt protection */
+
+       switch(map->port) {
+               case IF_PORT_UNKNOWN:
+                       /* Use autoneg */
+                       e100_set_speed(dev, 0);
+                       e100_set_duplex(dev, autoneg);
+                       break;
+               case IF_PORT_10BASET:
+                       e100_set_speed(dev, 10);
+                       e100_set_duplex(dev, autoneg);
+                       break;
+               case IF_PORT_100BASET:
+               case IF_PORT_100BASETX:
+                       e100_set_speed(dev, 100);
+                       e100_set_duplex(dev, autoneg);
+                       break;
+               case IF_PORT_100BASEFX:
+               case IF_PORT_10BASE2:
+               case IF_PORT_AUI:
+                       spin_unlock(&np->lock);
+                       return -EOPNOTSUPP;
+                       break;
+               default:
+                       printk(KERN_ERR "%s: Invalid media selected", dev->name);
+                       spin_unlock(&np->lock);
+                       return -EINVAL;
+       }
+       spin_unlock(&np->lock);
+       return 0;
+}
+
+static void
+update_rx_stats(struct net_device_stats *es)
+{
+       unsigned long r = *R_REC_COUNTERS;
+       /* update stats relevant to reception errors */
+       es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r);
+       es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r);
+       es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r);
+       es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r);
+}
+
+static void
+update_tx_stats(struct net_device_stats *es)
+{
+       unsigned long r = *R_TR_COUNTERS;
+       /* update stats relevant to transmission errors */
+       es->collisions +=
+               IO_EXTRACT(R_TR_COUNTERS, single_col, r) +
+               IO_EXTRACT(R_TR_COUNTERS, multiple_col, r);
+       es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       unsigned long flags;
+       spin_lock_irqsave(&lp->lock, flags);
+
+       update_rx_stats(&lp->stats);
+       update_tx_stats(&lp->stats);
+
+       spin_unlock_irqrestore(&lp->lock, flags);
+       return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1     Promiscuous mode, receive all packets
+ * num_addrs == 0      Normal mode, clear multicast list
+ * num_addrs > 0       Multicast mode, receive normal and MC packets,
+ *                     and do best-effort filtering.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int num_addr = dev->mc_count;
+       unsigned long int lo_bits;
+       unsigned long int hi_bits;
+       spin_lock(&lp->lock);
+       if (dev->flags & IFF_PROMISC)
+       {
+               /* promiscuous mode */
+               lo_bits = 0xfffffffful;
+               hi_bits = 0xfffffffful;
+
+               /* Enable individual receive */
+               SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive);
+               *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+       } else if (dev->flags & IFF_ALLMULTI) {
+               /* enable all multicasts */
+               lo_bits = 0xfffffffful;
+               hi_bits = 0xfffffffful;
+
+               /* Disable individual receive */
+               SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+               *R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
+       } else if (num_addr == 0) {
+               /* Normal, clear the mc list */
+               lo_bits = 0x00000000ul;
+               hi_bits = 0x00000000ul;
+
+               /* Disable individual receive */
+               SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+               *R_NETWORK_REC_CONFIG =  network_rec_config_shadow;
+       } else {
+               /* MC mode, receive normal and MC packets */
+               char hash_ix;
+               struct dev_mc_list *dmi = dev->mc_list;
+               int i;
+               char *baddr;
+               lo_bits = 0x00000000ul;
+               hi_bits = 0x00000000ul;
+               for (i=0; i<num_addr; i++) {
+                       /* Calculate the hash index for the GA registers */
+
+                       hash_ix = 0;
+                       baddr = dmi->dmi_addr;
+                       hash_ix ^= (*baddr) & 0x3f;
+                       hash_ix ^= ((*baddr) >> 6) & 0x03;
+                       ++baddr;
+                       hash_ix ^= ((*baddr) << 2) & 0x03c;
+                       hash_ix ^= ((*baddr) >> 4) & 0xf;
+                       ++baddr;
+                       hash_ix ^= ((*baddr) << 4) & 0x30;
+                       hash_ix ^= ((*baddr) >> 2) & 0x3f;
+                       ++baddr;
+                       hash_ix ^= (*baddr) & 0x3f;
+                       hash_ix ^= ((*baddr) >> 6) & 0x03;
+                       ++baddr;
+                       hash_ix ^= ((*baddr) << 2) & 0x03c;
+                       hash_ix ^= ((*baddr) >> 4) & 0xf;
+                       ++baddr;
+                       hash_ix ^= ((*baddr) << 4) & 0x30;
+                       hash_ix ^= ((*baddr) >> 2) & 0x3f;
+
+                       hash_ix &= 0x3f;
+
+                       if (hash_ix >= 32) {
+                               hi_bits |= (1 << (hash_ix-32));
+                       }
+                       else {
+                               lo_bits |= (1 << hash_ix);
+                       }
+                       dmi = dmi->next;
+               }
+               /* Disable individual receive */
+               SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard);
+               *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
+       }
+       *R_NETWORK_GA_0 = lo_bits;
+       *R_NETWORK_GA_1 = hi_bits;
+       spin_unlock(&lp->lock);
+}
+
+void
+e100_hardware_send_packet(char *buf, int length)
+{
+       D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
+
+       if (!led_active && time_after(jiffies, led_next_time)) {
+               /* light the network leds depending on the current speed. */
+               e100_set_network_leds(NETWORK_ACTIVITY);
+
+               /* Set the earliest time we may clear the LED */
+               led_next_time = jiffies + NET_FLASH_TIME;
+               led_active = 1;
+               mod_timer(&clear_led_timer, jiffies + HZ/10);
+       }
+
+       /* configure the tx dma descriptor */
+       myNextTxDesc->descr.sw_len = length;
+       myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait;
+       myNextTxDesc->descr.buf = virt_to_phys(buf);
+
+        /* Move end of list */
+        myLastTxDesc->descr.ctrl &= ~d_eol;
+        myLastTxDesc = myNextTxDesc;
+
+       /* Restart DMA channel */
+       *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart);
+}
+
+static void
+e100_clear_network_leds(unsigned long dummy)
+{
+       if (led_active && time_after(jiffies, led_next_time)) {
+               e100_set_network_leds(NO_NETWORK_ACTIVITY);
+
+               /* Set the earliest time we may set the LED */
+               led_next_time = jiffies + NET_FLASH_PAUSE;
+               led_active = 0;
+       }
+}
+
+static void
+e100_set_network_leds(int active)
+{
+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK)
+       int light_leds = (active == NO_NETWORK_ACTIVITY);
+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY)
+       int light_leds = (active == NETWORK_ACTIVITY);
+#else
+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"
+#endif
+
+       if (!current_speed) {
+               /* Make LED red, link is down */
+#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
+               LED_NETWORK_SET(LED_RED);
+#else
+               LED_NETWORK_SET(LED_OFF);
+#endif
+       }
+       else if (light_leds) {
+               if (current_speed == 10) {
+                       LED_NETWORK_SET(LED_ORANGE);
+               } else {
+                       LED_NETWORK_SET(LED_GREEN);
+               }
+       }
+       else {
+               LED_NETWORK_SET(LED_OFF);
+       }
+}
+
+static int
+etrax_init_module(void)
+{
+       return etrax_ethernet_init();
+}
+
+static int __init
+e100_boot_setup(char* str)
+{
+       struct sockaddr sa = {0};
+       int i;
+
+       /* Parse the colon separated Ethernet station address */
+       for (i = 0; i <  ETH_ALEN; i++) {
+               unsigned int tmp;
+               if (sscanf(str + 3*i, "%2x", &tmp) != 1) {
+                       printk(KERN_WARNING "Malformed station address");
+                       return 0;
+               }
+               sa.sa_data[i] = (char)tmp;
+       }
+
+       default_mac = sa;
+       return 1;
+}
+
+__setup("etrax100_eth=", e100_boot_setup);
+
+module_init(etrax_init_module);
diff --git a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h
new file mode 100644 (file)
index 0000000..7e7af0d
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * 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 Patton Electronics Company
+ * Copyright (C) 2002 Momentum Computer
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *             stevel@mvista.com or support@mvista.com
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * Ethernet driver definitions for the MIPS GT96100 Advanced
+ * Communication Controller.
+ * 
+ * Modified for the Marvellous GT64240 Retarded Communication Controller.
+ */
+#ifndef _GT64240ETH_H
+#define _GT64240ETH_H
+
+#include <asm/gt64240.h>
+
+#define ETHERNET_PORTS_DIFFERENCE_OFFSETS      0x400
+
+/* Translate those weanie names from Galileo/VxWorks header files: */
+
+#define GT64240_MRR                    MAIN_ROUTING_REGISTER
+#define GT64240_CIU_ARBITER_CONFIG     COMM_UNIT_ARBITER_CONFIGURATION_REGISTER
+#define GT64240_CIU_ARBITER_CONTROL    COMM_UNIT_ARBITER_CONTROL
+#define GT64240_MAIN_LOW_CAUSE         LOW_INTERRUPT_CAUSE_REGISTER
+#define GT64240_MAIN_HIGH_CAUSE        HIGH_INTERRUPT_CAUSE_REGISTER
+#define GT64240_CPU_LOW_MASK           CPU_INTERRUPT_MASK_REGISTER_LOW
+#define GT64240_CPU_HIGH_MASK          CPU_INTERRUPT_MASK_REGISTER_HIGH
+#define GT64240_CPU_SELECT_CAUSE       CPU_SELECT_CAUSE_REGISTER
+
+#define GT64240_ETH_PHY_ADDR_REG       ETHERNET_PHY_ADDRESS_REGISTER
+#define GT64240_ETH_PORT_CONFIG        ETHERNET0_PORT_CONFIGURATION_REGISTER
+#define GT64240_ETH_PORT_CONFIG_EXT    ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER
+#define GT64240_ETH_PORT_COMMAND       ETHERNET0_PORT_COMMAND_REGISTER
+#define GT64240_ETH_PORT_STATUS        ETHERNET0_PORT_STATUS_REGISTER
+#define GT64240_ETH_IO_SIZE            ETHERNET_PORTS_DIFFERENCE_OFFSETS
+#define GT64240_ETH_SMI_REG            ETHERNET_SMI_REGISTER
+#define GT64240_ETH_MIB_COUNT_BASE     ETHERNET0_MIB_COUNTER_BASE
+#define GT64240_ETH_SDMA_CONFIG        ETHERNET0_SDMA_CONFIGURATION_REGISTER
+#define GT64240_ETH_SDMA_COMM          ETHERNET0_SDMA_COMMAND_REGISTER
+#define GT64240_ETH_INT_MASK           ETHERNET0_INTERRUPT_MASK_REGISTER
+#define GT64240_ETH_INT_CAUSE          ETHERNET0_INTERRUPT_CAUSE_REGISTER
+#define GT64240_ETH_CURR_TX_DESC_PTR0  ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0
+#define GT64240_ETH_CURR_TX_DESC_PTR1  ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1
+#define GT64240_ETH_1ST_RX_DESC_PTR0   ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0
+#define GT64240_ETH_CURR_RX_DESC_PTR0  ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0
+#define GT64240_ETH_HASH_TBL_PTR       ETHERNET0_HASH_TABLE_POINTER_REGISTER
+
+/* Turn on NAPI by default */
+
+#define        GT64240_NAPI                    1
+
+/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */
+/* (Board-specific to the DSL3224 Rev A board ONLY!)                    */
+#define D3224_MPP_CTRL0_SETTING                0x66669900
+#define D3224_MPP_CTRL1_SETTING                0x00000000
+#define D3224_MPP_CTRL2_SETTING                0x00887700
+#define D3224_MPP_CTRL3_SETTING                0x00000044
+#define D3224_GPP_IO_CTRL_SETTING      0x0000e800
+#define D3224_GPP_LEVEL_CTRL_SETTING   0xf001f703
+#define D3224_GPP_VALUE_SETTING                0x00000000
+
+/* Keep the ring sizes a power of two for efficiency. */
+//-#define TX_RING_SIZE 16
+#define TX_RING_SIZE   64      /* TESTING !!! */
+#define RX_RING_SIZE   32
+#define PKT_BUF_SZ     1536    /* Size of each temporary Rx buffer. */
+
+#define RX_HASH_TABLE_SIZE 16384
+#define HASH_HOP_NUMBER 12
+
+#define NUM_INTERFACES 3
+
+#define GT64240ETH_TX_TIMEOUT HZ/4
+
+#define MIPS_GT64240_BASE 0xf4000000
+#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG)
+#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE)
+#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE)
+
+#if defined(CONFIG_MIPS_DSL3224)
+#define GT64240_ETHER0_IRQ 4
+#define GT64240_ETHER1_IRQ 4
+#else
+#define GT64240_ETHER0_IRQ -1
+#define GT64240_ETHER1_IRQ -1
+#endif
+
+#define REV_GT64240  0x1
+#define REV_GT64240A 0x10
+
+#define GT64240ETH_READ(gp, offset)                                    \
+       GT_READ((gp)->port_offset + (offset))
+
+#define GT64240ETH_WRITE(gp, offset, data)                             \
+       GT_WRITE((gp)->port_offset + (offset), (data))
+
+#define GT64240ETH_SETBIT(gp, offset, bits)                            \
+       GT64240ETH_WRITE((gp), (offset),                                \
+                        GT64240ETH_READ((gp), (offset)) | (bits))
+
+#define GT64240ETH_CLRBIT(gp, offset, bits)                            \
+       GT64240ETH_WRITE((gp), (offset),                                \
+                        GT64240ETH_READ((gp), (offset)) & ~(bits))
+
+#define GT64240_READ(ofs)              GT_READ(ofs)
+#define GT64240_WRITE(ofs, data)       GT_WRITE((ofs), (data))
+
+/* Bit definitions of the SMI Reg */
+enum {
+       smirDataMask = 0xffff,
+       smirPhyAdMask = 0x1f << 16,
+       smirPhyAdBit = 16,
+       smirRegAdMask = 0x1f << 21,
+       smirRegAdBit = 21,
+       smirOpCode = 1 << 26,
+       smirReadValid = 1 << 27,
+       smirBusy = 1 << 28
+};
+
+/* Bit definitions of the Port Config Reg */
+enum pcr_bits {
+       pcrPM = 1 << 0,
+       pcrRBM = 1 << 1,
+       pcrPBF = 1 << 2,
+       pcrEN = 1 << 7,
+       pcrLPBKMask = 0x3 << 8,
+       pcrLPBKBit = 1 << 8,
+       pcrFC = 1 << 10,
+       pcrHS = 1 << 12,
+       pcrHM = 1 << 13,
+       pcrHDM = 1 << 14,
+       pcrHD = 1 << 15,
+       pcrISLMask = 0x7 << 28,
+       pcrISLBit = 28,
+       pcrACCS = 1 << 31
+};
+
+/* Bit definitions of the Port Config Extend Reg */
+enum pcxr_bits {
+       pcxrIGMP = 1,
+       pcxrSPAN = 2,
+       pcxrPAR = 4,
+       pcxrPRIOtxMask = 0x7 << 3,
+       pcxrPRIOtxBit = 3,
+       pcxrPRIOrxMask = 0x3 << 6,
+       pcxrPRIOrxBit = 6,
+       pcxrPRIOrxOverride = 1 << 8,
+       pcxrDPLXen = 1 << 9,
+       pcxrFCTLen = 1 << 10,
+       pcxrFLP = 1 << 11,
+       pcxrFCTL = 1 << 12,
+       pcxrMFLMask = 0x3 << 14,
+       pcxrMFLBit = 14,
+       pcxrMIBclrMode = 1 << 16,
+       pcxrSpeed = 1 << 18,
+       pcxrSpeeden = 1 << 19,
+       pcxrRMIIen = 1 << 20,
+       pcxrDSCPen = 1 << 21
+};
+
+/* Bit definitions of the Port Command Reg */
+enum pcmr_bits {
+       pcmrFJ = 1 << 15
+};
+
+
+/* Bit definitions of the Port Status Reg */
+enum psr_bits {
+       psrSpeed = 1,
+       psrDuplex = 2,
+       psrFctl = 4,
+       psrLink = 8,
+       psrPause = 1 << 4,
+       psrTxLow = 1 << 5,
+       psrTxHigh = 1 << 6,
+       psrTxInProg = 1 << 7
+};
+
+/* Bit definitions of the SDMA Config Reg */
+enum sdcr_bits {
+       sdcrRCMask = 0xf << 2,
+       sdcrRCBit = 2,
+       sdcrBLMR = 1 << 6,
+       sdcrBLMT = 1 << 7,
+       sdcrPOVR = 1 << 8,
+       sdcrRIFB = 1 << 9,
+       sdcrBSZMask = 0x3 << 12,
+       sdcrBSZBit = 12
+};
+
+/* Bit definitions of the SDMA Command Reg */
+enum sdcmr_bits {
+       sdcmrERD = 1 << 7,
+       sdcmrAR = 1 << 15,
+       sdcmrSTDH = 1 << 16,
+       sdcmrSTDL = 1 << 17,
+       sdcmrTXDH = 1 << 23,
+       sdcmrTXDL = 1 << 24,
+       sdcmrAT = 1 << 31
+};
+
+/* Bit definitions of the Interrupt Cause Reg */
+enum icr_bits {
+       icrRxBuffer = 1,
+       icrTxBufferHigh = 1 << 2,
+       icrTxBufferLow = 1 << 3,
+       icrTxEndHigh = 1 << 6,
+       icrTxEndLow = 1 << 7,
+       icrRxError = 1 << 8,
+       icrTxErrorHigh = 1 << 10,
+       icrTxErrorLow = 1 << 11,
+       icrRxOVR = 1 << 12,
+       icrTxUdr = 1 << 13,
+       icrRxBufferQ0 = 1 << 16,
+       icrRxBufferQ1 = 1 << 17,
+       icrRxBufferQ2 = 1 << 18,
+       icrRxBufferQ3 = 1 << 19,
+       icrRxErrorQ0 = 1 << 20,
+       icrRxErrorQ1 = 1 << 21,
+       icrRxErrorQ2 = 1 << 22,
+       icrRxErrorQ3 = 1 << 23,
+       icrMIIPhySTC = 1 << 28,
+       icrSMIdone = 1 << 29,
+       icrEtherIntSum = 1 << 31
+};
+
+
+/* The Rx and Tx descriptor lists. */
+#ifdef __LITTLE_ENDIAN
+typedef struct {
+       u32 cmdstat;
+       u16 reserved;           //-prk21aug01    u32 reserved:16;
+       u16 byte_cnt;           //-prk21aug01    u32 byte_cnt:16;
+       u32 buff_ptr;
+       u32 next;
+} gt64240_td_t;
+
+typedef struct {
+       u32 cmdstat;
+       u16 byte_cnt;           //-prk21aug01    u32 byte_cnt:16;
+       u16 buff_sz;            //-prk21aug01    u32 buff_sz:16;
+       u32 buff_ptr;
+       u32 next;
+} gt64240_rd_t;
+#elif defined(__BIG_ENDIAN)
+typedef struct {
+       u16 byte_cnt;           //-prk21aug01    u32 byte_cnt:16;
+       u16 reserved;           //-prk21aug01    u32 reserved:16;
+       u32 cmdstat;
+       u32 next;
+       u32 buff_ptr;
+} gt64240_td_t;
+
+typedef struct {
+       u16 buff_sz;            //-prk21aug01    u32 buff_sz:16;
+       u16 byte_cnt;           //-prk21aug01    u32 byte_cnt:16;
+       u32 cmdstat;
+       u32 next;
+       u32 buff_ptr;
+} gt64240_rd_t;
+#else
+#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined!
+#endif
+
+
+/* Values for the Tx command-status descriptor entry. */
+enum td_cmdstat {
+       txOwn = 1 << 31,
+       txAutoMode = 1 << 30,
+       txEI = 1 << 23,
+       txGenCRC = 1 << 22,
+       txPad = 1 << 18,
+       txFirst = 1 << 17,
+       txLast = 1 << 16,
+       txErrorSummary = 1 << 15,
+       txReTxCntMask = 0x0f << 10,
+       txReTxCntBit = 10,
+       txCollision = 1 << 9,
+       txReTxLimit = 1 << 8,
+       txUnderrun = 1 << 6,
+       txLateCollision = 1 << 5
+};
+
+
+/* Values for the Rx command-status descriptor entry. */
+enum rd_cmdstat {
+       rxOwn = 1 << 31,
+       rxAutoMode = 1 << 30,
+       rxEI = 1 << 23,
+       rxFirst = 1 << 17,
+       rxLast = 1 << 16,
+       rxErrorSummary = 1 << 15,
+       rxIGMP = 1 << 14,
+       rxHashExpired = 1 << 13,
+       rxMissedFrame = 1 << 12,
+       rxFrameType = 1 << 11,
+       rxShortFrame = 1 << 8,
+       rxMaxFrameLen = 1 << 7,
+       rxOverrun = 1 << 6,
+       rxCollision = 1 << 4,
+       rxCRCError = 1
+};
+
+/* Bit fields of a Hash Table Entry */
+enum hash_table_entry {
+       hteValid = 1,
+       hteSkip = 2,
+       hteRD = 4
+};
+
+// The MIB counters
+typedef struct {
+       u32 byteReceived;
+       u32 byteSent;
+       u32 framesReceived;
+       u32 framesSent;
+       u32 totalByteReceived;
+       u32 totalFramesReceived;
+       u32 broadcastFramesReceived;
+       u32 multicastFramesReceived;
+       u32 cRCError;
+       u32 oversizeFrames;
+       u32 fragments;
+       u32 jabber;
+       u32 collision;
+       u32 lateCollision;
+       u32 frames64;
+       u32 frames65_127;
+       u32 frames128_255;
+       u32 frames256_511;
+       u32 frames512_1023;
+       u32 frames1024_MaxSize;
+       u32 macRxError;
+       u32 droppedFrames;
+       u32 outMulticastFrames;
+       u32 outBroadcastFrames;
+       u32 undersizeFrames;
+} mib_counters_t;
+
+
+struct gt64240_private {
+       gt64240_rd_t *rx_ring;
+       gt64240_td_t *tx_ring;
+       // The Rx and Tx rings must be 16-byte aligned
+       dma_addr_t rx_ring_dma;
+       dma_addr_t tx_ring_dma;
+       char *hash_table;
+       // The Hash Table must be 8-byte aligned
+       dma_addr_t hash_table_dma;
+       int hash_mode;
+
+       // The Rx buffers must be 8-byte aligned
+       char *rx_buff;
+       dma_addr_t rx_buff_dma;
+       // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
+       // of payload must be 8-byte aligned
+       struct sk_buff *tx_skbuff[TX_RING_SIZE];
+       int rx_next_out;        /* The next free ring entry to receive */
+       int tx_next_in;         /* The next free ring entry to send */
+       int tx_next_out;        /* The last ring entry the ISR processed */
+       int tx_count;           /* current # of pkts waiting to be sent in Tx ring */
+       int intr_work_done;     /* number of Rx and Tx pkts processed in the isr */
+       int tx_full;            /* Tx ring is full */
+
+       mib_counters_t mib;
+       struct net_device_stats stats;
+
+       int io_size;
+       int port_num;           // 0 or 1
+       u32 port_offset;
+
+       int phy_addr;           // PHY address
+       u32 last_psr;           // last value of the port status register
+
+       int options;            /* User-settable misc. driver options. */
+       int drv_flags;
+       spinlock_t lock;        /* Serialise access to device */
+       struct mii_if_info mii_if;
+
+       u32 msg_enable;
+};
+
+#endif /* _GT64240ETH_H */
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
new file mode 100644 (file)
index 0000000..41d38b3
--- /dev/null
@@ -0,0 +1,2646 @@
+/*
+ * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports
+ * Copyright (C) 2002 Matthew Dharm <mdharm@momenco.com>
+ *
+ * Based on the 64360 driver from:
+ * Copyright (C) 2002 rabeeh@galileo.co.il
+ *
+ * Copyright (C) 2003 PMC-Sierra, Inc.,
+ *     written by Manish Lachwani (lachwani@pmc-sierra.com)
+ *
+ * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <asm/smp.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/ip.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include "mv643xx_eth.h"
+
+/*
+ * The first part is the high level driver of the gigE ethernet ports. 
+ */
+
+/* Definition for configuring driver */
+#undef MV64340_RX_QUEUE_FILL_ON_TASK
+
+/* Constants */
+#define EXTRA_BYTES 32
+#define WRAP       ETH_HLEN + 2 + 4 + 16
+#define BUFFER_MTU dev->mtu + WRAP
+#define INT_CAUSE_UNMASK_ALL           0x0007ffff
+#define INT_CAUSE_UNMASK_ALL_EXT       0x0011ffff
+#ifdef MV64340_RX_FILL_ON_TASK
+#define INT_CAUSE_MASK_ALL             0x00000000
+#define INT_CAUSE_CHECK_BITS           INT_CAUSE_UNMASK_ALL
+#define INT_CAUSE_CHECK_BITS_EXT       INT_CAUSE_UNMASK_ALL_EXT
+#endif
+
+/* Static function declarations */
+static int mv64340_eth_real_open(struct net_device *);
+static int mv64340_eth_real_stop(struct net_device *);
+static int mv64340_eth_change_mtu(struct net_device *, int);
+static struct net_device_stats *mv64340_eth_get_stats(struct net_device *);
+static void eth_port_init_mac_tables(unsigned int eth_port_num);
+#ifdef MV64340_NAPI
+static int mv64340_poll(struct net_device *dev, int *budget);
+#endif
+
+unsigned char prom_mac_addr_base[6];
+unsigned long mv64340_sram_base;
+
+/*
+ * Changes MTU (maximum transfer unit) of the gigabit ethenret port
+ *
+ * Input : pointer to ethernet interface network device structure
+ *         new mtu size 
+ * Output : 0 upon success, -EINVAL upon failure
+ */
+static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&mp->lock, flags);
+
+       if ((new_mtu > 9500) || (new_mtu < 64)) {
+               spin_unlock_irqrestore(&mp->lock, flags);
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+       /* 
+        * Stop then re-open the interface. This will allocate RX skb's with
+        * the new MTU.
+        * There is a possible danger that the open will not successed, due
+        * to memory is full, which might fail the open function.
+        */
+       if (netif_running(dev)) {
+               if (mv64340_eth_real_stop(dev))
+                       printk(KERN_ERR
+                              "%s: Fatal error on stopping device\n",
+                              dev->name);
+               if (mv64340_eth_real_open(dev))
+                       printk(KERN_ERR
+                              "%s: Fatal error on opening device\n",
+                              dev->name);
+       }
+
+       spin_unlock_irqrestore(&mp->lock, flags);
+       return 0;
+}
+
+/*
+ * mv64340_eth_rx_task
+ *                                                                    
+ * Fills / refills RX queue on a certain gigabit ethernet port
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void mv64340_eth_rx_task(void *data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       struct mv64340_private *mp = netdev_priv(dev);
+       struct pkt_info pkt_info;
+       struct sk_buff *skb;
+
+       if (test_and_set_bit(0, &mp->rx_task_busy))
+               panic("%s: Error in test_set_bit / clear_bit", dev->name);
+
+       while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) {
+               /* The +8 for buffer allignment and another 32 byte extra */
+
+               skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES);
+               if (!skb)
+                       /* Better luck next time */
+                       break;
+               mp->rx_ring_skbs++;
+               pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT;
+               pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES;
+               /* Allign buffer to 8 bytes */
+               if (pkt_info.byte_cnt & ~0x7) {
+                       pkt_info.byte_cnt &= ~0x7;
+                       pkt_info.byte_cnt += 8;
+               }
+               pkt_info.buf_ptr =
+                   pci_map_single(0, skb->data,
+                                  dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES,
+                                  PCI_DMA_FROMDEVICE);
+               pkt_info.return_info = skb;
+               if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) {
+                       printk(KERN_ERR
+                              "%s: Error allocating RX Ring\n", dev->name);
+                       break;
+               }
+               skb_reserve(skb, 2);
+       }
+       clear_bit(0, &mp->rx_task_busy);
+       /*
+        * If RX ring is empty of SKB, set a timer to try allocating
+        * again in a later time .
+        */
+       if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) {
+               printk(KERN_INFO "%s: Rx ring is empty\n", dev->name);
+               /* After 100mSec */
+               mp->timeout.expires = jiffies + (HZ / 10);
+               add_timer(&mp->timeout);
+               mp->rx_timer_flag = 1;
+       }
+#if MV64340_RX_QUEUE_FILL_ON_TASK
+       else {
+               /* Return interrupts */
+               MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num),
+                        INT_CAUSE_UNMASK_ALL);
+       }
+#endif
+}
+
+/*
+ * mv64340_eth_rx_task_timer_wrapper
+ *                                                                    
+ * Timer routine to wake up RX queue filling task. This function is
+ * used only in case the RX queue is empty, and all alloc_skb has
+ * failed (due to out of memory event).
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void mv64340_eth_rx_task_timer_wrapper(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       struct mv64340_private *mp = netdev_priv(dev);
+
+       mp->rx_timer_flag = 0;
+       mv64340_eth_rx_task((void *) data);
+}
+
+
+/*
+ * mv64340_eth_update_mac_address
+ *                                                                    
+ * Update the MAC address of the port in the address table
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void mv64340_eth_update_mac_address(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned int port_num = mp->port_num;
+
+       eth_port_init_mac_tables(port_num);
+       memcpy(mp->port_mac_addr, dev->dev_addr, 6);
+       eth_port_uc_addr_set(port_num, mp->port_mac_addr);
+}
+
+/*
+ * mv64340_eth_set_rx_mode
+ *                                                                    
+ * Change from promiscuos to regular rx mode
+ *
+ * Input : pointer to ethernet interface network device structure
+ * Output : N/A
+ */
+static void mv64340_eth_set_rx_mode(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+
+       if (dev->flags & IFF_PROMISC) {
+               ethernet_set_config_reg
+                   (mp->port_num,
+                    ethernet_get_config_reg(mp->port_num) |
+                    ETH_UNICAST_PROMISCUOUS_MODE);
+       } else {
+               ethernet_set_config_reg
+                   (mp->port_num,
+                    ethernet_get_config_reg(mp->port_num) &
+                    ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE);
+       }
+}
+
+
+/*
+ * mv64340_eth_set_mac_address
+ *                                                                    
+ * Change the interface's mac address.
+ * No special hardware thing should be done because interface is always
+ * put in promiscuous mode.
+ *
+ * Input : pointer to ethernet interface network device structure and
+ *         a pointer to the designated entry to be added to the cache.
+ * Output : zero upon success, negative upon failure
+ */
+static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr)
+{
+       int i;
+
+       for (i = 0; i < 6; i++)
+               /* +2 is for the offset of the HW addr type */
+               dev->dev_addr[i] = ((unsigned char *) addr)[i + 2];
+       mv64340_eth_update_mac_address(dev);
+       return 0;
+}
+
+/*
+ * mv64340_eth_tx_timeout
+ *                                                                    
+ * Called upon a timeout on transmitting a packet
+ *
+ * Input : pointer to ethernet interface network device structure.
+ * Output : N/A
+ */
+static void mv64340_eth_tx_timeout(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+
+       printk(KERN_INFO "%s: TX timeout  ", dev->name);
+
+       /* Do the reset outside of interrupt context */
+       schedule_work(&mp->tx_timeout_task);
+}
+
+/*
+ * mv64340_eth_tx_timeout_task
+ *
+ * Actual routine to reset the adapter when a timeout on Tx has occurred
+ */
+static void mv64340_eth_tx_timeout_task(struct net_device *dev)
+{
+        struct mv64340_private *mp = netdev_priv(dev);
+
+        netif_device_detach(dev);
+        eth_port_reset(mp->port_num);
+        eth_port_start(mp);
+        netif_device_attach(dev);
+}
+
+/*
+ * mv64340_eth_free_tx_queue
+ *
+ * Input : dev - a pointer to the required interface
+ *
+ * Output : 0 if was able to release skb , nonzero otherwise
+ */
+static int mv64340_eth_free_tx_queue(struct net_device *dev,
+                             unsigned int eth_int_cause_ext)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       struct net_device_stats *stats = &mp->stats;
+       struct pkt_info pkt_info;
+       int released = 1;
+
+       if (!(eth_int_cause_ext & (BIT0 | BIT8)))
+               return released;
+
+       spin_lock(&mp->lock);
+
+       /* Check only queue 0 */
+       while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) {
+               if (pkt_info.cmd_sts & BIT0) {
+                       printk("%s: Error in TX\n", dev->name);
+                       stats->tx_errors++;
+               }
+
+               /* 
+                * If return_info is different than 0, release the skb.
+                * The case where return_info is not 0 is only in case
+                * when transmitted a scatter/gather packet, where only
+                * last skb releases the whole chain.
+                */
+               if (pkt_info.return_info) {
+                       dev_kfree_skb_irq((struct sk_buff *)
+                                         pkt_info.return_info);
+                       released = 0;
+                       if (skb_shinfo(pkt_info.return_info)->nr_frags)
+                               pci_unmap_page(NULL, pkt_info.buf_ptr,
+                                       pkt_info.byte_cnt, PCI_DMA_TODEVICE);
+
+                       if (mp->tx_ring_skbs != 1)
+                               mp->tx_ring_skbs--;
+               } else 
+                       pci_unmap_page(NULL, pkt_info.buf_ptr,
+                                       pkt_info.byte_cnt, PCI_DMA_TODEVICE);
+
+               /* 
+                * Decrement the number of outstanding skbs counter on
+                * the TX queue.
+                */
+               if (mp->tx_ring_skbs == 0)
+                       panic("ERROR - TX outstanding SKBs counter is corrupted");
+
+       }
+
+       spin_unlock(&mp->lock);
+
+       return released;
+}
+
+/*
+ * mv64340_eth_receive
+ *
+ * This function is forward packets that are received from the port's
+ * queues toward kernel core or FastRoute them to another interface.
+ *
+ * Input : dev - a pointer to the required interface
+ *         max - maximum number to receive (0 means unlimted)
+ *
+ * Output : number of served packets
+ */
+#ifdef MV64340_NAPI
+static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max,
+                                                               int budget)
+#else
+static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max)
+#endif
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       struct net_device_stats *stats = &mp->stats;
+       unsigned int received_packets = 0;
+       struct sk_buff *skb;
+       struct pkt_info pkt_info;
+
+#ifdef MV64340_NAPI
+       while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {
+#else
+       while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) {
+#endif
+               mp->rx_ring_skbs--;
+               received_packets++;
+#ifdef MV64340_NAPI
+               budget--;
+#endif
+               /* Update statistics. Note byte count includes 4 byte CRC count */
+               stats->rx_packets++;
+               stats->rx_bytes += pkt_info.byte_cnt;
+               skb = (struct sk_buff *) pkt_info.return_info;
+               /*
+                * In case received a packet without first / last bits on OR
+                * the error summary bit is on, the packets needs to be dropeed.
+                */
+               if (((pkt_info.cmd_sts
+                     & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) !=
+                    (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC))
+                   || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) {
+                       stats->rx_dropped++;
+                       if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC |
+                                                ETH_RX_LAST_DESC)) !=
+                           (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) {
+                               if (net_ratelimit())
+                                       printk(KERN_ERR
+                                              "%s: Received packet spread on multiple"
+                                              " descriptors\n",
+                                              dev->name);
+                       }
+                       if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)
+                               stats->rx_errors++;
+
+                       dev_kfree_skb_irq(skb);
+               } else {
+                       /*
+                        * The -4 is for the CRC in the trailer of the
+                        * received packet
+                        */
+                       skb_put(skb, pkt_info.byte_cnt - 4);
+                       skb->dev = dev;
+
+                       if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               skb->csum = htons((pkt_info.cmd_sts
+                                                       & 0x0007fff8) >> 3);
+                       }
+                       skb->protocol = eth_type_trans(skb, dev);
+#ifdef MV64340_NAPI
+                       netif_receive_skb(skb);
+#else
+                       netif_rx(skb);
+#endif
+               }
+       }
+
+       return received_packets;
+}
+
+/*
+ * mv64340_eth_int_handler
+ *
+ * Main interrupt handler for the gigbit ethernet ports
+ *
+ * Input : irq - irq number (not used)
+ *         dev_id - a pointer to the required interface's data structure
+ *         regs   - not used
+ * Output : N/A
+ */
+
+static irqreturn_t mv64340_eth_int_handler(int irq, void *dev_id,
+       struct pt_regs *regs)
+{
+       struct net_device *dev = (struct net_device *) dev_id;
+       struct mv64340_private *mp = netdev_priv(dev);
+       u32 eth_int_cause, eth_int_cause_ext = 0;
+       unsigned int port_num = mp->port_num;
+
+       /* Read interrupt cause registers */
+       eth_int_cause = MV_READ(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) &
+                       INT_CAUSE_UNMASK_ALL;
+
+       if (eth_int_cause & BIT1)
+               eth_int_cause_ext =
+               MV_READ(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
+               INT_CAUSE_UNMASK_ALL_EXT;
+
+#ifdef MV64340_NAPI
+       if (!(eth_int_cause & 0x0007fffd)) {
+       /* Dont ack the Rx interrupt */
+#endif
+               /*
+                * Clear specific ethernet port intrerrupt registers by
+                * acknowleding relevant bits.
+                */
+               MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),
+                        ~eth_int_cause);
+               if (eth_int_cause_ext != 0x0)
+                       MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),
+                                ~eth_int_cause_ext);
+
+               /* UDP change : We may need this */
+               if ((eth_int_cause_ext & 0x0000ffff) &&
+                   (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) &&
+                   (MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1))
+                                         netif_wake_queue(dev);
+#ifdef MV64340_NAPI
+       } else {
+               if (netif_rx_schedule_prep(dev)) {
+                       /* Mask all the interrupts */
+                       MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0);
+                       MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0);
+                       __netif_rx_schedule(dev);
+               }
+#else
+               {
+               if (eth_int_cause & (BIT2 | BIT11))
+                       mv64340_eth_receive_queue(dev, 0);
+
+               /*
+                * After forwarded received packets to upper layer,  add a task
+                * in an interrupts enabled context that refills the RX ring
+                * with skb's.
+                */
+#if MV64340_RX_QUEUE_FILL_ON_TASK
+               /* Unmask all interrupts on ethernet port */
+               MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),
+                        INT_CAUSE_MASK_ALL);
+               queue_task(&mp->rx_task, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+#else
+               mp->rx_task.func(dev);
+#endif
+#endif
+       }
+       /* PHY status changed */
+       if (eth_int_cause_ext & (BIT16 | BIT20)) {
+               unsigned int phy_reg_data;
+
+               /* Check Link status on ethernet port */
+               eth_port_read_smi_reg(port_num, 1, &phy_reg_data);
+               if (!(phy_reg_data & 0x20)) {
+                       netif_stop_queue(dev);
+               } else {
+                       netif_wake_queue(dev);
+
+                       /*
+                        * Start all TX queues on ethernet port. This is good in
+                        * case of previous packets where not transmitted, due
+                        * to link down and this command re-enables all TX
+                        * queues.
+                        * Note that it is possible to get a TX resource error
+                        * interrupt after issuing this, since not all TX queues
+                        * are enabled, or has anything to send.
+                        */
+                       MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1);
+               }
+       }
+
+       /*
+        * If no real interrupt occured, exit.
+        * This can happen when using gigE interrupt coalescing mechanism.
+        */
+       if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0))
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+}
+
+#ifdef MV64340_COAL
+
+/*
+ * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path
+ *
+ * DESCRIPTION:
+ *     This routine sets the RX coalescing interrupt mechanism parameter.
+ *     This parameter is a timeout counter, that counts in 64 t_clk
+ *     chunks ; that when timeout event occurs a maskable interrupt
+ *     occurs.
+ *     The parameter is calculated using the tClk of the MV-643xx chip
+ *     , and the required delay of the interrupt in usec.
+ *
+ * INPUT:
+ *     unsigned int eth_port_num      Ethernet port number
+ *     unsigned int t_clk        t_clk of the MV-643xx chip in HZ units
+ *     unsigned int delay       Delay in usec
+ *
+ * OUTPUT:
+ *     Interrupt coalescing mechanism value is set in MV-643xx chip.
+ *
+ * RETURN:
+ *     The interrupt coalescing value set in the gigE port.
+ *
+ */
+static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num,
+       unsigned int t_clk, unsigned int delay)
+{
+       unsigned int coal = ((t_clk / 1000000) * delay) / 64;
+
+       /* Set RX Coalescing mechanism */
+       MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num),
+                ((coal & 0x3fff) << 8) |
+                (MV_READ(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num))
+                 & 0xffc000ff));
+
+       return coal;
+}
+#endif
+
+/*
+ * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path
+ *
+ * DESCRIPTION:
+ *     This routine sets the TX coalescing interrupt mechanism parameter.
+ *     This parameter is a timeout counter, that counts in 64 t_clk
+ *     chunks ; that when timeout event occurs a maskable interrupt
+ *     occurs.
+ *     The parameter is calculated using the t_cLK frequency of the 
+ *     MV-643xx chip and the required delay in the interrupt in uSec
+ *
+ * INPUT:
+ *     unsigned int eth_port_num      Ethernet port number
+ *     unsigned int t_clk        t_clk of the MV-643xx chip in HZ units
+ *     unsigned int delay       Delay in uSeconds
+ *
+ * OUTPUT:
+ *     Interrupt coalescing mechanism value is set in MV-643xx chip.
+ *
+ * RETURN:
+ *     The interrupt coalescing value set in the gigE port.
+ *
+ */
+static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num,
+       unsigned int t_clk, unsigned int delay)
+{
+       unsigned int coal;
+       coal = ((t_clk / 1000000) * delay) / 64;
+       /* Set TX Coalescing mechanism */
+       MV_WRITE(MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num),
+                coal << 4);
+       return coal;
+}
+
+/*
+ * mv64340_eth_open
+ *
+ * This function is called when openning the network device. The function
+ * should initialize all the hardware, initialize cyclic Rx/Tx
+ * descriptors chain and buffers and allocate an IRQ to the network
+ * device.
+ *
+ * Input : a pointer to the network device structure
+ *
+ * Output : zero of success , nonzero if fails.
+ */
+
+static int mv64340_eth_open(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned int port_num = mp->port_num;
+       int err = err;
+
+       spin_lock_irq(&mp->lock);
+
+       err = request_irq(dev->irq, mv64340_eth_int_handler,
+                         SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev);
+
+       if (err) {
+               printk(KERN_ERR "Can not assign IRQ number to MV64340_eth%d\n",
+                      port_num);
+               err = -EAGAIN;
+               goto out;
+       }
+
+       if (mv64340_eth_real_open(dev)) {
+               printk("%s: Error opening interface\n", dev->name);
+               err = -EBUSY;
+               goto out_free;
+       }
+
+       spin_unlock_irq(&mp->lock);
+
+       return 0;
+
+out_free:
+       free_irq(dev->irq, dev);
+
+out:
+       spin_unlock_irq(&mp->lock);
+
+       return err;
+}
+
+/*
+ * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory.
+ *
+ * DESCRIPTION:
+ *       This function prepares a Rx chained list of descriptors and packet 
+ *       buffers in a form of a ring. The routine must be called after port 
+ *       initialization routine and before port start routine. 
+ *       The Ethernet SDMA engine uses CPU bus addresses to access the various 
+ *       devices in the system (i.e. DRAM). This function uses the ethernet 
+ *       struct 'virtual to physical' routine (set by the user) to set the ring 
+ *       with physical addresses.
+ *
+ * INPUT:
+ *     struct mv64340_private   *mp   Ethernet Port Control srtuct. 
+ *      int                    rx_desc_num       Number of Rx descriptors
+ *      int                    rx_buff_size      Size of Rx buffer
+ *      unsigned int    rx_desc_base_addr  Rx descriptors memory area base addr.
+ *      unsigned int    rx_buff_base_addr  Rx buffer memory area base addr.
+ *
+ * OUTPUT:
+ *      The routine updates the Ethernet port control struct with information 
+ *      regarding the Rx descriptors and buffers.
+ *
+ * RETURN:
+ *      false if the given descriptors memory area is not aligned according to
+ *      Ethernet SDMA specifications.
+ *      true otherwise.
+ */
+static int ether_init_rx_desc_ring(struct mv64340_private * mp,
+       unsigned long rx_buff_base_addr)
+{
+       unsigned long buffer_addr = rx_buff_base_addr;
+       volatile struct eth_rx_desc *p_rx_desc;
+       int rx_desc_num = mp->rx_ring_size;
+       unsigned long rx_desc_base_addr = (unsigned long) mp->p_rx_desc_area;
+       int rx_buff_size = 1536;        /* Dummy, will be replaced later */
+       int i;
+
+       p_rx_desc = (struct eth_rx_desc *) rx_desc_base_addr;
+
+       /* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */
+       if (rx_buff_base_addr & 0xf)
+               return 0;
+
+       /* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes  */
+       if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE))
+               return 0;
+
+       /* Rx buffers must be 64-bit aligned.       */
+       if ((rx_buff_base_addr + rx_buff_size) & 0x7)
+               return 0;
+
+       /* initialize the Rx descriptors ring */
+       for (i = 0; i < rx_desc_num; i++) {
+               p_rx_desc[i].buf_size = rx_buff_size;
+               p_rx_desc[i].byte_cnt = 0x0000;
+               p_rx_desc[i].cmd_sts =
+                       ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT;
+               p_rx_desc[i].next_desc_ptr = mp->rx_desc_dma +
+                       ((i + 1) % rx_desc_num) * sizeof(struct eth_rx_desc);
+               p_rx_desc[i].buf_ptr = buffer_addr;
+
+               mp->rx_skb[i] = NULL;
+               buffer_addr += rx_buff_size;
+       }
+
+       /* Save Rx desc pointer to driver struct. */
+       mp->rx_curr_desc_q = 0;
+       mp->rx_used_desc_q = 0;
+
+       mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc);
+
+       mp->port_rx_queue_command |= 1;
+
+       return 1;
+}
+
+/*
+ * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory.
+ *
+ * DESCRIPTION:
+ *       This function prepares a Tx chained list of descriptors and packet 
+ *       buffers in a form of a ring. The routine must be called after port 
+ *       initialization routine and before port start routine. 
+ *       The Ethernet SDMA engine uses CPU bus addresses to access the various 
+ *       devices in the system (i.e. DRAM). This function uses the ethernet 
+ *       struct 'virtual to physical' routine (set by the user) to set the ring 
+ *       with physical addresses.
+ *
+ * INPUT:
+ *     struct mv64340_private   *mp   Ethernet Port Control srtuct. 
+ *      int            tx_desc_num        Number of Tx descriptors
+ *      int            tx_buff_size       Size of Tx buffer
+ *      unsigned int    tx_desc_base_addr  Tx descriptors memory area base addr.
+ *
+ * OUTPUT:
+ *      The routine updates the Ethernet port control struct with information 
+ *      regarding the Tx descriptors and buffers.
+ *
+ * RETURN:
+ *      false if the given descriptors memory area is not aligned according to
+ *      Ethernet SDMA specifications.
+ *      true otherwise.
+ */
+static int ether_init_tx_desc_ring(struct mv64340_private *mp)
+{
+       unsigned long tx_desc_base_addr = (unsigned long) mp->p_tx_desc_area;
+       int tx_desc_num = mp->tx_ring_size;
+       struct eth_tx_desc *p_tx_desc;
+       int i;
+
+       /* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */
+       if (tx_desc_base_addr & 0xf)
+               return 0;
+
+       /* save the first desc pointer to link with the last descriptor */
+       p_tx_desc = (struct eth_tx_desc *) tx_desc_base_addr;
+
+       /* Initialize the Tx descriptors ring */
+       for (i = 0; i < tx_desc_num; i++) {
+               p_tx_desc[i].byte_cnt   = 0x0000;
+               p_tx_desc[i].l4i_chk    = 0x0000;
+               p_tx_desc[i].cmd_sts    = 0x00000000;
+               p_tx_desc[i].next_desc_ptr = mp->tx_desc_dma +
+                       ((i + 1) % tx_desc_num) * sizeof(struct eth_tx_desc);
+               p_tx_desc[i].buf_ptr    = 0x00000000;
+               mp->tx_skb[i]           = NULL;
+       }
+
+       /* Set Tx desc pointer in driver struct. */
+       mp->tx_curr_desc_q = 0;
+       mp->tx_used_desc_q = 0;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        mp->tx_first_desc_q = 0;
+#endif
+       /* Init Tx ring base and size parameters */
+       mp->tx_desc_area_size   = tx_desc_num * sizeof(struct eth_tx_desc);
+
+       /* Add the queue to the list of Tx queues of this port */
+       mp->port_tx_queue_command |= 1;
+
+       return 1;
+}
+
+/* Helper function for mv64340_eth_open */
+static int mv64340_eth_real_open(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned int port_num = mp->port_num;
+       u32 phy_reg_data;
+       unsigned int size;
+
+       /* Stop RX Queues */
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
+                0x0000ff00);
+
+       /* Clear the ethernet port interrupts */
+       MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+       MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+
+       /* Unmask RX buffer and TX end interrupt */
+       MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),
+                INT_CAUSE_UNMASK_ALL);
+
+       /* Unmask phy and link status changes interrupts */
+       MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+                INT_CAUSE_UNMASK_ALL_EXT);
+
+       /* Set the MAC Address */
+       memcpy(mp->port_mac_addr, dev->dev_addr, 6);
+
+       eth_port_init(mp);
+
+       INIT_WORK(&mp->rx_task, (void (*)(void *)) mv64340_eth_rx_task, dev);
+
+       memset(&mp->timeout, 0, sizeof(struct timer_list));
+       mp->timeout.function = mv64340_eth_rx_task_timer_wrapper;
+       mp->timeout.data = (unsigned long) dev;
+
+       mp->rx_task_busy = 0;
+       mp->rx_timer_flag = 0;
+
+       /* Allocate TX ring */
+       mp->tx_ring_skbs = 0;
+       mp->tx_ring_size = MV64340_TX_QUEUE_SIZE;
+       size = mp->tx_ring_size * sizeof(struct eth_tx_desc);
+       mp->tx_desc_area_size = size;
+
+       /* Assumes allocated ring is 16 bytes alligned */
+       mp->p_tx_desc_area = pci_alloc_consistent(NULL, size, &mp->tx_desc_dma);
+       if (!mp->p_tx_desc_area) {
+               printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n",
+                      dev->name, size);
+               return -ENOMEM;
+       }
+       memset((void *) mp->p_tx_desc_area, 0, mp->tx_desc_area_size);
+
+       /* Dummy will be replaced upon real tx */
+       ether_init_tx_desc_ring(mp);
+
+       /* Allocate RX ring */
+       /* Meantime RX Ring are fixed - but must be configurable by user */
+       mp->rx_ring_size = MV64340_RX_QUEUE_SIZE;
+       mp->rx_ring_skbs = 0;
+       size = mp->rx_ring_size * sizeof(struct eth_rx_desc);
+       mp->rx_desc_area_size = size;
+
+       /* Assumes allocated ring is 16 bytes aligned */
+
+       mp->p_rx_desc_area = pci_alloc_consistent(NULL, size, &mp->rx_desc_dma);
+
+       if (!mp->p_rx_desc_area) {
+               printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n",
+                      dev->name, size);
+               printk(KERN_ERR "%s: Freeing previously allocated TX queues...",
+                      dev->name);
+               pci_free_consistent(0, mp->tx_desc_area_size,
+                                   (void *) mp->p_tx_desc_area,
+                                   mp->tx_desc_dma);
+               return -ENOMEM;
+       }
+       memset(mp->p_rx_desc_area, 0, size);
+
+       if (!(ether_init_rx_desc_ring(mp, 0)))
+               panic("%s: Error initializing RX Ring", dev->name);
+
+       mv64340_eth_rx_task(dev);       /* Fill RX ring with skb's */
+
+       eth_port_start(mp);
+
+       /* Interrupt Coalescing */
+
+#ifdef MV64340_COAL
+       mp->rx_int_coal =
+               eth_port_set_rx_coal(port_num, 133000000, MV64340_RX_COAL);
+#endif
+
+       mp->tx_int_coal =
+               eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL);  
+
+       /* Increase the Rx side buffer size */
+
+       MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) |
+                       (MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num))
+                                       & 0xfff1ffff));
+
+       /* Check Link status on phy */
+       eth_port_read_smi_reg(port_num, 1, &phy_reg_data);
+       if (!(phy_reg_data & 0x20))
+               netif_stop_queue(dev);
+       else
+               netif_start_queue(dev);
+
+       return 0;
+}
+
+static void mv64340_eth_free_tx_rings(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned int port_num = mp->port_num;
+       unsigned int curr;
+
+       /* Stop Tx Queues */
+       MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
+                0x0000ff00);
+
+       /* Free TX rings */
+       /* Free outstanding skb's on TX rings */
+       for (curr = 0;
+            (mp->tx_ring_skbs) && (curr < MV64340_TX_QUEUE_SIZE);
+            curr++) {
+               if (mp->tx_skb[curr]) {
+                       dev_kfree_skb(mp->tx_skb[curr]);
+                       mp->tx_ring_skbs--;
+               }
+       }
+       if (mp->tx_ring_skbs != 0)
+               printk("%s: Error on Tx descriptor free - could not free %d"
+                    " descriptors\n", dev->name,
+                    mp->tx_ring_skbs);
+       pci_free_consistent(0, mp->tx_desc_area_size,
+                           (void *) mp->p_tx_desc_area, mp->tx_desc_dma);
+}
+
+static void mv64340_eth_free_rx_rings(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned int port_num = mp->port_num;
+       int curr;
+
+       /* Stop RX Queues */
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
+                0x0000ff00);
+
+       /* Free RX rings */
+       /* Free preallocated skb's on RX rings */
+       for (curr = 0;
+               mp->rx_ring_skbs && (curr < MV64340_RX_QUEUE_SIZE);
+               curr++) {
+               if (mp->rx_skb[curr]) {
+                       dev_kfree_skb(mp->rx_skb[curr]);
+                       mp->rx_ring_skbs--;
+               }
+       }
+
+       if (mp->rx_ring_skbs != 0)
+               printk(KERN_ERR
+                      "%s: Error in freeing Rx Ring. %d skb's still"
+                      " stuck in RX Ring - ignoring them\n", dev->name,
+                      mp->rx_ring_skbs);
+       pci_free_consistent(0, mp->rx_desc_area_size,
+                           (void *) mp->p_rx_desc_area,
+                           mp->rx_desc_dma);
+}
+
+/*
+ * mv64340_eth_stop
+ *
+ * This function is used when closing the network device. 
+ * It updates the hardware, 
+ * release all memory that holds buffers and descriptors and release the IRQ.
+ * Input : a pointer to the device structure
+ * Output : zero if success , nonzero if fails
+ */
+
+/* Helper function for mv64340_eth_stop */
+
+static int mv64340_eth_real_stop(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       unsigned int port_num = mp->port_num;
+
+       netif_stop_queue(dev);
+
+       mv64340_eth_free_tx_rings(dev);
+       mv64340_eth_free_rx_rings(dev);
+
+       eth_port_reset(mp->port_num);
+
+       /* Disable ethernet port interrupts */
+       MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+       MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+
+       /* Mask RX buffer and TX end interrupt */
+       MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 0);
+
+       /* Mask phy and link status changes interrupts */
+       MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0);
+
+       return 0;
+}
+
+static int mv64340_eth_stop(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+
+       spin_lock_irq(&mp->lock);
+
+       mv64340_eth_real_stop(dev);
+
+       free_irq(dev->irq, dev);
+       spin_unlock_irq(&mp->lock);
+
+       return 0;
+}
+
+#ifdef MV64340_NAPI
+static void mv64340_tx(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+        struct pkt_info pkt_info;
+
+       while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) {
+               if (pkt_info.return_info) {
+                       dev_kfree_skb_irq((struct sk_buff *)
+                                                  pkt_info.return_info);
+                       if (skb_shinfo(pkt_info.return_info)->nr_frags) 
+                                 pci_unmap_page(NULL, pkt_info.buf_ptr,
+                                             pkt_info.byte_cnt,
+                                             PCI_DMA_TODEVICE);
+
+                         if (mp->tx_ring_skbs != 1)
+                                  mp->tx_ring_skbs--;
+                } else 
+                       pci_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt,
+                                      PCI_DMA_TODEVICE);
+       }
+
+       if (netif_queue_stopped(dev) &&
+            MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1)
+                       netif_wake_queue(dev);
+}
+
+/*
+ * mv64340_poll
+ *
+ * This function is used in case of NAPI
+ */
+static int mv64340_poll(struct net_device *dev, int *budget)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       int     done = 1, orig_budget, work_done;
+       unsigned int port_num = mp->port_num;
+       unsigned long flags;
+
+#ifdef MV64340_TX_FAST_REFILL
+       if (++mp->tx_clean_threshold > 5) {
+               spin_lock_irqsave(&mp->lock, flags);
+               mv64340_tx(dev);
+               mp->tx_clean_threshold = 0;
+               spin_unlock_irqrestore(&mp->lock, flags);
+       }
+#endif
+
+       if ((u32)(MV_READ(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))                                      != (u32)mp->rx_used_desc_q) {
+               orig_budget = *budget;
+               if (orig_budget > dev->quota)
+                       orig_budget = dev->quota;
+               work_done = mv64340_eth_receive_queue(dev, 0, orig_budget);
+               mp->rx_task.func(dev);
+               *budget -= work_done;
+               dev->quota -= work_done;
+               if (work_done >= orig_budget)
+                       done = 0;
+       }
+
+       if (done) {
+               spin_lock_irqsave(&mp->lock, flags);
+               __netif_rx_complete(dev);
+               MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0);
+                MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0);
+               MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 
+                                               INT_CAUSE_UNMASK_ALL);
+               MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
+                                                INT_CAUSE_UNMASK_ALL_EXT);
+               spin_unlock_irqrestore(&mp->lock, flags);
+       }
+
+       return done ? 0 : 1;
+}
+#endif
+
+/*
+ * mv64340_eth_start_xmit
+ *
+ * This function is queues a packet in the Tx descriptor for 
+ * required port.
+ *
+ * Input : skb - a pointer to socket buffer
+ *         dev - a pointer to the required port
+ *
+ * Output : zero upon success
+ */
+static int mv64340_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+       struct net_device_stats *stats = &mp->stats;
+       ETH_FUNC_RET_STATUS status;
+       unsigned long flags;
+       struct pkt_info pkt_info;
+
+       if (netif_queue_stopped(dev)) {
+               printk(KERN_ERR
+                      "%s: Tried sending packet when interface is stopped\n",
+                      dev->name);
+               return 1;
+       }
+
+       /* This is a hard error, log it. */
+       if ((MV64340_TX_QUEUE_SIZE - mp->tx_ring_skbs) <=
+           (skb_shinfo(skb)->nr_frags + 1)) {
+               netif_stop_queue(dev);
+               printk(KERN_ERR
+                      "%s: Bug in mv64340_eth - Trying to transmit when"
+                      " queue full !\n", dev->name);
+               return 1;
+       }
+
+       /* Paranoid check - this shouldn't happen */
+       if (skb == NULL) {
+               stats->tx_dropped++;
+               return 1;
+       }
+
+       spin_lock_irqsave(&mp->lock, flags);
+
+       /* Update packet info data structure -- DMA owned, first last */
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+       if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) {
+#endif
+               pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT |
+                                  ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC;
+
+               pkt_info.byte_cnt = skb->len;
+               pkt_info.buf_ptr = pci_map_single(0, skb->data, skb->len,
+                                                 PCI_DMA_TODEVICE);
+
+
+               pkt_info.return_info = skb;
+               status = eth_port_send(mp, &pkt_info);
+               if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL))
+                       printk(KERN_ERR "%s: Error on transmitting packet\n",
+                                      dev->name);
+               mp->tx_ring_skbs++;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+       } else {
+               unsigned int    frag;
+               u32             ipheader;
+
+                /* first frag which is skb header */
+                pkt_info.byte_cnt = skb_headlen(skb);
+                pkt_info.buf_ptr = pci_map_single(0, skb->data,
+                                        skb_headlen(skb), PCI_DMA_TODEVICE);
+                pkt_info.return_info = 0;
+                ipheader = skb->nh.iph->ihl << 11;
+                pkt_info.cmd_sts = ETH_TX_FIRST_DESC | 
+                                       ETH_GEN_TCP_UDP_CHECKSUM |
+                                       ETH_GEN_IP_V_4_CHECKSUM |
+                                        ipheader;
+               /* CPU already calculated pseudo header checksum. So, use it */
+                pkt_info.l4i_chk = skb->h.th->check;
+                status = eth_port_send(mp, &pkt_info);
+               if (status != ETH_OK) {
+                       if ((status == ETH_ERROR))
+                               printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name);
+                       if (status == ETH_QUEUE_FULL)
+                               printk("Error on Queue Full \n");
+                       if (status == ETH_QUEUE_LAST_RESOURCE)
+                               printk("Tx resource error \n");
+               }
+
+                /* Check for the remaining frags */
+                for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+                        skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+                        pkt_info.l4i_chk = 0x0000;
+                        pkt_info.cmd_sts = 0x00000000;
+
+                        /* Last Frag enables interrupt and frees the skb */
+                        if (frag == (skb_shinfo(skb)->nr_frags - 1)) {
+                                pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT |
+                                                        ETH_TX_LAST_DESC;
+                                pkt_info.return_info = skb;
+                                mp->tx_ring_skbs++;
+                        }
+                        else {
+                                pkt_info.return_info = 0;
+                        }
+                        pkt_info.byte_cnt = this_frag->size;
+                        if (this_frag->size < 8)
+                                printk("%d : \n", skb_shinfo(skb)->nr_frags);
+
+                        pkt_info.buf_ptr = pci_map_page(NULL, this_frag->page,
+                                        this_frag->page_offset,
+                                        this_frag->size, PCI_DMA_TODEVICE);
+
+                        status = eth_port_send(mp, &pkt_info);
+
+                       if (status != ETH_OK) {
+                               if ((status == ETH_ERROR))
+                                       printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name);
+
+                                        if (status == ETH_QUEUE_LAST_RESOURCE)
+                                       printk("Tx resource error \n");
+
+                               if (status == ETH_QUEUE_FULL)
+                                       printk("Queue is full \n");
+                       }
+                }
+        }
+#endif
+
+       /* Check if TX queue can handle another skb. If not, then
+        * signal higher layers to stop requesting TX
+        */
+       if (MV64340_TX_QUEUE_SIZE <= (mp->tx_ring_skbs + 1))
+               /* 
+                * Stop getting skb's from upper layers.
+                * Getting skb's from upper layers will be enabled again after
+                * packets are released.
+                */
+               netif_stop_queue(dev);
+
+       /* Update statistics and start of transmittion time */
+       stats->tx_bytes += skb->len;
+       stats->tx_packets++;
+       dev->trans_start = jiffies;
+
+       spin_unlock_irqrestore(&mp->lock, flags);
+
+       return 0;               /* success */
+}
+
+/*
+ * mv64340_eth_get_stats
+ *
+ * Returns a pointer to the interface statistics.
+ *
+ * Input : dev - a pointer to the required interface
+ *
+ * Output : a pointer to the interface's statistics
+ */
+
+static struct net_device_stats *mv64340_eth_get_stats(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+
+       return &mp->stats;
+}
+
+/*/
+ * mv64340_eth_init
+ *                                                                    
+ * First function called after registering the network device. 
+ * It's purpose is to initialize the device as an ethernet device, 
+ * fill the structure that was given in registration with pointers
+ * to functions, and setting the MAC address of the interface
+ *
+ * Input : number of port to initialize
+ * Output : -ENONMEM if failed , 0 if success
+ */
+static struct net_device *mv64340_eth_init(int port_num)
+{
+       struct mv64340_private *mp;
+       struct net_device *dev;
+       int err;
+
+       dev = alloc_etherdev(sizeof(struct mv64340_private));
+       if (!dev)
+               return NULL;
+
+       mp = netdev_priv(dev);
+
+       dev->irq = ETH_PORT0_IRQ_NUM + port_num;
+
+       dev->open = mv64340_eth_open;
+       dev->stop = mv64340_eth_stop;
+       dev->hard_start_xmit = mv64340_eth_start_xmit;
+       dev->get_stats = mv64340_eth_get_stats;
+       dev->set_mac_address = mv64340_eth_set_mac_address;
+       dev->set_multicast_list = mv64340_eth_set_rx_mode;
+
+       /* No need to Tx Timeout */
+       dev->tx_timeout = mv64340_eth_tx_timeout;
+#ifdef MV64340_NAPI
+        dev->poll = mv64340_poll;
+        dev->weight = 64;
+#endif
+
+       dev->watchdog_timeo = 2 * HZ;
+       dev->tx_queue_len = MV64340_TX_QUEUE_SIZE;
+       dev->base_addr = 0;
+       dev->change_mtu = mv64340_eth_change_mtu;
+
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+#ifdef MAX_SKB_FRAGS
+#ifndef CONFIG_JAGUAR_DMALOW
+        /*
+         * Zero copy can only work if we use Discovery II memory. Else, we will
+         * have to map the buffers to ISA memory which is only 16 MB
+         */
+        dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM;
+#endif
+#endif
+#endif
+
+       mp->port_num = port_num;
+
+       /* Configure the timeout task */
+        INIT_WORK(&mp->tx_timeout_task,
+                  (void (*)(void *))mv64340_eth_tx_timeout_task, dev);
+
+       spin_lock_init(&mp->lock);
+
+       /* set MAC addresses */
+       memcpy(dev->dev_addr, prom_mac_addr_base, 6);
+       dev->dev_addr[5] += port_num;
+
+       err = register_netdev(dev);
+       if (err)
+               goto out_free_dev;
+
+       printk(KERN_NOTICE "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+               dev->name, port_num,
+               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+       if (dev->features & NETIF_F_SG)
+               printk("Scatter Gather Enabled  ");
+
+       if (dev->features & NETIF_F_IP_CSUM)
+               printk("TX TCP/IP Checksumming Supported  \n");
+
+       printk("RX TCP/UDP Checksum Offload ON, \n");
+       printk("TX and RX Interrupt Coalescing ON \n");
+
+#ifdef MV64340_NAPI
+       printk("RX NAPI Enabled \n");
+#endif
+
+       return dev;
+
+out_free_dev:
+       free_netdev(dev);
+
+       return NULL;
+}
+
+static void mv64340_eth_remove(struct net_device *dev)
+{
+       struct mv64340_private *mp = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       flush_scheduled_work();
+       free_netdev(dev);
+}
+
+static struct net_device *mv64340_dev0;
+static struct net_device *mv64340_dev1;
+static struct net_device *mv64340_dev2;
+
+/*
+ * mv64340_init_module
+ *
+ * Registers the network drivers into the Linux kernel
+ *
+ * Input : N/A
+ *
+ * Output : N/A
+ */
+static int __init mv64340_init_module(void)
+{
+       printk(KERN_NOTICE "MV-643xx 10/100/1000 Ethernet Driver\n");
+
+#ifdef CONFIG_MV643XX_ETH_0
+       mv64340_dev0 = mv64340_eth_init(0);
+       if (!mv64340_dev0) {
+               printk(KERN_ERR
+                      "Error registering MV-64360 ethernet port 0\n");
+       }
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+       mv64340_dev1 = mv64340_eth_init(1);
+       if (!mv64340_dev1) {
+               printk(KERN_ERR
+                      "Error registering MV-64360 ethernet port 1\n");
+       }
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+       mv64340_dev2 = mv64340_eth_init(2);
+       if (!mv64340_dev2) {
+               printk(KERN_ERR
+                      "Error registering MV-64360 ethernet port 2\n");
+       }
+#endif
+       return 0;
+}
+
+/*
+ * mv64340_cleanup_module
+ *
+ * Registers the network drivers into the Linux kernel
+ *
+ * Input : N/A
+ *
+ * Output : N/A
+ */
+static void __exit mv64340_cleanup_module(void)
+{
+       if (mv64340_dev2)
+               mv64340_eth_remove(mv64340_dev2);
+       if (mv64340_dev1)
+               mv64340_eth_remove(mv64340_dev1);
+       if (mv64340_dev0)
+               mv64340_eth_remove(mv64340_dev0);
+}
+
+module_init(mv64340_init_module);
+module_exit(mv64340_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani");
+MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340");
+
+/*
+ *  The second part is the low level driver of the gigE ethernet ports.
+ */
+
+/*
+ * Marvell's Gigabit Ethernet controller low level driver
+ *
+ * DESCRIPTION:
+ *       This file introduce low level API to Marvell's Gigabit Ethernet
+ *             controller. This Gigabit Ethernet Controller driver API controls
+ *             1) Operations (i.e. port init, start, reset etc').
+ *             2) Data flow (i.e. port send, receive etc').
+ *             Each Gigabit Ethernet port is controlled via
+ *              struct mv64340_private.
+ *             This struct includes user configuration information as well as
+ *             driver internal data needed for its operations.
+ *
+ *             Supported Features:  
+ *             - This low level driver is OS independent. Allocating memory for
+ *               the descriptor rings and buffers are not within the scope of
+ *               this driver.
+ *             - The user is free from Rx/Tx queue managing.
+ *             - This low level driver introduce functionality API that enable
+ *               the to operate Marvell's Gigabit Ethernet Controller in a
+ *               convenient way.
+ *             - Simple Gigabit Ethernet port operation API.
+ *             - Simple Gigabit Ethernet port data flow API.
+ *             - Data flow and operation API support per queue functionality.
+ *             - Support cached descriptors for better performance.
+ *             - Enable access to all four DRAM banks and internal SRAM memory
+ *               spaces.
+ *             - PHY access and control API.
+ *             - Port control register configuration API.
+ *             - Full control over Unicast and Multicast MAC configurations.
+ *                                                                
+ *             Operation flow:
+ *
+ *             Initialization phase
+ *             This phase complete the initialization of the the mv64340_private
+ *             struct. 
+ *             User information regarding port configuration has to be set
+ *             prior to calling the port initialization routine.
+ *
+ *             In this phase any port Tx/Rx activity is halted, MIB counters
+ *             are cleared, PHY address is set according to user parameter and
+ *             access to DRAM and internal SRAM memory spaces.
+ *
+ *             Driver ring initialization
+ *             Allocating memory for the descriptor rings and buffers is not 
+ *             within the scope of this driver. Thus, the user is required to
+ *             allocate memory for the descriptors ring and buffers. Those
+ *             memory parameters are used by the Rx and Tx ring initialization
+ *             routines in order to curve the descriptor linked list in a form
+ *             of a ring.
+ *             Note: Pay special attention to alignment issues when using
+ *             cached descriptors/buffers. In this phase the driver store
+ *             information in the mv64340_private struct regarding each queue
+ *             ring.
+ *
+ *             Driver start 
+ *             This phase prepares the Ethernet port for Rx and Tx activity.
+ *             It uses the information stored in the mv64340_private struct to 
+ *             initialize the various port registers.
+ *
+ *             Data flow:
+ *             All packet references to/from the driver are done using
+ *              struct pkt_info.
+ *             This struct is a unified struct used with Rx and Tx operations. 
+ *             This way the user is not required to be familiar with neither
+ *             Tx nor Rx descriptors structures.
+ *             The driver's descriptors rings are management by indexes.
+ *             Those indexes controls the ring resources and used to indicate
+ *             a SW resource error:
+ *             'current' 
+ *             This index points to the current available resource for use. For 
+ *             example in Rx process this index will point to the descriptor  
+ *             that will be passed to the user upon calling the receive routine.
+ *             In Tx process, this index will point to the descriptor
+ *             that will be assigned with the user packet info and transmitted.
+ *             'used'    
+ *             This index points to the descriptor that need to restore its 
+ *             resources. For example in Rx process, using the Rx buffer return
+ *             API will attach the buffer returned in packet info to the
+ *             descriptor pointed by 'used'. In Tx process, using the Tx
+ *             descriptor return will merely return the user packet info with
+ *             the command status of  the transmitted buffer pointed by the
+ *             'used' index. Nevertheless, it is essential to use this routine
+ *             to update the 'used' index.
+ *             'first'
+ *             This index supports Tx Scatter-Gather. It points to the first 
+ *             descriptor of a packet assembled of multiple buffers. For example
+ *             when in middle of Such packet we have a Tx resource error the 
+ *             'curr' index get the value of 'first' to indicate that the ring 
+ *             returned to its state before trying to transmit this packet.
+ *
+ *             Receive operation:
+ *             The eth_port_receive API set the packet information struct,
+ *             passed by the caller, with received information from the 
+ *             'current' SDMA descriptor. 
+ *             It is the user responsibility to return this resource back
+ *             to the Rx descriptor ring to enable the reuse of this source.
+ *             Return Rx resource is done using the eth_rx_return_buff API.
+ *
+ *             Transmit operation:
+ *             The eth_port_send API supports Scatter-Gather which enables to
+ *             send a packet spanned over multiple buffers. This means that
+ *             for each packet info structure given by the user and put into
+ *             the Tx descriptors ring, will be transmitted only if the 'LAST'
+ *             bit will be set in the packet info command status field. This
+ *             API also consider restriction regarding buffer alignments and
+ *             sizes.
+ *             The user must return a Tx resource after ensuring the buffer
+ *             has been transmitted to enable the Tx ring indexes to update.
+ *
+ *             BOARD LAYOUT
+ *             This device is on-board.  No jumper diagram is necessary.
+ *
+ *             EXTERNAL INTERFACE
+ *
+ *       Prior to calling the initialization routine eth_port_init() the user
+ *      must set the following fields under mv64340_private struct:
+ *       port_num             User Ethernet port number.
+ *       port_mac_addr[6]          User defined port MAC address.
+ *       port_config          User port configuration value.
+ *       port_config_extend    User port config extend value.
+ *       port_sdma_config      User port SDMA config value.
+ *       port_serial_control   User port serial control value.
+ *
+ *       This driver introduce a set of default values:
+ *       PORT_CONFIG_VALUE           Default port configuration value
+ *       PORT_CONFIG_EXTEND_VALUE    Default port extend configuration value
+ *       PORT_SDMA_CONFIG_VALUE      Default sdma control value
+ *       PORT_SERIAL_CONTROL_VALUE   Default port serial control value
+ *
+ *             This driver data flow is done using the struct pkt_info which
+ *              is a unified struct for Rx and Tx operations:
+ *
+ *             byte_cnt        Tx/Rx descriptor buffer byte count.
+ *             l4i_chk         CPU provided TCP Checksum. For Tx operation
+ *                              only.
+ *             cmd_sts         Tx/Rx descriptor command status.
+ *             buf_ptr         Tx/Rx descriptor buffer pointer.
+ *             return_info     Tx/Rx user resource return information.
+ */
+
+/* defines */
+/* SDMA command macros */
+#define ETH_ENABLE_TX_QUEUE(eth_port) \
+       MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1)
+
+#define ETH_DISABLE_TX_QUEUE(eth_port) \
+       MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port),      \
+                (1 << 8))
+
+#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port),       \
+                (1 << rx_queue))
+
+#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port),       \
+                (1 << (8 + rx_queue)))
+
+#define LINK_UP_TIMEOUT                100000
+#define PHY_BUSY_TIMEOUT       10000000
+
+/* locals */
+
+/* PHY routines */
+static int ethernet_phy_get(unsigned int eth_port_num);
+
+/* Ethernet Port routines */
+static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble,
+       int option);
+
+/*
+ * eth_port_init - Initialize the Ethernet port driver
+ *
+ * DESCRIPTION:
+ *       This function prepares the ethernet port to start its activity:
+ *       1) Completes the ethernet port driver struct initialization toward port
+ *           start routine.
+ *       2) Resets the device to a quiescent state in case of warm reboot.
+ *       3) Enable SDMA access to all four DRAM banks as well as internal SRAM.
+ *       4) Clean MAC tables. The reset status of those tables is unknown.
+ *       5) Set PHY address. 
+ *       Note: Call this routine prior to eth_port_start routine and after
+ *       setting user values in the user fields of Ethernet port control
+ *       struct.
+ *
+ * INPUT:
+ *       struct mv64340_private *mp   Ethernet port control struct
+ *
+ * OUTPUT:
+ *       See description.
+ *
+ * RETURN:
+ *       None.
+ */
+static void eth_port_init(struct mv64340_private * mp)
+{
+       mp->port_config = PORT_CONFIG_VALUE;
+       mp->port_config_extend = PORT_CONFIG_EXTEND_VALUE;
+#if defined(__BIG_ENDIAN)
+       mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE;
+#elif defined(__LITTLE_ENDIAN)
+       mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE |
+               ETH_BLM_RX_NO_SWAP | ETH_BLM_TX_NO_SWAP;
+#else
+#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be defined!
+#endif
+       mp->port_serial_control = PORT_SERIAL_CONTROL_VALUE;
+
+       mp->port_rx_queue_command = 0;
+       mp->port_tx_queue_command = 0;
+
+       mp->rx_resource_err = 0;
+       mp->tx_resource_err = 0;
+
+       eth_port_reset(mp->port_num);
+
+       eth_port_init_mac_tables(mp->port_num);
+
+       ethernet_phy_reset(mp->port_num);
+}
+
+/*
+ * eth_port_start - Start the Ethernet port activity.
+ *
+ * DESCRIPTION:
+ *       This routine prepares the Ethernet port for Rx and Tx activity:
+ *       1. Initialize Tx and Rx Current Descriptor Pointer for each queue that
+ *          has been initialized a descriptor's ring (using
+ *          ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx)
+ *       2. Initialize and enable the Ethernet configuration port by writing to
+ *          the port's configuration and command registers.
+ *       3. Initialize and enable the SDMA by writing to the SDMA's 
+ *          configuration and command registers.  After completing these steps,
+ *          the ethernet port SDMA can starts to perform Rx and Tx activities.
+ *
+ *       Note: Each Rx and Tx queue descriptor's list must be initialized prior
+ *       to calling this function (use ether_init_tx_desc_ring for Tx queues
+ *       and ether_init_rx_desc_ring for Rx queues).
+ *
+ * INPUT:
+ *       struct mv64340_private        *mp   Ethernet port control struct
+ *
+ * OUTPUT:
+ *       Ethernet port is ready to receive and transmit.
+ *
+ * RETURN:
+ *       false if the port PHY is not up.
+ *       true otherwise.
+ */
+static int eth_port_start(struct mv64340_private *mp)
+{
+       unsigned int eth_port_num = mp->port_num;
+       int tx_curr_desc, rx_curr_desc;
+       unsigned int phy_reg_data;
+
+       /* Assignment of Tx CTRP of given queue */
+       tx_curr_desc = mp->tx_curr_desc_q;
+       MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num),
+                (struct eth_tx_desc *) mp->tx_desc_dma + tx_curr_desc);
+
+       /* Assignment of Rx CRDP of given queue */
+       rx_curr_desc = mp->rx_curr_desc_q;
+       MV_WRITE(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num),
+                (struct eth_rx_desc *) mp->rx_desc_dma + rx_curr_desc);
+
+       /* Add the assigned Ethernet address to the port's address table */
+       eth_port_uc_addr_set(mp->port_num, mp->port_mac_addr);
+
+       /* Assign port configuration and command. */
+       MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num),
+                mp->port_config);
+
+       MV_WRITE(MV64340_ETH_PORT_CONFIG_EXTEND_REG(eth_port_num),
+                mp->port_config_extend);
+
+       MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num),
+                mp->port_serial_control);
+
+       MV_SET_REG_BITS(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num),
+                       ETH_SERIAL_PORT_ENABLE);
+
+       /* Assign port SDMA configuration */
+       MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num),
+                mp->port_sdma_config);
+
+       /* Enable port Rx. */
+       MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port_num),
+                mp->port_rx_queue_command);
+
+       /* Check if link is up */
+       eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data);
+
+       if (!(phy_reg_data & 0x20))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * eth_port_uc_addr_set - This function Set the port Unicast address.
+ *
+ * DESCRIPTION:
+ *             This function Set the port Ethernet MAC address.
+ *
+ * INPUT:
+ *     unsigned int eth_port_num     Port number.
+ *     char *        p_addr            Address to be set 
+ *
+ * OUTPUT:
+ *     Set MAC address low and high registers. also calls eth_port_uc_addr() 
+ *       To set the unicast table with the proper information.
+ *
+ * RETURN:
+ *     N/A.
+ *
+ */
+static void eth_port_uc_addr_set(unsigned int eth_port_num,
+                                unsigned char *p_addr)
+{
+       unsigned int mac_h;
+       unsigned int mac_l;
+
+       mac_l = (p_addr[4] << 8) | (p_addr[5]);
+       mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) |
+           (p_addr[2] << 8) | (p_addr[3] << 0);
+
+       MV_WRITE(MV64340_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
+       MV_WRITE(MV64340_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
+
+       /* Accept frames of this address */
+       eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR);
+
+       return;
+}
+
+/*
+ * eth_port_uc_addr - This function Set the port unicast address table
+ *
+ * DESCRIPTION:
+ *     This function locates the proper entry in the Unicast table for the 
+ *     specified MAC nibble and sets its properties according to function 
+ *     parameters.
+ *
+ * INPUT:
+ *     unsigned int    eth_port_num      Port number.
+ *     unsigned char uc_nibble         Unicast MAC Address last nibble. 
+ *     int                     option      0 = Add, 1 = remove address.
+ *
+ * OUTPUT:
+ *     This function add/removes MAC addresses from the port unicast address
+ *     table. 
+ *
+ * RETURN:
+ *     true is output succeeded.
+ *     false if option parameter is invalid.
+ *
+ */
+static int eth_port_uc_addr(unsigned int eth_port_num,
+       unsigned char uc_nibble, int option)
+{
+       unsigned int unicast_reg;
+       unsigned int tbl_offset;
+       unsigned int reg_offset;
+
+       /* Locate the Unicast table entry */
+       uc_nibble = (0xf & uc_nibble);
+       tbl_offset = (uc_nibble / 4) * 4;       /* Register offset from unicast table base */
+       reg_offset = uc_nibble % 4;     /* Entry offset within the above register */
+
+       switch (option) {
+       case REJECT_MAC_ADDR:
+               /* Clear accepts frame bit at specified unicast DA table entry */
+               unicast_reg = MV_READ((MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
+                                 (eth_port_num) + tbl_offset));
+
+               unicast_reg &= (0x0E << (8 * reg_offset));
+
+               MV_WRITE(
+                        (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
+                         (eth_port_num) + tbl_offset), unicast_reg);
+               break;
+
+       case ACCEPT_MAC_ADDR:
+               /* Set accepts frame bit at unicast DA filter table entry */
+               unicast_reg =
+                   MV_READ(
+                                (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
+                                 (eth_port_num) + tbl_offset));
+
+               unicast_reg |= (0x01 << (8 * reg_offset));
+
+               MV_WRITE(
+                        (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
+                         (eth_port_num) + tbl_offset), unicast_reg);
+
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables
+ *
+ * DESCRIPTION:
+ *       Go through all the DA filter tables (Unicast, Special Multicast &
+ *       Other Multicast) and set each entry to 0.
+ *
+ * INPUT:
+ *     unsigned int    eth_port_num   Ethernet Port number.
+ *
+ * OUTPUT:
+ *       Multicast and Unicast packets are rejected.
+ *
+ * RETURN:
+ *       None.
+ */
+static void eth_port_init_mac_tables(unsigned int eth_port_num)
+{
+       int table_index;
+
+       /* Clear DA filter unicast table (Ex_dFUT) */
+       for (table_index = 0; table_index <= 0xC; table_index += 4)
+               MV_WRITE(
+                        (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE
+                         (eth_port_num) + table_index), 0);
+
+       for (table_index = 0; table_index <= 0xFC; table_index += 4) {
+               /* Clear DA filter special multicast table (Ex_dFSMT) */
+               MV_WRITE(
+                        (MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
+                         (eth_port_num) + table_index), 0);
+               /* Clear DA filter other multicast table (Ex_dFOMT) */
+               MV_WRITE((MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE
+                         (eth_port_num) + table_index), 0);
+       }
+}
+
+/*
+ * eth_clear_mib_counters - Clear all MIB counters
+ *
+ * DESCRIPTION:
+ *       This function clears all MIB counters of a specific ethernet port.
+ *       A read from the MIB counter will reset the counter.
+ *
+ * INPUT:
+ *     unsigned int    eth_port_num   Ethernet Port number.
+ *
+ * OUTPUT:
+ *       After reading all MIB counters, the counters resets.
+ *
+ * RETURN:
+ *       MIB counter value.
+ *
+ */
+static void eth_clear_mib_counters(unsigned int eth_port_num)
+{
+       int i;
+
+       /* Perform dummy reads from MIB counters */
+       for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4)
+               MV_READ(MV64340_ETH_MIB_COUNTERS_BASE(eth_port_num) + i);
+}
+
+
+/*
+ * ethernet_phy_get - Get the ethernet port PHY address.
+ *
+ * DESCRIPTION:
+ *       This routine returns the given ethernet port PHY address.
+ *
+ * INPUT:
+ *             unsigned int   eth_port_num   Ethernet Port number.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       PHY address.
+ *
+ */
+static int ethernet_phy_get(unsigned int eth_port_num)
+{
+       unsigned int reg_data;
+
+       reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG);
+
+       return ((reg_data >> (5 * eth_port_num)) & 0x1f);
+}
+
+/*
+ * ethernet_phy_reset - Reset Ethernet port PHY.
+ *
+ * DESCRIPTION:
+ *       This routine utilize the SMI interface to reset the ethernet port PHY.
+ *       The routine waits until the link is up again or link up is timeout.
+ *
+ * INPUT:
+ *     unsigned int   eth_port_num   Ethernet Port number.
+ *
+ * OUTPUT:
+ *       The ethernet port PHY renew its link.
+ *
+ * RETURN:
+ *       None.
+ *
+ */
+static int ethernet_phy_reset(unsigned int eth_port_num)
+{
+       unsigned int time_out = 50;
+       unsigned int phy_reg_data;
+
+       /* Reset the PHY */
+       eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data);
+       phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */
+       eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data);
+
+       /* Poll on the PHY LINK */
+       do {
+               eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data);
+
+               if (time_out-- == 0)
+                       return 0;
+       } while (!(phy_reg_data & 0x20));
+
+       return 1;
+}
+
+/*
+ * eth_port_reset - Reset Ethernet port
+ *
+ * DESCRIPTION:
+ *     This routine resets the chip by aborting any SDMA engine activity and
+ *      clearing the MIB counters. The Receiver and the Transmit unit are in 
+ *      idle state after this command is performed and the port is disabled.
+ *
+ * INPUT:
+ *     unsigned int   eth_port_num   Ethernet Port number.
+ *
+ * OUTPUT:
+ *       Channel activity is halted.
+ *
+ * RETURN:
+ *       None.
+ *
+ */
+static void eth_port_reset(unsigned int eth_port_num)
+{
+       unsigned int reg_data;
+
+       /* Stop Tx port activity. Check port Tx activity. */
+       reg_data =
+           MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port_num));
+
+       if (reg_data & 0xFF) {
+               /* Issue stop command for active channels only */
+               MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG
+                        (eth_port_num), (reg_data << 8));
+
+               /* Wait for all Tx activity to terminate. */
+               do {
+                       /* Check port cause register that all Tx queues are stopped */
+                       reg_data =
+                           MV_READ
+                           (MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG
+                            (eth_port_num));
+               }
+               while (reg_data & 0xFF);
+       }
+
+       /* Stop Rx port activity. Check port Rx activity. */
+       reg_data =
+           MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG
+                        (eth_port_num));
+
+       if (reg_data & 0xFF) {
+               /* Issue stop command for active channels only */
+               MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG
+                        (eth_port_num), (reg_data << 8));
+
+               /* Wait for all Rx activity to terminate. */
+               do {
+                       /* Check port cause register that all Rx queues are stopped */
+                       reg_data =
+                           MV_READ
+                           (MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG
+                            (eth_port_num));
+               }
+               while (reg_data & 0xFF);
+       }
+
+
+       /* Clear all MIB counters */
+       eth_clear_mib_counters(eth_port_num);
+
+       /* Reset the Enable bit in the Configuration Register */
+       reg_data =
+           MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num));
+       reg_data &= ~ETH_SERIAL_PORT_ENABLE;
+       MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), reg_data);
+
+       return;
+}
+
+/*
+ * ethernet_set_config_reg - Set specified bits in configuration register.
+ *
+ * DESCRIPTION:
+ *       This function sets specified bits in the given ethernet 
+ *       configuration register. 
+ *
+ * INPUT:
+ *     unsigned int   eth_port_num   Ethernet Port number.
+ *      unsigned int    value   32 bit value.
+ *
+ * OUTPUT:
+ *      The set bits in the value parameter are set in the configuration 
+ *      register.
+ *
+ * RETURN:
+ *      None.
+ *
+ */
+static void ethernet_set_config_reg(unsigned int eth_port_num,
+                                   unsigned int value)
+{
+       unsigned int eth_config_reg;
+
+       eth_config_reg =
+           MV_READ(MV64340_ETH_PORT_CONFIG_REG(eth_port_num));
+       eth_config_reg |= value;
+       MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num),
+                eth_config_reg);
+}
+
+/*
+ * ethernet_get_config_reg - Get the port configuration register
+ *
+ * DESCRIPTION:
+ *       This function returns the configuration register value of the given 
+ *       ethernet port.
+ *
+ * INPUT:
+ *     unsigned int   eth_port_num   Ethernet Port number.
+ *
+ * OUTPUT:
+ *       None.
+ *
+ * RETURN:
+ *       Port configuration register value.
+ */
+static unsigned int ethernet_get_config_reg(unsigned int eth_port_num)
+{
+       unsigned int eth_config_reg;
+
+       eth_config_reg = MV_READ(MV64340_ETH_PORT_CONFIG_EXTEND_REG
+                                     (eth_port_num));
+       return eth_config_reg;
+}
+
+
+/*
+ * eth_port_read_smi_reg - Read PHY registers
+ *
+ * DESCRIPTION:
+ *       This routine utilize the SMI interface to interact with the PHY in 
+ *       order to perform PHY register read.
+ *
+ * INPUT:
+ *     unsigned int   eth_port_num   Ethernet Port number.
+ *       unsigned int   phy_reg   PHY register address offset.
+ *       unsigned int   *value   Register value buffer.
+ *
+ * OUTPUT:
+ *       Write the value of a specified PHY register into given buffer.
+ *
+ * RETURN:
+ *       false if the PHY is busy or read data is not in valid state.
+ *       true otherwise.
+ *
+ */
+static int eth_port_read_smi_reg(unsigned int eth_port_num,
+       unsigned int phy_reg, unsigned int *value)
+{
+       int phy_addr = ethernet_phy_get(eth_port_num);
+       unsigned int time_out = PHY_BUSY_TIMEOUT;
+       unsigned int reg_value;
+
+       /* first check that it is not busy */
+       do {
+               reg_value = MV_READ(MV64340_ETH_SMI_REG);
+               if (time_out-- == 0)
+                       return 0;
+       } while (reg_value & ETH_SMI_BUSY);
+
+       /* not busy */
+
+       MV_WRITE(MV64340_ETH_SMI_REG,
+                (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ);
+
+       time_out = PHY_BUSY_TIMEOUT;    /* initialize the time out var again */
+
+       do {
+               reg_value = MV_READ(MV64340_ETH_SMI_REG);
+               if (time_out-- == 0)
+                       return 0;
+       } while (reg_value & ETH_SMI_READ_VALID);
+
+       /* Wait for the data to update in the SMI register */
+       for (time_out = 0; time_out < PHY_BUSY_TIMEOUT; time_out++);
+
+       reg_value = MV_READ(MV64340_ETH_SMI_REG);
+
+       *value = reg_value & 0xffff;
+
+       return 1;
+}
+
+/*
+ * eth_port_write_smi_reg - Write to PHY registers
+ *
+ * DESCRIPTION:
+ *       This routine utilize the SMI interface to interact with the PHY in 
+ *       order to perform writes to PHY registers.
+ *
+ * INPUT:
+ *     unsigned int   eth_port_num   Ethernet Port number.
+ *      unsigned int   phy_reg   PHY register address offset.
+ *      unsigned int    value   Register value.
+ *
+ * OUTPUT:
+ *      Write the given value to the specified PHY register.
+ *
+ * RETURN:
+ *      false if the PHY is busy.
+ *      true otherwise.
+ *
+ */
+static int eth_port_write_smi_reg(unsigned int eth_port_num,
+       unsigned int phy_reg, unsigned int value)
+{
+       unsigned int time_out = PHY_BUSY_TIMEOUT;
+       unsigned int reg_value;
+       int phy_addr;
+
+       phy_addr = ethernet_phy_get(eth_port_num);
+
+       /* first check that it is not busy */
+       do {
+               reg_value = MV_READ(MV64340_ETH_SMI_REG);
+               if (time_out-- == 0)
+                       return 0;
+       } while (reg_value & ETH_SMI_BUSY);
+
+       /* not busy */
+       MV_WRITE(MV64340_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) |
+                ETH_SMI_OPCODE_WRITE | (value & 0xffff));
+
+       return 1;
+}
+
+/*
+ * eth_port_send - Send an Ethernet packet
+ *
+ * DESCRIPTION:
+ *     This routine send a given packet described by p_pktinfo parameter. It 
+ *      supports transmitting of a packet spaned over multiple buffers. The 
+ *      routine updates 'curr' and 'first' indexes according to the packet 
+ *      segment passed to the routine. In case the packet segment is first, 
+ *      the 'first' index is update. In any case, the 'curr' index is updated. 
+ *      If the routine get into Tx resource error it assigns 'curr' index as 
+ *      'first'. This way the function can abort Tx process of multiple 
+ *      descriptors per packet.
+ *
+ * INPUT:
+ *     struct mv64340_private   *mp   Ethernet Port Control srtuct. 
+ *     struct pkt_info        *p_pkt_info       User packet buffer.
+ *
+ * OUTPUT:
+ *     Tx ring 'curr' and 'first' indexes are updated. 
+ *
+ * RETURN:
+ *      ETH_QUEUE_FULL in case of Tx resource error.
+ *     ETH_ERROR in case the routine can not access Tx desc ring.
+ *     ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource.
+ *      ETH_OK otherwise.
+ *
+ */
+#ifdef  MV64340_CHECKSUM_OFFLOAD_TX
+/*
+ * Modified to include the first descriptor pointer in case of SG
+ */
+static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp,
+                                         struct pkt_info * p_pkt_info)
+{
+       int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc;
+       volatile struct eth_tx_desc *current_descriptor;
+       volatile struct eth_tx_desc *first_descriptor;
+       u32 command_status, first_chip_ptr;
+
+       /* Do not process Tx ring in case of Tx ring resource error */
+       if (mp->tx_resource_err)
+               return ETH_QUEUE_FULL;
+
+       /* Get the Tx Desc ring indexes */
+       tx_desc_curr = mp->tx_curr_desc_q;
+       tx_desc_used = mp->tx_used_desc_q;
+
+       current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
+       if (current_descriptor == NULL)
+               return ETH_ERROR;
+
+       tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE;
+       command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
+
+       if (command_status & ETH_TX_FIRST_DESC) {
+               tx_first_desc = tx_desc_curr;
+               mp->tx_first_desc_q = tx_first_desc;
+
+                /* fill first descriptor */
+                first_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
+                first_descriptor->l4i_chk = p_pkt_info->l4i_chk;
+                first_descriptor->cmd_sts = command_status;
+                first_descriptor->byte_cnt = p_pkt_info->byte_cnt;
+                first_descriptor->buf_ptr = p_pkt_info->buf_ptr;
+                first_descriptor->next_desc_ptr = mp->tx_desc_dma +
+                       tx_next_desc * sizeof(struct eth_tx_desc);
+               wmb();
+        } else {
+                tx_first_desc = mp->tx_first_desc_q;
+                first_descriptor = &mp->p_tx_desc_area[tx_first_desc];
+                if (first_descriptor == NULL) {
+                        printk("First desc is NULL !!\n");
+                        return ETH_ERROR;
+                }
+                if (command_status & ETH_TX_LAST_DESC)
+                        current_descriptor->next_desc_ptr = 0x00000000;
+                else {
+                        command_status |= ETH_BUFFER_OWNED_BY_DMA;
+                        current_descriptor->next_desc_ptr = mp->tx_desc_dma +
+                               tx_next_desc * sizeof(struct eth_tx_desc);
+                }
+        }
+
+        if (p_pkt_info->byte_cnt < 8) {
+                printk(" < 8 problem \n");
+                return ETH_ERROR;
+        }
+
+        current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
+        current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
+        current_descriptor->l4i_chk = p_pkt_info->l4i_chk;
+        current_descriptor->cmd_sts = command_status;
+
+        mp->tx_skb[tx_desc_curr] = (struct sk_buff*) p_pkt_info->return_info;
+
+        wmb();
+
+        /* Set last desc with DMA ownership and interrupt enable. */
+        if (command_status & ETH_TX_LAST_DESC) {
+                current_descriptor->cmd_sts = command_status |
+                                        ETH_TX_ENABLE_INTERRUPT |
+                                        ETH_BUFFER_OWNED_BY_DMA;
+
+               if (!(command_status & ETH_TX_FIRST_DESC))
+                       first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA;
+               wmb();
+
+               first_chip_ptr = MV_READ(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(mp->port_num));
+
+               /* Apply send command */
+               if (first_chip_ptr == 0x00000000)
+                       MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(mp->port_num), (struct eth_tx_desc *) mp->tx_desc_dma + tx_first_desc);
+
+                ETH_ENABLE_TX_QUEUE(mp->port_num);
+
+               /*
+                * Finish Tx packet. Update first desc in case of Tx resource
+                * error */
+                tx_first_desc = tx_next_desc;
+                mp->tx_first_desc_q = tx_first_desc;
+       } else {
+               if (! (command_status & ETH_TX_FIRST_DESC) ) {
+                       current_descriptor->cmd_sts = command_status;
+                       wmb();
+               }
+       }
+
+        /* Check for ring index overlap in the Tx desc ring */
+        if (tx_next_desc == tx_desc_used) {
+                mp->tx_resource_err = 1;
+                mp->tx_curr_desc_q = tx_first_desc;
+
+                return ETH_QUEUE_LAST_RESOURCE;
+       }
+
+        mp->tx_curr_desc_q = tx_next_desc;
+        wmb();
+
+        return ETH_OK;
+}
+#else
+static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp,
+                                        struct pkt_info * p_pkt_info)
+{
+       int tx_desc_curr;
+       int tx_desc_used;
+       volatile struct eth_tx_desc* current_descriptor;
+       unsigned int command_status;
+
+       /* Do not process Tx ring in case of Tx ring resource error */
+       if (mp->tx_resource_err)
+               return ETH_QUEUE_FULL;
+
+       /* Get the Tx Desc ring indexes */
+       tx_desc_curr = mp->tx_curr_desc_q;
+       tx_desc_used = mp->tx_used_desc_q;
+       current_descriptor = &mp->p_tx_desc_area[tx_desc_curr];
+
+       if (current_descriptor == NULL)
+               return ETH_ERROR;
+
+       command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC;
+
+/* XXX Is this for real ?!?!? */
+       /* Buffers with a payload smaller than 8 bytes must be aligned to a
+        * 64-bit boundary. We use the memory allocated for Tx descriptor.
+        * This memory is located in TX_BUF_OFFSET_IN_DESC offset within the
+        * Tx descriptor. */
+       if (p_pkt_info->byte_cnt <= 8) {
+               printk(KERN_ERR
+                      "You have failed in the < 8 bytes errata - fixme\n");
+               return ETH_ERROR;
+       }
+       current_descriptor->buf_ptr = p_pkt_info->buf_ptr;
+       current_descriptor->byte_cnt = p_pkt_info->byte_cnt;
+       mp->tx_skb[tx_desc_curr] = (struct sk_buff *) p_pkt_info->return_info;
+
+       mb();
+
+       /* Set last desc with DMA ownership and interrupt enable. */
+       current_descriptor->cmd_sts = command_status |
+                       ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT;
+
+       /* Apply send command */
+       ETH_ENABLE_TX_QUEUE(mp->port_num);
+
+       /* Finish Tx packet. Update first desc in case of Tx resource error */
+       tx_desc_curr = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE;
+
+       /* Update the current descriptor */
+       mp->tx_curr_desc_q = tx_desc_curr;
+
+       /* Check for ring index overlap in the Tx desc ring */
+       if (tx_desc_curr == tx_desc_used) {
+               mp->tx_resource_err = 1;
+               return ETH_QUEUE_LAST_RESOURCE;
+       }
+
+       return ETH_OK;
+}
+#endif
+
+/*
+ * eth_tx_return_desc - Free all used Tx descriptors
+ *
+ * DESCRIPTION:
+ *     This routine returns the transmitted packet information to the caller.
+ *      It uses the 'first' index to support Tx desc return in case a transmit 
+ *      of a packet spanned over multiple buffer still in process.
+ *      In case the Tx queue was in "resource error" condition, where there are 
+ *      no available Tx resources, the function resets the resource error flag.
+ *
+ * INPUT:
+ *     struct mv64340_private   *mp   Ethernet Port Control srtuct. 
+ *     struct pkt_info        *p_pkt_info       User packet buffer.
+ *
+ * OUTPUT:
+ *     Tx ring 'first' and 'used' indexes are updated. 
+ *
+ * RETURN:
+ *     ETH_ERROR in case the routine can not access Tx desc ring.
+ *      ETH_RETRY in case there is transmission in process.
+ *     ETH_END_OF_JOB if the routine has nothing to release.
+ *      ETH_OK otherwise.
+ *
+ */
+static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private * mp,
+                                             struct pkt_info * p_pkt_info)
+{
+       int tx_desc_used, tx_desc_curr;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        int tx_first_desc;
+#endif
+       volatile struct eth_tx_desc *p_tx_desc_used;
+       unsigned int command_status;
+
+       /* Get the Tx Desc ring indexes */
+       tx_desc_curr = mp->tx_curr_desc_q;
+       tx_desc_used = mp->tx_used_desc_q;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        tx_first_desc = mp->tx_first_desc_q;
+#endif
+       p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used];
+
+       /* XXX Sanity check */
+       if (p_tx_desc_used == NULL)
+               return ETH_ERROR;
+
+       command_status = p_tx_desc_used->cmd_sts;
+
+       /* Still transmitting... */
+#ifndef MV64340_CHECKSUM_OFFLOAD_TX
+       if (command_status & (ETH_BUFFER_OWNED_BY_DMA))
+               return ETH_RETRY;
+#endif
+       /* Stop release. About to overlap the current available Tx descriptor */
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+       if (tx_desc_used == tx_first_desc && !mp->tx_resource_err)
+               return ETH_END_OF_JOB;
+#else
+       if (tx_desc_used == tx_desc_curr && !mp->tx_resource_err)
+               return ETH_END_OF_JOB;
+#endif
+
+       /* Pass the packet information to the caller */
+       p_pkt_info->cmd_sts = command_status;
+       p_pkt_info->return_info = mp->tx_skb[tx_desc_used];
+       mp->tx_skb[tx_desc_used] = NULL;
+
+       /* Update the next descriptor to release. */
+       mp->tx_used_desc_q = (tx_desc_used + 1) % MV64340_TX_QUEUE_SIZE;
+
+       /* Any Tx return cancels the Tx resource error status */
+       mp->tx_resource_err = 0;
+
+       return ETH_OK;
+}
+
+/*
+ * eth_port_receive - Get received information from Rx ring.
+ *
+ * DESCRIPTION:
+ *     This routine returns the received data to the caller. There is no 
+ *     data copying during routine operation. All information is returned 
+ *     using pointer to packet information struct passed from the caller. 
+ *      If the routine exhausts        Rx ring resources then the resource error flag 
+ *      is set.  
+ *
+ * INPUT:
+ *     struct mv64340_private   *mp   Ethernet Port Control srtuct. 
+ *     struct pkt_info        *p_pkt_info       User packet buffer.
+ *
+ * OUTPUT:
+ *     Rx ring current and used indexes are updated. 
+ *
+ * RETURN:
+ *     ETH_ERROR in case the routine can not access Rx desc ring.
+ *     ETH_QUEUE_FULL if Rx ring resources are exhausted.
+ *     ETH_END_OF_JOB if there is no received data.
+ *      ETH_OK otherwise.
+ */
+static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private * mp,
+                                           struct pkt_info * p_pkt_info)
+{
+       int rx_next_curr_desc, rx_curr_desc, rx_used_desc;
+       volatile struct eth_rx_desc * p_rx_desc;
+       unsigned int command_status;
+
+       /* Do not process Rx ring in case of Rx ring resource error */
+       if (mp->rx_resource_err)
+               return ETH_QUEUE_FULL;
+
+       /* Get the Rx Desc ring 'curr and 'used' indexes */
+       rx_curr_desc = mp->rx_curr_desc_q;
+       rx_used_desc = mp->rx_used_desc_q;
+
+       p_rx_desc = &mp->p_rx_desc_area[rx_curr_desc];
+
+       /* The following parameters are used to save readings from memory */
+       command_status = p_rx_desc->cmd_sts;
+
+       /* Nothing to receive... */
+       if (command_status & (ETH_BUFFER_OWNED_BY_DMA))
+               return ETH_END_OF_JOB;
+
+       p_pkt_info->byte_cnt = (p_rx_desc->byte_cnt) - RX_BUF_OFFSET;
+       p_pkt_info->cmd_sts = command_status;
+       p_pkt_info->buf_ptr = (p_rx_desc->buf_ptr) + RX_BUF_OFFSET;
+       p_pkt_info->return_info = mp->rx_skb[rx_curr_desc];
+       p_pkt_info->l4i_chk = p_rx_desc->buf_size;
+
+       /* Clean the return info field to indicate that the packet has been */
+       /* moved to the upper layers                                        */
+       mp->rx_skb[rx_curr_desc] = NULL;
+
+       /* Update current index in data structure */
+       rx_next_curr_desc = (rx_curr_desc + 1) % MV64340_RX_QUEUE_SIZE;
+       mp->rx_curr_desc_q = rx_next_curr_desc;
+
+       /* Rx descriptors exhausted. Set the Rx ring resource error flag */
+       if (rx_next_curr_desc == rx_used_desc)
+               mp->rx_resource_err = 1;
+
+       mb();
+       return ETH_OK;
+}
+
+/*
+ * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring.
+ *
+ * DESCRIPTION:
+ *     This routine returns a Rx buffer back to the Rx ring. It retrieves the 
+ *      next 'used' descriptor and attached the returned buffer to it.
+ *      In case the Rx ring was in "resource error" condition, where there are 
+ *      no available Rx resources, the function resets the resource error flag.
+ *
+ * INPUT:
+ *     struct mv64340_private *mp   Ethernet Port Control srtuct. 
+ *      struct pkt_info        *p_pkt_info   Information on the returned buffer.
+ *
+ * OUTPUT:
+ *     New available Rx resource in Rx descriptor ring.
+ *
+ * RETURN:
+ *     ETH_ERROR in case the routine can not access Rx desc ring.
+ *      ETH_OK otherwise.
+ */
+static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private * mp,
+       struct pkt_info * p_pkt_info)
+{
+       int used_rx_desc;       /* Where to return Rx resource */
+       volatile struct eth_rx_desc* p_used_rx_desc;
+
+       /* Get 'used' Rx descriptor */
+       used_rx_desc = mp->rx_used_desc_q;
+       p_used_rx_desc = &mp->p_rx_desc_area[used_rx_desc];
+
+       p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr;
+       p_used_rx_desc->buf_size = p_pkt_info->byte_cnt;
+       mp->rx_skb[used_rx_desc] = p_pkt_info->return_info;
+
+       /* Flush the write pipe */
+       mb();
+
+       /* Return the descriptor to DMA ownership */
+       p_used_rx_desc->cmd_sts =
+               ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT;
+
+       /* Flush descriptor and CPU pipe */
+       mb();
+
+       /* Move the used descriptor pointer to the next descriptor */
+       mp->rx_used_desc_q = (used_rx_desc + 1) % MV64340_RX_QUEUE_SIZE;
+
+       /* Any Rx return cancels the Rx resource error status */
+       mp->rx_resource_err = 0;
+
+       return ETH_OK;
+}
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
new file mode 100644 (file)
index 0000000..46a057d
--- /dev/null
@@ -0,0 +1,601 @@
+#ifndef __MV64340_ETH_H__
+#define __MV64340_ETH_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include <linux/mv643xx.h>
+
+#define        BIT0    0x00000001
+#define        BIT1    0x00000002
+#define        BIT2    0x00000004
+#define        BIT3    0x00000008
+#define        BIT4    0x00000010
+#define        BIT5    0x00000020
+#define        BIT6    0x00000040
+#define        BIT7    0x00000080
+#define        BIT8    0x00000100
+#define        BIT9    0x00000200
+#define        BIT10   0x00000400
+#define        BIT11   0x00000800
+#define        BIT12   0x00001000
+#define        BIT13   0x00002000
+#define        BIT14   0x00004000
+#define        BIT15   0x00008000
+#define        BIT16   0x00010000
+#define        BIT17   0x00020000
+#define        BIT18   0x00040000
+#define        BIT19   0x00080000
+#define        BIT20   0x00100000
+#define        BIT21   0x00200000
+#define        BIT22   0x00400000
+#define        BIT23   0x00800000
+#define        BIT24   0x01000000
+#define        BIT25   0x02000000
+#define        BIT26   0x04000000
+#define        BIT27   0x08000000
+#define        BIT28   0x10000000
+#define        BIT29   0x20000000
+#define        BIT30   0x40000000
+#define        BIT31   0x80000000
+
+/*
+ *  The first part is the high level driver of the gigE ethernet ports.
+ */
+
+#define ETH_PORT0_IRQ_NUM 48                   /* main high register, bit0 */
+#define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1  /* main high register, bit1 */
+#define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2  /* main high register, bit1 */
+
+/* Checksum offload for Tx works */
+#define  MV64340_CHECKSUM_OFFLOAD_TX
+#define         MV64340_NAPI
+#define         MV64340_TX_FAST_REFILL
+#undef  MV64340_COAL
+
+/* 
+ * Number of RX / TX descriptors on RX / TX rings.
+ * Note that allocating RX descriptors is done by allocating the RX
+ * ring AND a preallocated RX buffers (skb's) for each descriptor.
+ * The TX descriptors only allocates the TX descriptors ring,
+ * with no pre allocated TX buffers (skb's are allocated by higher layers.
+ */
+
+/* Default TX ring size is 1000 descriptors */
+#define MV64340_TX_QUEUE_SIZE 1000
+
+/* Default RX ring size is 400 descriptors */
+#define MV64340_RX_QUEUE_SIZE 400
+
+#define MV64340_TX_COAL 100
+#ifdef MV64340_COAL
+#define MV64340_RX_COAL 100
+#endif
+
+
+/*
+ * The second part is the low level driver of the gigE ethernet ports.   *
+ */
+
+
+/*
+ * Header File for : MV-643xx network interface header 
+ *
+ * DESCRIPTION:
+ *       This header file contains macros typedefs and function declaration for
+ *       the Marvell Gig Bit Ethernet Controller. 
+ *
+ * DEPENDENCIES:
+ *       None.
+ *
+ */
+
+/* Default port configuration value */
+#define PORT_CONFIG_VALUE                       \
+             ETH_UNICAST_NORMAL_MODE           |   \
+             ETH_DEFAULT_RX_QUEUE_0            |   \
+             ETH_DEFAULT_RX_ARP_QUEUE_0                |   \
+             ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP   |   \
+             ETH_RECEIVE_BC_IF_IP              |   \
+             ETH_RECEIVE_BC_IF_ARP             |   \
+             ETH_CAPTURE_TCP_FRAMES_DIS                |   \
+             ETH_CAPTURE_UDP_FRAMES_DIS                |   \
+             ETH_DEFAULT_RX_TCP_QUEUE_0                |   \
+             ETH_DEFAULT_RX_UDP_QUEUE_0                |   \
+             ETH_DEFAULT_RX_BPDU_QUEUE_0
+
+/* Default port extend configuration value */
+#define PORT_CONFIG_EXTEND_VALUE               \
+             ETH_SPAN_BPDU_PACKETS_AS_NORMAL   |   \
+             ETH_PARTITION_DISABLE
+
+
+/* Default sdma control value */
+#define PORT_SDMA_CONFIG_VALUE                 \
+                        ETH_RX_BURST_SIZE_16_64BIT     |       \
+                        GT_ETH_IPG_INT_RX(0)           |       \
+                        ETH_TX_BURST_SIZE_16_64BIT;
+
+#define GT_ETH_IPG_INT_RX(value)                \
+            ((value & 0x3fff) << 8)
+
+/* Default port serial control value */
+#define PORT_SERIAL_CONTROL_VALUE              \
+                       ETH_FORCE_LINK_PASS                     |       \
+                       ETH_ENABLE_AUTO_NEG_FOR_DUPLX           |       \
+                       ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL      |       \
+                       ETH_ADV_SYMMETRIC_FLOW_CTRL             |       \
+                       ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX       |       \
+                       ETH_FORCE_BP_MODE_NO_JAM                |       \
+                       BIT9                                    |       \
+                       ETH_DO_NOT_FORCE_LINK_FAIL              |       \
+                       ETH_RETRANSMIT_16_ATTEMPTS              |       \
+                       ETH_ENABLE_AUTO_NEG_SPEED_GMII          |       \
+                       ETH_DTE_ADV_0                           |       \
+                       ETH_DISABLE_AUTO_NEG_BYPASS             |       \
+                       ETH_AUTO_NEG_NO_CHANGE                  |       \
+                       ETH_MAX_RX_PACKET_9700BYTE              |       \
+                       ETH_CLR_EXT_LOOPBACK                    |       \
+                       ETH_SET_FULL_DUPLEX_MODE                |       \
+                       ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+#define RX_BUFFER_MAX_SIZE  0x4000000
+#define TX_BUFFER_MAX_SIZE  0x4000000
+
+/* MAC accepet/reject macros */
+#define ACCEPT_MAC_ADDR            0
+#define REJECT_MAC_ADDR            1
+
+/* Buffer offset from buffer pointer */
+#define RX_BUF_OFFSET                          0x2
+
+/* Gigabit Ethernet Unit Global Registers */
+
+/* MIB Counters register definitions */
+#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW   0x0
+#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH  0x4
+#define ETH_MIB_BAD_OCTETS_RECEIVED        0x8
+#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR  0xc
+#define ETH_MIB_GOOD_FRAMES_RECEIVED       0x10
+#define ETH_MIB_BAD_FRAMES_RECEIVED        0x14
+#define ETH_MIB_BROADCAST_FRAMES_RECEIVED  0x18
+#define ETH_MIB_MULTICAST_FRAMES_RECEIVED  0x1c
+#define ETH_MIB_FRAMES_64_OCTETS           0x20
+#define ETH_MIB_FRAMES_65_TO_127_OCTETS    0x24
+#define ETH_MIB_FRAMES_128_TO_255_OCTETS   0x28
+#define ETH_MIB_FRAMES_256_TO_511_OCTETS   0x2c
+#define ETH_MIB_FRAMES_512_TO_1023_OCTETS  0x30
+#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS  0x34
+#define ETH_MIB_GOOD_OCTETS_SENT_LOW       0x38
+#define ETH_MIB_GOOD_OCTETS_SENT_HIGH      0x3c
+#define ETH_MIB_GOOD_FRAMES_SENT           0x40
+#define ETH_MIB_EXCESSIVE_COLLISION        0x44
+#define ETH_MIB_MULTICAST_FRAMES_SENT      0x48
+#define ETH_MIB_BROADCAST_FRAMES_SENT      0x4c
+#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50
+#define ETH_MIB_FC_SENT                    0x54
+#define ETH_MIB_GOOD_FC_RECEIVED           0x58
+#define ETH_MIB_BAD_FC_RECEIVED            0x5c
+#define ETH_MIB_UNDERSIZE_RECEIVED         0x60
+#define ETH_MIB_FRAGMENTS_RECEIVED         0x64
+#define ETH_MIB_OVERSIZE_RECEIVED          0x68
+#define ETH_MIB_JABBER_RECEIVED            0x6c
+#define ETH_MIB_MAC_RECEIVE_ERROR          0x70
+#define ETH_MIB_BAD_CRC_EVENT              0x74
+#define ETH_MIB_COLLISION                  0x78
+#define ETH_MIB_LATE_COLLISION             0x7c
+
+/* Port serial status reg (PSR) */
+#define ETH_INTERFACE_GMII_MII                          0
+#define ETH_INTERFACE_PCM                               BIT0
+#define ETH_LINK_IS_DOWN                                0
+#define ETH_LINK_IS_UP                                  BIT1
+#define ETH_PORT_AT_HALF_DUPLEX                         0
+#define ETH_PORT_AT_FULL_DUPLEX                         BIT2
+#define ETH_RX_FLOW_CTRL_DISABLED                       0
+#define ETH_RX_FLOW_CTRL_ENBALED                        BIT3
+#define ETH_GMII_SPEED_100_10                           0
+#define ETH_GMII_SPEED_1000                             BIT4
+#define ETH_MII_SPEED_10                                0
+#define ETH_MII_SPEED_100                               BIT5
+#define ETH_NO_TX                                       0
+#define ETH_TX_IN_PROGRESS                              BIT7
+#define ETH_BYPASS_NO_ACTIVE                            0
+#define ETH_BYPASS_ACTIVE                               BIT8
+#define ETH_PORT_NOT_AT_PARTITION_STATE                 0
+#define ETH_PORT_AT_PARTITION_STATE                     BIT9
+#define ETH_PORT_TX_FIFO_NOT_EMPTY                      0
+#define ETH_PORT_TX_FIFO_EMPTY                          BIT10
+
+
+/* These macros describes the Port configuration reg (Px_cR) bits */
+#define ETH_UNICAST_NORMAL_MODE                         0
+#define ETH_UNICAST_PROMISCUOUS_MODE                    BIT0
+#define ETH_DEFAULT_RX_QUEUE_0                          0
+#define ETH_DEFAULT_RX_QUEUE_1                          BIT1
+#define ETH_DEFAULT_RX_QUEUE_2                          BIT2
+#define ETH_DEFAULT_RX_QUEUE_3                          (BIT2 | BIT1)
+#define ETH_DEFAULT_RX_QUEUE_4                          BIT3
+#define ETH_DEFAULT_RX_QUEUE_5                          (BIT3 | BIT1)
+#define ETH_DEFAULT_RX_QUEUE_6                          (BIT3 | BIT2)
+#define ETH_DEFAULT_RX_QUEUE_7                          (BIT3 | BIT2 | BIT1)
+#define ETH_DEFAULT_RX_ARP_QUEUE_0                      0
+#define ETH_DEFAULT_RX_ARP_QUEUE_1                      BIT4
+#define ETH_DEFAULT_RX_ARP_QUEUE_2                      BIT5
+#define ETH_DEFAULT_RX_ARP_QUEUE_3                      (BIT5 | BIT4)
+#define ETH_DEFAULT_RX_ARP_QUEUE_4                      BIT6
+#define ETH_DEFAULT_RX_ARP_QUEUE_5                      (BIT6 | BIT4)
+#define ETH_DEFAULT_RX_ARP_QUEUE_6                      (BIT6 | BIT5)
+#define ETH_DEFAULT_RX_ARP_QUEUE_7                      (BIT6 | BIT5 | BIT4)
+#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP                 0
+#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP                  BIT7
+#define ETH_RECEIVE_BC_IF_IP                            0
+#define ETH_REJECT_BC_IF_IP                             BIT8
+#define ETH_RECEIVE_BC_IF_ARP                           0
+#define ETH_REJECT_BC_IF_ARP                            BIT9
+#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY               BIT12
+#define ETH_CAPTURE_TCP_FRAMES_DIS                      0
+#define ETH_CAPTURE_TCP_FRAMES_EN                       BIT14
+#define ETH_CAPTURE_UDP_FRAMES_DIS                      0
+#define ETH_CAPTURE_UDP_FRAMES_EN                       BIT15
+#define ETH_DEFAULT_RX_TCP_QUEUE_0                      0
+#define ETH_DEFAULT_RX_TCP_QUEUE_1                      BIT16
+#define ETH_DEFAULT_RX_TCP_QUEUE_2                      BIT17
+#define ETH_DEFAULT_RX_TCP_QUEUE_3                      (BIT17 | BIT16)
+#define ETH_DEFAULT_RX_TCP_QUEUE_4                      BIT18
+#define ETH_DEFAULT_RX_TCP_QUEUE_5                      (BIT18 | BIT16)
+#define ETH_DEFAULT_RX_TCP_QUEUE_6                      (BIT18 | BIT17)
+#define ETH_DEFAULT_RX_TCP_QUEUE_7                      (BIT18 | BIT17 | BIT16)
+#define ETH_DEFAULT_RX_UDP_QUEUE_0                      0
+#define ETH_DEFAULT_RX_UDP_QUEUE_1                      BIT19
+#define ETH_DEFAULT_RX_UDP_QUEUE_2                      BIT20
+#define ETH_DEFAULT_RX_UDP_QUEUE_3                      (BIT20 | BIT19)
+#define ETH_DEFAULT_RX_UDP_QUEUE_4                      (BIT21
+#define ETH_DEFAULT_RX_UDP_QUEUE_5                      (BIT21 | BIT19)
+#define ETH_DEFAULT_RX_UDP_QUEUE_6                      (BIT21 | BIT20)
+#define ETH_DEFAULT_RX_UDP_QUEUE_7                      (BIT21 | BIT20 | BIT19)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_0                      0
+#define ETH_DEFAULT_RX_BPDU_QUEUE_1                     BIT22
+#define ETH_DEFAULT_RX_BPDU_QUEUE_2                     BIT23
+#define ETH_DEFAULT_RX_BPDU_QUEUE_3                     (BIT23 | BIT22)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_4                     BIT24
+#define ETH_DEFAULT_RX_BPDU_QUEUE_5                     (BIT24 | BIT22)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_6                     (BIT24 | BIT23)
+#define ETH_DEFAULT_RX_BPDU_QUEUE_7                     (BIT24 | BIT23 | BIT22)
+
+
+/* These macros describes the Port configuration extend reg (Px_cXR) bits*/
+#define ETH_CLASSIFY_EN                                 BIT0
+#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL                 0
+#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7             BIT1
+#define ETH_PARTITION_DISABLE                           0
+#define ETH_PARTITION_ENABLE                            BIT2
+
+
+/* Tx/Rx queue command reg (RQCR/TQCR)*/
+#define ETH_QUEUE_0_ENABLE                              BIT0
+#define ETH_QUEUE_1_ENABLE                              BIT1
+#define ETH_QUEUE_2_ENABLE                              BIT2
+#define ETH_QUEUE_3_ENABLE                              BIT3
+#define ETH_QUEUE_4_ENABLE                              BIT4
+#define ETH_QUEUE_5_ENABLE                              BIT5
+#define ETH_QUEUE_6_ENABLE                              BIT6
+#define ETH_QUEUE_7_ENABLE                              BIT7
+#define ETH_QUEUE_0_DISABLE                             BIT8
+#define ETH_QUEUE_1_DISABLE                             BIT9
+#define ETH_QUEUE_2_DISABLE                             BIT10
+#define ETH_QUEUE_3_DISABLE                             BIT11
+#define ETH_QUEUE_4_DISABLE                             BIT12
+#define ETH_QUEUE_5_DISABLE                             BIT13
+#define ETH_QUEUE_6_DISABLE                             BIT14
+#define ETH_QUEUE_7_DISABLE                             BIT15
+
+
+/* These macros describes the Port Sdma configuration reg (SDCR) bits */
+#define ETH_RIFB                                        BIT0
+#define ETH_RX_BURST_SIZE_1_64BIT                       0
+#define ETH_RX_BURST_SIZE_2_64BIT                       BIT1
+#define ETH_RX_BURST_SIZE_4_64BIT                       BIT2
+#define ETH_RX_BURST_SIZE_8_64BIT                       (BIT2 | BIT1)
+#define ETH_RX_BURST_SIZE_16_64BIT                      BIT3
+#define ETH_BLM_RX_NO_SWAP                              BIT4
+#define ETH_BLM_RX_BYTE_SWAP                            0
+#define ETH_BLM_TX_NO_SWAP                              BIT5
+#define ETH_BLM_TX_BYTE_SWAP                            0
+#define ETH_DESCRIPTORS_BYTE_SWAP                       BIT6
+#define ETH_DESCRIPTORS_NO_SWAP                         0
+#define ETH_TX_BURST_SIZE_1_64BIT                       0
+#define ETH_TX_BURST_SIZE_2_64BIT                       BIT22
+#define ETH_TX_BURST_SIZE_4_64BIT                       BIT23
+#define ETH_TX_BURST_SIZE_8_64BIT                       (BIT23 | BIT22)
+#define ETH_TX_BURST_SIZE_16_64BIT                      BIT24
+
+
+
+/* These macros describes the Port serial control reg (PSCR) bits */
+#define ETH_SERIAL_PORT_DISABLE                         0
+#define ETH_SERIAL_PORT_ENABLE                          BIT0
+#define ETH_FORCE_LINK_PASS                             BIT1
+#define ETH_DO_NOT_FORCE_LINK_PASS                      0
+#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX                   0
+#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX                  BIT2
+#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL               0
+#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL              BIT3
+#define ETH_ADV_NO_FLOW_CTRL                            0
+#define ETH_ADV_SYMMETRIC_FLOW_CTRL                     BIT4
+#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX               0
+#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS                  BIT5
+#define ETH_FORCE_BP_MODE_NO_JAM                        0
+#define ETH_FORCE_BP_MODE_JAM_TX                        BIT7
+#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR              BIT8
+#define ETH_FORCE_LINK_FAIL                             0
+#define ETH_DO_NOT_FORCE_LINK_FAIL                      BIT10
+#define ETH_RETRANSMIT_16_ATTEMPTS                      0
+#define ETH_RETRANSMIT_FOREVER                          BIT11
+#define ETH_DISABLE_AUTO_NEG_SPEED_GMII                 BIT13
+#define ETH_ENABLE_AUTO_NEG_SPEED_GMII                  0
+#define ETH_DTE_ADV_0                                   0
+#define ETH_DTE_ADV_1                                   BIT14
+#define ETH_DISABLE_AUTO_NEG_BYPASS                     0
+#define ETH_ENABLE_AUTO_NEG_BYPASS                      BIT15
+#define ETH_AUTO_NEG_NO_CHANGE                          0
+#define ETH_RESTART_AUTO_NEG                            BIT16
+#define ETH_MAX_RX_PACKET_1518BYTE                      0
+#define ETH_MAX_RX_PACKET_1522BYTE                      BIT17
+#define ETH_MAX_RX_PACKET_1552BYTE                      BIT18
+#define ETH_MAX_RX_PACKET_9022BYTE                      (BIT18 | BIT17)
+#define ETH_MAX_RX_PACKET_9192BYTE                      BIT19
+#define ETH_MAX_RX_PACKET_9700BYTE                      (BIT19 | BIT17)
+#define ETH_SET_EXT_LOOPBACK                            BIT20
+#define ETH_CLR_EXT_LOOPBACK                            0
+#define ETH_SET_FULL_DUPLEX_MODE                        BIT21
+#define ETH_SET_HALF_DUPLEX_MODE                        0
+#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX       BIT22
+#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX      0
+#define ETH_SET_GMII_SPEED_TO_10_100                    0
+#define ETH_SET_GMII_SPEED_TO_1000                      BIT23
+#define ETH_SET_MII_SPEED_TO_10                         0
+#define ETH_SET_MII_SPEED_TO_100                        BIT24
+
+
+/* SMI reg */
+#define ETH_SMI_BUSY           BIT28   /* 0 - Write, 1 - Read          */
+#define ETH_SMI_READ_VALID     BIT27   /* 0 - Write, 1 - Read          */
+#define ETH_SMI_OPCODE_WRITE   0       /* Completion of Read operation */
+#define ETH_SMI_OPCODE_READ    BIT26   /* Operation is in progress             */
+
+/* SDMA command status fields macros */
+
+/* Tx & Rx descriptors status */
+#define ETH_ERROR_SUMMARY                   (BIT0)
+
+/* Tx & Rx descriptors command */
+#define ETH_BUFFER_OWNED_BY_DMA             (BIT31)
+
+/* Tx descriptors status */
+#define ETH_LC_ERROR                        (0   )
+#define ETH_UR_ERROR                        (BIT1 )
+#define ETH_RL_ERROR                        (BIT2 )
+#define ETH_LLC_SNAP_FORMAT                 (BIT9 )
+
+/* Rx descriptors status */
+#define ETH_CRC_ERROR                       (0   )
+#define ETH_OVERRUN_ERROR                   (BIT1 )
+#define ETH_MAX_FRAME_LENGTH_ERROR          (BIT2 )
+#define ETH_RESOURCE_ERROR                  ((BIT2 | BIT1))
+#define ETH_VLAN_TAGGED                     (BIT19)
+#define ETH_BPDU_FRAME                      (BIT20)
+#define ETH_TCP_FRAME_OVER_IP_V_4           (0    )
+#define ETH_UDP_FRAME_OVER_IP_V_4           (BIT21)
+#define ETH_OTHER_FRAME_TYPE                (BIT22)
+#define ETH_LAYER_2_IS_ETH_V_2              (BIT23)
+#define ETH_FRAME_TYPE_IP_V_4               (BIT24)
+#define ETH_FRAME_HEADER_OK                 (BIT25)
+#define ETH_RX_LAST_DESC                    (BIT26)
+#define ETH_RX_FIRST_DESC                   (BIT27)
+#define ETH_UNKNOWN_DESTINATION_ADDR        (BIT28)
+#define ETH_RX_ENABLE_INTERRUPT             (BIT29)
+#define ETH_LAYER_4_CHECKSUM_OK             (BIT30)
+
+/* Rx descriptors byte count */
+#define ETH_FRAME_FRAGMENTED                (BIT2)
+
+/* Tx descriptors command */
+#define ETH_LAYER_4_CHECKSUM_FIRST_DESC                (BIT10)
+#define ETH_FRAME_SET_TO_VLAN               (BIT15)
+#define ETH_TCP_FRAME                       (0   )
+#define ETH_UDP_FRAME                       (BIT16)
+#define ETH_GEN_TCP_UDP_CHECKSUM            (BIT17)
+#define ETH_GEN_IP_V_4_CHECKSUM             (BIT18)
+#define ETH_ZERO_PADDING                    (BIT19)
+#define ETH_TX_LAST_DESC                    (BIT20)
+#define ETH_TX_FIRST_DESC                   (BIT21)
+#define ETH_GEN_CRC                         (BIT22)
+#define ETH_TX_ENABLE_INTERRUPT             (BIT23)
+#define ETH_AUTO_MODE                       (BIT30)
+
+/* typedefs */
+
+typedef enum _eth_func_ret_status {
+       ETH_OK,                 /* Returned as expected.                    */
+       ETH_ERROR,              /* Fundamental error.                       */
+       ETH_RETRY,              /* Could not process request. Try later.    */
+       ETH_END_OF_JOB,         /* Ring has nothing to process.             */
+       ETH_QUEUE_FULL,         /* Ring resource error.                     */
+       ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust.         */
+} ETH_FUNC_RET_STATUS;
+
+typedef enum _eth_target {
+       ETH_TARGET_DRAM,
+       ETH_TARGET_DEVICE,
+       ETH_TARGET_CBS,
+       ETH_TARGET_PCI0,
+       ETH_TARGET_PCI1
+} ETH_TARGET;
+
+/* These are for big-endian machines.  Little endian needs different
+ * definitions.
+ */
+#if defined(__BIG_ENDIAN)
+struct eth_rx_desc {
+       u16     byte_cnt;       /* Descriptor buffer byte count     */
+       u16     buf_size;       /* Buffer size                      */
+       u32     cmd_sts;        /* Descriptor command status        */
+       u32     next_desc_ptr;  /* Next descriptor pointer          */
+       u32     buf_ptr;        /* Descriptor buffer pointer        */
+};
+
+struct eth_tx_desc {
+       u16     byte_cnt;       /* buffer byte count */
+       u16     l4i_chk;        /* CPU provided TCP checksum */
+       u32     cmd_sts;        /* Command/status field */
+       u32     next_desc_ptr;  /* Pointer to next descriptor */
+       u32     buf_ptr;        /* pointer to buffer for this descriptor */
+};
+
+#elif defined(__LITTLE_ENDIAN)
+struct eth_rx_desc {
+       u32     cmd_sts;        /* Descriptor command status        */
+       u16     buf_size;       /* Buffer size                      */
+       u16     byte_cnt;       /* Descriptor buffer byte count     */
+       u32     buf_ptr;        /* Descriptor buffer pointer        */
+       u32     next_desc_ptr;  /* Next descriptor pointer          */
+};
+
+struct eth_tx_desc {
+       u32     cmd_sts;        /* Command/status field */
+       u16     l4i_chk;        /* CPU provided TCP checksum */
+       u16     byte_cnt;       /* buffer byte count */
+       u32     buf_ptr;        /* pointer to buffer for this descriptor */
+       u32     next_desc_ptr;  /* Pointer to next descriptor */
+};
+#else
+#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
+#endif
+
+/* Unified struct for Rx and Tx operations. The user is not required to */
+/* be familier with neither Tx nor Rx descriptors.                       */
+struct pkt_info {
+       unsigned short  byte_cnt;       /* Descriptor buffer byte count     */
+       unsigned short  l4i_chk;        /* Tx CPU provided TCP Checksum     */
+       unsigned int    cmd_sts;        /* Descriptor command status        */
+       dma_addr_t      buf_ptr;        /* Descriptor buffer pointer        */
+       struct sk_buff  * return_info;  /* User resource return information */
+};
+
+
+/* Ethernet port specific infomation */
+
+struct mv64340_private {
+       int     port_num;               /* User Ethernet port number */
+       u8      port_mac_addr[6];       /* User defined port MAC address. */
+       u32     port_config;            /* User port configuration value */
+       u32     port_config_extend;     /* User port config extend value */
+       u32     port_sdma_config;       /* User port SDMA config value */
+       u32     port_serial_control;    /* User port serial control value */
+       u32     port_tx_queue_command;  /* Port active Tx queues summary */
+       u32     port_rx_queue_command;  /* Port active Rx queues summary */
+
+       int     rx_resource_err;        /* Rx ring resource error flag */
+       int     tx_resource_err;        /* Tx ring resource error flag */
+
+       /* Tx/Rx rings managment indexes fields. For driver use */
+
+       /* Next available and first returning Rx resource */
+       int rx_curr_desc_q, rx_used_desc_q;
+
+       /* Next available and first returning Tx resource */
+       int tx_curr_desc_q, tx_used_desc_q;
+#ifdef MV64340_CHECKSUM_OFFLOAD_TX
+        int tx_first_desc_q;
+#endif
+
+#ifdef MV64340_TX_FAST_REFILL
+       u32     tx_clean_threshold;
+#endif
+
+       volatile struct eth_rx_desc     * p_rx_desc_area;
+       dma_addr_t                      rx_desc_dma;
+       unsigned int                    rx_desc_area_size;
+       struct sk_buff                  * rx_skb[MV64340_RX_QUEUE_SIZE];
+
+       volatile struct eth_tx_desc     * p_tx_desc_area;
+       dma_addr_t                      tx_desc_dma;
+       unsigned int                    tx_desc_area_size;
+       struct sk_buff                  * tx_skb[MV64340_TX_QUEUE_SIZE];
+
+       struct work_struct              tx_timeout_task;
+
+       /*
+        * Former struct mv64340_eth_priv members start here
+        */
+       struct net_device_stats stats;
+       spinlock_t lock;
+       /* Size of Tx Ring per queue */
+       unsigned int tx_ring_size;
+       /* Ammont of SKBs outstanding on Tx queue */
+       unsigned int tx_ring_skbs;
+       /* Size of Rx Ring per queue */
+       unsigned int rx_ring_size;
+       /* Ammount of SKBs allocated to Rx Ring per queue */
+       unsigned int rx_ring_skbs;
+
+       /*
+        * rx_task used to fill RX ring out of bottom half context 
+        */
+       struct work_struct rx_task;
+
+       /* 
+        * Used in case RX Ring is empty, which can be caused when 
+        * system does not have resources (skb's) 
+        */
+       struct timer_list timeout;
+       long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES)));
+       unsigned rx_timer_flag;
+
+       u32 rx_int_coal;
+       u32 tx_int_coal;
+};
+
+/* ethernet.h API list */
+
+/* Port operation control routines */
+static void eth_port_init(struct mv64340_private *mp);
+static void eth_port_reset(unsigned int eth_port_num);
+static int eth_port_start(struct mv64340_private *mp);
+
+static void ethernet_set_config_reg(unsigned int eth_port_num,
+                                   unsigned int value);
+static unsigned int ethernet_get_config_reg(unsigned int eth_port_num);
+
+/* Port MAC address routines */
+static void eth_port_uc_addr_set(unsigned int eth_port_num,
+                                unsigned char *p_addr);
+
+/* PHY and MIB routines */
+static int ethernet_phy_reset(unsigned int eth_port_num);
+
+static int eth_port_write_smi_reg(unsigned int eth_port_num,
+                                  unsigned int phy_reg,
+                                  unsigned int value);
+
+static int eth_port_read_smi_reg(unsigned int eth_port_num,
+                                 unsigned int phy_reg,
+                                 unsigned int *value);
+
+static void eth_clear_mib_counters(unsigned int eth_port_num);
+
+/* Port data flow control routines */
+static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private *mp,
+                                        struct pkt_info * p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private *mp,
+                                             struct pkt_info * p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private *mp,
+                                           struct pkt_info * p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private *mp,
+                                             struct pkt_info * p_pkt_info);
+
+#endif  /* __MV64340_ETH_H__ */
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
new file mode 100644 (file)
index 0000000..fe7866c
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * ACPI PCI Hot Plug IBM Extension
+ *
+ * Copyright (C) 2004 Vernon Mauery <vernux@us.ibm.com>
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * 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 <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <acpi/acpi_bus.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <asm/uaccess.h>
+#include <linux/moduleparam.h>
+
+#include "acpiphp.h"
+#include "pci_hotplug.h"
+
+#define DRIVER_VERSION "1.0.1"
+#define DRIVER_AUTHOR  "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
+#define DRIVER_DESC    "ACPI Hot Plug PCI Controller Driver IBM extension"
+
+static int debug;
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+module_param(debug, bool, 644);
+MODULE_PARM_DESC(debug, " Debugging mode enabled or not");
+#define MY_NAME "acpiphp_ibm"
+
+#undef dbg
+#define dbg(format, arg...)                            \
+do {                                                   \
+       if (debug)                                      \
+               printk(KERN_DEBUG "%s: " format,        \
+                               MY_NAME , ## arg);      \
+} while (0)
+
+#define FOUND_APCI 0x61504349
+/* these are the names for the IBM ACPI pseudo-device */
+#define IBM_HARDWARE_ID1 "IBM37D0"
+#define IBM_HARDWARE_ID2 "IBM37D4"
+
+/* union apci_descriptor - allows access to the
+ * various device descriptors that are embedded in the
+ * aPCI table
+ */
+union apci_descriptor {
+       struct {
+               char sig[4];
+               u8   len;
+       } header;
+       struct {
+               u8  type;
+               u8  len;
+               u16 slot_id;
+               u8  bus_id;
+               u8  dev_num;
+               u8  slot_num;
+               u8  slot_attr[2];
+               u8  attn;
+               u8  status[2];
+               u8  sun;
+       } slot;
+       struct {
+               u8 type;
+               u8 len;
+       } generic;
+};
+
+/* struct notification - keeps info about the device
+ * that cause the ACPI notification event
+ */
+struct notification {
+       struct acpi_device *device;
+       u8                  event;
+};
+
+static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status);
+static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);
+static void ibm_handle_events(acpi_handle handle, u32 event, void *context);
+static int ibm_get_table_from_acpi(char **bufp);
+static ssize_t ibm_read_apci_table(struct kobject *kobj,
+               char *buffer, loff_t pos, size_t size);
+static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
+               u32 lvl, void *context, void **rv);
+static int __init ibm_acpiphp_init(void);
+static void __exit ibm_acpiphp_exit(void);
+
+static acpi_handle ibm_acpi_handle;
+static struct notification ibm_note;
+static struct bin_attribute ibm_apci_table_attr = {
+           .attr = {
+                   .name = "apci_table",
+                   .owner = THIS_MODULE,
+                   .mode = S_IRUGO,
+           },
+           .read = ibm_read_apci_table,
+           .write = NULL,
+};
+static struct acpiphp_attention_info ibm_attention_info = 
+{
+       .set_attn = ibm_set_attention_status,
+       .get_attn = ibm_get_attention_status,
+       .owner = THIS_MODULE,
+};
+
+
+/**
+ * ibm_set_attention_status - callback method to set the attention LED
+ * @slot: the hotplug_slot to work with
+ * @status: what to set the LED to (0 or 1)
+ *
+ * Description: this method is registered with the acpiphp module as a
+ * callback to do the device specific task of setting the LED status
+ **/
+static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
+{
+       int retval = 0;
+       union acpi_object args[2]; 
+       struct acpi_object_list params = { .pointer = args, .count = 2 };
+       acpi_status stat; 
+       unsigned long rc = 0;
+       struct acpiphp_slot *acpi_slot;
+
+       acpi_slot = ((struct slot *)(slot->private))->acpi_slot;
+
+       dbg("%s: set slot %d attention status to %d\n", __FUNCTION__,
+                       acpi_slot->sun, (status ? 1 : 0));
+
+       args[0].type = ACPI_TYPE_INTEGER;
+       args[0].integer.value = acpi_slot->sun;
+       args[1].type = ACPI_TYPE_INTEGER;
+       args[1].integer.value = (status) ? 1 : 0;
+
+       stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", &params, &rc);
+       if (ACPI_FAILURE(stat)) {
+               retval = -ENODEV;
+               err("APLS evaluation failed:  0x%08x\n", stat);
+       } else if (!rc) {
+               retval = -ERANGE;
+               err("APLS method failed:  0x%08lx\n", rc);
+       }
+       return retval;
+}
+
+/**
+ * ibm_get_attention_status - callback method to get attention LED status
+ * @slot: the hotplug_slot to work with
+ * @status: returns what the LED is set to (0 or 1)
+ *
+ * Description: this method is registered with the acpiphp module as a
+ * callback to do the device specific task of getting the LED status
+ * 
+ * Because there is no direct method of getting the LED status directly
+ * from an ACPI call, we read the aPCI table and parse out our
+ * slot descriptor to read the status from that.
+ **/
+static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status)
+{
+       int retval = -EINVAL, ind = 0, size;
+       char *table = NULL;
+       struct acpiphp_slot *acpi_slot;
+       union apci_descriptor *des;
+
+       acpi_slot = ((struct slot *)(slot->private))->acpi_slot;
+
+       size = ibm_get_table_from_acpi(&table);
+       if (size <= 0 || !table)
+               goto get_attn_done;
+       // read the header
+       des = (union apci_descriptor *)&table[ind];
+       if (memcmp(des->header.sig, "aPCI", 4) != 0)
+               goto get_attn_done;
+       des = (union apci_descriptor *)&table[ind += des->header.len];
+       while (ind < size && (des->generic.type != 0x82 ||
+                       des->slot.slot_id != acpi_slot->sun))
+               des = (union apci_descriptor *)&table[ind += des->generic.len];
+       if (ind < size && des->slot.slot_id == acpi_slot->sun) {
+               retval = 0;
+               if (des->slot.attn & 0xa0 || des->slot.status[1] & 0x08)
+                       *status = 1;
+               else
+                       *status = 0;
+       }
+
+       dbg("%s: get slot %d attention status is %d retval=%x\n",
+                       __FUNCTION__, acpi_slot->sun, *status, retval);
+
+get_attn_done:
+       kfree(table);
+       return retval;
+}
+
+/**
+ * ibm_handle_events - listens for ACPI events for the IBM37D0 device
+ * @handle: an ACPI handle to the device that caused the event
+ * @event: the event info (device specific)
+ * @context: passed context (our notification struct)
+ *
+ * Description: this method is registered as a callback with the ACPI
+ * subsystem it is called when this device has an event to notify the OS of
+ *
+ * The events actually come from the device as two events that get
+ * synthesized into one event with data by this function.  The event
+ * ID comes first and then the slot number that caused it.  We report
+ * this as one event to the OS.
+ *
+ * From section 5.6.2.2 of the ACPI 2.0 spec, I understand that the OSPM will
+ * only re-enable the interrupt that causes this event AFTER this method
+ * has returned, thereby enforcing serial access for the notification struct.
+ **/
+static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
+{
+       u8 detail = event & 0x0f;
+       u8 subevent = event & 0xf0;
+       struct notification *note = context;
+
+       dbg("%s: Received notification %02x\n", __FUNCTION__, event);
+
+       if (subevent == 0x80) {
+               dbg("%s: generationg bus event\n", __FUNCTION__);
+               acpi_bus_generate_event(note->device, note->event, detail);
+       } else
+               note->event = event;
+}
+
+/**
+ * ibm_get_table_from_acpi - reads the APLS buffer from ACPI
+ * @bufp: address to pointer to allocate for the table
+ *
+ * Description: this method reads the APLS buffer in from ACPI and
+ * stores the "stripped" table into a single buffer
+ * it allocates and passes the address back in bufp
+ *
+ * If NULL is passed in as buffer, this method only calculates
+ * the size of the table and returns that without filling
+ * in the buffer
+ *
+ * returns < 0 on error or the size of the table on success
+ **/
+static int ibm_get_table_from_acpi(char **bufp)
+{
+       union acpi_object *package;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+       char *lbuf = NULL;
+       int i, size = -EIO;
+
+       status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               err("%s:  APCI evaluation failed\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       package = (union acpi_object *) buffer.pointer;
+       if(!(package) ||
+                       (package->type != ACPI_TYPE_PACKAGE) ||
+                       !(package->package.elements)) {
+               err("%s:  Invalid APCI object\n", __FUNCTION__);
+               goto read_table_done;
+       }
+
+       for(size = 0, i = 0; i < package->package.count; i++) {
+               if (package->package.elements[i].type != ACPI_TYPE_BUFFER) {
+                       err("%s:  Invalid APCI element %d\n", __FUNCTION__, i);
+                       goto read_table_done;
+               }
+               size += package->package.elements[i].buffer.length;
+       }
+
+       if (bufp == NULL)
+               goto read_table_done;
+
+       lbuf = kmalloc(size, GFP_KERNEL);
+       dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
+                       __FUNCTION__, package->package.count, size, lbuf);
+
+       if (lbuf) {
+               *bufp = lbuf;
+               memset(lbuf, 0, size);
+       } else {
+               size = -ENOMEM;
+               goto read_table_done;
+       }
+
+       size = 0;
+       for (i=0; i<package->package.count; i++) {
+               memcpy(&lbuf[size],
+                               package->package.elements[i].buffer.pointer,
+                               package->package.elements[i].buffer.length);
+               size += package->package.elements[i].buffer.length;
+       }
+
+read_table_done:
+       kfree(buffer.pointer);
+       return size;
+}
+
+/**
+ * ibm_read_apci_table - callback for the sysfs apci_table file
+ * @kobj: the kobject this binary attribute is a part of
+ * @buffer: the kernel space buffer to fill
+ * @pos: the offset into the file
+ * @size: the number of bytes requested
+ *
+ * Description: gets registered with sysfs as the reader callback
+ * to be executed when /sys/bus/pci/slots/apci_table gets read
+ *
+ * Since we don't get notified on open and close for this file,
+ * things get really tricky here...
+ * our solution is to only allow reading the table in all at once
+ **/
+static ssize_t ibm_read_apci_table(struct kobject *kobj,
+               char *buffer, loff_t pos, size_t size)
+{
+       int bytes_read = -EINVAL;
+       char *table = NULL;
+       
+       dbg("%s: pos = %d, size = %zd\n", __FUNCTION__, (int)pos, size);
+
+       if (pos == 0) {
+               bytes_read = ibm_get_table_from_acpi(&table);
+               if (bytes_read > 0 && bytes_read <= size)
+                       memcpy(buffer, table, bytes_read);
+               kfree(table);
+       }
+       return bytes_read;
+}
+
+/**
+ * ibm_find_acpi_device - callback to find our ACPI device
+ * @handle: the ACPI handle of the device we are inspecting
+ * @lvl: depth into the namespace tree
+ * @context: a pointer to our handle to fill when we find the device
+ * @rv: a return value to fill if desired
+ *
+ * Description: used as a callback when calling acpi_walk_namespace
+ * to find our device.  When this method returns non-zero
+ * acpi_walk_namespace quits its search and returns our value
+ **/
+static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
+               u32 lvl, void *context, void **rv)
+{
+       acpi_handle *phandle = (acpi_handle *)context;
+       acpi_status status; 
+       struct acpi_device_info info; 
+       struct acpi_buffer info_buffer = {
+               .length = sizeof(struct acpi_device_info),
+               .pointer = &info,
+       };
+
+       status = acpi_get_object_info(handle, &info_buffer);
+       if (ACPI_FAILURE(status)) {
+               err("%s:  Failed to get device information", __FUNCTION__);
+               return 0;
+       }
+       info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
+
+       if(info.current_status && (info.valid & ACPI_VALID_HID) &&
+                       (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) ||
+                       !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) {
+               dbg("found hardware: %s, handle: %p\n", info.hardware_id.value,
+                               handle);
+               *phandle = handle;
+               /* returning non-zero causes the search to stop
+                * and returns this value to the caller of 
+                * acpi_walk_namespace, but it also causes some warnings
+                * in the acpi debug code to print...
+                */
+               return FOUND_APCI;
+       }
+       return 0;
+}
+
+static int __init ibm_acpiphp_init(void)
+{
+       int retval = 0;
+       acpi_status status;
+       struct acpi_device *device;
+       struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+
+       dbg("%s\n", __FUNCTION__);
+
+       if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                       ACPI_UINT32_MAX, ibm_find_acpi_device,
+                       &ibm_acpi_handle, NULL) != FOUND_APCI) {
+               err("%s: acpi_walk_namespace failed\n", __FUNCTION__);
+               retval = -ENODEV;
+               goto init_return;
+       }
+       dbg("%s: found IBM aPCI device\n", __FUNCTION__);
+       if (acpi_bus_get_device(ibm_acpi_handle, &device)) {
+               err("%s: acpi_bus_get_device failed\n", __FUNCTION__);
+               retval = -ENODEV;
+               goto init_return;
+       }
+       if (acpiphp_register_attention(&ibm_attention_info)) {
+               retval = -ENODEV;
+               goto init_return;
+       }
+
+       ibm_note.device = device;
+       status = acpi_install_notify_handler(
+                       ibm_acpi_handle,
+                       ACPI_DEVICE_NOTIFY,
+                       ibm_handle_events,
+                       &ibm_note);
+       if (ACPI_FAILURE(status)) {
+               err("%s:  Failed to register notification handler\n",
+                               __FUNCTION__);
+               retval = -EBUSY;
+               goto init_cleanup;
+       }
+
+       ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL);
+       retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr);
+
+       return retval;
+
+init_cleanup:
+       acpiphp_unregister_attention(&ibm_attention_info);
+init_return:
+       return retval;
+}
+
+static void __exit ibm_acpiphp_exit(void)
+{
+       acpi_status status;
+       struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+
+       dbg("%s\n", __FUNCTION__);
+
+       if (acpiphp_unregister_attention(&ibm_attention_info))
+               err("%s: attention info deregistration failed", __FUNCTION__);
+
+          status = acpi_remove_notify_handler(
+                          ibm_acpi_handle,
+                          ACPI_DEVICE_NOTIFY,
+                          ibm_handle_events);
+          if (ACPI_FAILURE(status))
+                  err("%s:  Notification handler removal failed\n",
+                                  __FUNCTION__);
+       // remove the /sys entries
+       if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr))
+               err("%s: removal of sysfs file apci_table failed\n",
+                               __FUNCTION__);
+}
+
+module_init(ibm_acpiphp_init);
+module_exit(ibm_acpiphp_exit);
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
new file mode 100644 (file)
index 0000000..968eb32
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * File:       pci-acpi.c
+ * Purpose:    Provide PCI supports in ACPI
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acresrc.h>
+#include <acpi/acpi_bus.h>
+
+#include <linux/pci-acpi.h>
+
+static u32 ctrlset_buf[3] = {0, 0, 0};
+static u32 global_ctrlsets = 0;
+u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
+
+static acpi_status  
+acpi_query_osc (
+       acpi_handle     handle,
+       u32             level,
+       void            *context,
+       void            **retval )
+{
+       acpi_status             status;
+       struct acpi_object_list input;
+       union acpi_object       in_params[4];
+       struct acpi_buffer      output;
+       union acpi_object       out_obj;        
+       u32                     osc_dw0;
+
+       /* Setting up output buffer */
+       output.length = sizeof(out_obj) + 3*sizeof(u32);  
+       output.pointer = &out_obj;
+       
+       /* Setting up input parameters */
+       input.count = 4;
+       input.pointer = in_params;
+       in_params[0].type               = ACPI_TYPE_BUFFER;
+       in_params[0].buffer.length      = 16;
+       in_params[0].buffer.pointer     = OSC_UUID;
+       in_params[1].type               = ACPI_TYPE_INTEGER;
+       in_params[1].integer.value      = 1;
+       in_params[2].type               = ACPI_TYPE_INTEGER;
+       in_params[2].integer.value      = 3;
+       in_params[3].type               = ACPI_TYPE_BUFFER;
+       in_params[3].buffer.length      = 12;
+       in_params[3].buffer.pointer     = (u8 *)context;
+
+       status = acpi_evaluate_object(handle, "_OSC", &input, &output);
+       if (ACPI_FAILURE (status)) {
+               printk(KERN_DEBUG  
+                       "Evaluate _OSC Set fails. Status = 0x%04x\n", status);
+               return status;
+       }
+       if (out_obj.type != ACPI_TYPE_BUFFER) {
+               printk(KERN_DEBUG  
+                       "Evaluate _OSC returns wrong type\n");
+               return AE_TYPE;
+       }
+       osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+       if (osc_dw0) {
+               if (osc_dw0 & OSC_REQUEST_ERROR)
+                       printk(KERN_DEBUG "_OSC request fails\n"); 
+               if (osc_dw0 & OSC_INVALID_UUID_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid UUID\n"); 
+               if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid revision\n"); 
+               if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
+                       /* Update Global Control Set */
+                       global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8));
+                       return AE_OK;
+               }
+               return AE_ERROR;
+       }
+
+       /* Update Global Control Set */
+       global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8));
+       return AE_OK;
+}
+
+
+static acpi_status  
+acpi_run_osc (
+       acpi_handle     handle,
+       u32             level,
+       void            *context,
+       void            **retval )
+{
+       acpi_status             status;
+       struct acpi_object_list input;
+       union acpi_object       in_params[4];
+       struct acpi_buffer      output;
+       union acpi_object       out_obj;        
+       u32                     osc_dw0;
+
+       /* Setting up output buffer */
+       output.length = sizeof(out_obj) + 3*sizeof(u32);  
+       output.pointer = &out_obj;
+       
+       /* Setting up input parameters */
+       input.count = 4;
+       input.pointer = in_params;
+       in_params[0].type               = ACPI_TYPE_BUFFER;
+       in_params[0].buffer.length      = 16;
+       in_params[0].buffer.pointer     = OSC_UUID;
+       in_params[1].type               = ACPI_TYPE_INTEGER;
+       in_params[1].integer.value      = 1;
+       in_params[2].type               = ACPI_TYPE_INTEGER;
+       in_params[2].integer.value      = 3;
+       in_params[3].type               = ACPI_TYPE_BUFFER;
+       in_params[3].buffer.length      = 12;
+       in_params[3].buffer.pointer     = (u8 *)context;
+
+       status = acpi_evaluate_object(handle, "_OSC", &input, &output);
+       if (ACPI_FAILURE (status)) {
+               printk(KERN_DEBUG  
+                       "Evaluate _OSC Set fails. Status = 0x%04x\n", status);
+               return status;
+       }
+       if (out_obj.type != ACPI_TYPE_BUFFER) {
+               printk(KERN_DEBUG  
+                       "Evaluate _OSC returns wrong type\n");
+               return AE_TYPE;
+       }
+       osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+       if (osc_dw0) {
+               if (osc_dw0 & OSC_REQUEST_ERROR)
+                       printk(KERN_DEBUG "_OSC request fails\n"); 
+               if (osc_dw0 & OSC_INVALID_UUID_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid UUID\n"); 
+               if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
+                       printk(KERN_DEBUG "_OSC invalid revision\n"); 
+               if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
+                       printk(KERN_DEBUG "_OSC FW not grant req. control\n");
+                       return AE_SUPPORT;
+               }
+               return AE_ERROR;
+       }
+       return AE_OK;
+}
+
+/**
+ * pci_osc_support_set - register OS support to Firmware
+ * @flags: OS support bits
+ *
+ * Update OS support fields and doing a _OSC Query to obtain an update
+ * from Firmware on supported control bits.
+ **/
+acpi_status pci_osc_support_set(u32 flags)
+{
+       u32 temp;
+
+       if (!(flags & OSC_SUPPORT_MASKS)) {
+               return AE_TYPE;
+       }
+       ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
+
+       /* do _OSC query for all possible controls */
+       temp = ctrlset_buf[OSC_CONTROL_TYPE];
+       ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+       ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
+       acpi_get_devices ( PCI_ROOT_HID_STRING,
+                       acpi_query_osc,
+                       ctrlset_buf,
+                       NULL );
+       ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
+       ctrlset_buf[OSC_CONTROL_TYPE] = temp;
+       return AE_OK;
+}
+EXPORT_SYMBOL(pci_osc_support_set);
+
+/**
+ * pci_osc_control_set - commit requested control to Firmware
+ * @flags: driver's requested control bits
+ *
+ * Attempt to take control from Firmware on requested control bits.
+ **/
+acpi_status pci_osc_control_set(u32 flags)
+{
+       acpi_status     status;
+       u32             ctrlset;
+
+       ctrlset = (flags & OSC_CONTROL_MASKS);
+       if (!ctrlset) {
+               return AE_TYPE;
+       }
+       if (ctrlset_buf[OSC_SUPPORT_TYPE] && 
+               ((global_ctrlsets & ctrlset) != ctrlset)) {
+               return AE_SUPPORT;
+       }
+       ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
+       status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+                               acpi_run_osc,
+                               ctrlset_buf,
+                               NULL );
+       if (ACPI_FAILURE (status)) {
+               ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
+       }
+       
+       return status;
+}
+EXPORT_SYMBOL(pci_osc_control_set);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
new file mode 100644 (file)
index 0000000..54e4ba7
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * drivers/pci/rom.c
+ *
+ * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
+ * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
+ *
+ * PCI ROM access routines
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+
+/**
+ * pci_enable_rom - enable ROM decoding for a PCI device
+ * @dev: PCI device to enable
+ *
+ * Enable ROM decoding on @dev.  This involves simply turning on the last
+ * bit of the PCI ROM BAR.  Note that some cards may share address decoders
+ * between the ROM and other resources, so enabling it may disable access
+ * to MMIO registers or other card memory.
+ */
+static void
+pci_enable_rom(struct pci_dev *pdev)
+{
+       u32 rom_addr;
+       
+       pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
+       rom_addr |= PCI_ROM_ADDRESS_ENABLE;
+       pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
+}
+
+/**
+ * pci_disable_rom - disable ROM decoding for a PCI device
+ * @dev: PCI device to disable
+ *
+ * Disable ROM decoding on a PCI device by turning off the last bit in the
+ * ROM BAR.
+ */
+static void
+pci_disable_rom(struct pci_dev *pdev)
+{
+       u32 rom_addr;
+       pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
+       rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
+       pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
+}
+
+/**
+ * pci_map_rom - map a PCI ROM to kernel space
+ * @dev: pointer to pci device struct
+ * @size: pointer to receive size of pci window over ROM
+ * @return: kernel virtual pointer to image of ROM
+ *
+ * Map a PCI ROM into kernel space. If ROM is boot video ROM,
+ * the shadow BIOS copy will be returned instead of the 
+ * actual ROM.
+ */
+void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
+{
+       struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+       loff_t start;
+       void __iomem *rom;
+       void __iomem *image;
+       int last_image;
+       
+       if (res->flags & IORESOURCE_ROM_SHADOW) {       /* IORESOURCE_ROM_SHADOW only set on x86 */
+               start = (loff_t)0xC0000;        /* primary video rom always starts here */
+               *size = 0x20000;                /* cover C000:0 through E000:0 */
+       } else {
+               if (res->flags & IORESOURCE_ROM_COPY) {
+                       *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+                       return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE);
+               } else {
+                       /* assign the ROM an address if it doesn't have one */
+                       if (res->parent == NULL)
+                               pci_assign_resource(pdev, PCI_ROM_RESOURCE);
+       
+                       start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
+                       *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+                       if (*size == 0)
+                               return NULL;
+                       
+                       /* Enable ROM space decodes */
+                       pci_enable_rom(pdev);
+               }
+       }
+       
+       rom = ioremap(start, *size);
+       if (!rom) {
+               /* restore enable if ioremap fails */
+               if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY)))
+                       pci_disable_rom(pdev);
+               return NULL;
+       }               
+
+       /* Try to find the true size of the ROM since sometimes the PCI window */
+       /* size is much larger than the actual size of the ROM. */
+       /* True size is important if the ROM is going to be copied. */
+       image = rom;
+       do {
+               void __iomem *pds;
+               /* Standard PCI ROMs start out with these bytes 55 AA */
+               if (readb(image) != 0x55)
+                       break;
+               if (readb(image + 1) != 0xAA)
+                       break;
+               /* get the PCI data structure and check its signature */
+               pds = image + readw(image + 24);
+               if (readb(pds) != 'P')
+                       break;
+               if (readb(pds + 1) != 'C')
+                       break;
+               if (readb(pds + 2) != 'I')
+                       break;
+               if (readb(pds + 3) != 'R')
+                       break;
+               last_image = readb(pds + 21) & 0x80;
+               /* this length is reliable */
+               image += readw(pds + 16) * 512;
+       } while (!last_image);
+
+       *size = image - rom;
+
+       return rom;
+}
+
+/**
+ * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
+ * @dev: pointer to pci device struct
+ * @size: pointer to receive size of pci window over ROM
+ * @return: kernel virtual pointer to image of ROM
+ *
+ * Map a PCI ROM into kernel space. If ROM is boot video ROM,
+ * the shadow BIOS copy will be returned instead of the 
+ * actual ROM.
+ */
+void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
+{
+       struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+       void __iomem *rom;
+       
+       rom = pci_map_rom(pdev, size);
+       if (!rom)
+               return NULL;
+               
+       if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW))
+               return rom;
+               
+       res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
+       if (!res->start) 
+               return rom;
+
+       res->end = res->start + *size; 
+       memcpy_fromio((void*)res->start, rom, *size);
+       pci_unmap_rom(pdev, rom);
+       res->flags |= IORESOURCE_ROM_COPY;
+       
+       return (void __iomem *)res->start;
+}
+
+/**
+ * pci_unmap_rom - unmap the ROM from kernel space
+ * @dev: pointer to pci device struct
+ * @rom: virtual address of the previous mapping
+ *
+ * Remove a mapping of a previously mapped ROM
+ */
+void 
+pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
+{
+       struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+
+       if (res->flags & IORESOURCE_ROM_COPY)
+               return;
+               
+       iounmap(rom);
+               
+       /* Disable again before continuing, leave enabled if pci=rom */
+       if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
+               pci_disable_rom(pdev);
+}
+
+/**
+ * pci_remove_rom - disable the ROM and remove its sysfs attribute
+ * @dev: pointer to pci device struct
+ *
+ */
+void 
+pci_remove_rom(struct pci_dev *pdev) 
+{
+       struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+       
+       if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+               sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
+       if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY)))
+               pci_disable_rom(pdev);
+}
+
+/**
+ * pci_cleanup_rom - internal routine for freeing the ROM copy created 
+ * by pci_map_rom_copy called from remove.c
+ * @dev: pointer to pci device struct
+ *
+ */
+void 
+pci_cleanup_rom(struct pci_dev *pdev) 
+{
+       struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+       if (res->flags & IORESOURCE_ROM_COPY) {
+               kfree((void*)res->start);
+               res->flags &= ~IORESOURCE_ROM_COPY;
+               res->start = 0;
+               res->end = 0;
+       }
+}
+
+EXPORT_SYMBOL(pci_map_rom);
+EXPORT_SYMBOL(pci_map_rom_copy);
+EXPORT_SYMBOL(pci_unmap_rom);
+EXPORT_SYMBOL(pci_remove_rom);
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
new file mode 100644 (file)
index 0000000..836058d
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ *  drivers/pcmcia/m32r_cfc.c
+ *
+ *  Device driver for the CFC functionality of M32R.
+ *
+ *  Copyright (c) 2001, 2002, 2003, 2004
+ *    Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+#undef MAX_IO_WIN      /* FIXME */
+#define MAX_IO_WIN 1
+#undef MAX_WIN         /* FIXME */
+#define MAX_WIN 1
+
+#include "m32r_cfc.h"
+
+#ifdef DEBUG
+static int m32r_cfc_debug;
+module_param(m32r_cfc_debug, int, 0644);
+#define debug(lvl, fmt, arg...) do {                           \
+       if (m32r_cfc_debug > (lvl))                             \
+               printk(KERN_DEBUG "m32r_cfc: " fmt , ## arg);   \
+} while (0)
+#else
+#define debug(n, args...) do { } while (0)
+#endif
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;
+
+typedef struct pcc_socket {
+       u_short                 type, flags;
+       struct pcmcia_socket    socket;
+       unsigned int            number;
+       ioaddr_t                ioaddr;
+       u_long                  mapaddr;
+       u_long                  base;   /* PCC register base */
+       u_char                  cs_irq1, cs_irq2, intr;
+       pccard_io_map           io_map[MAX_IO_WIN];
+       pccard_mem_map          mem_map[MAX_WIN];
+       u_char                  io_win;
+       u_char                  mem_win;
+       pcc_as_t                current_space;
+       u_char                  last_iodbex;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *proc;
+#endif
+} pcc_socket_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_t socket[M32R_MAX_PCC] = {
+       { 0, }, /* ... */
+};
+
+/*====================================================================*/
+
+static unsigned int pcc_get(u_short, unsigned int);
+static void pcc_set(u_short, unsigned int , unsigned int );
+
+static spinlock_t pcc_lock = SPIN_LOCK_UNLOCKED;
+
+#if !defined(CONFIG_PLAT_USRV)
+static inline u_long pcc_port2addr(unsigned long port, int size) {
+       u_long addr = 0;
+       u_long odd;
+
+       if (size == 1) {        /* byte access */
+               odd = (port&1) << 11;
+               port -= port & 1;
+               addr = CFC_IO_MAPBASE_BYTE - CFC_IOPORT_BASE + odd + port;
+       } else if (size == 2)
+               addr = CFC_IO_MAPBASE_WORD - CFC_IOPORT_BASE + port;
+
+       return addr;
+}
+#else  /* CONFIG_PLAT_USRV */
+static inline u_long pcc_port2addr(unsigned long port, int size) {
+       u_long odd;
+       u_long addr = ((port - CFC_IOPORT_BASE) & 0xf000) << 8;
+
+       if (size == 1) {        /* byte access */
+               odd = port & 1;
+               port -= odd;
+               odd <<= 11;
+               addr = (addr | CFC_IO_MAPBASE_BYTE) + odd + (port & 0xfff);
+       } else if (size == 2)   /* word access */
+               addr = (addr | CFC_IO_MAPBASE_WORD) + (port & 0xfff);
+
+       return addr;
+}
+#endif /* CONFIG_PLAT_USRV */
+
+void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size,
+       size_t nmemb, int flag)
+{
+       u_long addr;
+       unsigned char *bp = (unsigned char *)buf;
+       unsigned long flags;
+
+       debug(3, "m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, "
+                "size=%u, nmemb=%d, flag=%d\n",
+                 sock, port, buf, size, nmemb, flag);
+
+       addr = pcc_port2addr(port, 1);
+       if (!addr) {
+               printk("m32r_cfc:ioread_byte null port :%#lx\n",port);
+               return;
+       }
+       debug(3, "m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr);
+
+       spin_lock_irqsave(&pcc_lock, flags);
+       /* read Byte */
+       while (nmemb--)
+               *bp++ = readb(addr);
+       spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size,
+       size_t nmemb, int flag)
+{
+       u_long addr;
+       unsigned short *bp = (unsigned short *)buf;
+       unsigned long flags;
+
+       debug(3, "m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, "
+                "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+                sock, port, buf, size, nmemb, flag);
+
+       if (size != 2)
+               printk("m32r_cfc: ioread_word :illigal size %u : %#lx\n", size,
+                       port);
+       if (size == 9)
+               printk("m32r_cfc: ioread_word :insw \n");
+
+       addr = pcc_port2addr(port, 2);
+       if (!addr) {
+               printk("m32r_cfc:ioread_word null port :%#lx\n",port);
+               return;
+       }
+       debug(3, "m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr);
+
+       spin_lock_irqsave(&pcc_lock, flags);
+       /* read Word */
+       while (nmemb--)
+               *bp++ = readw(addr);
+       spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size,
+       size_t nmemb, int flag)
+{
+       u_long addr;
+       unsigned char *bp = (unsigned char *)buf;
+       unsigned long flags;
+
+       debug(3, "m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, "
+                "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+                sock, port, buf, size, nmemb, flag);
+
+       /* write Byte */
+       addr = pcc_port2addr(port, 1);
+       if (!addr) {
+               printk("m32r_cfc:iowrite_byte null port:%#lx\n",port);
+               return;
+       }
+       debug(3, "m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr);
+
+       spin_lock_irqsave(&pcc_lock, flags);
+       while (nmemb--)
+               writeb(*bp++, addr);
+       spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size,
+       size_t nmemb, int flag)
+{
+       u_long addr;
+       unsigned short *bp = (unsigned short *)buf;
+       unsigned long flags;
+
+       debug(3, "m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, "
+                "buf=%p, size=%u, nmemb=%d, flag=%d\n",
+                sock, port, buf, size, nmemb, flag);
+
+       if(size != 2)
+               printk("m32r_cfc: iowrite_word :illigal size %u : %#lx\n",
+                       size, port);
+       if(size == 9)
+               printk("m32r_cfc: iowrite_word :outsw \n");
+
+       addr = pcc_port2addr(port, 2);
+       if (!addr) {
+               printk("m32r_cfc:iowrite_word null addr :%#lx\n",port);
+               return;
+       }
+#if 1
+       if (addr & 1) {
+               printk("m32r_cfc:iowrite_word port addr (%#lx):%#lx\n", port,
+                       addr);
+               return;
+       }
+#endif
+       debug(3, "m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr);
+
+       spin_lock_irqsave(&pcc_lock, flags);
+       while (nmemb--)
+               writew(*bp++, addr);
+       spin_unlock_irqrestore(&pcc_lock, flags);
+}
+
+/*====================================================================*/
+
+#define IS_ALIVE               0x8000
+
+typedef struct pcc_t {
+       char                    *name;
+       u_short                 flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+#if !defined(CONFIG_PLAT_USRV)
+       { "m32r_cfc", 0 }, { "", 0 },
+#else  /* CONFIG_PLAT_USRV */
+       { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 },
+       { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "", 0 },
+#endif /* CONFIG_PLAT_USRV */
+};
+
+static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+       unsigned int val = inw(reg);
+       debug(3, "m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val);
+       return val;
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+       outw(data, reg);
+       debug(3, "m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data);
+}
+
+/*======================================================================
+
+       See if a card is present, powered up, in IO mode, and already
+       bound to a (non PC Card) Linux driver.  We leave these alone.
+
+       We make an exception for cards that seem to be serial devices.
+
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+       unsigned int stat;
+
+       debug(3, "m32r_cfc: is_alive:\n");
+
+       printk("CF: ");
+       stat = pcc_get(sock, (unsigned int)PLD_CFSTS);
+       if (!stat)
+               printk("No ");
+       printk("Card is detected at socket %d : stat = 0x%08x\n", sock, stat);
+       debug(3, "m32r_cfc: is_alive: sock stat is 0x%04x\n", stat);
+
+       return 0;
+}
+
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr, ioaddr_t ioaddr)
+{
+       pcc_socket_t *t = &socket[pcc_sockets];
+
+       debug(3, "m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, "
+                "mapaddr=%#lx, ioaddr=%08x\n",
+                base, irq, mapaddr, ioaddr);
+
+       /* add sockets */
+       t->ioaddr = ioaddr;
+       t->mapaddr = mapaddr;
+#if !defined(CONFIG_PLAT_USRV)
+       t->base = 0;
+       t->flags = 0;
+       t->cs_irq1 = irq;               // insert irq
+       t->cs_irq2 = irq + 1;           // eject irq
+#else  /* CONFIG_PLAT_USRV */
+       t->base = base;
+       t->flags = 0;
+       t->cs_irq1 = 0;                 // insert irq
+       t->cs_irq2 = 0;                 // eject irq
+#endif /* CONFIG_PLAT_USRV */
+
+       if (is_alive(pcc_sockets))
+               t->flags |= IS_ALIVE;
+
+       /* add pcc */
+#if !defined(CONFIG_PLAT_USRV)
+       request_region((unsigned int)PLD_CFRSTCR, 0x20, "m32r_cfc");
+#else  /* CONFIG_PLAT_USRV */
+       {
+               unsigned int reg_base;
+
+               reg_base = (unsigned int)PLD_CFRSTCR;
+               reg_base |= pcc_sockets << 8;
+               request_region(reg_base, 0x20, "m32r_cfc");
+       }
+#endif /* CONFIG_PLAT_USRV */
+       printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+       printk("pcc at 0x%08lx\n", t->base);
+
+       /* Update socket interrupt information, capabilities */
+       t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+       t->socket.map_size = M32R_PCC_MAPSIZE;
+       t->socket.io_offset = ioaddr;   /* use for io access offset */
+       t->socket.irq_mask = 0;
+#if !defined(CONFIG_PLAT_USRV)
+       t->socket.pci_irq = PLD_IRQ_CFIREQ ;    /* card interrupt */
+#else  /* CONFIG_PLAT_USRV */
+       t->socket.pci_irq = PLD_IRQ_CF0 + pcc_sockets;
+#endif /* CONFIG_PLAT_USRV */
+
+#ifndef CONFIG_PLAT_USRV
+       /* insert interrupt */
+       request_irq(irq, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);
+       /* eject interrupt */
+       request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);
+
+       debug(3, "m32r_cfc: enable CFMSK, RDYSEL\n");
+       pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01);
+#endif /* CONFIG_PLAT_USRV */
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+       pcc_set(pcc_sockets, (unsigned int)PLD_CFCR1, 0x0200);
+#endif
+       pcc_sockets++;
+
+       return;
+}
+
+
+/*====================================================================*/
+
+static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+       int i;
+       u_int events = 0;
+       int handled = 0;
+
+       debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p, regs=%p\n",
+               irq, dev, regs);
+       for (i = 0; i < pcc_sockets; i++) {
+               if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq)
+                       continue;
+
+               handled = 1;
+               debug(3, "m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ",
+                       i, irq);
+               events |= SS_DETECT;    /* insert or eject */
+               if (events)
+                       pcmcia_parse_events(&socket[i].socket, events);
+       }
+       debug(3, "m32r_cfc: pcc_interrupt: done\n");
+
+       return IRQ_RETVAL(handled);
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+       debug(3, "m32r_cfc: pcc_interrupt_wrapper:\n");
+       pcc_interrupt(0, NULL, NULL);
+       init_timer(&poll_timer);
+       poll_timer.expires = jiffies + poll_interval;
+       add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+       u_int status;
+
+       debug(3, "m32r_cfc: _pcc_get_status:\n");
+       status = pcc_get(sock, (unsigned int)PLD_CFSTS);
+       *value = (status) ? SS_DETECT : 0;
+       debug(3, "m32r_cfc: _pcc_get_status: status=0x%08x\n", status);
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+       if ( status ) {
+               /* enable CF power */
+               status = inw((unsigned int)PLD_CPCR);
+               if (!(status & PLD_CPCR_CF)) {
+                       debug(3, "m32r_cfc: _pcc_get_status: "
+                                "power on (CPCR=0x%08x)\n", status);
+                       status |= PLD_CPCR_CF;
+                       outw(status, (unsigned int)PLD_CPCR);
+                       udelay(100);
+               }
+               *value |= SS_POWERON;
+
+               pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);/* enable buffer */
+               udelay(100);
+
+               *value |= SS_READY;             /* always ready */
+               *value |= SS_3VCARD;
+       } else {
+               /* disable CF power */
+               status = inw((unsigned int)PLD_CPCR);
+               status &= ~PLD_CPCR_CF;
+               outw(status, (unsigned int)PLD_CPCR);
+               udelay(100);
+               debug(3, "m32r_cfc: _pcc_get_status: "
+                        "power off (CPCR=0x%08x)\n", status);
+       }
+#elif defined(CONFIG_PLAT_MAPPI2)
+       if ( status ) {
+               status = pcc_get(sock, (unsigned int)PLD_CPCR);
+               if (status == 0) { /* power off */
+                       pcc_set(sock, (unsigned int)PLD_CPCR, 1);
+                       pcc_set(sock, (unsigned int)PLD_CFBUFCR,0); /* force buffer off for ZA-36 */
+                       udelay(50);
+               }
+               status = pcc_get(sock, (unsigned int)PLD_CFBUFCR);
+               if (status != 0) { /* buffer off */
+                       pcc_set(sock, (unsigned int)PLD_CFBUFCR,0);
+                       udelay(50);
+                       pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0101);
+                       udelay(25); /* for IDE reset */
+                       pcc_set(sock, (unsigned int)PLD_CFRSTCR, 0x0100);
+                       mdelay(2);  /* for IDE reset */
+               } else {
+                       *value |= SS_POWERON;
+                       *value |= SS_READY;
+               }
+       }
+#else
+#error no platform configuration
+#endif
+       debug(3, "m32r_cfc: _pcc_get_status: GetStatus(%d) = %#4.4x\n",
+                sock, *value);
+       return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_get_socket(u_short sock, socket_state_t *state)
+{
+//     pcc_socket_t *t = &socket[sock];
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+       state->flags = 0;
+       state->csc_mask = SS_DETECT;
+       state->csc_mask |= SS_READY;
+       state->io_irq = 0;
+       state->Vcc = 33;        /* 3.3V fixed */
+       state->Vpp = 33;
+#endif
+       debug(3, "m32r_cfc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+                 "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+                 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+       return 0;
+} /* _get_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_socket(u_short sock, socket_state_t *state)
+{
+#if defined(CONFIG_PLAT_MAPPI2)
+       u_long reg = 0;
+#endif
+       debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+                 "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+                 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT)
+       if (state->Vcc) {
+               if ((state->Vcc != 50) && (state->Vcc != 33))
+                       return -EINVAL;
+               /* accept 5V and 3.3V */
+       }
+#elif defined(CONFIG_PLAT_MAPPI2)
+       if (state->Vcc) {
+               /*
+                * 5V only
+                */
+               if (state->Vcc == 50) {
+                       reg |= PCCSIGCR_VEN;
+               } else {
+                       return -EINVAL;
+               }
+       }
+#endif
+
+       if (state->flags & SS_RESET) {
+               debug(3, ":RESET\n");
+               pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101);
+       }else{
+               pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x100);
+       }
+       if (state->flags & SS_OUTPUT_ENA){
+               debug(3, ":OUTPUT_ENA\n");
+               /* bit clear */
+               pcc_set(sock,(unsigned int)PLD_CFBUFCR,0);
+       } else {
+               pcc_set(sock,(unsigned int)PLD_CFBUFCR,1);
+       }
+
+#ifdef DEBUG
+       if(state->flags & SS_IOCARD){
+               debug(3, ":IOCARD");
+       }
+       if (state->flags & SS_PWR_AUTO) {
+               debug(3, ":PWR_AUTO");
+       }
+       if (state->csc_mask & SS_DETECT)
+               debug(3, ":csc-SS_DETECT");
+       if (state->flags & SS_IOCARD) {
+               if (state->csc_mask & SS_STSCHG)
+                       debug(3, ":STSCHG");
+       } else {
+               if (state->csc_mask & SS_BATDEAD)
+                       debug(3, ":BATDEAD");
+               if (state->csc_mask & SS_BATWARN)
+                       debug(3, ":BATWARN");
+               if (state->csc_mask & SS_READY)
+                       debug(3, ":READY");
+       }
+       debug(3, "\n");
+#endif
+       return 0;
+} /* _set_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+       u_char map;
+
+       debug(3, "m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, "
+                 "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+                 io->speed, io->start, io->stop);
+       map = io->map;
+
+       return 0;
+} /* _set_io_map */
+
+/*====================================================================*/
+
+static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+       u_char map = mem->map;
+       u_long addr;
+       pcc_socket_t *t = &socket[sock];
+
+       debug(3, "m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, "
+                "%#5.5lx, %#5.5x)\n", sock, map, mem->flags,
+                mem->speed, mem->static_start, mem->card_start);
+
+       /*
+        * sanity check
+        */
+       if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff)){
+               return -EINVAL;
+       }
+
+       /*
+        * de-activate
+        */
+       if ((mem->flags & MAP_ACTIVE) == 0) {
+               t->current_space = as_none;
+               return 0;
+       }
+
+       /*
+        * Set mode
+        */
+       if (mem->flags & MAP_ATTRIB) {
+               t->current_space = as_attr;
+       } else {
+               t->current_space = as_comm;
+       }
+
+       /*
+        * Set address
+        */
+       addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK);
+       mem->static_start = addr + mem->card_start;
+
+       return 0;
+
+} /* _set_mem_map */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+       Routines for accessing socket information and register dumps via
+       /proc/bus/pccard/...
+
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+       pcc_socket_t *s = container_of(class_dev, struct pcc_socket,
+               socket.dev);
+
+       return sprintf(buf, "type:     %s\nbase addr:    0x%08lx\n",
+               pcc[s->type].name, s->base);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+       /* FIXME */
+
+       return 0;
+}
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at
+ * some time... */
+#define LOCKED(x) do {                                 \
+       int retval;                                     \
+       unsigned long flags;                            \
+       spin_lock_irqsave(&pcc_lock, flags);            \
+       retval = x;                                     \
+       spin_unlock_irqrestore(&pcc_lock, flags);       \
+       return retval;                                  \
+} while (0)
+
+
+static int pcc_get_status(struct pcmcia_socket *s, u_int *value)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE) {
+               debug(3, "m32r_cfc: pcc_get_status: sock(%d) -EINVAL\n", sock);
+               *value = 0;
+               return -EINVAL;
+       }
+       debug(3, "m32r_cfc: pcc_get_status: sock(%d)\n", sock);
+       LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE) {
+               debug(3, "m32r_cfc: pcc_get_socket: sock(%d) -EINVAL\n", sock);
+               return -EINVAL;
+       }
+       debug(3, "m32r_cfc: pcc_get_socket: sock(%d)\n", sock);
+       LOCKED(_pcc_get_socket(sock, state));
+}
+
+static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE) {
+               debug(3, "m32r_cfc: pcc_set_socket: sock(%d) -EINVAL\n", sock);
+               return -EINVAL;
+       }
+       debug(3, "m32r_cfc: pcc_set_socket: sock(%d)\n", sock);
+       LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE) {
+               debug(3, "m32r_cfc: pcc_set_io_map: sock(%d) -EINVAL\n", sock);
+               return -EINVAL;
+       }
+       debug(3, "m32r_cfc: pcc_set_io_map: sock(%d)\n", sock);
+       LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE) {
+               debug(3, "m32r_cfc: pcc_set_mem_map: sock(%d) -EINVAL\n", sock);
+               return -EINVAL;
+       }
+       debug(3, "m32r_cfc: pcc_set_mem_map: sock(%d)\n", sock);
+       LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(struct pcmcia_socket *s)
+{
+       debug(3, "m32r_cfc: pcc_init()\n");
+       return 0;
+}
+
+static int pcc_suspend(struct pcmcia_socket *sock)
+{
+       debug(3, "m32r_cfc: pcc_suspend()\n");
+       return pcc_set_socket(sock, &dead_socket);
+}
+
+static struct pccard_operations pcc_operations = {
+       .init                   = pcc_init,
+       .suspend                = pcc_suspend,
+       .get_status             = pcc_get_status,
+       .get_socket             = pcc_get_socket,
+       .set_socket             = pcc_set_socket,
+       .set_io_map             = pcc_set_io_map,
+       .set_mem_map            = pcc_set_mem_map,
+};
+
+/*====================================================================*/
+
+static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level)
+{
+       int ret = 0;
+       if (level == SUSPEND_SAVE_STATE)
+               ret = pcmcia_socket_dev_suspend(dev, state);
+       return ret;
+}
+
+static int m32r_pcc_resume(struct device *dev, u32 level)
+{
+       int ret = 0;
+       if (level == RESUME_RESTORE_STATE)
+               ret = pcmcia_socket_dev_resume(dev);
+       return ret;
+}
+
+
+static struct device_driver pcc_driver = {
+       .name = "cfc",
+       .bus = &platform_bus_type,
+       .suspend = m32r_pcc_suspend,
+       .resume = m32r_pcc_resume,
+};
+
+static struct platform_device pcc_device = {
+       .name = "cfc",
+       .id = 0,
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+       int i, ret;
+
+       ret = driver_register(&pcc_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_device_register(&pcc_device);
+       if (ret){
+               driver_unregister(&pcc_driver);
+               return ret;
+       }
+
+#if defined(CONFIG_PLAT_MAPPI2)
+       pcc_set(0, (unsigned int)PLD_CFCR0, 0x0f0f);
+       pcc_set(0, (unsigned int)PLD_CFCR1, 0x0200);
+#endif
+
+       pcc_sockets = 0;
+
+#if !defined(CONFIG_PLAT_USRV)
+       add_pcc_socket(M32R_PCC0_BASE, PLD_IRQ_CFC_INSERT, CFC_ATTR_MAPBASE,
+                      CFC_IOPORT_BASE);
+#else  /* CONFIG_PLAT_USRV */
+       {
+               ulong base, mapaddr;
+               ioaddr_t ioaddr;
+
+               for (i = 0 ; i < M32R_MAX_PCC ; i++) {
+                       base = (ulong)PLD_CFRSTCR;
+                       base = base | (i << 8);
+                       ioaddr = (i + 1) << 12;
+                       mapaddr = CFC_ATTR_MAPBASE | (i << 20);
+                       add_pcc_socket(base, 0, mapaddr, ioaddr);
+               }
+       }
+#endif /* CONFIG_PLAT_USRV */
+
+       if (pcc_sockets == 0) {
+               printk("socket is not found.\n");
+               platform_device_unregister(&pcc_device);
+               driver_unregister(&pcc_driver);
+               return -ENODEV;
+       }
+
+       /* Set up interrupt handler(s) */
+
+       for (i = 0 ; i < pcc_sockets ; i++) {
+               socket[i].socket.dev.dev = &pcc_device.dev;
+               socket[i].socket.ops = &pcc_operations;
+               socket[i].socket.owner = THIS_MODULE;
+               socket[i].number = i;
+               ret = pcmcia_register_socket(&socket[i].socket);
+               if (ret && i--) {
+                       for (; i>= 0; i--)
+                               pcmcia_unregister_socket(&socket[i].socket);
+                       break;
+               }
+#if 0  /* driver model ordering issue */
+               class_device_create_file(&socket[i].socket.dev,
+                                        &class_device_attr_info);
+               class_device_create_file(&socket[i].socket.dev,
+                                        &class_device_attr_exca);
+#endif
+       }
+
+       /* Finally, schedule a polling interrupt */
+       if (poll_interval != 0) {
+               poll_timer.function = pcc_interrupt_wrapper;
+               poll_timer.data = 0;
+               init_timer(&poll_timer);
+               poll_timer.expires = jiffies + poll_interval;
+               add_timer(&poll_timer);
+       }
+
+       return 0;
+} /* init_m32r_pcc */
+
+static void __exit exit_m32r_pcc(void)
+{
+       int i;
+
+       for (i = 0; i < pcc_sockets; i++)
+               pcmcia_unregister_socket(&socket[i].socket);
+
+       platform_device_unregister(&pcc_device);
+       if (poll_interval != 0)
+               del_timer_sync(&poll_timer);
+
+       driver_unregister(&pcc_driver);
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff --git a/drivers/pcmcia/m32r_cfc.h b/drivers/pcmcia/m32r_cfc.h
new file mode 100644 (file)
index 0000000..17c1db7
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+#if !defined(CONFIG_M32R_CFC_NUM)
+#define M32R_MAX_PCC   2
+#else
+#define M32R_MAX_PCC   CONFIG_M32R_CFC_NUM
+#endif
+
+/*
+ * M32R PC Card Controler
+ */
+#define M32R_PCC0_BASE        0x00ef7000
+#define M32R_PCC1_BASE        0x00ef7020
+
+/*
+ * Register offsets
+ */
+#define PCCR            0x00
+#define PCADR           0x04
+#define PCMOD           0x08
+#define PCIRC           0x0c
+#define PCCSIGCR        0x10
+#define PCATCR          0x14
+
+/*
+ * PCCR
+ */
+#define PCCR_PCEN       (1UL<<(31-31))
+
+/*
+ * PCIRC
+ */
+#define PCIRC_BWERR     (1UL<<(31-7))
+#define PCIRC_CDIN1     (1UL<<(31-14))
+#define PCIRC_CDIN2     (1UL<<(31-15))
+#define PCIRC_BEIEN     (1UL<<(31-23))
+#define PCIRC_CIIEN     (1UL<<(31-30))
+#define PCIRC_COIEN     (1UL<<(31-31))
+
+/*
+ * PCCSIGCR
+ */
+#define PCCSIGCR_SEN    (1UL<<(31-3))
+#define PCCSIGCR_VEN    (1UL<<(31-7))
+#define PCCSIGCR_CRST   (1UL<<(31-15))
+#define PCCSIGCR_COCR   (1UL<<(31-31))
+
+/*
+ *
+ */
+#define PCMOD_AS_ATTRIB        (1UL<<(31-19))
+#define PCMOD_AS_IO    (1UL<<(31-18))
+
+#define PCMOD_CBSZ     (1UL<<(31-23)) /* set for 8bit */
+
+#define PCMOD_DBEX     (1UL<<(31-31)) /* set for excahnge */
+
+/*
+ * M32R PCC Map addr
+ */
+
+#define M32R_PCC0_MAPBASE        0x14000000
+#define M32R_PCC1_MAPBASE        0x16000000
+
+#define M32R_PCC_MAPMAX                 0x02000000
+
+#define M32R_PCC_MAPSIZE        0x00001000 /* XXX */
+#define M32R_PCC_MAPMASK       (~(M32R_PCC_MAPMAX-1))
+
+#define CFC_IOPORT_BASE                0x1000
+
+#if !defined(CONFIG_PLAT_USRV)
+#define CFC_ATTR_MAPBASE        0x0c014000
+#define CFC_IO_MAPBASE_BYTE     0xac012000
+#define CFC_IO_MAPBASE_WORD     0xac002000
+#else  /* CONFIG_PLAT_USRV */
+#define CFC_ATTR_MAPBASE       0x04014000
+#define CFC_IO_MAPBASE_BYTE    0xa4012000
+#define CFC_IO_MAPBASE_WORD    0xa4002000
+#endif /* CONFIG_PLAT_USRV */
+
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
new file mode 100644 (file)
index 0000000..aae7a16
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ *  drivers/pcmcia/m32r_pcc.c
+ *
+ *  Device driver for the PCMCIA functionality of M32R.
+ *
+ *  Copyright (c) 2001, 2002, 2003, 2004
+ *    Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/addrspace.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+/* XXX: should be moved into asm/irq.h */
+#define PCC0_IRQ 24
+#define PCC1_IRQ 25
+
+#include "m32r_pcc.h"
+
+#define CHAOS_PCC_DEBUG
+#ifdef CHAOS_PCC_DEBUG
+       static volatile u_short dummy_readbuf;
+#endif
+
+#define PCC_DEBUG_DBEX
+
+#ifdef DEBUG
+static int m32r_pcc_debug;
+module_param(m32r_pcc_debug, int, 0644);
+#define debug(lvl, fmt, arg...) do {                           \
+       if (m32r_pcc_debug > (lvl))                             \
+               printk(KERN_DEBUG "m32r_pcc: " fmt , ## arg);   \
+} while (0)
+#else
+#define debug(n, args...) do { } while (0)
+#endif
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;
+
+typedef struct pcc_socket {
+       u_short                 type, flags;
+       struct pcmcia_socket    socket;
+       unsigned int            number;
+       ioaddr_t                ioaddr;
+       u_long                  mapaddr;
+       u_long                  base;   /* PCC register base */
+       u_char                  cs_irq, intr;
+       pccard_io_map           io_map[MAX_IO_WIN];
+       pccard_mem_map          mem_map[MAX_WIN];
+       u_char                  io_win;
+       u_char                  mem_win;
+       pcc_as_t                current_space;
+       u_char                  last_iodbex;
+#ifdef CHAOS_PCC_DEBUG
+       u_char                  last_iosize;
+#endif
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *proc;
+#endif
+} pcc_socket_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_t socket[M32R_MAX_PCC] = {
+       { 0, }, /* ... */
+};
+
+/*====================================================================*/
+
+static unsigned int pcc_get(u_short, unsigned int);
+static void pcc_set(u_short, unsigned int , unsigned int );
+
+static spinlock_t pcc_lock = SPIN_LOCK_UNLOCKED;
+
+void pcc_iorw(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int wr, int flag)
+{
+       u_long addr;
+       u_long flags;
+       int need_ex;
+#ifdef PCC_DEBUG_DBEX
+       int _dbex;
+#endif
+       pcc_socket_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+       int map_changed = 0;
+#endif
+
+       /* Need lock ? */
+       spin_lock_irqsave(&pcc_lock, flags);
+
+       /*
+        * Check if need dbex
+        */
+       need_ex = (size > 1 && flag == 0) ? PCMOD_DBEX : 0;
+#ifdef PCC_DEBUG_DBEX
+       _dbex = need_ex;
+       need_ex = 0;
+#endif
+
+       /*
+        * calculate access address
+        */
+       addr = t->mapaddr + port - t->ioaddr + KSEG1; /* XXX */
+
+       /*
+        * Check current mapping
+        */
+       if (t->current_space != as_io || t->last_iodbex != need_ex) {
+
+               u_long cbsz;
+
+               /*
+                * Disable first
+                */
+               pcc_set(sock, PCCR, 0);
+
+               /*
+                * Set mode and io address
+                */
+               cbsz = (t->flags & MAP_16BIT) ? 0 : PCMOD_CBSZ;
+               pcc_set(sock, PCMOD, PCMOD_AS_IO | cbsz | need_ex);
+               pcc_set(sock, PCADR, addr & 0x1ff00000);
+
+               /*
+                * Enable and read it
+                */
+               pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+               map_changed = (t->current_space == as_attr && size == 2); /* XXX */
+#else
+               map_changed = 1;
+#endif
+#endif
+               t->current_space = as_io;
+       }
+
+       /*
+        * access to IO space
+        */
+       if (size == 1) {
+               /* Byte */
+               unsigned char *bp = (unsigned char *)buf;
+
+#ifdef CHAOS_DEBUG
+               if (map_changed) {
+                       dummy_readbuf = readb(addr);
+               }
+#endif
+               if (wr) {
+                       /* write Byte */
+                       while (nmemb--) {
+                               writeb(*bp++, addr);
+                       }
+               } else {
+                       /* read Byte */
+                       while (nmemb--) {
+                       *bp++ = readb(addr);
+                       }
+               }
+       } else {
+               /* Word */
+               unsigned short *bp = (unsigned short *)buf;
+
+#ifdef CHAOS_PCC_DEBUG
+               if (map_changed) {
+                       dummy_readbuf = readw(addr);
+               }
+#endif
+               if (wr) {
+                       /* write Word */
+                       while (nmemb--) {
+#ifdef PCC_DEBUG_DBEX
+                               if (_dbex) {
+                                       unsigned char *cp = (unsigned char *)bp;
+                                       unsigned short tmp;
+                                       tmp = cp[1] << 8 | cp[0];
+                                       writew(tmp, addr);
+                                       bp++;
+                               } else
+#endif
+                               writew(*bp++, addr);
+               }
+           } else {
+               /* read Word */
+               while (nmemb--) {
+#ifdef  PCC_DEBUG_DBEX
+                               if (_dbex) {
+                                       unsigned char *cp = (unsigned char *)bp;
+                                       unsigned short tmp;
+                                       tmp = readw(addr);
+                                       cp[0] = tmp & 0xff;
+                                       cp[1] = (tmp >> 8) & 0xff;
+                                       bp++;
+                               } else
+#endif
+                               *bp++ = readw(addr);
+               }
+           }
+       }
+
+#if 1
+       /* addr is no longer used */
+       if ((addr = pcc_get(sock, PCIRC)) & PCIRC_BWERR) {
+         printk("m32r_pcc: BWERR detected : port 0x%04lx : iosize %dbit\n",
+                        port, size * 8);
+         pcc_set(sock, PCIRC, addr);
+       }
+#endif
+       /*
+        * save state
+        */
+       t->last_iosize = size;
+       t->last_iodbex = need_ex;
+
+       /* Need lock ? */
+
+       spin_unlock_irqrestore(&pcc_lock,flags);
+
+       return;
+}
+
+void pcc_ioread(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+       pcc_iorw(sock, port, buf, size, nmemb, 0, flag);
+}
+
+void pcc_iowrite(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+    pcc_iorw(sock, port, buf, size, nmemb, 1, flag);
+}
+
+/*====================================================================*/
+
+#define IS_ALIVE               0x8000
+
+typedef struct pcc_t {
+       char                    *name;
+       u_short                 flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+       { "xnux2", 0 }, { "xnux2", 0 },
+};
+
+static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+       return inl(socket[sock].base + reg);
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+       outl(data, socket[sock].base + reg);
+}
+
+/*======================================================================
+
+       See if a card is present, powered up, in IO mode, and already
+       bound to a (non PC Card) Linux driver.  We leave these alone.
+
+       We make an exception for cards that seem to be serial devices.
+
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+       unsigned int stat;
+       unsigned int f;
+
+       stat = pcc_get(sock, PCIRC);
+       f = (stat & (PCIRC_CDIN1 | PCIRC_CDIN2)) >> 16;
+       if(!f){
+               printk("m32r_pcc: No Card is detected at socket %d : stat = 0x%08x\n",stat,sock);
+               return 0;
+       }
+       if(f!=3)
+               printk("m32r_pcc: Insertion fail (%.8x) at socket %d\n",stat,sock);
+       else
+               printk("m32r_pcc: Card is Inserted at socket %d(%.8x)\n",sock,stat);
+       return 0;
+}
+
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr, ioaddr_t ioaddr)
+{
+       pcc_socket_t *t = &socket[pcc_sockets];
+
+       /* add sockets */
+       t->ioaddr = ioaddr;
+       t->mapaddr = mapaddr;
+       t->base = base;
+#ifdef CHAOS_PCC_DEBUG
+       t->flags = MAP_16BIT;
+#else
+       t->flags = 0;
+#endif
+       if (is_alive(pcc_sockets))
+               t->flags |= IS_ALIVE;
+
+       /* add pcc */
+       if (t->base > 0) {
+               request_region(t->base, 0x20, "m32r-pcc");
+       }
+
+       printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+       printk("pcc at 0x%08lx\n", t->base);
+
+       /* Update socket interrupt information, capabilities */
+       t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+       t->socket.map_size = M32R_PCC_MAPSIZE;
+       t->socket.io_offset = ioaddr;   /* use for io access offset */
+       t->socket.irq_mask = 0;
+       t->socket.pci_irq = 2 + pcc_sockets; /* XXX */
+
+       request_irq(irq, pcc_interrupt, 0, "m32r-pcc", pcc_interrupt);
+
+       pcc_sockets++;
+
+       return;
+}
+
+
+/*====================================================================*/
+
+static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+       int i, j, irc;
+       u_int events, active;
+       int handled = 0;
+
+       debug(4, "m32r: pcc_interrupt(%d)\n", irq);
+
+       for (j = 0; j < 20; j++) {
+               active = 0;
+               for (i = 0; i < pcc_sockets; i++) {
+                       if ((socket[i].cs_irq != irq) &&
+                               (socket[i].socket.pci_irq != irq))
+                               continue;
+                       handled = 1;
+                       irc = pcc_get(i, PCIRC);
+                       irc >>=16;
+                       debug(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc);
+                       if (!irc)
+                               continue;
+
+                       events = (irc) ? SS_DETECT : 0;
+                       events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0;
+                       debug(2, " event 0x%02x\n", events);
+
+                       if (events)
+                               pcmcia_parse_events(&socket[i].socket, events);
+
+                       active |= events;
+                       active = 0;
+               }
+               if (!active) break;
+       }
+       if (j == 20)
+               printk(KERN_NOTICE "m32r-pcc: infinite loop in interrupt handler\n");
+
+       debug(4, "m32r-pcc: interrupt done\n");
+
+       return IRQ_RETVAL(handled);
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+       pcc_interrupt(0, NULL, NULL);
+       init_timer(&poll_timer);
+       poll_timer.expires = jiffies + poll_interval;
+       add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+       u_int status;
+
+       status = pcc_get(sock,PCIRC);
+       *value = ((status & PCIRC_CDIN1) && (status & PCIRC_CDIN2))
+               ? SS_DETECT : 0;
+
+       status = pcc_get(sock,PCCR);
+
+#if 0
+       *value |= (status & PCCR_PCEN) ? SS_READY : 0;
+#else
+       *value |= SS_READY; /* XXX: always */
+#endif
+
+       status = pcc_get(sock,PCCSIGCR);
+       *value |= (status & PCCSIGCR_VEN) ? SS_POWERON : 0;
+
+       debug(3, "m32r-pcc: GetStatus(%d) = %#4.4x\n", sock, *value);
+       return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_get_socket(u_short sock, socket_state_t *state)
+{
+       debug(3, "m32r-pcc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+                 "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+                 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+       return 0;
+} /* _get_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_socket(u_short sock, socket_state_t *state)
+{
+       u_long reg = 0;
+
+       debug(3, "m32r-pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+                 "io_irq %d, csc_mask %#2.2x)", sock, state->flags,
+                 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+       if (state->Vcc) {
+               /*
+                * 5V only
+                */
+               if (state->Vcc == 50) {
+                       reg |= PCCSIGCR_VEN;
+               } else {
+                       return -EINVAL;
+               }
+       }
+
+       if (state->flags & SS_RESET) {
+               debug(3, ":RESET\n");
+               reg |= PCCSIGCR_CRST;
+       }
+       if (state->flags & SS_OUTPUT_ENA){
+               debug(3, ":OUTPUT_ENA\n");
+               /* bit clear */
+       } else {
+               reg |= PCCSIGCR_SEN;
+       }
+
+       pcc_set(sock,PCCSIGCR,reg);
+
+#ifdef DEBUG
+       if(state->flags & SS_IOCARD){
+               debug(3, ":IOCARD");
+       }
+       if (state->flags & SS_PWR_AUTO) {
+               debug(3, ":PWR_AUTO");
+       }
+       if (state->csc_mask & SS_DETECT)
+               debug(3, ":csc-SS_DETECT");
+       if (state->flags & SS_IOCARD) {
+               if (state->csc_mask & SS_STSCHG)
+                       debug(3, ":STSCHG");
+       } else {
+               if (state->csc_mask & SS_BATDEAD)
+                       debug(3, ":BATDEAD");
+               if (state->csc_mask & SS_BATWARN)
+                       debug(3, ":BATWARN");
+               if (state->csc_mask & SS_READY)
+                       debug(3, ":READY");
+       }
+       debug(3, "\n");
+#endif
+       return 0;
+} /* _set_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+       u_char map;
+
+       debug(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, "
+                 "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+                 io->speed, io->start, io->stop);
+       map = io->map;
+
+       return 0;
+} /* _set_io_map */
+
+/*====================================================================*/
+
+static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+       u_char map = mem->map;
+       u_long mode;
+       u_long addr;
+       pcc_socket_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+       pcc_as_t last = t->current_space;
+#endif
+#endif
+
+       debug(3, "m32r-pcc: SetMemMap(%d, %d, %#2.2x, %d ns, "
+                "%#5.5lx,  %#5.5x)\n", sock, map, mem->flags,
+                mem->speed, mem->static_start, mem->card_start);
+
+       /*
+        * sanity check
+        */
+       if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff)){
+               return -EINVAL;
+       }
+
+       /*
+        * de-activate
+        */
+       if ((mem->flags & MAP_ACTIVE) == 0) {
+               t->current_space = as_none;
+               return 0;
+       }
+
+       /*
+        * Disable first
+        */
+       pcc_set(sock, PCCR, 0);
+
+       /*
+        * Set mode
+        */
+       if (mem->flags & MAP_ATTRIB) {
+               mode = PCMOD_AS_ATTRIB | PCMOD_CBSZ;
+               t->current_space = as_attr;
+       } else {
+               mode = 0; /* common memory */
+               t->current_space = as_comm;
+       }
+       pcc_set(sock, PCMOD, mode);
+
+       /*
+        * Set address
+        */
+       addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK);
+       pcc_set(sock, PCADR, addr);
+
+       mem->static_start = addr + mem->card_start;
+
+       /*
+        * Enable again
+        */
+       pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+       if (last != as_attr) {
+#else
+       if (1) {
+#endif
+               dummy_readbuf = *(u_char *)(addr + KSEG1);
+       }
+#endif
+
+       return 0;
+
+} /* _set_mem_map */
+
+#if 0 /* driver model ordering issue */
+/*======================================================================
+
+       Routines for accessing socket information and register dumps via
+       /proc/bus/pccard/...
+
+======================================================================*/
+
+static ssize_t show_info(struct class_device *class_dev, char *buf)
+{
+       pcc_socket_t *s = container_of(class_dev, struct pcc_socket,
+               socket.dev);
+
+       return sprintf(buf, "type:     %s\nbase addr:    0x%08lx\n",
+               pcc[s->type].name, s->base);
+}
+
+static ssize_t show_exca(struct class_device *class_dev, char *buf)
+{
+       /* FIXME */
+
+       return 0;
+}
+
+static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
+static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
+#endif
+
+/*====================================================================*/
+
+/* this is horribly ugly... proper locking needs to be done here at
+ * some time... */
+#define LOCKED(x) do {                                 \
+       int retval;                                     \
+       unsigned long flags;                            \
+       spin_lock_irqsave(&pcc_lock, flags);            \
+       retval = x;                                     \
+       spin_unlock_irqrestore(&pcc_lock, flags);       \
+       return retval;                                  \
+} while (0)
+
+
+static int pcc_get_status(struct pcmcia_socket *s, u_int *value)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE) {
+               *value = 0;
+               return -EINVAL;
+       }
+       LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE)
+               return -EINVAL;
+       LOCKED(_pcc_get_socket(sock, state));
+}
+
+static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE)
+               return -EINVAL;
+
+       LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE)
+               return -EINVAL;
+       LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
+{
+       unsigned int sock = container_of(s, struct pcc_socket, socket)->number;
+
+       if (socket[sock].flags & IS_ALIVE)
+               return -EINVAL;
+       LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(struct pcmcia_socket *s)
+{
+       debug(4, "m32r-pcc: init call\n");
+       return 0;
+}
+
+static int pcc_suspend(struct pcmcia_socket *sock)
+{
+       return pcc_set_socket(sock, &dead_socket);
+}
+
+static struct pccard_operations pcc_operations = {
+       .init                   = pcc_init,
+       .suspend                = pcc_suspend,
+       .get_status             = pcc_get_status,
+       .get_socket             = pcc_get_socket,
+       .set_socket             = pcc_set_socket,
+       .set_io_map             = pcc_set_io_map,
+       .set_mem_map            = pcc_set_mem_map,
+};
+
+/*====================================================================*/
+
+static int m32r_pcc_suspend(struct device *dev, u32 state, u32 level)
+{
+       int ret = 0;
+       if (level == SUSPEND_SAVE_STATE)
+               ret = pcmcia_socket_dev_suspend(dev, state);
+       return ret;
+}
+
+static int m32r_pcc_resume(struct device *dev, u32 level)
+{
+       int ret = 0;
+       if (level == RESUME_RESTORE_STATE)
+               ret = pcmcia_socket_dev_resume(dev);
+       return ret;
+}
+
+
+static struct device_driver pcc_driver = {
+       .name = "pcc",
+       .bus = &platform_bus_type,
+       .suspend = m32r_pcc_suspend,
+       .resume = m32r_pcc_resume,
+};
+
+static struct platform_device pcc_device = {
+       .name = "pcc",
+       .id = 0,
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+       int i, ret;
+
+       ret = driver_register(&pcc_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_device_register(&pcc_device);
+       if (ret){
+               driver_unregister(&pcc_driver);
+               return ret;
+       }
+
+       printk(KERN_INFO "m32r PCC probe:\n");
+
+       pcc_sockets = 0;
+
+       add_pcc_socket(M32R_PCC0_BASE, PCC0_IRQ, M32R_PCC0_MAPBASE, 0x1000);
+
+#ifdef CONFIG_M32RPCC_SLOT2
+       add_pcc_socket(M32R_PCC1_BASE, PCC1_IRQ, M32R_PCC1_MAPBASE, 0x2000);
+#endif
+
+       if (pcc_sockets == 0) {
+               printk("socket is not found.\n");
+               platform_device_unregister(&pcc_device);
+               driver_unregister(&pcc_driver);
+               return -ENODEV;
+       }
+
+       /* Set up interrupt handler(s) */
+
+       for (i = 0 ; i < pcc_sockets ; i++) {
+               socket[i].socket.dev.dev = &pcc_device.dev;
+               socket[i].socket.ops = &pcc_operations;
+               socket[i].socket.owner = THIS_MODULE;
+               socket[i].number = i;
+               ret = pcmcia_register_socket(&socket[i].socket);
+               if (ret && i--) {
+                       for (; i>= 0; i--)
+                               pcmcia_unregister_socket(&socket[i].socket);
+                       break;
+               }
+#if 0  /* driver model ordering issue */
+               class_device_create_file(&socket[i].socket.dev,
+                                        &class_device_attr_info);
+               class_device_create_file(&socket[i].socket.dev,
+                                        &class_device_attr_exca);
+#endif
+       }
+
+       /* Finally, schedule a polling interrupt */
+       if (poll_interval != 0) {
+               poll_timer.function = pcc_interrupt_wrapper;
+               poll_timer.data = 0;
+               init_timer(&poll_timer);
+               poll_timer.expires = jiffies + poll_interval;
+               add_timer(&poll_timer);
+       }
+
+       return 0;
+} /* init_m32r_pcc */
+
+static void __exit exit_m32r_pcc(void)
+{
+       int i;
+
+       for (i = 0; i < pcc_sockets; i++)
+               pcmcia_unregister_socket(&socket[i].socket);
+
+       platform_device_unregister(&pcc_device);
+       if (poll_interval != 0)
+               del_timer_sync(&poll_timer);
+
+       driver_unregister(&pcc_driver);
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+MODULE_LICENSE("Dual MPL/GPL");
+/*====================================================================*/
diff --git a/drivers/pcmcia/m32r_pcc.h b/drivers/pcmcia/m32r_pcc.h
new file mode 100644 (file)
index 0000000..e4fffe4
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+#define M32R_MAX_PCC   2
+
+/*
+ * M32R PC Card Controler
+ */
+#define M32R_PCC0_BASE        0x00ef7000
+#define M32R_PCC1_BASE        0x00ef7020
+
+/*
+ * Register offsets
+ */
+#define PCCR            0x00
+#define PCADR           0x04
+#define PCMOD           0x08
+#define PCIRC           0x0c
+#define PCCSIGCR        0x10
+#define PCATCR          0x14
+
+/*
+ * PCCR
+ */
+#define PCCR_PCEN       (1UL<<(31-31))
+
+/*
+ * PCIRC
+ */
+#define PCIRC_BWERR     (1UL<<(31-7))
+#define PCIRC_CDIN1     (1UL<<(31-14))
+#define PCIRC_CDIN2     (1UL<<(31-15))
+#define PCIRC_BEIEN     (1UL<<(31-23))
+#define PCIRC_CIIEN     (1UL<<(31-30))
+#define PCIRC_COIEN     (1UL<<(31-31))
+
+/*
+ * PCCSIGCR
+ */
+#define PCCSIGCR_SEN    (1UL<<(31-3))
+#define PCCSIGCR_VEN    (1UL<<(31-7))
+#define PCCSIGCR_CRST   (1UL<<(31-15))
+#define PCCSIGCR_COCR   (1UL<<(31-31))
+
+/*
+ *
+ */
+#define PCMOD_AS_ATTRIB        (1UL<<(31-19))
+#define PCMOD_AS_IO    (1UL<<(31-18))
+
+#define PCMOD_CBSZ     (1UL<<(31-23)) /* set for 8bit */
+
+#define PCMOD_DBEX     (1UL<<(31-31)) /* set for excahnge */
+
+/*
+ * M32R PCC Map addr
+ */
+#define M32R_PCC0_MAPBASE        0x14000000
+#define M32R_PCC1_MAPBASE        0x16000000
+
+#define M32R_PCC_MAPMAX                 0x02000000
+
+#define M32R_PCC_MAPSIZE        0x00001000 /* XXX */
+#define M32R_PCC_MAPMASK       (~(M32R_PCC_MAPMAX-1))
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c
new file mode 100644 (file)
index 0000000..673d345
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * PCMCIA 16-bit compatibility 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) 2004 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/init.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"
+
+int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_get_first_tuple(s, handle->Function, tuple);
+}
+EXPORT_SYMBOL(pcmcia_get_first_tuple);
+
+int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_get_next_tuple(s, handle->Function, tuple);
+}
+EXPORT_SYMBOL(pcmcia_get_next_tuple);
+
+int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_get_tuple_data(s, tuple);
+}
+EXPORT_SYMBOL(pcmcia_get_tuple_data);
+
+int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+       return pccard_parse_tuple(tuple, parse);
+}
+EXPORT_SYMBOL(pcmcia_parse_tuple);
+
+int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
+{
+       struct pcmcia_socket *s;
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       s = SOCKET(handle);
+       return pccard_validate_cis(s, handle->Function, 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)
+{
+       struct pcmcia_socket *skt;
+    
+       if (CHECK_HANDLE(handle))
+               return CS_BAD_HANDLE;
+       skt = SOCKET(handle);
+       if (!skt)
+               return CS_BAD_HANDLE;
+
+       return pccard_reset_card(skt);
+}
+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);
+
+#ifdef CONFIG_PCMCIA_OBSOLETE
+
+int pcmcia_get_first_window(window_handle_t *win, win_req_t *req)
+{
+    if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC))
+       return CS_BAD_HANDLE;
+
+    return pcmcia_get_window(((client_handle_t)*win)->Socket, win, 0, req);
+}
+EXPORT_SYMBOL(pcmcia_get_first_window);
+
+int pcmcia_get_next_window(window_handle_t *win, win_req_t *req)
+{
+    if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC))
+       return CS_BAD_HANDLE;
+    return pcmcia_get_window((*win)->sock, win, (*win)->index+1, req);
+}
+EXPORT_SYMBOL(pcmcia_get_next_window);
+
+#endif
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
new file mode 100644 (file)
index 0000000..0782cdc
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Plug and Play ACPI configuration
+#
+config PNPACPI
+       bool "Plug and Play ACPI support (EXPERIMENTAL)"
+       depends on PNP && ACPI_BUS && EXPERIMENTAL
+       default y
+       ---help---
+         Linux uses the PNPACPI to autodetect built-in
+         mainboard resources (e.g. parallel port resources).
+
+          Some features (e.g. real hotplug) are not currently
+          implemented.
+
+          If you would like the kernel to detect and allocate resources to
+          your mainboard devices (on some systems they are disabled by the
+          BIOS) say Y here.  Also the PNPACPI can help prevent resource
+          conflicts between mainboard devices and other bus devices.
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
new file mode 100644 (file)
index 0000000..905326f
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the kernel PNPACPI driver.
+#
+
+obj-y := core.o rsparser.o
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
new file mode 100644 (file)
index 0000000..9a9352f
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * pnpacpi -- PnP ACPI driver
+ *
+ * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/acpi.h>
+#include <linux/pnp.h>
+#include <acpi/acpi_bus.h>
+#include "pnpacpi.h"
+
+static int num = 0;
+
+static char __initdata excluded_id_list[] =
+       "PNP0C0A," /* Battery */
+       "PNP0C0C,PNP0C0E,PNP0C0D," /* Button */
+       "PNP0C09," /* EC */
+       "PNP0C0B," /* Fan */
+       "PNP0A03," /* PCI root */
+       "PNP0C0F," /* Link device */
+       "PNP0000," /* PIC */
+       "PNP0100," /* Timer */
+       ;
+static inline int is_exclusive_device(struct acpi_device *dev)
+{
+       return (!acpi_match_ids(dev, excluded_id_list));
+}
+
+void *pnpacpi_kmalloc(size_t size, int f)
+{
+       void *p = kmalloc(size, f);
+       if (p)
+               memset(p, 0, size);
+       return p;
+}
+
+/*
+ * Compatible Device IDs
+ */
+#define TEST_HEX(c) \
+       if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
+               return 0
+#define TEST_ALPHA(c) \
+       if (!('@' <= (c) || (c) <= 'Z')) \
+               return 0
+static int __init ispnpidacpi(char *id)
+{
+       TEST_ALPHA(id[0]);
+       TEST_ALPHA(id[1]);
+       TEST_ALPHA(id[2]);
+       TEST_HEX(id[3]);
+       TEST_HEX(id[4]);
+       TEST_HEX(id[5]);
+       TEST_HEX(id[6]);
+       if (id[7] != '\0')
+               return 0;
+       return 1;
+}
+
+static void __init pnpidacpi_to_pnpid(char *id, char *str)
+{
+       str[0] = id[0];
+       str[1] = id[1];
+       str[2] = id[2];
+       str[3] = tolower(id[3]);
+       str[4] = tolower(id[4]);
+       str[5] = tolower(id[5]);
+       str[6] = tolower(id[6]);
+       str[7] = '\0';
+}
+
+static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+{
+       acpi_status status;
+       status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data, 
+               &dev->res);
+       return ACPI_FAILURE(status) ? -ENODEV : 0;
+}
+
+static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+{
+       acpi_handle handle = dev->data;
+       struct acpi_buffer buffer;
+       int ret = 0;
+       acpi_status status;
+
+       ret = pnpacpi_build_resource_template(handle, &buffer);
+       if (ret)
+               return ret;
+       ret = pnpacpi_encode_resources(res, &buffer);
+       if (ret) {
+               kfree(buffer.pointer);
+               return ret;
+       }
+       status = acpi_set_current_resources(handle, &buffer);
+       if (ACPI_FAILURE(status))
+               ret = -EINVAL;
+       kfree(buffer.pointer);
+       return ret;
+}
+
+static int pnpacpi_disable_resources(struct pnp_dev *dev)
+{
+       acpi_status status;
+       
+       /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
+       status = acpi_evaluate_object((acpi_handle)dev->data, 
+               "_DIS", NULL, NULL);
+       return ACPI_FAILURE(status) ? -ENODEV : 0;
+}
+
+struct pnp_protocol pnpacpi_protocol = {
+       .name   = "Plug and Play ACPI",
+       .get    = pnpacpi_get_resources,
+       .set    = pnpacpi_set_resources,
+       .disable = pnpacpi_disable_resources,
+};
+
+static int __init pnpacpi_add_device(struct acpi_device *device)
+{
+       acpi_handle temp = NULL;
+       acpi_status status;
+       struct pnp_id *dev_id;
+       struct pnp_dev *dev;
+
+       if (!ispnpidacpi(acpi_device_hid(device)) ||
+               is_exclusive_device(device))
+               return 0;
+
+       pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
+       dev =  pnpacpi_kmalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+       if (!dev) {
+               pnp_err("Out of memory");
+               return -ENOMEM;
+       }
+       dev->data = device->handle;
+       /* .enabled means if the device can decode the resources */
+       dev->active = device->status.enabled;
+       status = acpi_get_handle(device->handle, "_SRS", &temp);
+       if (ACPI_SUCCESS(status))
+               dev->capabilities |= PNP_CONFIGURABLE;
+       dev->capabilities |= PNP_READ;
+       if (device->flags.dynamic_status)
+               dev->capabilities |= PNP_WRITE;
+       if (device->flags.removable)
+               dev->capabilities |= PNP_REMOVABLE;
+       status = acpi_get_handle(device->handle, "_DIS", &temp);
+       if (ACPI_SUCCESS(status))
+               dev->capabilities |= PNP_DISABLE;
+
+       dev->protocol = &pnpacpi_protocol;
+
+       if (strlen(acpi_device_name(device)))
+               strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
+       else
+               strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
+
+       dev->number = num;
+       
+       /* set the initial values for the PnP device */
+       dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
+       if (!dev_id)
+               goto err;
+       pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
+       pnp_add_id(dev_id, dev);
+
+       if(dev->active) {
+               /* parse allocated resource */
+               status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
+               if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+                       pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", dev_id->id);
+                       goto err1;
+               }
+       }
+
+       if(dev->capabilities & PNP_CONFIGURABLE) {
+               status = pnpacpi_parse_resource_option_data(device->handle, 
+                       dev);
+               if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+                       pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
+                       goto err1;
+               }
+       }
+       
+       /* parse compatible ids */
+       if (device->flags.compatible_ids) {
+               struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+               int i;
+
+               for (i = 0; i < cid_list->count; i++) {
+                       if (!ispnpidacpi(cid_list->id[i].value))
+                               continue;
+                       dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), 
+                               GFP_KERNEL);
+                       if (!dev_id)
+                               continue;
+
+                       pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
+                       pnp_add_id(dev_id, dev);
+               }
+       }
+
+       /* clear out the damaged flags */
+       if (!dev->active)
+               pnp_init_resource_table(&dev->res);
+       pnp_add_device(dev);
+       num ++;
+
+       return AE_OK;
+err1:
+       kfree(dev_id);
+err:
+       kfree(dev);
+       return -EINVAL;
+}
+
+static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
+       u32 lvl, void *context, void **rv)
+{
+       struct acpi_device *device;
+
+       if (!acpi_bus_get_device(handle, &device))
+               pnpacpi_add_device(device);
+       return AE_OK;
+}
+
+int __init pnpacpi_init(void)
+{
+       if (acpi_disabled) {
+               pnp_info("PnP ACPI: ACPI disable");
+               return 0;
+       }
+       pnp_info("PnP ACPI init");
+       pnp_register_protocol(&pnpacpi_protocol);
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+                       ACPI_UINT32_MAX, pnpacpi_add_device_handler,
+                       NULL, NULL);
+       pnp_info("PnP ACPI: found %d devices", num);
+       return 0;
+}
+subsys_initcall(pnpacpi_init);
+
+EXPORT_SYMBOL(pnpacpi_protocol);
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
new file mode 100644 (file)
index 0000000..76f907e
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef ACPI_PNP_H
+#define ACPI_PNP_H
+
+#include <acpi/acpi_bus.h>
+#include <linux/acpi.h>
+#include <linux/pnp.h>
+
+void *pnpacpi_kmalloc(size_t size, int f);
+acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
+acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
+int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
+int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*);
+#endif
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
new file mode 100644 (file)
index 0000000..df102f9
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * pnpacpi -- PnP ACPI driver
+ *
+ * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include "pnpacpi.h"
+
+#ifdef CONFIG_IA64
+#define valid_IRQ(i) (1)
+#else
+#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
+#endif
+
+/*
+ * Allocated Resources
+ */
+static int irq_flags(int edge_level, int active_high_low)
+{
+       int flag;
+       if (edge_level == ACPI_LEVEL_SENSITIVE) {
+               if(active_high_low == ACPI_ACTIVE_LOW)
+                       flag = IORESOURCE_IRQ_LOWLEVEL;
+               else
+                       flag = IORESOURCE_IRQ_HIGHLEVEL;
+       }
+       else {
+               if(active_high_low == ACPI_ACTIVE_LOW)
+                       flag = IORESOURCE_IRQ_LOWEDGE;
+               else
+                       flag = IORESOURCE_IRQ_HIGHEDGE;
+       }
+       return flag;
+}
+
+static void decode_irq_flags(int flag, int *edge_level, int *active_high_low)
+{
+       switch (flag) {
+       case IORESOURCE_IRQ_LOWLEVEL:
+               *edge_level = ACPI_LEVEL_SENSITIVE;
+               *active_high_low = ACPI_ACTIVE_LOW;
+               break;
+       case IORESOURCE_IRQ_HIGHLEVEL:  
+               *edge_level = ACPI_LEVEL_SENSITIVE;
+               *active_high_low = ACPI_ACTIVE_HIGH;
+               break;
+       case IORESOURCE_IRQ_LOWEDGE:
+               *edge_level = ACPI_EDGE_SENSITIVE;
+               *active_high_low = ACPI_ACTIVE_LOW;
+               break;
+       case IORESOURCE_IRQ_HIGHEDGE:
+               *edge_level = ACPI_EDGE_SENSITIVE;
+               *active_high_low = ACPI_ACTIVE_HIGH;
+               break;
+       }
+}
+
+static void
+pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
+{
+       int i = 0;
+       while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
+                       i < PNP_MAX_IRQ)
+               i++;
+       if (i < PNP_MAX_IRQ) {
+               res->irq_resource[i].flags = IORESOURCE_IRQ;  //Also clears _UNSET flag
+               if (irq == -1) {
+                       res->irq_resource[i].flags |= IORESOURCE_DISABLED;
+                       return;
+               }
+               res->irq_resource[i].start =(unsigned long) irq;
+               res->irq_resource[i].end = (unsigned long) irq;
+       }
+}
+
+static void
+pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
+{
+       int i = 0;
+       while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) &&
+                       i < PNP_MAX_DMA)
+               i++;
+       if (i < PNP_MAX_DMA) {
+               res->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
+               if (dma == -1) {
+                       res->dma_resource[i].flags |= IORESOURCE_DISABLED;
+                       return;
+               }
+               res->dma_resource[i].start =(unsigned long) dma;
+               res->dma_resource[i].end = (unsigned long) dma;
+       }
+}
+
+static void
+pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
+       int io, int len)
+{
+       int i = 0;
+       while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
+                       i < PNP_MAX_PORT)
+               i++;
+       if (i < PNP_MAX_PORT) {
+               res->port_resource[i].flags = IORESOURCE_IO;  // Also clears _UNSET flag
+               if (len <= 0 || (io + len -1) >= 0x10003) {
+                       res->port_resource[i].flags |= IORESOURCE_DISABLED;
+                       return;
+               }
+               res->port_resource[i].start = (unsigned long) io;
+               res->port_resource[i].end = (unsigned long)(io + len - 1);
+       }
+}
+
+static void
+pnpacpi_parse_allocated_memresource(struct pnp_resource_table * res,
+       int mem, int len)
+{
+       int i = 0;
+       while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
+                       (i < PNP_MAX_MEM))
+               i++;
+       if (i < PNP_MAX_MEM) {
+               res->mem_resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
+               if (len <= 0) {
+                       res->mem_resource[i].flags |= IORESOURCE_DISABLED;
+                       return;
+               }
+               res->mem_resource[i].start = (unsigned long) mem;
+               res->mem_resource[i].end = (unsigned long)(mem + len - 1);
+       }
+}
+
+
+static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
+       void *data)
+{
+       struct pnp_resource_table * res_table = (struct pnp_resource_table *)data;
+
+       switch (res->id) {
+       case ACPI_RSTYPE_IRQ:
+               if ((res->data.irq.number_of_interrupts > 0) &&
+                       valid_IRQ(res->data.irq.interrupts[0])) {
+                       pnpacpi_parse_allocated_irqresource(res_table, 
+                               acpi_register_gsi(res->data.irq.interrupts[0],
+                                       res->data.irq.edge_level,
+                                       res->data.irq.active_high_low));
+                       pcibios_penalize_isa_irq(res->data.irq.interrupts[0]);
+               }
+               break;
+
+       case ACPI_RSTYPE_EXT_IRQ:
+               if ((res->data.extended_irq.number_of_interrupts > 0) &&
+                       valid_IRQ(res->data.extended_irq.interrupts[0])) {
+                       pnpacpi_parse_allocated_irqresource(res_table, 
+                               acpi_register_gsi(res->data.extended_irq.interrupts[0],
+                                       res->data.extended_irq.edge_level,
+                                       res->data.extended_irq.active_high_low));
+                       pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0]);
+               }
+               break;
+       case ACPI_RSTYPE_DMA:
+               if (res->data.dma.number_of_channels > 0)
+                       pnpacpi_parse_allocated_dmaresource(res_table, 
+                                       res->data.dma.channels[0]);
+               break;
+       case ACPI_RSTYPE_IO:
+               pnpacpi_parse_allocated_ioresource(res_table, 
+                               res->data.io.min_base_address, 
+                               res->data.io.range_length);
+               break;
+       case ACPI_RSTYPE_FIXED_IO:
+               pnpacpi_parse_allocated_ioresource(res_table, 
+                               res->data.fixed_io.base_address, 
+                               res->data.fixed_io.range_length);
+               break;
+       case ACPI_RSTYPE_MEM24:
+               pnpacpi_parse_allocated_memresource(res_table, 
+                               res->data.memory24.min_base_address, 
+                               res->data.memory24.range_length);
+               break;
+       case ACPI_RSTYPE_MEM32:
+               pnpacpi_parse_allocated_memresource(res_table, 
+                               res->data.memory32.min_base_address, 
+                               res->data.memory32.range_length);
+               break;
+       case ACPI_RSTYPE_FIXED_MEM32:
+               pnpacpi_parse_allocated_memresource(res_table, 
+                               res->data.fixed_memory32.range_base_address, 
+                               res->data.fixed_memory32.range_length);
+               break;
+       case ACPI_RSTYPE_ADDRESS16:
+               pnpacpi_parse_allocated_memresource(res_table, 
+                               res->data.address16.min_address_range, 
+                               res->data.address16.address_length);
+               break;
+       case ACPI_RSTYPE_ADDRESS32:
+               pnpacpi_parse_allocated_memresource(res_table, 
+                               res->data.address32.min_address_range, 
+                               res->data.address32.address_length);
+               break;
+       case ACPI_RSTYPE_ADDRESS64:
+               pnpacpi_parse_allocated_memresource(res_table, 
+               res->data.address64.min_address_range, 
+               res->data.address64.address_length);
+               break;
+       default:
+               pnp_warn("PnPACPI: Alloc type : %d not handle", 
+                               res->id);
+               return AE_ERROR;
+       }
+                       
+       return AE_OK;
+}
+
+acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table * res)
+{
+       /* Blank the resource table values */
+       pnp_init_resource_table(res);
+
+       return acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_allocated_resource, res);
+}
+
+static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_resource_dma *p)
+{
+       int i;
+       struct pnp_dma * dma;
+
+       if (p->number_of_channels == 0)
+               return;
+       dma = pnpacpi_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
+       if (!dma)
+               return;
+
+       for(i = 0; i < p->number_of_channels; i++)
+               dma->map |= 1 << p->channels[i];
+       dma->flags = 0;
+       if (p->bus_master)
+               dma->flags |= IORESOURCE_DMA_MASTER;
+       switch (p->type) {
+       case ACPI_COMPATIBILITY:
+               dma->flags |= IORESOURCE_DMA_COMPATIBLE;
+               break;
+       case ACPI_TYPE_A:
+               dma->flags |= IORESOURCE_DMA_TYPEA;
+               break;
+       case ACPI_TYPE_B:
+               dma->flags |= IORESOURCE_DMA_TYPEB;
+               break;
+       case ACPI_TYPE_F:
+               dma->flags |= IORESOURCE_DMA_TYPEF;
+               break;
+       default:
+               /* Set a default value ? */
+               dma->flags |= IORESOURCE_DMA_COMPATIBLE;
+               pnp_err("Invalid DMA type");
+       }
+       switch (p->transfer) {
+       case ACPI_TRANSFER_8:
+               dma->flags |= IORESOURCE_DMA_8BIT;
+               break;
+       case ACPI_TRANSFER_8_16:
+               dma->flags |= IORESOURCE_DMA_8AND16BIT;
+               break;
+       case ACPI_TRANSFER_16:
+               dma->flags |= IORESOURCE_DMA_16BIT;
+               break;
+       default:
+               /* Set a default value ? */
+               dma->flags |= IORESOURCE_DMA_8AND16BIT;
+               pnp_err("Invalid DMA transfer type");
+       }
+
+       pnp_register_dma_resource(option,dma);
+       return;
+}
+
+       
+static void pnpacpi_parse_irq_option(struct pnp_option *option,
+       struct acpi_resource_irq *p)
+{
+       int i;
+       struct pnp_irq * irq;
+       
+       if (p->number_of_interrupts == 0)
+               return;
+       irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+       if (!irq)
+               return;
+
+       for(i = 0; i < p->number_of_interrupts; i++)
+               if (p->interrupts[i])
+                       __set_bit(p->interrupts[i], irq->map);
+       irq->flags = irq_flags(p->edge_level, p->active_high_low);
+
+       pnp_register_irq_resource(option, irq);
+       return;
+}
+
+static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+       struct acpi_resource_ext_irq *p)
+{
+       int i;
+       struct pnp_irq * irq;
+
+       if (p->number_of_interrupts == 0)
+               return;
+       irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
+       if (!irq)
+               return;
+
+       for(i = 0; i < p->number_of_interrupts; i++)
+               if (p->interrupts[i])
+                       __set_bit(p->interrupts[i], irq->map);
+       irq->flags = irq_flags(p->edge_level, p->active_high_low);
+
+       pnp_register_irq_resource(option, irq);
+       return;
+}
+
+static void
+pnpacpi_parse_port_option(struct pnp_option *option,
+       struct acpi_resource_io *io)
+{
+       struct pnp_port * port;
+
+       if (io->range_length == 0)
+               return;
+       port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+       if (!port)
+               return;
+       port->min = io->min_base_address;
+       port->max = io->max_base_address;
+       port->align = io->alignment;
+       port->size = io->range_length;
+       port->flags = ACPI_DECODE_16 == io->io_decode ? 
+               PNP_PORT_FLAG_16BITADDR : 0;
+       pnp_register_port_resource(option,port);
+       return;
+}
+
+static void
+pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+       struct acpi_resource_fixed_io *io)
+{
+       struct pnp_port * port;
+
+       if (io->range_length == 0)
+               return;
+       port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
+       if (!port)
+               return;
+       port->min = port->max = io->base_address;
+       port->size = io->range_length;
+       port->align = 0;
+       port->flags = PNP_PORT_FLAG_FIXED;
+       pnp_register_port_resource(option,port);
+       return;
+}
+
+static void
+pnpacpi_parse_mem24_option(struct pnp_option *option,
+       struct acpi_resource_mem24 *p)
+{
+       struct pnp_mem * mem;
+
+       if (p->range_length == 0)
+               return;
+       mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       if (!mem)
+               return;
+       mem->min = p->min_base_address;
+       mem->max = p->max_base_address;
+       mem->align = p->alignment;
+       mem->size = p->range_length;
+
+       mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
+                       IORESOURCE_MEM_WRITEABLE : 0;
+
+       pnp_register_mem_resource(option,mem);
+       return;
+}
+
+static void
+pnpacpi_parse_mem32_option(struct pnp_option *option,
+       struct acpi_resource_mem32 *p)
+{
+       struct pnp_mem * mem;
+
+       if (p->range_length == 0)
+               return;
+       mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       if (!mem)
+               return;
+       mem->min = p->min_base_address;
+       mem->max = p->max_base_address;
+       mem->align = p->alignment;
+       mem->size = p->range_length;
+
+       mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
+                       IORESOURCE_MEM_WRITEABLE : 0;
+
+       pnp_register_mem_resource(option,mem);
+       return;
+}
+
+static void
+pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+       struct acpi_resource_fixed_mem32 *p)
+{
+       struct pnp_mem * mem;
+
+       if (p->range_length == 0)
+               return;
+       mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
+       if (!mem)
+               return;
+       mem->min = mem->max = p->range_base_address;
+       mem->size = p->range_length;
+       mem->align = 0;
+
+       mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
+                       IORESOURCE_MEM_WRITEABLE : 0;
+
+       pnp_register_mem_resource(option,mem);
+       return;
+}
+
+struct acpipnp_parse_option_s {
+       struct pnp_option *option;
+       struct pnp_dev *dev;
+};
+
+static acpi_status pnpacpi_option_resource(struct acpi_resource *res, 
+       void *data)
+{
+       int priority = 0;
+       struct acpipnp_parse_option_s *parse_data = (struct acpipnp_parse_option_s *)data;
+       struct pnp_dev *dev = parse_data->dev;
+       struct pnp_option *option = parse_data->option;
+
+       switch (res->id) {
+               case ACPI_RSTYPE_IRQ:
+                       pnpacpi_parse_irq_option(option, &res->data.irq);
+                       break;
+               case ACPI_RSTYPE_EXT_IRQ:
+                       pnpacpi_parse_ext_irq_option(option,
+                               &res->data.extended_irq);
+                       break;
+               case ACPI_RSTYPE_DMA:
+                       pnpacpi_parse_dma_option(option, &res->data.dma);       
+                       break;
+               case ACPI_RSTYPE_IO:
+                       pnpacpi_parse_port_option(option, &res->data.io);
+                       break;
+               case ACPI_RSTYPE_FIXED_IO:
+                       pnpacpi_parse_fixed_port_option(option,
+                               &res->data.fixed_io);
+                       break;
+               case ACPI_RSTYPE_MEM24:
+                       pnpacpi_parse_mem24_option(option, &res->data.memory24);
+                       break;
+               case ACPI_RSTYPE_MEM32:
+                       pnpacpi_parse_mem32_option(option, &res->data.memory32);
+                       break;
+               case ACPI_RSTYPE_FIXED_MEM32:
+                       pnpacpi_parse_fixed_mem32_option(option,
+                               &res->data.fixed_memory32);
+                       break;
+               case ACPI_RSTYPE_START_DPF:
+                       switch (res->data.start_dpf.compatibility_priority) {
+                               case ACPI_GOOD_CONFIGURATION:
+                                       priority = PNP_RES_PRIORITY_PREFERRED;
+                                       break;
+                                       
+                               case ACPI_ACCEPTABLE_CONFIGURATION:
+                                       priority = PNP_RES_PRIORITY_ACCEPTABLE;
+                                       break;
+
+                               case ACPI_SUB_OPTIMAL_CONFIGURATION:
+                                       priority = PNP_RES_PRIORITY_FUNCTIONAL;
+                                       break;
+                               default:
+                                       priority = PNP_RES_PRIORITY_INVALID;
+                                       break;
+                       }
+                       /* TBD: Considering performace/robustness bits */
+                       option = pnp_register_dependent_option(dev, priority);
+                       if (!option)
+                               return AE_ERROR;
+                       parse_data->option = option;    
+                       break;
+               case ACPI_RSTYPE_END_DPF:
+                       return AE_CTRL_TERMINATE;
+               default:
+                       pnp_warn("PnPACPI:Option type: %d not handle", res->id);
+                       return AE_ERROR;
+       }
+                       
+       return AE_OK;
+}
+
+acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle, 
+       struct pnp_dev *dev)
+{
+       acpi_status status;
+       struct acpipnp_parse_option_s parse_data;
+
+       parse_data.option = pnp_register_independent_option(dev);
+       if (!parse_data.option)
+               return AE_ERROR;
+       parse_data.dev = dev;
+       status = acpi_walk_resources(handle, METHOD_NAME__PRS, 
+               pnpacpi_option_resource, &parse_data);
+
+       return status;
+}
+
+/*
+ * Set resource
+ */
+static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
+       void *data)
+{
+       int *res_cnt = (int *)data;
+       switch (res->id) {
+       case ACPI_RSTYPE_IRQ:
+       case ACPI_RSTYPE_EXT_IRQ:
+       case ACPI_RSTYPE_DMA:
+       case ACPI_RSTYPE_IO:
+       case ACPI_RSTYPE_FIXED_IO:
+       case ACPI_RSTYPE_MEM24:
+       case ACPI_RSTYPE_MEM32:
+       case ACPI_RSTYPE_FIXED_MEM32:
+#if 0
+       case ACPI_RSTYPE_ADDRESS16:
+       case ACPI_RSTYPE_ADDRESS32:
+       case ACPI_RSTYPE_ADDRESS64:
+#endif
+               (*res_cnt) ++;
+       default:
+               return AE_OK;
+       }
+       return AE_OK;
+}
+
+static acpi_status pnpacpi_type_resources(struct acpi_resource *res,
+       void *data)
+{
+       struct acpi_resource **resource = (struct acpi_resource **)data;        
+       switch (res->id) {
+       case ACPI_RSTYPE_IRQ:
+       case ACPI_RSTYPE_EXT_IRQ:
+       case ACPI_RSTYPE_DMA:
+       case ACPI_RSTYPE_IO:
+       case ACPI_RSTYPE_FIXED_IO:
+       case ACPI_RSTYPE_MEM24:
+       case ACPI_RSTYPE_MEM32:
+       case ACPI_RSTYPE_FIXED_MEM32:
+#if 0
+       case ACPI_RSTYPE_ADDRESS16:
+       case ACPI_RSTYPE_ADDRESS32:
+       case ACPI_RSTYPE_ADDRESS64:
+#endif
+               (*resource)->id = res->id;
+               (*resource)++;
+       default:
+               return AE_OK;
+       }
+
+       return AE_OK;
+}
+
+int pnpacpi_build_resource_template(acpi_handle handle, 
+       struct acpi_buffer *buffer)
+{
+       struct acpi_resource *resource;
+       int res_cnt = 0;
+       acpi_status status;
+
+       status = acpi_walk_resources(handle, METHOD_NAME__CRS, 
+               pnpacpi_count_resources, &res_cnt);
+       if (ACPI_FAILURE(status)) {
+               pnp_err("Evaluate _CRS failed");
+               return -EINVAL;
+       }
+       if (!res_cnt)
+               return -EINVAL;
+       buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
+       buffer->pointer = pnpacpi_kmalloc(buffer->length - 1, GFP_KERNEL);
+       if (!buffer->pointer)
+               return -ENOMEM;
+       pnp_dbg("Res cnt %d", res_cnt);
+       resource = (struct acpi_resource *)buffer->pointer;
+       status = acpi_walk_resources(handle, METHOD_NAME__CRS, 
+               pnpacpi_type_resources, &resource);
+       if (ACPI_FAILURE(status)) {
+               kfree(buffer->pointer);
+               pnp_err("Evaluate _CRS failed");
+               return -EINVAL;
+       }
+       /* resource will pointer the end resource now */
+       resource->id = ACPI_RSTYPE_END_TAG;
+
+       return 0;
+}
+
+static void pnpacpi_encode_irq(struct acpi_resource *resource, 
+       struct resource *p)
+{
+       int edge_level, active_high_low;
+       
+       decode_irq_flags(p->flags & IORESOURCE_BITS, &edge_level, 
+               &active_high_low);
+       resource->id = ACPI_RSTYPE_IRQ;
+       resource->length = sizeof(struct acpi_resource);
+       resource->data.irq.edge_level = edge_level;
+       resource->data.irq.active_high_low = active_high_low;
+       if (edge_level == ACPI_EDGE_SENSITIVE)
+               resource->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+       else
+               resource->data.irq.shared_exclusive = ACPI_SHARED;
+       resource->data.irq.number_of_interrupts = 1;
+       resource->data.irq.interrupts[0] = p->start;
+}
+
+static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
+       struct resource *p)
+{
+       int edge_level, active_high_low;
+       
+       decode_irq_flags(p->flags & IORESOURCE_BITS, &edge_level, 
+               &active_high_low);
+       resource->id = ACPI_RSTYPE_EXT_IRQ;
+       resource->length = sizeof(struct acpi_resource);
+       resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
+       resource->data.extended_irq.edge_level = edge_level;
+       resource->data.extended_irq.active_high_low = active_high_low;
+       if (edge_level == ACPI_EDGE_SENSITIVE)
+               resource->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+       else
+               resource->data.irq.shared_exclusive = ACPI_SHARED;
+       resource->data.extended_irq.number_of_interrupts = 1;
+       resource->data.extended_irq.interrupts[0] = p->start;
+}
+
+static void pnpacpi_encode_dma(struct acpi_resource *resource,
+       struct resource *p)
+{
+       resource->id = ACPI_RSTYPE_DMA;
+       resource->length = sizeof(struct acpi_resource);
+       /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
+       if (p->flags & IORESOURCE_DMA_COMPATIBLE)
+               resource->data.dma.type = ACPI_COMPATIBILITY;
+       else if (p->flags & IORESOURCE_DMA_TYPEA)
+               resource->data.dma.type = ACPI_TYPE_A;
+       else if (p->flags & IORESOURCE_DMA_TYPEB)
+               resource->data.dma.type = ACPI_TYPE_B;
+       else if (p->flags & IORESOURCE_DMA_TYPEF)
+               resource->data.dma.type = ACPI_TYPE_F;
+       if (p->flags & IORESOURCE_DMA_8BIT)
+               resource->data.dma.transfer = ACPI_TRANSFER_8;
+       else if (p->flags & IORESOURCE_DMA_8AND16BIT)
+               resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+       else if (p->flags & IORESOURCE_DMA_16BIT)
+               resource->data.dma.transfer = ACPI_TRANSFER_16;
+       resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
+       resource->data.dma.number_of_channels = 1;
+       resource->data.dma.channels[0] = p->start;
+}
+
+static void pnpacpi_encode_io(struct acpi_resource *resource,
+       struct resource *p)
+{
+       resource->id = ACPI_RSTYPE_IO;
+       resource->length = sizeof(struct acpi_resource);
+       /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
+       resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
+               ACPI_DECODE_16 : ACPI_DECODE_10; 
+       resource->data.io.min_base_address = p->start;
+       resource->data.io.max_base_address = p->end;
+       resource->data.io.alignment = 0; /* Correct? */
+       resource->data.io.range_length = p->end - p->start + 1;
+}
+
+static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
+       struct resource *p)
+{
+       resource->id = ACPI_RSTYPE_FIXED_IO;
+       resource->length = sizeof(struct acpi_resource);
+       resource->data.fixed_io.base_address = p->start;
+       resource->data.fixed_io.range_length = p->end - p->start + 1;
+}
+
+static void pnpacpi_encode_mem24(struct acpi_resource *resource,
+       struct resource *p)
+{
+       resource->id = ACPI_RSTYPE_MEM24;
+       resource->length = sizeof(struct acpi_resource);
+       /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
+       resource->data.memory24.read_write_attribute =
+               (p->flags & IORESOURCE_MEM_WRITEABLE) ?
+               ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+       resource->data.memory24.min_base_address = p->start;
+       resource->data.memory24.max_base_address = p->end;
+       resource->data.memory24.alignment = 0;
+       resource->data.memory24.range_length = p->end - p->start + 1;
+}
+
+static void pnpacpi_encode_mem32(struct acpi_resource *resource,
+       struct resource *p)
+{
+       resource->id = ACPI_RSTYPE_MEM32;
+       resource->length = sizeof(struct acpi_resource);
+       resource->data.memory32.read_write_attribute =
+               (p->flags & IORESOURCE_MEM_WRITEABLE) ?
+               ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+       resource->data.memory32.min_base_address = p->start;
+       resource->data.memory32.max_base_address = p->end;
+       resource->data.memory32.alignment = 0;
+       resource->data.memory32.range_length = p->end - p->start + 1;
+}
+
+static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
+       struct resource *p)
+{
+       resource->id = ACPI_RSTYPE_FIXED_MEM32;
+       resource->length = sizeof(struct acpi_resource);
+       resource->data.fixed_memory32.read_write_attribute =
+               (p->flags & IORESOURCE_MEM_WRITEABLE) ?
+               ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+       resource->data.fixed_memory32.range_base_address = p->start;
+       resource->data.fixed_memory32.range_length = p->end - p->start + 1;
+}
+
+int pnpacpi_encode_resources(struct pnp_resource_table *res_table, 
+       struct acpi_buffer *buffer)
+{
+       int i = 0;
+       /* pnpacpi_build_resource_template allocates extra mem */
+       int res_cnt = (buffer->length - 1)/sizeof(struct acpi_resource) - 1;
+       struct acpi_resource *resource = (struct acpi_resource*)buffer->pointer;
+       int port = 0, irq = 0, dma = 0, mem = 0;
+
+       pnp_dbg("res cnt %d", res_cnt);
+       while (i < res_cnt) {
+               switch(resource->id) {
+               case ACPI_RSTYPE_IRQ:
+                       pnp_dbg("Encode irq");
+                       pnpacpi_encode_irq(resource, 
+                               &res_table->irq_resource[irq]);
+                       irq++;
+                       break;
+
+               case ACPI_RSTYPE_EXT_IRQ:
+                       pnp_dbg("Encode ext irq");
+                       pnpacpi_encode_ext_irq(resource, 
+                               &res_table->irq_resource[irq]);
+                       irq++;
+                       break;
+               case ACPI_RSTYPE_DMA:
+                       pnp_dbg("Encode dma");
+                       pnpacpi_encode_dma(resource, 
+                               &res_table->dma_resource[dma]);
+                       dma ++;
+                       break;
+               case ACPI_RSTYPE_IO:
+                       pnp_dbg("Encode io");
+                       pnpacpi_encode_io(resource, 
+                               &res_table->port_resource[port]);
+                       port ++;
+                       break;
+               case ACPI_RSTYPE_FIXED_IO:
+                       pnp_dbg("Encode fixed io");
+                       pnpacpi_encode_fixed_io(resource,
+                               &res_table->port_resource[port]);
+                       port ++;
+                       break;
+               case ACPI_RSTYPE_MEM24:
+                       pnp_dbg("Encode mem24");
+                       pnpacpi_encode_mem24(resource,
+                               &res_table->mem_resource[mem]);
+                       mem ++;
+                       break;
+               case ACPI_RSTYPE_MEM32:
+                       pnp_dbg("Encode mem32");
+                       pnpacpi_encode_mem32(resource,
+                               &res_table->mem_resource[mem]);
+                       mem ++;
+                       break;
+               case ACPI_RSTYPE_FIXED_MEM32:
+                       pnp_dbg("Encode fixed mem32");
+                       pnpacpi_encode_fixed_mem32(resource,
+                               &res_table->mem_resource[mem]);
+                       mem ++;
+                       break;
+               default: /* other type */
+                       pnp_warn("Invalid type");
+                       return -EINVAL;
+               }
+               resource ++;
+               i ++;
+       }
+       return 0;
+}
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
new file mode 100644 (file)
index 0000000..5fd3ad8
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * drivers/s390/char/monreader.c
+ *
+ * Character device driver for reading z/VM *MONITOR service records.
+ *
+ * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ *
+ * Author: Gerald Schaefer <geraldsc@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/ebcdic.h>
+#include <asm/extmem.h>
+#include <linux/poll.h>
+#include "../net/iucv.h"
+
+
+//#define MON_DEBUG                    /* Debug messages on/off */
+
+#define MON_NAME "monreader"
+
+#define P_INFO(x...)   printk(KERN_INFO MON_NAME " info: " x)
+#define P_ERROR(x...)  printk(KERN_ERR MON_NAME " error: " x)
+#define P_WARNING(x...)        printk(KERN_WARNING MON_NAME " warning: " x)
+
+#ifdef MON_DEBUG
+#define P_DEBUG(x...)   printk(KERN_DEBUG MON_NAME " debug: " x)
+#else
+#define P_DEBUG(x...)   do {} while (0)
+#endif
+
+#define MON_COLLECT_SAMPLE 0x80
+#define MON_COLLECT_EVENT  0x40
+#define MON_SERVICE       "*MONITOR"
+#define MON_IN_USE        0x01
+#define MON_MSGLIM        255
+
+static char mon_dcss_name[9] = "MONDCSS\0";
+
+struct mon_msg {
+       u32 pos;
+       u32 mca_offset;
+       iucv_MessagePending local_eib;
+       char msglim_reached;
+       char replied_msglim;
+};
+
+struct mon_private {
+       u16 pathid;
+       iucv_handle_t iucv_handle;
+       struct mon_msg *msg_array[MON_MSGLIM];
+       unsigned int   write_index;
+       unsigned int   read_index;
+       atomic_t msglim_count;
+       atomic_t read_ready;
+       atomic_t iucv_connected;
+       atomic_t iucv_severed;
+};
+
+static unsigned long mon_in_use = 0;
+
+static unsigned long mon_dcss_start;
+static unsigned long mon_dcss_end;
+
+static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
+
+static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static u8 user_data_connect[16] = {
+       /* Version code, must be 0x01 for shared mode */
+       0x01,
+       /* what to collect */
+       MON_COLLECT_SAMPLE | MON_COLLECT_EVENT,
+       /* DCSS name in EBCDIC, 8 bytes padded with blanks */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static u8 user_data_sever[16] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+
+/******************************************************************************
+ *                             helper functions                               *
+ *****************************************************************************/
+/*
+ * Create the 8 bytes EBCDIC DCSS segment name from
+ * an ASCII name, incl. padding
+ */
+static inline void
+dcss_mkname(char *ascii_name, char *ebcdic_name)
+{
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               if (ascii_name[i] == '\0')
+                       break;
+               ebcdic_name[i] = toupper(ascii_name[i]);
+       };
+       for (; i < 8; i++)
+               ebcdic_name[i] = ' ';
+       ASCEBC(ebcdic_name, 8);
+}
+
+/*
+ * print appropriate error message for segment_load()/segment_type()
+ * return code
+ */
+static void
+mon_segment_warn(int rc, char* seg_name)
+{
+       switch (rc) {
+       case -ENOENT:
+               P_WARNING("cannot load/query segment %s, does not exist\n",
+                         seg_name);
+               break;
+       case -ENOSYS:
+               P_WARNING("cannot load/query segment %s, not running on VM\n",
+                         seg_name);
+               break;
+       case -EIO:
+               P_WARNING("cannot load/query segment %s, hardware error\n",
+                         seg_name);
+               break;
+       case -ENOTSUPP:
+               P_WARNING("cannot load/query segment %s, is a multi-part "
+                         "segment\n", seg_name);
+               break;
+       case -ENOSPC:
+               P_WARNING("cannot load/query segment %s, overlaps with "
+                         "storage\n", seg_name);
+               break;
+       case -EBUSY:
+               P_WARNING("cannot load/query segment %s, overlaps with "
+                         "already loaded dcss\n", seg_name);
+               break;
+       case -EPERM:
+               P_WARNING("cannot load/query segment %s, already loaded in "
+                         "incompatible mode\n", seg_name);
+               break;
+       case -ENOMEM:
+               P_WARNING("cannot load/query segment %s, out of memory\n",
+                         seg_name);
+               break;
+       case -ERANGE:
+               P_WARNING("cannot load/query segment %s, exceeds kernel "
+                         "mapping range\n", seg_name);
+               break;
+       default:
+               P_WARNING("cannot load/query segment %s, return value %i\n",
+                         seg_name, rc);
+               break;
+       }
+}
+
+static inline unsigned long
+mon_mca_start(struct mon_msg *monmsg)
+{
+       return monmsg->local_eib.ln1msg1.iprmmsg1_u32;
+}
+
+static inline unsigned long
+mon_mca_end(struct mon_msg *monmsg)
+{
+       return monmsg->local_eib.ln1msg2.ipbfln1f;
+}
+
+static inline u8
+mon_mca_type(struct mon_msg *monmsg, u8 index)
+{
+       return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
+}
+
+static inline u32
+mon_mca_size(struct mon_msg *monmsg)
+{
+       return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
+}
+
+static inline u32
+mon_rec_start(struct mon_msg *monmsg)
+{
+       return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
+}
+
+static inline u32
+mon_rec_end(struct mon_msg *monmsg)
+{
+       return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
+}
+
+static inline int
+mon_check_mca(struct mon_msg *monmsg)
+{
+       if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
+           (mon_rec_start(monmsg) < mon_dcss_start) ||
+           (mon_rec_end(monmsg) > mon_dcss_end) ||
+           (mon_mca_type(monmsg, 0) == 0) ||
+           (mon_mca_size(monmsg) % 12 != 0) ||
+           (mon_mca_end(monmsg) <= mon_mca_start(monmsg)) ||
+           (mon_mca_end(monmsg) > mon_dcss_end) ||
+           (mon_mca_start(monmsg) < mon_dcss_start) ||
+           ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0)))
+       {
+               P_DEBUG("READ, IGNORED INVALID MCA\n\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static inline int
+mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
+{
+       u8 prmmsg[8];
+       int rc;
+
+       P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = "
+               "0x%08X\n\n",
+               monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
+               monmsg->local_eib.iptrgcls);
+       rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid,
+                               monmsg->local_eib.ipmsgid,
+                               monmsg->local_eib.iptrgcls,
+                               0, prmmsg);
+       atomic_dec(&monpriv->msglim_count);
+       if (likely(!monmsg->msglim_reached)) {
+               monmsg->pos = 0;
+               monmsg->mca_offset = 0;
+               monpriv->read_index = (monpriv->read_index + 1) %
+                                     MON_MSGLIM;
+               atomic_dec(&monpriv->read_ready);
+       } else
+               monmsg->replied_msglim = 1;
+       if (rc) {
+               P_ERROR("read, IUCV reply failed with rc = %i\n\n", rc);
+               return -EIO;
+       }
+       return 0;
+}
+
+static inline struct mon_private *
+mon_alloc_mem(void)
+{
+       int i,j;
+       struct mon_private *monpriv;
+
+       monpriv = kmalloc(sizeof(struct mon_private), GFP_KERNEL);
+       if (!monpriv) {
+               P_ERROR("no memory for monpriv\n");
+               return NULL;
+       }
+       memset(monpriv, 0, sizeof(struct mon_private));
+       for (i = 0; i < MON_MSGLIM; i++) {
+               monpriv->msg_array[i] = kmalloc(sizeof(struct mon_msg),
+                                                   GFP_KERNEL);
+               if (!monpriv->msg_array[i]) {
+                       P_ERROR("open, no memory for msg_array\n");
+                       for (j = 0; j < i; j++)
+                               kfree(monpriv->msg_array[j]);
+                       return NULL;
+               }
+               memset(monpriv->msg_array[i], 0, sizeof(struct mon_msg));
+       }
+       return monpriv;
+}
+
+static inline void
+mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
+{
+#ifdef MON_DEBUG
+       u8 msg_type[2], mca_type;
+       unsigned long records_len;
+
+       records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1;
+
+       memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2);
+       EBCASC(msg_type, 2);
+       mca_type = mon_mca_type(monmsg, 0);
+       EBCASC(&mca_type, 1);
+
+       P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n",
+               monpriv->read_index, monpriv->write_index);
+       P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n",
+               monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
+               monmsg->local_eib.iptrgcls);
+       P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n",
+               msg_type[0], msg_type[1], mca_type ? mca_type : 'X',
+               mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2));
+       P_DEBUG("read, MCA: start = 0x%lX, end = 0x%lX\n",
+               mon_mca_start(monmsg), mon_mca_end(monmsg));
+       P_DEBUG("read, REC: start = 0x%X, end = 0x%X, len = %lu\n\n",
+               mon_rec_start(monmsg), mon_rec_end(monmsg), records_len);
+       if (mon_mca_size(monmsg) > 12)
+               P_DEBUG("READ, MORE THAN ONE MCA\n\n");
+#endif
+}
+
+static inline void
+mon_next_mca(struct mon_msg *monmsg)
+{
+       if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
+               return;
+       P_DEBUG("READ, NEXT MCA\n\n");
+       monmsg->mca_offset += 12;
+       monmsg->pos = 0;
+}
+
+static inline struct mon_msg *
+mon_next_message(struct mon_private *monpriv)
+{
+       struct mon_msg *monmsg;
+
+       if (!atomic_read(&monpriv->read_ready))
+               return NULL;
+       monmsg = monpriv->msg_array[monpriv->read_index];
+       if (unlikely(monmsg->replied_msglim)) {
+               monmsg->replied_msglim = 0;
+               monmsg->msglim_reached = 0;
+               monmsg->pos = 0;
+               monmsg->mca_offset = 0;
+               P_WARNING("read, message limit reached\n");
+               monpriv->read_index = (monpriv->read_index + 1) %
+                                     MON_MSGLIM;
+               atomic_dec(&monpriv->read_ready);
+               return ERR_PTR(-EOVERFLOW);
+       }
+       return monmsg;
+}
+
+
+/******************************************************************************
+ *                               IUCV handler                                 *
+ *****************************************************************************/
+static void
+mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data)
+{
+       struct mon_private *monpriv = (struct mon_private *) pgm_data;
+
+       P_DEBUG("IUCV connection completed\n");
+       P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = "
+               "0x%02X, Sample = 0x%02X\n",
+               eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]);
+       atomic_set(&monpriv->iucv_connected, 1);
+       wake_up(&mon_conn_wait_queue);
+}
+
+static void
+mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data)
+{
+       struct mon_private *monpriv = (struct mon_private *) pgm_data;
+
+       P_ERROR("IUCV connection severed with rc = 0x%X\n",
+               (u8) eib->ipuser[0]);
+       atomic_set(&monpriv->iucv_severed, 1);
+       wake_up(&mon_conn_wait_queue);
+       wake_up_interruptible(&mon_read_wait_queue);
+}
+
+static void
+mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
+{
+       struct mon_private *monpriv = (struct mon_private *) pgm_data;
+
+       P_DEBUG("IUCV message pending\n");
+       memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib,
+              sizeof(iucv_MessagePending));
+       if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
+               P_WARNING("IUCV message pending, message limit (%i) reached\n",
+                         MON_MSGLIM);
+               monpriv->msg_array[monpriv->write_index]->msglim_reached = 1;
+       }
+       monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM;
+       atomic_inc(&monpriv->read_ready);
+       wake_up_interruptible(&mon_read_wait_queue);
+}
+
+static iucv_interrupt_ops_t mon_iucvops = {
+       .ConnectionComplete = mon_iucv_ConnectionComplete,
+       .ConnectionSevered  = mon_iucv_ConnectionSevered,
+       .MessagePending     = mon_iucv_MessagePending,
+};
+
+/******************************************************************************
+ *                               file operations                              *
+ *****************************************************************************/
+static int
+mon_open(struct inode *inode, struct file *filp)
+{
+       int rc, i;
+       struct mon_private *monpriv;
+
+       /*
+        * only one user allowed
+        */
+       if (test_and_set_bit(MON_IN_USE, &mon_in_use))
+               return -EBUSY;
+
+       monpriv = mon_alloc_mem();
+       if (!monpriv)
+               return -ENOMEM;
+
+       /*
+        * Register with IUCV and connect to *MONITOR service
+        */
+       monpriv->iucv_handle = iucv_register_program("my_monreader    ",
+                                                       MON_SERVICE,
+                                                       NULL,
+                                                       &mon_iucvops,
+                                                       monpriv);
+       if (!monpriv->iucv_handle) {
+               P_ERROR("failed to register with iucv driver\n");
+               rc = -EIO;
+               goto out_error;
+       }
+       P_INFO("open, registered with IUCV\n");
+
+       rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect,
+                         MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL,
+                         monpriv->iucv_handle, NULL);
+       if (rc) {
+               P_ERROR("iucv connection to *MONITOR failed with "
+                       "IPUSER SEVER code = %i\n", rc);
+               rc = -EIO;
+               goto out_unregister;
+       }
+       /*
+        * Wait for connection confirmation
+        */
+       wait_event(mon_conn_wait_queue,
+                  atomic_read(&monpriv->iucv_connected) ||
+                  atomic_read(&monpriv->iucv_severed));
+       if (atomic_read(&monpriv->iucv_severed)) {
+               atomic_set(&monpriv->iucv_severed, 0);
+               atomic_set(&monpriv->iucv_connected, 0);
+               rc = -EIO;
+               goto out_unregister;
+       }
+       P_INFO("open, established connection to *MONITOR service\n\n");
+       filp->private_data = monpriv;
+       return nonseekable_open(inode, filp);
+
+out_unregister:
+       iucv_unregister_program(monpriv->iucv_handle);
+out_error:
+       for (i = 0; i < MON_MSGLIM; i++)
+               kfree(monpriv->msg_array[i]);
+       kfree(monpriv);
+       clear_bit(MON_IN_USE, &mon_in_use);
+       return rc;
+}
+
+static int
+mon_close(struct inode *inode, struct file *filp)
+{
+       int rc, i;
+       struct mon_private *monpriv = filp->private_data;
+
+       /*
+        * Close IUCV connection and unregister
+        */
+       rc = iucv_sever(monpriv->pathid, user_data_sever);
+       if (rc)
+               P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
+       else
+               P_INFO("close, terminated connection to *MONITOR service\n");
+
+       rc = iucv_unregister_program(monpriv->iucv_handle);
+       if (rc)
+               P_ERROR("close, iucv_unregister failed with rc = %i\n", rc);
+       else
+               P_INFO("close, unregistered with IUCV\n");
+
+       atomic_set(&monpriv->iucv_severed, 0);
+       atomic_set(&monpriv->iucv_connected, 0);
+       atomic_set(&monpriv->read_ready, 0);
+       atomic_set(&monpriv->msglim_count, 0);
+       monpriv->write_index  = 0;
+       monpriv->read_index   = 0;
+
+       for (i = 0; i < MON_MSGLIM; i++)
+               kfree(monpriv->msg_array[i]);
+       kfree(monpriv);
+       clear_bit(MON_IN_USE, &mon_in_use);
+       return 0;
+}
+
+static ssize_t
+mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
+{
+       struct mon_private *monpriv = filp->private_data;
+       struct mon_msg *monmsg;
+       int ret;
+       u32 mce_start;
+
+       monmsg = mon_next_message(monpriv);
+       if (IS_ERR(monmsg))
+               return PTR_ERR(monmsg);
+
+       if (!monmsg) {
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               ret = wait_event_interruptible(mon_read_wait_queue,
+                                       atomic_read(&monpriv->read_ready) ||
+                                       atomic_read(&monpriv->iucv_severed));
+               if (ret)
+                       return ret;
+               if (unlikely(atomic_read(&monpriv->iucv_severed)))
+                       return -EIO;
+               monmsg = monpriv->msg_array[monpriv->read_index];
+       }
+
+       if (!monmsg->pos) {
+               monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset;
+               mon_read_debug(monmsg, monpriv);
+       }
+       if (mon_check_mca(monmsg))
+               goto reply;
+
+       /* read monitor control element (12 bytes) first */
+       mce_start = mon_mca_start(monmsg) + monmsg->mca_offset;
+       if ((monmsg->pos >= mce_start) && (monmsg->pos < mce_start + 12)) {
+               count = min(count, (size_t) mce_start + 12 - monmsg->pos);
+               ret = copy_to_user(data, (void *) (unsigned long) monmsg->pos,
+                                  count);
+               if (ret)
+                       return -EFAULT;
+               monmsg->pos += count;
+               if (monmsg->pos == mce_start + 12)
+                       monmsg->pos = mon_rec_start(monmsg);
+               goto out_copy;
+       }
+
+       /* read records */
+       if (monmsg->pos <= mon_rec_end(monmsg)) {
+               count = min(count, (size_t) mon_rec_end(monmsg) - monmsg->pos
+                                           + 1);
+               ret = copy_to_user(data, (void *) (unsigned long) monmsg->pos,
+                                  count);
+               if (ret)
+                       return -EFAULT;
+               monmsg->pos += count;
+               if (monmsg->pos > mon_rec_end(monmsg))
+                       mon_next_mca(monmsg);
+               goto out_copy;
+       }
+reply:
+       ret = mon_send_reply(monmsg, monpriv);
+       return ret;
+
+out_copy:
+       *ppos += count;
+       return count;
+}
+
+static unsigned int
+mon_poll(struct file *filp, struct poll_table_struct *p)
+{
+       struct mon_private *monpriv = filp->private_data;
+
+       poll_wait(filp, &mon_read_wait_queue, p);
+       if (unlikely(atomic_read(&monpriv->iucv_severed)))
+               return POLLERR;
+       if (atomic_read(&monpriv->read_ready))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static struct file_operations mon_fops = {
+       .owner   = THIS_MODULE,
+       .open    = &mon_open,
+       .release = &mon_close,
+       .read    = &mon_read,
+       .poll    = &mon_poll,
+};
+
+static struct miscdevice mon_dev = {
+       .name       = "monreader",
+       .devfs_name = "monreader",
+       .fops       = &mon_fops,
+       .minor      = MISC_DYNAMIC_MINOR,
+};
+
+/******************************************************************************
+ *                              module init/exit                              *
+ *****************************************************************************/
+static int __init
+mon_init(void)
+{
+       int rc;
+
+       if (!MACHINE_IS_VM) {
+               P_ERROR("not running under z/VM, driver not loaded\n");
+               return -ENODEV;
+       }
+
+       rc = segment_type(mon_dcss_name);
+       if (rc < 0) {
+               mon_segment_warn(rc, mon_dcss_name);
+               return rc;
+       }
+       if (rc != SEG_TYPE_SC) {
+               P_ERROR("segment %s has unsupported type, should be SC\n",
+                       mon_dcss_name);
+               return -EINVAL;
+       }
+
+       rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
+                         &mon_dcss_start, &mon_dcss_end);
+       if (rc < 0) {
+               mon_segment_warn(rc, mon_dcss_name);
+               return -EINVAL;
+       }
+       dcss_mkname(mon_dcss_name, &user_data_connect[8]);
+
+       rc = misc_register(&mon_dev);
+       if (rc < 0 ) {
+               P_ERROR("misc_register failed, rc = %i\n", rc);
+               goto out;
+       }
+       P_INFO("Loaded segment %s from %p to %p, size = %lu Byte\n",
+               mon_dcss_name, (void *) mon_dcss_start, (void *) mon_dcss_end,
+               mon_dcss_end - mon_dcss_start + 1);
+       return 0;
+
+out:
+       segment_unload(mon_dcss_name);
+       return rc;
+}
+
+static void __exit
+mon_exit(void)
+{
+       segment_unload(mon_dcss_name);
+       WARN_ON(misc_deregister(&mon_dev) != 0);
+       return;
+}
+
+
+module_init(mon_init);
+module_exit(mon_exit);
+
+module_param_string(mondcss, mon_dcss_name, 9, 0444);
+MODULE_PARM_DESC(mondcss, "Name of DCSS segment to be used for *MONITOR "
+                "service, max. 8 chars. Default is MONDCSS");
+
+MODULE_AUTHOR("Gerald Schaefer <geraldsc@de.ibm.com>");
+MODULE_DESCRIPTION("Character device driver for reading z/VM "
+                  "monitor service records.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
new file mode 100644 (file)
index 0000000..88694e7
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+ * drivers/s390/char/vmlogrdr.c
+ *     character device driver for reading z/VM system service records
+ *
+ *
+ *     Copyright (C) 2004 IBM Corporation
+ *     character device driver for reading z/VM system service records,
+ *     Version 1.0
+ *     Author(s): Xenia Tkatschow <xenia@us.ibm.com>
+ *                Stefan Weinhuber <wein@de.ibm.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include <asm/cpcmd.h>
+#include <asm/debug.h>
+#include <asm/ebcdic.h>
+#include "../net/iucv.h"
+#include <linux/kmod.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/string.h>
+
+
+
+MODULE_AUTHOR
+       ("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n"
+        "                            Stefan Weinhuber (wein@de.ibm.com)");
+MODULE_DESCRIPTION ("Character device driver for reading z/VM "
+                   "system service records.");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * The size of the buffer for iucv data transfer is one page,
+ * but in addition to the data we read from iucv we also
+ * place an integer and some characters into that buffer,
+ * so the maximum size for record data is a little less then
+ * one page.
+ */
+#define NET_BUFFER_SIZE        (PAGE_SIZE - sizeof(int) - sizeof(FENCE))
+
+/*
+ * The elements that are concurrently accessed by bottom halves are
+ * connection_established, iucv_path_severed, local_interrupt_buffer
+ * and receive_ready. The first three can be protected by
+ * priv_lock.  receive_ready is atomic, so it can be incremented and
+ * decremented without holding a lock.
+ * The variable dev_in_use needs to be protected by the lock, since
+ * it's a flag used by open to make sure that the device is opened only
+ * by one user at the same time.
+ */
+struct vmlogrdr_priv_t {
+       char system_service[8];
+       char internal_name[8];
+       char recording_name[8];
+       u16 pathid;
+       int connection_established;
+       int iucv_path_severed;
+       iucv_MessagePending local_interrupt_buffer;
+       atomic_t receive_ready;
+       iucv_handle_t iucv_handle;
+       int minor_num;
+       char * buffer;
+       char * current_position;
+       int remaining;
+       ulong residual_length;
+       int buffer_free;
+       int dev_in_use; /* 1: already opened, 0: not opened*/
+       spinlock_t priv_lock;
+       struct device  *device;
+       struct class_device  *class_device;
+       int autorecording;
+       int autopurge;
+};
+
+
+/*
+ * File operation structure for vmlogrdr devices
+ */
+static int vmlogrdr_open(struct inode *, struct file *);
+static int vmlogrdr_release(struct inode *, struct file *);
+static ssize_t vmlogrdr_read (struct file *filp, char *data, size_t count,
+                              loff_t * ppos);
+
+static struct file_operations vmlogrdr_fops = {
+       .owner   = THIS_MODULE,
+       .open    = vmlogrdr_open,
+       .release = vmlogrdr_release,
+       .read    = vmlogrdr_read,
+};
+
+
+static u8 iucvMagic[16] = {
+       0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+       0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
+};
+
+
+static u8 mask[] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+
+static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+
+static void
+vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data);
+static void
+vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data);
+static void
+vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data);
+
+
+static iucv_interrupt_ops_t vmlogrdr_iucvops = {
+       .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete,
+       .ConnectionSevered  = vmlogrdr_iucv_ConnectionSevered,
+       .MessagePending     = vmlogrdr_iucv_MessagePending,
+};
+
+
+DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
+
+/*
+ * pointer to system service private structure
+ * minor number 0 --> logrec
+ * minor number 1 --> account
+ * minor number 2 --> symptom
+ */
+
+static struct vmlogrdr_priv_t sys_ser[] = {
+       { .system_service = "*LOGREC ",
+         .internal_name  = "logrec",
+         .recording_name = "EREP",
+         .minor_num      = 0,
+         .buffer_free    = 1,
+         .priv_lock      = SPIN_LOCK_UNLOCKED,
+         .autorecording  = 1,
+         .autopurge      = 1,
+       },
+       { .system_service = "*ACCOUNT",
+         .internal_name  = "account",
+         .recording_name = "ACCOUNT",
+         .minor_num      = 1,
+         .buffer_free    = 1,
+         .priv_lock      = SPIN_LOCK_UNLOCKED,
+         .autorecording  = 1,
+         .autopurge      = 1,
+       },
+       { .system_service = "*SYMPTOM",
+         .internal_name  = "symptom",
+         .recording_name = "SYMPTOM",
+         .minor_num      = 2,
+         .buffer_free    = 1,
+         .priv_lock      = SPIN_LOCK_UNLOCKED,
+         .autorecording  = 1,
+         .autopurge      = 1,
+       }
+};
+
+#define MAXMINOR  (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t))
+
+static char FENCE[] = {"EOR"};
+static int vmlogrdr_major = 0;
+static struct cdev  *vmlogrdr_cdev = NULL;
+static int recording_class_AB;
+
+
+static void
+vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib,
+                                  void * pgm_data)
+{
+       struct vmlogrdr_priv_t * logptr = pgm_data;
+       spin_lock(&logptr->priv_lock);
+       logptr->connection_established = 1;
+       spin_unlock(&logptr->priv_lock);
+       wake_up(&conn_wait_queue);
+       return;
+}
+
+
+static void
+vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
+{
+       u8 reason = (u8) eib->ipuser[8];
+       struct vmlogrdr_priv_t * logptr = pgm_data;
+
+       printk (KERN_ERR "vmlogrdr: connection severed with"
+               " reason %i\n", reason);
+
+       spin_lock(&logptr->priv_lock);
+       logptr->connection_established = 0;
+       logptr->iucv_path_severed = 1;
+       spin_unlock(&logptr->priv_lock);
+
+       wake_up(&conn_wait_queue);
+       /* just in case we're sleeping waiting for a record */
+       wake_up_interruptible(&read_wait_queue);
+}
+
+
+static void
+vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
+{
+       struct vmlogrdr_priv_t * logptr = pgm_data;
+
+       /*
+        * This function is the bottom half so it should be quick.
+        * Copy the external interrupt data into our local eib and increment
+        * the usage count
+        */
+       spin_lock(&logptr->priv_lock);
+       memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib));
+       atomic_inc(&logptr->receive_ready);
+       spin_unlock(&logptr->priv_lock);
+       wake_up_interruptible(&read_wait_queue);
+}
+
+
+static int
+vmlogrdr_get_recording_class_AB(void) {
+       char cp_command[]="QUERY COMMAND RECORDING ";
+       char cp_response[80];
+       char *tail;
+       int len,i;
+
+       printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command);
+       cpcmd(cp_command, cp_response, sizeof(cp_response));
+       printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response);
+       len = strnlen(cp_response,sizeof(cp_response));
+       // now the parsing
+       tail=strnchr(cp_response,len,'=');
+       if (!tail)
+               return 0;
+       tail++;
+       if (!strncmp("ANY",tail,3))
+               return 1;
+       if (!strncmp("NONE",tail,4))
+               return 0;
+       /*
+        * expect comma separated list of classes here, if one of them
+        * is A or B return 1 otherwise 0
+        */
+        for (i=tail-cp_response; i<len; i++)
+               if ( cp_response[i]=='A' || cp_response[i]=='B' )
+                       return 1;
+       return 0;
+}
+
+
+static int
+vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
+
+       char cp_command[80];
+       char cp_response[160];
+       char *onoff, *qid_string;
+
+       memset(cp_command, 0x00, sizeof(cp_command));
+       memset(cp_response, 0x00, sizeof(cp_response));
+
+        onoff = ((action == 1) ? "ON" : "OFF");
+       qid_string = ((recording_class_AB == 1) ? " QID * " : "");
+
+        /*
+        * The recording commands needs to be called with option QID
+        * for guests that have previlege classes A or B.
+        * Purging has to be done as separate step, because recording
+        * can't be switched on as long as records are on the queue.
+        * Doing both at the same time doesn't work.
+        */
+
+       if (purge) {
+               snprintf(cp_command, sizeof(cp_command),
+                        "RECORDING %s PURGE %s",
+                        logptr->recording_name,
+                        qid_string);
+
+               printk (KERN_DEBUG "vmlogrdr: recording command: %s\n",
+                       cp_command);
+               cpcmd(cp_command, cp_response, sizeof(cp_response));
+               printk (KERN_DEBUG "vmlogrdr: recording response: %s",
+                       cp_response);
+       }
+
+       memset(cp_command, 0x00, sizeof(cp_command));
+       memset(cp_response, 0x00, sizeof(cp_response));
+       snprintf(cp_command, sizeof(cp_command), "RECORDING %s %s %s",
+               logptr->recording_name,
+               onoff,
+               qid_string);
+
+       printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
+       cpcmd(cp_command, cp_response, sizeof(cp_response));
+       printk (KERN_DEBUG "vmlogrdr: recording response: %s",
+               cp_response);
+       /* The recording command will usually answer with 'Command complete'
+        * on success, but when the specific service was never connected
+        * before then there might be an additional informational message
+        * 'HCPCRC8072I Recording entry not found' before the
+         * 'Command complete'. So I use strstr rather then the strncmp.
+        */
+       if (strstr(cp_response,"Command complete"))
+               return 0;
+       else
+               return -EIO;
+
+}
+
+
+static int
+vmlogrdr_open (struct inode *inode, struct file *filp)
+{
+       int dev_num = 0;
+       struct vmlogrdr_priv_t * logptr = NULL;
+       int connect_rc = 0;
+       int ret;
+
+       dev_num = iminor(inode);
+       if (dev_num > MAXMINOR)
+               return -ENODEV;
+
+       logptr = &sys_ser[dev_num];
+       if (logptr == NULL)
+               return -ENODEV;
+
+       /*
+        * only allow for blocking reads to be open
+        */
+       if (filp->f_flags & O_NONBLOCK)
+               return -ENOSYS;
+
+       /* Besure this device hasn't already been opened */
+       spin_lock_bh(&logptr->priv_lock);
+       if (logptr->dev_in_use) {
+               spin_unlock_bh(&logptr->priv_lock);
+               return -EBUSY;
+       } else {
+               logptr->dev_in_use = 1;
+               spin_unlock_bh(&logptr->priv_lock);
+       }
+
+       atomic_set(&logptr->receive_ready, 0);
+       logptr->buffer_free = 1;
+
+       /* set the file options */
+       filp->private_data = logptr;
+       filp->f_op = &vmlogrdr_fops;
+
+       /* start recording for this service*/
+       ret=0;
+       if (logptr->autorecording)
+               ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
+       if (ret)
+               printk (KERN_WARNING "vmlogrdr: failed to start "
+                       "recording automatically\n");
+
+       /* Register with iucv driver */
+       logptr->iucv_handle = iucv_register_program(iucvMagic,
+                       logptr->system_service, mask, &vmlogrdr_iucvops,
+                       logptr);
+
+       if (logptr->iucv_handle == NULL) {
+               printk (KERN_ERR "vmlogrdr: failed to register with"
+                       "iucv driver\n");
+               goto not_registered;
+       }
+
+       /* create connection to the system service */
+       spin_lock_bh(&logptr->priv_lock);
+       logptr->connection_established = 0;
+       logptr->iucv_path_severed = 0;
+       spin_unlock_bh(&logptr->priv_lock);
+
+       connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic,
+                                       logptr->system_service, iucv_host, 0,
+                                       NULL, NULL,
+                                       logptr->iucv_handle, NULL);
+       if (connect_rc) {
+               printk (KERN_ERR "vmlogrdr: iucv connection to %s "
+                       "failed with rc %i \n", logptr->system_service,
+                       connect_rc);
+               goto not_connected;
+       }
+
+       /* We've issued the connect and now we must wait for a
+        * ConnectionComplete or ConnectinSevered Interrupt
+        * before we can continue to process.
+        */
+       wait_event(conn_wait_queue, (logptr->connection_established)
+                  || (logptr->iucv_path_severed));
+       if (logptr->iucv_path_severed) {
+               goto not_connected;
+       }
+
+       return 0;
+
+not_connected:
+       iucv_unregister_program(logptr->iucv_handle);
+       logptr->iucv_handle = NULL;
+not_registered:
+       if (logptr->autorecording)
+               vmlogrdr_recording(logptr,0,logptr->autopurge);
+       logptr->dev_in_use = 0;
+       return -EIO;
+
+
+}
+
+
+static int
+vmlogrdr_release (struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       struct vmlogrdr_priv_t * logptr = filp->private_data;
+
+       iucv_unregister_program(logptr->iucv_handle);
+       logptr->iucv_handle = NULL;
+
+       if (logptr->autorecording) {
+               ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
+               if (ret)
+                       printk (KERN_WARNING "vmlogrdr: failed to stop "
+                               "recording automatically\n");
+       }
+       logptr->dev_in_use = 0;
+
+       return 0;
+}
+
+
+static int
+vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
+       int rc, *temp;
+       /* we need to keep track of two data sizes here:
+        * The number of bytes we need to receive from iucv and
+        * the total number of bytes we actually write into the buffer.
+        */
+       int user_data_count, iucv_data_count;
+       char * buffer;
+
+       if (atomic_read(&priv->receive_ready)) {
+               spin_lock_bh(&priv->priv_lock);
+               if (priv->residual_length){
+                       /* receive second half of a record */
+                       iucv_data_count = priv->residual_length;
+                       user_data_count = 0;
+                       buffer = priv->buffer;
+               } else {
+                       /* receive a new record:
+                        * We need to return the total length of the record
+                         * + size of FENCE in the first 4 bytes of the buffer.
+                        */
+                       iucv_data_count =
+                               priv->local_interrupt_buffer.ln1msg2.ipbfln1f;
+                       user_data_count = sizeof(int);
+                       temp = (int*)priv->buffer;
+                       *temp= iucv_data_count + sizeof(FENCE);
+                       buffer = priv->buffer + sizeof(int);
+               }
+               /*
+                * If the record is bigger then our buffer, we receive only
+                * a part of it. We can get the rest later.
+                */
+               if (iucv_data_count > NET_BUFFER_SIZE)
+                       iucv_data_count = NET_BUFFER_SIZE;
+               rc = iucv_receive(priv->pathid,
+                                 priv->local_interrupt_buffer.ipmsgid,
+                                 priv->local_interrupt_buffer.iptrgcls,
+                                 buffer,
+                                 iucv_data_count,
+                                 NULL,
+                                 NULL,
+                                 &priv->residual_length);
+               spin_unlock_bh(&priv->priv_lock);
+               /* An rc of 5 indicates that the record was bigger then
+                * the buffer, which is OK for us. A 9 indicates that the
+                * record was purged befor we could receive it.
+                */
+               if (rc == 5)
+                       rc = 0;
+               if (rc == 9)
+                       atomic_set(&priv->receive_ready, 0);
+       } else {
+               rc = 1;
+       }
+       if (!rc) {
+               priv->buffer_free = 0;
+               user_data_count += iucv_data_count;
+               priv->current_position = priv->buffer;
+               if (priv->residual_length == 0){
+                       /* the whole record has been captured,
+                        * now add the fence */
+                       atomic_dec(&priv->receive_ready);
+                       buffer = priv->buffer + user_data_count;
+                       memcpy(buffer, FENCE, sizeof(FENCE));
+                       user_data_count += sizeof(FENCE);
+               }
+               priv->remaining = user_data_count;
+       }
+
+       return rc;
+}
+
+
+static ssize_t
+vmlogrdr_read (struct file *filp, char *data, size_t count, loff_t * ppos)
+{
+       int rc;
+       struct vmlogrdr_priv_t * priv = filp->private_data;
+
+       while (priv->buffer_free) {
+               rc = vmlogrdr_receive_data(priv);
+               if (rc) {
+                       rc = wait_event_interruptible(read_wait_queue,
+                                       atomic_read(&priv->receive_ready));
+                       if (rc)
+                               return rc;
+               }
+       }
+       /* copy only up to end of record */
+       if (count > priv->remaining)
+               count = priv->remaining;
+
+       if (copy_to_user(data, priv->current_position, count))
+               return -EFAULT;
+
+       *ppos += count;
+       priv->current_position += count;
+       priv->remaining -= count;
+
+       /* if all data has been transferred, set buffer free */
+       if (priv->remaining == 0)
+               priv->buffer_free = 1;
+
+       return count;
+}
+
+static ssize_t
+vmlogrdr_autopurge_store(struct device * dev, const char * buf, size_t count) {
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       ssize_t ret = count;
+
+       switch (buf[0]) {
+       case '0':
+               priv->autopurge=0;
+               break;
+       case '1':
+               priv->autopurge=1;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+
+static ssize_t
+vmlogrdr_autopurge_show(struct device *dev, char *buf) {
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       return sprintf(buf, "%u\n", priv->autopurge);
+}
+
+
+static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show,
+                  vmlogrdr_autopurge_store);
+
+
+static ssize_t
+vmlogrdr_purge_store(struct device * dev, const char * buf, size_t count) {
+
+       char cp_command[80];
+       char cp_response[80];
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+
+       if (buf[0] != '1')
+               return -EINVAL;
+
+       memset(cp_command, 0x00, sizeof(cp_command));
+       memset(cp_response, 0x00, sizeof(cp_response));
+
+        /*
+        * The recording command needs to be called with option QID
+        * for guests that have previlege classes A or B.
+        * Other guests will not recognize the command and we have to
+        * issue the same command without the QID parameter.
+        */
+
+       if (recording_class_AB)
+               snprintf(cp_command, sizeof(cp_command),
+                        "RECORDING %s PURGE QID * ",
+                        priv->recording_name);
+       else
+               snprintf(cp_command, sizeof(cp_command),
+                        "RECORDING %s PURGE ",
+                        priv->recording_name);
+
+       printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
+       cpcmd(cp_command, cp_response, sizeof(cp_response));
+       printk (KERN_DEBUG "vmlogrdr: recording response: %s",
+               cp_response);
+
+       return count;
+}
+
+
+static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);
+
+
+static ssize_t
+vmlogrdr_autorecording_store(struct device *dev, const char *buf,
+                            size_t count) {
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       ssize_t ret = count;
+
+       switch (buf[0]) {
+       case '0':
+               priv->autorecording=0;
+               break;
+       case '1':
+               priv->autorecording=1;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+
+static ssize_t
+vmlogrdr_autorecording_show(struct device *dev, char *buf) {
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       return sprintf(buf, "%u\n", priv->autorecording);
+}
+
+
+static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show,
+                  vmlogrdr_autorecording_store);
+
+
+static ssize_t
+vmlogrdr_recording_store(struct device * dev, const char * buf, size_t count) {
+
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       ssize_t ret;
+
+       switch (buf[0]) {
+       case '0':
+               ret = vmlogrdr_recording(priv,0,0);
+               break;
+       case '1':
+               ret = vmlogrdr_recording(priv,1,0);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       if (ret)
+               return ret;
+       else
+               return count;
+
+}
+
+
+static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
+
+
+static ssize_t
+vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
+
+       char cp_command[] = "QUERY RECORDING ";
+       int len;
+
+       cpcmd(cp_command, buf, 4096);
+       len = strlen(buf);
+       return len;
+}
+
+
+static DRIVER_ATTR(recording_status, 0444, vmlogrdr_recording_status_show,
+                  NULL);
+
+static struct attribute *vmlogrdr_attrs[] = {
+       &dev_attr_autopurge.attr,
+       &dev_attr_purge.attr,
+       &dev_attr_autorecording.attr,
+       &dev_attr_recording.attr,
+       NULL,
+};
+
+static struct attribute_group vmlogrdr_attr_group = {
+       .attrs = vmlogrdr_attrs,
+};
+
+static struct class_simple *vmlogrdr_class;
+static struct device_driver vmlogrdr_driver = {
+       .name = "vmlogrdr",
+       .bus  = &iucv_bus,
+};
+
+
+static int
+vmlogrdr_register_driver(void) {
+       int ret;
+
+       ret = driver_register(&vmlogrdr_driver);
+       if (ret) {
+               printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
+               return ret;
+       }
+
+       ret = driver_create_file(&vmlogrdr_driver,
+                                &driver_attr_recording_status);
+       if (ret) {
+               printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
+               goto unregdriver;
+       }
+
+       vmlogrdr_class = class_simple_create(THIS_MODULE, "vmlogrdr");
+       if (IS_ERR(vmlogrdr_class)) {
+               printk(KERN_ERR "vmlogrdr: failed to create class.\n");
+               ret=PTR_ERR(vmlogrdr_class);
+               vmlogrdr_class=NULL;
+               goto unregattr;
+       }
+       return 0;
+
+unregattr:
+       driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
+unregdriver:
+       driver_unregister(&vmlogrdr_driver);
+       return ret;
+}
+
+
+static void
+vmlogrdr_unregister_driver(void) {
+       class_simple_destroy(vmlogrdr_class);
+       vmlogrdr_class = NULL;
+       driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
+       driver_unregister(&vmlogrdr_driver);
+       return;
+}
+
+
+static int
+vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
+       struct device *dev;
+       int ret;
+
+       dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+       if (dev) {
+               memset(dev, 0, sizeof(struct device));
+               snprintf(dev->bus_id, BUS_ID_SIZE, "%s",
+                        priv->internal_name);
+               dev->bus = &iucv_bus;
+               dev->parent = iucv_root;
+               dev->driver = &vmlogrdr_driver;
+               /*
+                * The release function could be called after the
+                * module has been unloaded. It's _only_ task is to
+                * free the struct. Therefore, we specify kfree()
+                * directly here. (Probably a little bit obfuscating
+                * but legitime ...).
+                */
+               dev->release = (void (*)(struct device *))kfree;
+       } else
+               return -ENOMEM;
+       ret = device_register(dev);
+       if (ret)
+               return ret;
+
+       ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group);
+       if (ret) {
+               device_unregister(dev);
+               return ret;
+       }
+       priv->class_device = class_simple_device_add(
+                               vmlogrdr_class,
+                               MKDEV(vmlogrdr_major, priv->minor_num),
+                               dev,
+                               "%s", dev->bus_id );
+       if (IS_ERR(priv->class_device)) {
+               ret = PTR_ERR(priv->class_device);
+               priv->class_device=NULL;
+               sysfs_remove_group(&dev->kobj, &vmlogrdr_attr_group);
+               device_unregister(dev);
+               return ret;
+       }
+       dev->driver_data = priv;
+       priv->device = dev;
+       return 0;
+}
+
+
+static int
+vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
+       class_simple_device_remove(MKDEV(vmlogrdr_major, priv->minor_num));
+       if (priv->device != NULL) {
+               sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
+               device_unregister(priv->device);
+               priv->device=NULL;
+       }
+       return 0;
+}
+
+
+static int
+vmlogrdr_register_cdev(dev_t dev) {
+       int rc = 0;
+       vmlogrdr_cdev = cdev_alloc();
+       if (!vmlogrdr_cdev) {
+               return -ENOMEM;
+       }
+       vmlogrdr_cdev->owner = THIS_MODULE;
+       vmlogrdr_cdev->ops = &vmlogrdr_fops;
+       vmlogrdr_cdev->dev = dev;
+       rc = cdev_add(vmlogrdr_cdev, vmlogrdr_cdev->dev, MAXMINOR);
+       if (!rc)
+               return 0;
+
+       // cleanup: cdev is not fully registered, no cdev_del here!
+       kobject_put(&vmlogrdr_cdev->kobj);
+       vmlogrdr_cdev=NULL;
+       return rc;
+}
+
+
+static void
+vmlogrdr_cleanup(void) {
+        int i;
+       if (vmlogrdr_cdev) {
+               cdev_del(vmlogrdr_cdev);
+               vmlogrdr_cdev=NULL;
+       }
+       for (i=0; i < MAXMINOR; ++i ) {
+               vmlogrdr_unregister_device(&sys_ser[i]);
+               free_page((unsigned long)sys_ser[i].buffer);
+       }
+       vmlogrdr_unregister_driver();
+       if (vmlogrdr_major) {
+               unregister_chrdev_region(MKDEV(vmlogrdr_major, 0), MAXMINOR);
+               vmlogrdr_major=0;
+       }
+}
+
+
+static int
+vmlogrdr_init(void)
+{
+       int rc;
+       int i;
+       dev_t dev;
+
+       if (! MACHINE_IS_VM) {
+               printk (KERN_ERR "vmlogrdr: not running under VM, "
+                               "driver not loaded.\n");
+               return -ENODEV;
+       }
+
+        recording_class_AB = vmlogrdr_get_recording_class_AB();
+
+       rc = alloc_chrdev_region(&dev, 0, MAXMINOR, "vmlogrdr");
+       if (rc)
+               return rc;
+       vmlogrdr_major = MAJOR(dev);
+
+       rc=vmlogrdr_register_driver();
+       if (rc)
+               goto cleanup;
+
+       for (i=0; i < MAXMINOR; ++i ) {
+               sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL);
+               if (!sys_ser[i].buffer) {
+                       rc = ENOMEM;
+                       break;
+               }
+               sys_ser[i].current_position = sys_ser[i].buffer;
+               rc=vmlogrdr_register_device(&sys_ser[i]);
+               if (rc)
+                       break;
+       }
+       if (rc)
+               goto cleanup;
+
+       rc = vmlogrdr_register_cdev(dev);
+       if (rc)
+               goto cleanup;
+       printk (KERN_INFO "vmlogrdr: driver loaded\n");
+       return 0;
+
+cleanup:
+       vmlogrdr_cleanup();
+       printk (KERN_ERR "vmlogrdr: driver not loaded.\n");
+       return rc;
+}
+
+
+static void
+vmlogrdr_exit(void)
+{
+       vmlogrdr_cleanup();
+       printk (KERN_INFO "vmlogrdr: driver unloaded\n");
+       return;
+}
+
+
+module_init(vmlogrdr_init);
+module_exit(vmlogrdr_exit);
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
new file mode 100644 (file)
index 0000000..22cf4fe
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Watchdog implementation based on z/VM Watchdog Timer API
+ *
+ * The user space watchdog daemon can use this driver as
+ * /dev/vmwatchdog to have z/VM execute the specified CP
+ * command when the timeout expires. The default command is
+ * "IPL", which which cause an immediate reboot.
+ */
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/watchdog.h>
+
+#include <asm/ebcdic.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAX_CMDLEN 240
+#define MIN_INTERVAL 15
+static char vmwdt_cmd[MAX_CMDLEN] = "IPL";
+static int vmwdt_conceal;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int vmwdt_nowayout = 1;
+#else
+static int vmwdt_nowayout = 0;
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
+MODULE_DESCRIPTION("z/VM Watchdog Timer");
+module_param_string(cmd, vmwdt_cmd, MAX_CMDLEN, 0644);
+MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers");
+module_param_named(conceal, vmwdt_conceal, bool, 0644);
+MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog "
+               " is active");
+module_param_named(nowayout, vmwdt_nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
+               " (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+static unsigned int vmwdt_interval = 60;
+static unsigned long vmwdt_is_open;
+static int vmwdt_expect_close;
+
+enum vmwdt_func {
+       /* function codes */
+       wdt_init   = 0,
+       wdt_change = 1,
+       wdt_cancel = 2,
+       /* flags */
+       wdt_conceal = 0x80000000,
+};
+
+static int __diag288(enum vmwdt_func func, unsigned int timeout,
+                           char *cmd, size_t len)
+{
+       register unsigned long __func asm("2");
+       register unsigned long __timeout asm("3");
+       register unsigned long __cmdp asm("4");
+       register unsigned long __cmdl asm("5");
+       int err;
+
+       __func = func;
+       __timeout = timeout;
+       __cmdp = virt_to_phys(cmd);
+       __cmdl = len;
+       err = 0;
+       asm volatile (
+#ifdef __s390x__
+                      "diag %2,%4,0x288\n"
+               "1:     \n"
+               ".section .fixup,\"ax\"\n"
+               "2:     lghi %0,%1\n"
+               "       jg 1b\n"
+               ".previous\n"
+               ".section __ex_table,\"a\"\n"
+               "       .align 8\n"
+               "       .quad 1b,2b\n"
+               ".previous\n"
+#else
+                      "diag %2,%4,0x288\n"
+               "1:     \n"
+               ".section .fixup,\"ax\"\n"
+               "2:     lhi %0,%1\n"
+               "       bras 1,3f\n"
+               "       .long 1b\n"
+               "3:     l 1,0(1)\n"
+               "       br 1\n"
+               ".previous\n"
+               ".section __ex_table,\"a\"\n"
+               "       .align 4\n"
+               "       .long 1b,2b\n"
+               ".previous\n"
+#endif
+               : "+&d"(err)
+               : "i"(-EINVAL), "d"(__func), "d"(__timeout),
+                 "d"(__cmdp), "d"(__cmdl)
+               : "1", "cc");
+       return err;
+}
+
+static int vmwdt_keepalive(void)
+{
+       /* we allocate new memory every time to avoid having
+        * to track the state. static allocation is not an
+        * option since that might not be contiguous in real
+        * storage in case of a modular build */
+       static char *ebc_cmd;
+       size_t len;
+       int ret;
+       unsigned int func;
+
+       ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
+       if (!ebc_cmd)
+               return -ENOMEM;
+
+       len = strlcpy(ebc_cmd, vmwdt_cmd, MAX_CMDLEN);
+       ASCEBC(ebc_cmd, MAX_CMDLEN);
+       EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
+
+       func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init;
+       ret = __diag288(func, vmwdt_interval, ebc_cmd, len);
+       kfree(ebc_cmd);
+
+       if (ret) {
+               printk(KERN_WARNING "%s: problem setting interval %d, "
+                       "cmd %s\n", __FUNCTION__, vmwdt_interval,
+                       vmwdt_cmd);
+       }
+       return ret;
+}
+
+static int vmwdt_disable(void)
+{
+       int ret = __diag288(wdt_cancel, 0, "", 0);
+       if (ret) {
+               printk(KERN_WARNING "%s: problem disabling watchdog\n",
+                       __FUNCTION__);
+       }
+       return ret;
+}
+
+static int __init vmwdt_probe(void)
+{
+       /* there is no real way to see if the watchdog is supported,
+        * so we try initializing it with a NOP command ("BEGIN")
+        * that won't cause any harm even if the following disable
+        * fails for some reason */
+       static char __initdata ebc_begin[] = {
+               194, 197, 199, 201, 213
+       };
+       if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) {
+               printk(KERN_INFO "z/VM watchdog not available\n");
+               return -EINVAL;
+       }
+       return vmwdt_disable();
+}
+
+static int vmwdt_open(struct inode *i, struct file *f)
+{
+       int ret;
+       if (test_and_set_bit(0, &vmwdt_is_open))
+               return -EBUSY;
+       ret = vmwdt_keepalive();
+       if (ret)
+               clear_bit(0, &vmwdt_is_open);
+       return ret ? ret : nonseekable_open(i, f);
+}
+
+static int vmwdt_close(struct inode *i, struct file *f)
+{
+       if (vmwdt_expect_close == 42)
+               vmwdt_disable();
+       vmwdt_expect_close = 0;
+       clear_bit(0, &vmwdt_is_open);
+       return 0;
+}
+
+static struct watchdog_info vmwdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .firmware_version = 0,
+       .identity = "z/VM Watchdog Timer",
+};
+
+static int vmwdt_ioctl(struct inode *i, struct file *f,
+                         unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user((void __user *)arg, &vmwdt_info,
+                                       sizeof(vmwdt_info)))
+                       return -EFAULT;
+               return 0;
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, (int *)arg);
+       case WDIOC_GETTEMP:
+               return -EINVAL;
+       case WDIOC_SETOPTIONS:
+               {
+                       int options, ret;
+                       if (get_user(options, (int __user *)arg))
+                               return -EFAULT;
+                       ret = -EINVAL;
+                       if (options & WDIOS_DISABLECARD) {
+                               ret = vmwdt_disable();
+                               if (ret)
+                                       return ret;
+                       }
+                       if (options & WDIOS_ENABLECARD) {
+                               ret = vmwdt_keepalive();
+                       }
+                       return ret;
+               }
+       case WDIOC_GETTIMEOUT:
+               return put_user(vmwdt_interval, (int __user *)arg);
+       case WDIOC_SETTIMEOUT:
+               {
+                       int interval;
+                       if (get_user(interval, (int __user *)arg))
+                               return -EFAULT;
+                       if (interval < MIN_INTERVAL)
+                               return -EINVAL;
+                       vmwdt_interval = interval;
+               }
+               return vmwdt_keepalive();
+       case WDIOC_KEEPALIVE:
+               return vmwdt_keepalive();
+       }
+
+       return -EINVAL;
+}
+
+static ssize_t vmwdt_write(struct file *f, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       if(count) {
+               if (!vmwdt_nowayout) {
+                       size_t i;
+
+                       /* note: just in case someone wrote the magic character
+                        * five months ago... */
+                       vmwdt_expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf+i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       vmwdt_expect_close = 42;
+                       }
+               }
+               /* someone wrote to us, we should restart timer */
+               vmwdt_keepalive();
+       }
+       return count;
+}
+
+static struct file_operations vmwdt_fops = {
+       .open    = &vmwdt_open,
+       .release = &vmwdt_close,
+       .ioctl   = &vmwdt_ioctl,
+       .write   = &vmwdt_write,
+       .owner   = THIS_MODULE,
+};
+
+static struct miscdevice vmwdt_dev = {
+       .minor      = WATCHDOG_MINOR,
+       .name       = "watchdog",
+       .fops       = &vmwdt_fops,
+};
+
+static int __init vmwdt_init(void)
+{
+       int ret;
+
+       ret = vmwdt_probe();
+       if (ret)
+               return ret;
+       return misc_register(&vmwdt_dev);
+}
+module_init(vmwdt_init);
+
+static void __exit vmwdt_exit(void)
+{
+       WARN_ON(misc_deregister(&vmwdt_dev) != 0);
+}
+module_exit(vmwdt_exit);
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
new file mode 100644 (file)
index 0000000..c34403c
--- /dev/null
@@ -0,0 +1,1202 @@
+/*
+ * Initio A100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 2003-2004 Christoph Hellwig
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * Revision History:
+ * 07/02/98 hl - v.91n Initial drivers.
+ * 09/14/98 hl - v1.01 Support new Kernel.
+ * 09/22/98 hl - v1.01a Support reset.
+ * 09/24/98 hl - v1.01b Fixed reset.
+ * 10/05/98 hl - v1.02 split the source code and release.
+ * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
+ * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
+ * 08/08/99 bv - v1.02c Use waitForPause again.
+ * 06/25/02 Doug Ledford <dledford@redhat.com> - v1.02d
+ *          - Remove limit on number of controllers
+ *          - Port to DMA mapping API
+ *          - Clean up interrupt handler registration
+ *          - Fix memory leaks
+ *          - Fix allocation of scsi host structs and private data
+ * 11/18/03 Christoph Hellwig <hch@lst.de>
+ *         - Port to new probing API
+ *         - Fix some more leaks in init failure cases
+ * 9/28/04 Christoph Hellwig <hch@lst.de>
+ *         - merge the two source files
+ *         - remove internal queueing code
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "a100u2w.h"
+
+
+#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
+#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
+
+static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
+static void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
+
+static NVRAM nvram, *nvramp = &nvram;
+static UCHAR dftNvRam[64] =
+{
+/*----------header -------------*/
+       0x01,                   /* 0x00: Sub System Vendor ID 0 */
+       0x11,                   /* 0x01: Sub System Vendor ID 1 */
+       0x60,                   /* 0x02: Sub System ID 0        */
+       0x10,                   /* 0x03: Sub System ID 1        */
+       0x00,                   /* 0x04: SubClass               */
+       0x01,                   /* 0x05: Vendor ID 0            */
+       0x11,                   /* 0x06: Vendor ID 1            */
+       0x60,                   /* 0x07: Device ID 0            */
+       0x10,                   /* 0x08: Device ID 1            */
+       0x00,                   /* 0x09: Reserved               */
+       0x00,                   /* 0x0A: Reserved               */
+       0x01,                   /* 0x0B: Revision of Data Structure     */
+                               /* -- Host Adapter Structure --- */
+       0x01,                   /* 0x0C: Number Of SCSI Channel */
+       0x01,                   /* 0x0D: BIOS Configuration 1   */
+       0x00,                   /* 0x0E: BIOS Configuration 2   */
+       0x00,                   /* 0x0F: BIOS Configuration 3   */
+                               /* --- SCSI Channel 0 Configuration --- */
+       0x07,                   /* 0x10: H/A ID                 */
+       0x83,                   /* 0x11: Channel Configuration  */
+       0x20,                   /* 0x12: MAX TAG per target     */
+       0x0A,                   /* 0x13: SCSI Reset Recovering time     */
+       0x00,                   /* 0x14: Channel Configuration4 */
+       0x00,                   /* 0x15: Channel Configuration5 */
+                               /* SCSI Channel 0 Target Configuration  */
+                               /* 0x16-0x25                    */
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+                               /* --- SCSI Channel 1 Configuration --- */
+       0x07,                   /* 0x26: H/A ID                 */
+       0x83,                   /* 0x27: Channel Configuration  */
+       0x20,                   /* 0x28: MAX TAG per target     */
+       0x0A,                   /* 0x29: SCSI Reset Recovering time     */
+       0x00,                   /* 0x2A: Channel Configuration4 */
+       0x00,                   /* 0x2B: Channel Configuration5 */
+                               /* SCSI Channel 1 Target Configuration  */
+                               /* 0x2C-0x3B                    */
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+       0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+       0x00,                   /* 0x3C: Reserved               */
+       0x00,                   /* 0x3D: Reserved               */
+       0x00,                   /* 0x3E: Reserved               */
+       0x00                    /* 0x3F: Checksum               */
+};
+
+
+/***************************************************************************/
+static void waitForPause(unsigned amount)
+{
+       ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
+       while (time_before_eq(jiffies, the_time))
+               cpu_relax();
+}
+
+/***************************************************************************/
+static UCHAR waitChipReady(ORC_HCS * hcsp)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
+               if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP)       /* Wait HOSTSTOP set */
+                       return 1;
+               waitForPause(100);      /* wait 100ms before try again  */
+       }
+       return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitFWReady(ORC_HCS * hcsp)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
+               if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY)         /* Wait READY set */
+                       return 1;
+               waitForPause(100);      /* wait 100ms before try again  */
+       }
+       return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
+               if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST))     /* Wait SCSIRST done */
+                       return 1;
+               waitForPause(100);      /* wait 100ms before try again  */
+       }
+       return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitHDOoff(ORC_HCS * hcsp)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
+               if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO))         /* Wait HDO off */
+                       return 1;
+               waitForPause(100);      /* wait 100ms before try again  */
+       }
+       return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
+               if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
+                       return 1;       /* Wait HDI set */
+               waitForPause(100);      /* wait 100ms before try again  */
+       }
+       return 0;
+}
+
+/***************************************************************************/
+static unsigned short get_FW_version(ORC_HCS * hcsp)
+{
+       UCHAR bData;
+       union {
+               unsigned short sVersion;
+               unsigned char cVersion[2];
+       } Version;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION);
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       if (waitHDIset(hcsp, &bData) == 0)      /* Wait HDI set   */
+               return 0;
+       Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+       ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI            */
+
+       if (waitHDIset(hcsp, &bData) == 0)      /* Wait HDI set   */
+               return 0;
+       Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+       ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI            */
+
+       return (Version.sVersion);
+}
+
+/***************************************************************************/
+static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value)
+{
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM);    /* Write command */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);    /* Write address */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, value);      /* Write value  */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       return 1;
+}
+
+/***************************************************************************/
+static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn)
+{
+       unsigned char bData;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM);    /* Write command */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);    /* Write address */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       if (waitHDIset(hcsp, &bData) == 0)      /* Wait HDI set   */
+               return 0;
+       *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+       ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI    */
+
+       return 1;
+}
+
+/***************************************************************************/
+static void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+{
+       scbp->SCB_Status = ORCSCB_POST;
+       ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
+       return;
+}
+
+
+/***********************************************************************
+ Read SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+static int se2_rd_all(ORC_HCS * hcsp)
+{
+       int i;
+       UCHAR *np, chksum = 0;
+
+       np = (UCHAR *) nvramp;
+       for (i = 0; i < 64; i++, np++) {        /* <01> */
+               if (get_NVRAM(hcsp, (unsigned char) i, np) == 0)
+                       return -1;
+//      *np++ = get_NVRAM(hcsp, (unsigned char ) i);
+       }
+
+/*------ Is ckecksum ok ? ------*/
+       np = (UCHAR *) nvramp;
+       for (i = 0; i < 63; i++)
+               chksum += *np++;
+
+       if (nvramp->CheckSum != (UCHAR) chksum)
+               return -1;
+       return 1;
+}
+
+/************************************************************************
+ Update SCSI H/A configuration parameters from serial EEPROM
+*************************************************************************/
+static void se2_update_all(ORC_HCS * hcsp)
+{                              /* setup default pattern  */
+       int i;
+       UCHAR *np, *np1, chksum = 0;
+
+       /* Calculate checksum first   */
+       np = (UCHAR *) dftNvRam;
+       for (i = 0; i < 63; i++)
+               chksum += *np++;
+       *np = chksum;
+
+       np = (UCHAR *) dftNvRam;
+       np1 = (UCHAR *) nvramp;
+       for (i = 0; i < 64; i++, np++, np1++) {
+               if (*np != *np1) {
+                       set_NVRAM(hcsp, (unsigned char) i, *np);
+               }
+       }
+       return;
+}
+
+/*************************************************************************
+ Function name  : read_eeprom
+**************************************************************************/
+static void read_eeprom(ORC_HCS * hcsp)
+{
+       if (se2_rd_all(hcsp) != 1) {
+               se2_update_all(hcsp);   /* setup default pattern        */
+               se2_rd_all(hcsp);       /* load again                   */
+       }
+}
+
+
+/***************************************************************************/
+static UCHAR load_FW(ORC_HCS * hcsp)
+{
+       U32 dData;
+       USHORT wBIOSAddress;
+       USHORT i;
+       UCHAR *pData, bData;
+
+
+       bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG);
+       ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG);       /* Enable EEPROM programming */
+       ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00);
+       ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00);
+       if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) {
+               ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
+               return 0;
+       }
+       ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01);
+       if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) {
+               ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
+               return 0;
+       }
+       ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);       /* Enable SRAM programming */
+       pData = (UCHAR *) & dData;
+       dData = 0;              /* Initial FW address to 0 */
+       ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10);
+       *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);         /* Read from BIOS */
+       ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11);
+       *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);   /* Read from BIOS */
+       ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12);
+       *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);   /* Read from BIOS */
+       ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2));
+       ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData);      /* Write FW address */
+
+       wBIOSAddress = (USHORT) dData;  /* FW code locate at BIOS address + ? */
+       for (i = 0, pData = (UCHAR *) & dData;  /* Download the code    */
+            i < 0x1000;        /* Firmware code size = 4K      */
+            i++, wBIOSAddress++) {
+               ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
+               *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);       /* Read from BIOS */
+               if ((i % 4) == 3) {
+                       ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData);        /* Write every 4 bytes */
+                       pData = (UCHAR *) & dData;
+               }
+       }
+
+       ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);       /* Reset program count 0 */
+       wBIOSAddress -= 0x1000; /* Reset the BIOS adddress      */
+       for (i = 0, pData = (UCHAR *) & dData;  /* Check the code       */
+            i < 0x1000;        /* Firmware code size = 4K      */
+            i++, wBIOSAddress++) {
+               ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
+               *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);       /* Read from BIOS */
+               if ((i % 4) == 3) {
+                       if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) {
+                               ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);  /* Reset program to 0 */
+                               ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /*Disable EEPROM programming */
+                               return 0;
+                       }
+                       pData = (UCHAR *) & dData;
+               }
+       }
+       ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);  /* Reset program to 0   */
+       ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
+       return 1;
+}
+
+/***************************************************************************/
+static void setup_SCBs(ORC_HCS * hcsp)
+{
+       ORC_SCB *pVirScb;
+       int i;
+       ESCB *pVirEscb;
+       dma_addr_t pPhysEscb;
+
+       /* Setup SCB HCS_Base and SCB Size registers */
+       ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, ORC_MAXQUEUE);     /* Total number of SCBs */
+       /* SCB HCS_Base address 0      */
+       ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
+       /* SCB HCS_Base address 1      */
+       ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray);
+
+       /* setup scatter list address with one buffer */
+       pVirScb = hcsp->HCS_virScbArray;
+       pVirEscb = hcsp->HCS_virEscbArray;
+
+       for (i = 0; i < ORC_MAXQUEUE; i++) {
+               pPhysEscb = (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
+               pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
+               pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
+               pVirScb->SCB_EScb = pVirEscb;
+               pVirScb->SCB_ScbIdx = i;
+               pVirScb++;
+               pVirEscb++;
+       }
+
+       return;
+}
+
+/***************************************************************************/
+static void initAFlag(ORC_HCS * hcsp)
+{
+       UCHAR i, j;
+
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               for (j = 0; j < 8; j++) {
+                       hcsp->BitAllocFlag[i][j] = 0xffffffff;
+               }
+       }
+}
+
+/***************************************************************************/
+static int init_orchid(ORC_HCS * hcsp)
+{
+       UBYTE *readBytep;
+       USHORT revision;
+       UCHAR i;
+
+       initAFlag(hcsp);
+       ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF);       /* Disable all interrupt        */
+       if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) {       /* Orchid is ready              */
+               revision = get_FW_version(hcsp);
+               if (revision == 0xFFFF) {
+                       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);     /* Reset Host Adapter   */
+                       if (waitChipReady(hcsp) == 0)
+                               return (-1);
+                       load_FW(hcsp);  /* Download FW                  */
+                       setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
+                       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0);  /* clear HOSTSTOP       */
+                       if (waitFWReady(hcsp) == 0)
+                               return (-1);
+                       /* Wait for firmware ready     */
+               } else {
+                       setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
+               }
+       } else {                /* Orchid is not Ready          */
+               ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);     /* Reset Host Adapter   */
+               if (waitChipReady(hcsp) == 0)
+                       return (-1);
+               load_FW(hcsp);  /* Download FW                  */
+               setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
+               ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);        /* Do Hardware Reset &  */
+
+               /*     clear HOSTSTOP  */
+               if (waitFWReady(hcsp) == 0)             /* Wait for firmware ready      */
+                       return (-1);
+       }
+
+/*------------- get serial EEProm settting -------*/
+
+       read_eeprom(hcsp);
+
+       if (nvramp->Revision != 1)
+               return (-1);
+
+       hcsp->HCS_SCSI_ID = nvramp->SCSI0Id;
+       hcsp->HCS_BIOS = nvramp->BIOSConfig1;
+       hcsp->HCS_MaxTar = MAX_TARGETS;
+       readBytep = (UCHAR *) & (nvramp->Target00Config);
+       for (i = 0; i < 16; readBytep++, i++) {
+               hcsp->TargetFlag[i] = *readBytep;
+               hcsp->MaximumTags[i] = ORC_MAXTAGS;
+       }                       /* for                          */
+
+       if (nvramp->SCSI0Config & NCC_BUSRESET) {       /* Reset SCSI bus               */
+               hcsp->HCS_Flags |= HCF_SCSI_RESET;
+       }
+       ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB);       /* enable RP FIFO interrupt     */
+       return (0);
+}
+
+/*****************************************************************************
+ Function name  : orc_reset_scsi_bus
+ Description    : Reset registers, reset a hanging bus and
+                  kill active and disconnected commands for target w/o soft reset
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int orc_reset_scsi_bus(ORC_HCS * pHCB)
+{                              /* I need Host Control Block Information */
+       ULONG flags;
+
+       spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
+
+       initAFlag(pHCB);
+       /* reset scsi bus */
+       ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST);
+       if (waitSCSIRSTdone(pHCB) == 0) {
+               spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+               return FAILED;
+       } else {
+               spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+               return SUCCESS;
+       }
+}
+
+/*****************************************************************************
+ Function name  : orc_device_reset
+ Description    : Reset registers, reset a hanging bus and
+                  kill active and disconnected commands for target w/o soft reset
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target)
+{                              /* I need Host Control Block Information */
+       ORC_SCB *pScb;
+       ESCB *pVirEscb;
+       ORC_SCB *pVirScb;
+       UCHAR i;
+       ULONG flags;
+
+       spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
+       pScb = (ORC_SCB *) NULL;
+       pVirEscb = (ESCB *) NULL;
+
+       /* setup scatter list address with one buffer */
+       pVirScb = pHCB->HCS_virScbArray;
+
+       initAFlag(pHCB);
+       /* device reset */
+       for (i = 0; i < ORC_MAXQUEUE; i++) {
+               pVirEscb = pVirScb->SCB_EScb;
+               if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt))
+                       break;
+               pVirScb++;
+       }
+
+       if (i == ORC_MAXQUEUE) {
+               printk("Unable to Reset - No SCB Found\n");
+               spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+               return FAILED;
+       }
+       if ((pScb = orc_alloc_scb(pHCB)) == NULL) {
+               spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+               return FAILED;
+       }
+       pScb->SCB_Opcode = ORC_BUSDEVRST;
+       pScb->SCB_Target = target;
+       pScb->SCB_HaStat = 0;
+       pScb->SCB_TaStat = 0;
+       pScb->SCB_Status = 0x0;
+       pScb->SCB_Link = 0xFF;
+       pScb->SCB_Reserved0 = 0;
+       pScb->SCB_Reserved1 = 0;
+       pScb->SCB_XferLen = 0;
+       pScb->SCB_SGLen = 0;
+
+       pVirEscb->SCB_Srb = NULL;
+       pVirEscb->SCB_Srb = SCpnt;
+       orc_exec_scb(pHCB, pScb);       /* Start execute SCB            */
+       spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+       return SUCCESS;
+}
+
+
+/***************************************************************************/
+static ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp)
+{
+       ORC_SCB *pTmpScb;
+       UCHAR Ch;
+       ULONG idx;
+       UCHAR index;
+       UCHAR i;
+
+       Ch = hcsp->HCS_Index;
+       for (i = 0; i < 8; i++) {
+               for (index = 0; index < 32; index++) {
+                       if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) {
+                               hcsp->BitAllocFlag[Ch][i] &= ~(1 << index);
+                               break;
+                       }
+               }
+               idx = index + 32 * i;
+               pTmpScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB)));
+               return (pTmpScb);
+       }
+       return (NULL);
+}
+
+static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp)
+{
+       ORC_SCB *pTmpScb;
+       ULONG flags;
+
+       spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+       pTmpScb = __orc_alloc_scb(hcsp);
+       spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+       return (pTmpScb);
+}
+
+
+/***************************************************************************/
+static void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+{
+       ULONG flags;
+       UCHAR Index;
+       UCHAR i;
+       UCHAR Ch;
+
+       spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+       Ch = hcsp->HCS_Index;
+       Index = scbp->SCB_ScbIdx;
+       i = Index / 32;
+       Index %= 32;
+       hcsp->BitAllocFlag[Ch][i] |= (1 << Index);
+       spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+}
+
+/*****************************************************************************
+ Function name  : abort_SCB
+ Description    : Abort a queued command.
+                        (commands that are on the bus can't be aborted easily)
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb)
+{
+       unsigned char bData, bStatus;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB);  /* Write command */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx);   /* Write address */
+       ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+       if (waitHDOoff(hcsp) == 0)      /* Wait HDO off   */
+               return 0;
+
+       if (waitHDIset(hcsp, &bData) == 0)      /* Wait HDI set   */
+               return 0;
+       bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+       ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI    */
+
+       if (bStatus == 1)       /* 0 - Successfully               */
+               return 0;       /* 1 - Fail                     */
+       return 1;
+}
+
+/*****************************************************************************
+ Function name  : inia100_abort
+ Description    : Abort a queued command.
+                        (commands that are on the bus can't be aborted easily)
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt)
+{
+       ESCB *pVirEscb;
+       ORC_SCB *pVirScb;
+       UCHAR i;
+       ULONG flags;
+
+       spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+
+       pVirScb = hcsp->HCS_virScbArray;
+
+       for (i = 0; i < ORC_MAXQUEUE; i++, pVirScb++) {
+               pVirEscb = pVirScb->SCB_EScb;
+               if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) {
+                       if (pVirScb->SCB_TagMsg == 0) {
+                               spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+                               return FAILED;
+                       } else {
+                               if (abort_SCB(hcsp, pVirScb)) {
+                                       pVirEscb->SCB_Srb = NULL;
+                                       spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+                                       return SUCCESS;
+                               } else {
+                                       spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+                                       return FAILED;
+                               }
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+       return FAILED;
+}
+
+/***********************************************************************
+ Routine Description:
+         This is the interrupt service routine for the Orchid SCSI adapter.
+         It reads the interrupt register to determine if the adapter is indeed
+         the source of the interrupt and clears the interrupt at the device.
+ Arguments:
+         HwDeviceExtension - HBA miniport driver's adapter data storage
+ Return Value:
+***********************************************************************/
+static void orc_interrupt(
+                         ORC_HCS * hcsp
+)
+{
+       BYTE bScbIdx;
+       ORC_SCB *pScb;
+
+       if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) {
+               return;         // 0;
+
+       }
+       do {
+               bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE);
+
+               pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx));
+               pScb->SCB_Status = 0x0;
+
+               inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb);
+       } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT));
+       return;                 //1;
+
+}                              /* End of I1060Interrupt() */
+
+/*****************************************************************************
+ Function name  : inia100BuildSCB
+ Description    : 
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt)
+{                              /* Create corresponding SCB     */
+       struct scatterlist *pSrbSG;
+       ORC_SG *pSG;            /* Pointer to SG list           */
+       int i, count_sg;
+       ESCB *pEScb;
+
+       pEScb = pSCB->SCB_EScb;
+       pEScb->SCB_Srb = SCpnt;
+       pSG = NULL;
+
+       pSCB->SCB_Opcode = ORC_EXECSCSI;
+       pSCB->SCB_Flags = SCF_NO_DCHK;  /* Clear done bit               */
+       pSCB->SCB_Target = SCpnt->device->id;
+       pSCB->SCB_Lun = SCpnt->device->lun;
+       pSCB->SCB_Reserved0 = 0;
+       pSCB->SCB_Reserved1 = 0;
+       pSCB->SCB_SGLen = 0;
+
+       if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {
+               pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
+               if (SCpnt->use_sg) {
+                       pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
+                       count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,
+                                       SCpnt->sc_data_direction);
+                       pSCB->SCB_SGLen = (U32) (count_sg * 8);
+                       for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {
+                               pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);
+                               pSG->SG_Len = (U32) sg_dma_len(pSrbSG);
+                       }
+               } else if (SCpnt->request_bufflen != 0) {/* Non SG */
+                       pSCB->SCB_SGLen = 0x8;
+                       SCpnt->SCp.dma_handle = pci_map_single(pHCB->pdev,
+                                       SCpnt->request_buffer,
+                                       SCpnt->request_bufflen,
+                                       SCpnt->sc_data_direction);
+                       pSG->SG_Ptr = (U32) SCpnt->SCp.dma_handle;
+                       pSG->SG_Len = (U32) SCpnt->request_bufflen;
+               } else {
+                       pSCB->SCB_SGLen = 0;
+                       pSG->SG_Ptr = 0;
+                       pSG->SG_Len = 0;
+               }
+       }
+       pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;
+       pSCB->SCB_HaStat = 0;
+       pSCB->SCB_TaStat = 0;
+       pSCB->SCB_Link = 0xFF;
+       pSCB->SCB_SenseLen = SENSE_SIZE;
+       pSCB->SCB_CDBLen = SCpnt->cmd_len;
+       if (pSCB->SCB_CDBLen >= IMAX_CDB) {
+               printk("max cdb length= %x\b", SCpnt->cmd_len);
+               pSCB->SCB_CDBLen = IMAX_CDB;
+       }
+       pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
+       if (SCpnt->device->tagged_supported) {  /* Tag Support                  */
+               pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;    /* Do simple tag only   */
+       } else {
+               pSCB->SCB_TagMsg = 0;   /* No tag support               */
+       }
+       memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);
+       return;
+}
+
+/*****************************************************************************
+ Function name  : inia100_queue
+ Description    : Queue a command and setup interrupts for a free bus.
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *))
+{
+       register ORC_SCB *pSCB;
+       ORC_HCS *pHCB;          /* Point to Host adapter control block */
+
+       pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
+       SCpnt->scsi_done = done;
+       /* Get free SCSI control block  */
+       if ((pSCB = orc_alloc_scb(pHCB)) == NULL)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       inia100BuildSCB(pHCB, pSCB, SCpnt);
+       orc_exec_scb(pHCB, pSCB);       /* Start execute SCB            */
+
+       return (0);
+}
+
+/*****************************************************************************
+ Function name  : inia100_abort
+ Description    : Abort a queued command.
+                        (commands that are on the bus can't be aborted easily)
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_abort(struct scsi_cmnd * SCpnt)
+{
+       ORC_HCS *hcsp;
+
+       hcsp = (ORC_HCS *) SCpnt->device->host->hostdata;
+       return orc_abort_srb(hcsp, SCpnt);
+}
+
+/*****************************************************************************
+ Function name  : inia100_reset
+ Description    : Reset registers, reset a hanging bus and
+                  kill active and disconnected commands for target w/o soft reset
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_bus_reset(struct scsi_cmnd * SCpnt)
+{                              /* I need Host Control Block Information */
+       ORC_HCS *pHCB;
+       pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
+       return orc_reset_scsi_bus(pHCB);
+}
+
+/*****************************************************************************
+ Function name  : inia100_device_reset
+ Description    : Reset the device
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_device_reset(struct scsi_cmnd * SCpnt)
+{                              /* I need Host Control Block Information */
+       ORC_HCS *pHCB;
+       pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
+       return orc_device_reset(pHCB, SCpnt, SCpnt->device->id);
+
+}
+
+/*****************************************************************************
+ Function name  : inia100SCBPost
+ Description    : This is callback routine be called when orc finish one
+                       SCSI command.
+ Input          : pHCB  -       Pointer to host adapter control block.
+                 pSCB  -       Pointer to SCSI control block.
+ Output         : None.
+ Return         : None.
+*****************************************************************************/
+static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
+{
+       struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
+       ORC_HCS *pHCB;
+       ORC_SCB *pSCB;
+       ESCB *pEScb;
+
+       pHCB = (ORC_HCS *) pHcb;
+       pSCB = (ORC_SCB *) pScb;
+       pEScb = pSCB->SCB_EScb;
+       if ((pSRB = (struct scsi_cmnd *) pEScb->SCB_Srb) == 0) {
+               printk("inia100SCBPost: SRB pointer is empty\n");
+               orc_release_scb(pHCB, pSCB);    /* Release SCB for current channel */
+               return;
+       }
+       pEScb->SCB_Srb = NULL;
+
+       switch (pSCB->SCB_HaStat) {
+       case 0x0:
+       case 0xa:               /* Linked command complete without error and linked normally */
+       case 0xb:               /* Linked command complete without error interrupt generated */
+               pSCB->SCB_HaStat = 0;
+               break;
+
+       case 0x11:              /* Selection time out-The initiator selection or target
+                                  reselection was not complete within the SCSI Time out period */
+               pSCB->SCB_HaStat = DID_TIME_OUT;
+               break;
+
+       case 0x14:              /* Target bus phase sequence failure-An invalid bus phase or bus
+                                  phase sequence was requested by the target. The host adapter
+                                  will generate a SCSI Reset Condition, notifying the host with
+                                  a SCRD interrupt */
+               pSCB->SCB_HaStat = DID_RESET;
+               break;
+
+       case 0x1a:              /* SCB Aborted. 07/21/98 */
+               pSCB->SCB_HaStat = DID_ABORT;
+               break;
+
+       case 0x12:              /* Data overrun/underrun-The target attempted to transfer more data
+                                  than was allocated by the Data Length field or the sum of the
+                                  Scatter / Gather Data Length fields. */
+       case 0x13:              /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+       case 0x16:              /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */
+
+       default:
+               printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
+               pSCB->SCB_HaStat = DID_ERROR;   /* Couldn't find any better */
+               break;
+       }
+
+       if (pSCB->SCB_TaStat == 2) {    /* Check condition              */
+               memcpy((unsigned char *) &pSRB->sense_buffer[0],
+                  (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);
+       }
+       pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+
+       if (pSRB->use_sg) {
+               pci_unmap_sg(pHCB->pdev,
+                            (struct scatterlist *)pSRB->request_buffer,
+                            pSRB->use_sg, pSRB->sc_data_direction);
+       } else if (pSRB->request_bufflen != 0) {
+               pci_unmap_single(pHCB->pdev, pSRB->SCp.dma_handle,
+                                pSRB->request_bufflen,
+                                pSRB->sc_data_direction);
+       }
+
+       pSRB->scsi_done(pSRB);  /* Notify system DONE           */
+
+       orc_release_scb(pHCB, pSCB);    /* Release SCB for current channel */
+}
+
+/*
+ * Interrupt handler (main routine of the driver)
+ */
+static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs)
+{
+       struct Scsi_Host *host = (struct Scsi_Host *)devid;
+       ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
+       unsigned long flags;
+
+       spin_lock_irqsave(host->host_lock, flags);
+       orc_interrupt(pHcb);
+       spin_unlock_irqrestore(host->host_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static struct scsi_host_template inia100_template = {
+       .proc_name              = "inia100",
+       .name                   = inia100_REVID,
+       .queuecommand           = inia100_queue,
+       .eh_abort_handler       = inia100_abort,
+       .eh_bus_reset_handler   = inia100_bus_reset,
+       .eh_device_reset_handler = inia100_device_reset,
+       .can_queue              = 1,
+       .this_id                = 1,
+       .sg_tablesize           = SG_ALL,
+       .cmd_per_lun            = 1,
+       .use_clustering         = ENABLE_CLUSTERING,
+};
+
+static int __devinit inia100_probe_one(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       struct Scsi_Host *shost;
+       ORC_HCS *pHCB;
+       unsigned long port, bios;
+       int error = -ENODEV;
+       u32 sz;
+       unsigned long dBiosAdr;
+       char *pbBiosAdr;
+
+       if (pci_enable_device(pdev))
+               goto out;
+       if (pci_set_dma_mask(pdev, 0xffffffffULL)) {
+               printk(KERN_WARNING "Unable to set 32bit DMA "
+                                   "on inia100 adapter, ignoring.\n");
+               goto out_disable_device;
+       }
+
+       pci_set_master(pdev);
+
+       port = pci_resource_start(pdev, 0);
+       if (!request_region(port, 256, "inia100")) {
+               printk(KERN_WARNING "inia100: io port 0x%lx, is busy.\n", port);
+               goto out_disable_device;
+       }
+
+       /* <02> read from base address + 0x50 offset to get the bios balue. */
+       bios = ORC_RDWORD(port, 0x50);
+
+
+       shost = scsi_host_alloc(&inia100_template, sizeof(ORC_HCS));
+       if (!shost)
+               goto out_release_region;
+
+       pHCB = (ORC_HCS *)shost->hostdata;
+       pHCB->pdev = pdev;
+       pHCB->HCS_Base = port;
+       pHCB->HCS_BIOS = bios;
+       spin_lock_init(&pHCB->BitAllocFlagLock);
+
+       /* Get total memory needed for SCB */
+       sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
+       pHCB->HCS_virScbArray = pci_alloc_consistent(pdev, sz,
+                       &pHCB->HCS_physScbArray);
+       if (!pHCB->HCS_virScbArray) {
+               printk("inia100: SCB memory allocation error\n");
+               goto out_host_put;
+       }
+       memset(pHCB->HCS_virScbArray, 0, sz);
+
+       /* Get total memory needed for ESCB */
+       sz = ORC_MAXQUEUE * sizeof(ESCB);
+       pHCB->HCS_virEscbArray = pci_alloc_consistent(pdev, sz,
+                       &pHCB->HCS_physEscbArray);
+       if (!pHCB->HCS_virEscbArray) {
+               printk("inia100: ESCB memory allocation error\n");
+               goto out_free_scb_array;
+       }
+       memset(pHCB->HCS_virEscbArray, 0, sz);
+
+       dBiosAdr = pHCB->HCS_BIOS;
+       dBiosAdr = (dBiosAdr << 4);
+       pbBiosAdr = phys_to_virt(dBiosAdr);
+       if (init_orchid(pHCB)) {        /* Initialize orchid chip */
+               printk("inia100: initial orchid fail!!\n");
+               goto out_free_escb_array;
+       }
+
+       shost->io_port = pHCB->HCS_Base;
+       shost->n_io_port = 0xff;
+       shost->can_queue = ORC_MAXQUEUE;
+       shost->unique_id = shost->io_port;
+       shost->max_id = pHCB->HCS_MaxTar;
+       shost->max_lun = 16;
+       shost->irq = pHCB->HCS_Intr = pdev->irq;
+       shost->this_id = pHCB->HCS_SCSI_ID;     /* Assign HCS index */
+       shost->sg_tablesize = TOTAL_SG_ENTRY;
+
+       /* Initial orc chip           */
+       error = request_irq(pdev->irq, inia100_intr, SA_SHIRQ,
+                       "inia100", shost);
+       if (error < 0) {
+               printk(KERN_WARNING "inia100: unable to get irq %d\n",
+                               pdev->irq);
+               goto out_free_escb_array;
+       }
+
+       pci_set_drvdata(pdev, shost);
+
+       error = scsi_add_host(shost, &pdev->dev);
+       if (error)
+               goto out_free_irq;
+
+       scsi_scan_host(shost);
+       return 0;
+
+ out_free_irq:
+        free_irq(shost->irq, shost);
+ out_free_escb_array:
+       pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
+                       pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
+ out_free_scb_array:
+       pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
+                       pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+ out_host_put:
+       scsi_host_put(shost);
+ out_release_region:
+        release_region(port, 256);
+ out_disable_device:
+       pci_disable_device(pdev);
+ out:
+       return error;
+}
+
+static void __devexit inia100_remove_one(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       ORC_HCS *pHCB = (ORC_HCS *)shost->hostdata;
+
+       scsi_remove_host(shost);
+
+        free_irq(shost->irq, shost);
+       pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
+                       pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
+       pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
+                       pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+        release_region(shost->io_port, 256);
+
+       scsi_host_put(shost);
+} 
+
+static struct pci_device_id inia100_pci_tbl[] = {
+       {PCI_VENDOR_ID_INIT, 0x1060, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0,}
+};
+MODULE_DEVICE_TABLE(pci, inia100_pci_tbl);
+
+static struct pci_driver inia100_pci_driver = {
+       .name           = "inia100",
+       .id_table       = inia100_pci_tbl,
+       .probe          = inia100_probe_one,
+       .remove         = __devexit_p(inia100_remove_one),
+};
+
+static int __init inia100_init(void)
+{
+       return pci_module_init(&inia100_pci_driver);
+}
+
+static void __exit inia100_exit(void)
+{
+       pci_unregister_driver(&inia100_pci_driver);
+}
+
+MODULE_DESCRIPTION("Initio A100U2W SCSI driver");
+MODULE_AUTHOR("Initio Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_init(inia100_init);
+module_exit(inia100_exit);
diff --git a/drivers/scsi/a100u2w.h b/drivers/scsi/a100u2w.h
new file mode 100644 (file)
index 0000000..6f542d2
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Initio A100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * Revision History:
+ * 06/18/98 HL, Initial production Version 1.02
+ * 12/19/98 bv, Use spinlocks for 2.1.95 and up
+ * 06/25/02 Doug Ledford <dledford@redhat.com>
+ *      - This and the i60uscsi.h file are almost identical,
+ *        merged them into a single header used by both .c files.
+ */
+
+#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d"
+
+#define ULONG   unsigned long
+#define USHORT  unsigned short
+#define UCHAR   unsigned char
+#define BYTE    unsigned char
+#define WORD    unsigned short
+#define DWORD   unsigned long
+#define UBYTE   unsigned char
+#define UWORD   unsigned short
+#define UDWORD  unsigned long
+#define U32     u32
+
+#if 1
+#define ORC_MAXQUEUE           245
+#define ORC_MAXTAGS            64
+#else
+#define ORC_MAXQUEUE           25
+#define ORC_MAXTAGS            8
+#endif
+
+#define TOTAL_SG_ENTRY         32
+#define MAX_TARGETS            16
+#define IMAX_CDB                       15
+#define SENSE_SIZE             14
+
+/************************************************************************/
+/*              Scatter-Gather Element Structure                        */
+/************************************************************************/
+typedef struct ORC_SG_Struc {
+       U32 SG_Ptr;             /* Data Pointer */
+       U32 SG_Len;             /* Data Length */
+} ORC_SG;
+
+/* SCSI related definition                                              */
+#define DISC_NOT_ALLOW          0x80   /* Disconnect is not allowed    */
+#define DISC_ALLOW              0xC0   /* Disconnect is allowed        */
+
+
+#define ORC_OFFSET_SCB                 16
+#define ORC_MAX_SCBS               250
+#define MAX_CHANNELS       2
+#define MAX_ESCB_ELE                           64
+#define TCF_DRV_255_63     0x0400
+
+/********************************************************/
+/*      Orchid Host Command Set                         */
+/********************************************************/
+#define ORC_CMD_NOP            0x00    /* Host command - NOP             */
+#define ORC_CMD_VERSION                0x01    /* Host command - Get F/W version */
+#define ORC_CMD_ECHO           0x02    /* Host command - ECHO            */
+#define ORC_CMD_SET_NVM                0x03    /* Host command - Set NVRAM       */
+#define ORC_CMD_GET_NVM                0x04    /* Host command - Get NVRAM       */
+#define ORC_CMD_GET_BUS_STATUS 0x05    /* Host command - Get SCSI bus status */
+#define ORC_CMD_ABORT_SCB      0x06    /* Host command - Abort SCB       */
+#define ORC_CMD_ISSUE_SCB      0x07    /* Host command - Issue SCB       */
+
+/********************************************************/
+/*              Orchid Register Set                     */
+/********************************************************/
+#define ORC_GINTS      0xA0    /* Global Interrupt Status        */
+#define QINT           0x04    /* Reply Queue Interrupt  */
+#define ORC_GIMSK      0xA1    /* Global Interrupt MASK  */
+#define MQINT          0x04    /* Mask Reply Queue Interrupt     */
+#define        ORC_GCFG        0xA2    /* Global Configure               */
+#define EEPRG          0x01    /* Enable EEPROM programming */
+#define        ORC_GSTAT       0xA3    /* Global status          */
+#define WIDEBUS                0x10    /* Wide SCSI Devices connected    */
+#define ORC_HDATA      0xA4    /* Host Data                      */
+#define ORC_HCTRL      0xA5    /* Host Control                   */
+#define SCSIRST                0x80    /* SCSI bus reset         */
+#define HDO                    0x40    /* Host data out          */
+#define HOSTSTOP               0x02    /* Host stop RISC engine  */
+#define DEVRST         0x01    /* Device reset                   */
+#define ORC_HSTUS      0xA6    /* Host Status                    */
+#define HDI                    0x02    /* Host data in                   */
+#define RREADY         0x01    /* RISC engine is ready to receive */
+#define        ORC_NVRAM       0xA7    /* Nvram port address             */
+#define SE2CS          0x008
+#define SE2CLK         0x004
+#define SE2DO          0x002
+#define SE2DI          0x001
+#define ORC_PQUEUE     0xA8    /* Posting queue FIFO             */
+#define ORC_PQCNT      0xA9    /* Posting queue FIFO Cnt */
+#define ORC_RQUEUE     0xAA    /* Reply queue FIFO               */
+#define ORC_RQUEUECNT  0xAB    /* Reply queue FIFO Cnt           */
+#define        ORC_FWBASEADR   0xAC    /* Firmware base address  */
+
+#define        ORC_EBIOSADR0 0xB0      /* External Bios address */
+#define        ORC_EBIOSADR1 0xB1      /* External Bios address */
+#define        ORC_EBIOSADR2 0xB2      /* External Bios address */
+#define        ORC_EBIOSDATA 0xB3      /* External Bios address */
+
+#define        ORC_SCBSIZE     0xB7    /* SCB size register              */
+#define        ORC_SCBBASE0    0xB8    /* SCB base address 0             */
+#define        ORC_SCBBASE1    0xBC    /* SCB base address 1             */
+
+#define        ORC_RISCCTL     0xE0    /* RISC Control                   */
+#define PRGMRST                0x002
+#define DOWNLOAD               0x001
+#define        ORC_PRGMCTR0    0xE2    /* RISC program counter           */
+#define        ORC_PRGMCTR1    0xE3    /* RISC program counter           */
+#define        ORC_RISCRAM     0xEC    /* RISC RAM data port 4 bytes     */
+
+typedef struct orc_extended_scb {      /* Extended SCB                 */
+       ORC_SG ESCB_SGList[TOTAL_SG_ENTRY];     /*0 Start of SG list              */
+       struct scsi_cmnd *SCB_Srb;      /*50 SRB Pointer */
+} ESCB;
+
+/***********************************************************************
+               SCSI Control Block
+************************************************************************/
+typedef struct orc_scb {       /* Scsi_Ctrl_Blk                */
+       UBYTE SCB_Opcode;       /*00 SCB command code&residual  */
+       UBYTE SCB_Flags;        /*01 SCB Flags                  */
+       UBYTE SCB_Target;       /*02 Target Id                  */
+       UBYTE SCB_Lun;          /*03 Lun                        */
+       U32 SCB_Reserved0;      /*04 Reserved for ORCHID must 0 */
+       U32 SCB_XferLen;        /*08 Data Transfer Length       */
+       U32 SCB_Reserved1;      /*0C Reserved for ORCHID must 0 */
+       U32 SCB_SGLen;          /*10 SG list # * 8              */
+       U32 SCB_SGPAddr;        /*14 SG List Buf physical Addr  */
+       U32 SCB_SGPAddrHigh;    /*18 SG Buffer high physical Addr */
+       UBYTE SCB_HaStat;       /*1C Host Status                */
+       UBYTE SCB_TaStat;       /*1D Target Status              */
+       UBYTE SCB_Status;       /*1E SCB status                 */
+       UBYTE SCB_Link;         /*1F Link pointer, default 0xFF */
+       UBYTE SCB_SenseLen;     /*20 Sense Allocation Length    */
+       UBYTE SCB_CDBLen;       /*21 CDB Length                 */
+       UBYTE SCB_Ident;        /*22 Identify                   */
+       UBYTE SCB_TagMsg;       /*23 Tag Message                */
+       UBYTE SCB_CDB[IMAX_CDB];        /*24 SCSI CDBs                  */
+       UBYTE SCB_ScbIdx;       /*3C Index for this ORCSCB      */
+       U32 SCB_SensePAddr;     /*34 Sense Buffer physical Addr */
+
+       ESCB *SCB_EScb;         /*38 Extended SCB Pointer       */
+#ifndef ALPHA
+       UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use    */
+#endif
+} ORC_SCB;
+
+/* Opcodes of ORCSCB_Opcode */
+#define ORC_EXECSCSI   0x00    /* SCSI initiator command with residual */
+#define ORC_BUSDEVRST  0x01    /* SCSI Bus Device Reset  */
+
+/* Status of ORCSCB_Status */
+#define ORCSCB_COMPLETE        0x00    /* SCB request completed  */
+#define ORCSCB_POST    0x01    /* SCB is posted by the HOST      */
+
+/* Bit Definition for ORCSCB_Flags */
+#define SCF_DISINT     0x01    /* Disable HOST interrupt */
+#define SCF_DIR                0x18    /* Direction bits         */
+#define SCF_NO_DCHK    0x00    /* Direction determined by SCSI   */
+#define SCF_DIN                0x08    /* From Target to Initiator       */
+#define SCF_DOUT       0x10    /* From Initiator to Target       */
+#define SCF_NO_XF      0x18    /* No data transfer               */
+#define SCF_POLL   0x40
+
+/* Error Codes for ORCSCB_HaStat */
+#define HOST_SEL_TOUT  0x11
+#define HOST_DO_DU     0x12
+#define HOST_BUS_FREE  0x13
+#define HOST_BAD_PHAS  0x14
+#define HOST_INV_CMD   0x16
+#define HOST_SCSI_RST  0x1B
+#define HOST_DEV_RST   0x1C
+
+
+/* Error Codes for ORCSCB_TaStat */
+#define TARGET_CHK_COND        0x02
+#define TARGET_BUSY    0x08
+#define TARGET_TAG_FULL        0x28
+
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+
+typedef struct ORC_Tar_Ctrl_Struc {
+       UBYTE TCS_DrvDASD;      /* 6 */
+       UBYTE TCS_DrvSCSI;      /* 7 */
+       UBYTE TCS_DrvHead;      /* 8 */
+       UWORD TCS_DrvFlags;     /* 4 */
+       UBYTE TCS_DrvSector;    /* 7 */
+} ORC_TCS;
+
+/* Bit Definition for TCF_DrvFlags */
+#define        TCS_DF_NODASD_SUPT      0x20    /* Suppress OS/2 DASD Mgr support */
+#define        TCS_DF_NOSCSI_SUPT      0x40    /* Suppress OS/2 SCSI Mgr support */
+
+
+/***********************************************************************
+              Host Adapter Control Structure
+************************************************************************/
+typedef struct ORC_Ha_Ctrl_Struc {
+       USHORT HCS_Base;        /* 00 */
+       UBYTE HCS_Index;        /* 02 */
+       UBYTE HCS_Intr;         /* 04 */
+       UBYTE HCS_SCSI_ID;      /* 06    H/A SCSI ID */
+       UBYTE HCS_BIOS;         /* 07    BIOS configuration */
+
+       UBYTE HCS_Flags;        /* 0B */
+       UBYTE HCS_HAConfig1;    /* 1B    SCSI0MAXTags */
+       UBYTE HCS_MaxTar;       /* 1B    SCSI0MAXTags */
+
+       USHORT HCS_Units;       /* Number of units this adapter  */
+       USHORT HCS_AFlags;      /* Adapter info. defined flags   */
+       ULONG HCS_Timeout;      /* Adapter timeout value   */
+       ORC_SCB *HCS_virScbArray;       /* 28 Virtual Pointer to SCB array */
+       dma_addr_t HCS_physScbArray;    /* Scb Physical address */
+       ESCB *HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */
+       dma_addr_t HCS_physEscbArray;   /* scatter list Physical address */
+       UBYTE TargetFlag[16];   /* 30  target configuration, TCF_EN_TAG */
+       UBYTE MaximumTags[16];  /* 40  ORC_MAX_SCBS */
+       UBYTE ActiveTags[16][16];       /* 50 */
+       ORC_TCS HCS_Tcs[16];    /* 28 */
+       U32 BitAllocFlag[MAX_CHANNELS][8];      /* Max STB is 256, So 256/32 */
+       spinlock_t BitAllocFlagLock;
+       struct pci_dev *pdev;
+} ORC_HCS;
+
+/* Bit Definition for HCS_Flags */
+
+#define HCF_SCSI_RESET 0x01    /* SCSI BUS RESET         */
+#define HCF_PARITY     0x02    /* parity card                    */
+#define HCF_LVDS       0x10    /* parity card                    */
+
+/* Bit Definition for TargetFlag */
+
+#define TCF_EN_255         0x08
+#define TCF_EN_TAG         0x10
+#define TCF_BUSY             0x20
+#define TCF_DISCONNECT 0x40
+#define TCF_SPIN_UP      0x80
+
+/* Bit Definition for HCS_AFlags */
+#define        HCS_AF_IGNORE           0x01    /* Adapter ignore         */
+#define        HCS_AF_DISABLE_RESET    0x10    /* Adapter disable reset  */
+#define        HCS_AF_DISABLE_ADPT     0x80    /* Adapter disable                */
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+        UCHAR SubVendorID0;     /* 00 - Sub Vendor ID           */
+        UCHAR SubVendorID1;     /* 00 - Sub Vendor ID           */
+        UCHAR SubSysID0;        /* 02 - Sub System ID           */
+        UCHAR SubSysID1;        /* 02 - Sub System ID           */
+        UCHAR SubClass;         /* 04 - Sub Class               */
+        UCHAR VendorID0;        /* 05 - Vendor ID               */
+        UCHAR VendorID1;        /* 05 - Vendor ID               */
+        UCHAR DeviceID0;        /* 07 - Device ID               */
+        UCHAR DeviceID1;        /* 07 - Device ID               */
+        UCHAR Reserved0[2];     /* 09 - Reserved                */
+        UCHAR Revision;         /* 0B - Revision of data structure */
+        /* ----Host Adapter Structure ---- */
+        UCHAR NumOfCh;          /* 0C - Number of SCSI channel  */
+        UCHAR BIOSConfig1;      /* 0D - BIOS configuration 1    */
+        UCHAR BIOSConfig2;      /* 0E - BIOS boot channel&target ID */
+        UCHAR BIOSConfig3;      /* 0F - BIOS configuration 3    */
+        /* ----SCSI channel Structure ---- */
+        /* from "CTRL-I SCSI Host Adapter SetUp menu "  */
+        UCHAR SCSI0Id;          /* 10 - Channel 0 SCSI ID       */
+        UCHAR SCSI0Config;      /* 11 - Channel 0 SCSI configuration */
+        UCHAR SCSI0MaxTags;     /* 12 - Channel 0 Maximum tags  */
+        UCHAR SCSI0ResetTime;   /* 13 - Channel 0 Reset recovering time */
+        UCHAR ReservedforChannel0[2];   /* 14 - Reserved                */
+
+        /* ----SCSI target Structure ----  */
+        /* from "CTRL-I SCSI device SetUp menu "                        */
+        UCHAR Target00Config;   /* 16 - Channel 0 Target 0 config */
+        UCHAR Target01Config;   /* 17 - Channel 0 Target 1 config */
+        UCHAR Target02Config;   /* 18 - Channel 0 Target 2 config */
+        UCHAR Target03Config;   /* 19 - Channel 0 Target 3 config */
+        UCHAR Target04Config;   /* 1A - Channel 0 Target 4 config */
+        UCHAR Target05Config;   /* 1B - Channel 0 Target 5 config */
+        UCHAR Target06Config;   /* 1C - Channel 0 Target 6 config */
+        UCHAR Target07Config;   /* 1D - Channel 0 Target 7 config */
+        UCHAR Target08Config;   /* 1E - Channel 0 Target 8 config */
+        UCHAR Target09Config;   /* 1F - Channel 0 Target 9 config */
+        UCHAR Target0AConfig;   /* 20 - Channel 0 Target A config */
+        UCHAR Target0BConfig;   /* 21 - Channel 0 Target B config */
+        UCHAR Target0CConfig;   /* 22 - Channel 0 Target C config */
+        UCHAR Target0DConfig;   /* 23 - Channel 0 Target D config */
+        UCHAR Target0EConfig;   /* 24 - Channel 0 Target E config */
+        UCHAR Target0FConfig;   /* 25 - Channel 0 Target F config */
+
+        UCHAR SCSI1Id;          /* 26 - Channel 1 SCSI ID       */
+        UCHAR SCSI1Config;      /* 27 - Channel 1 SCSI configuration */
+        UCHAR SCSI1MaxTags;     /* 28 - Channel 1 Maximum tags  */
+        UCHAR SCSI1ResetTime;   /* 29 - Channel 1 Reset recovering time */
+        UCHAR ReservedforChannel1[2];   /* 2A - Reserved                */
+
+        /* ----SCSI target Structure ----  */
+        /* from "CTRL-I SCSI device SetUp menu "                                          */
+        UCHAR Target10Config;   /* 2C - Channel 1 Target 0 config */
+        UCHAR Target11Config;   /* 2D - Channel 1 Target 1 config */
+        UCHAR Target12Config;   /* 2E - Channel 1 Target 2 config */
+        UCHAR Target13Config;   /* 2F - Channel 1 Target 3 config */
+        UCHAR Target14Config;   /* 30 - Channel 1 Target 4 config */
+        UCHAR Target15Config;   /* 31 - Channel 1 Target 5 config */
+        UCHAR Target16Config;   /* 32 - Channel 1 Target 6 config */
+        UCHAR Target17Config;   /* 33 - Channel 1 Target 7 config */
+        UCHAR Target18Config;   /* 34 - Channel 1 Target 8 config */
+        UCHAR Target19Config;   /* 35 - Channel 1 Target 9 config */
+        UCHAR Target1AConfig;   /* 36 - Channel 1 Target A config */
+        UCHAR Target1BConfig;   /* 37 - Channel 1 Target B config */
+        UCHAR Target1CConfig;   /* 38 - Channel 1 Target C config */
+        UCHAR Target1DConfig;   /* 39 - Channel 1 Target D config */
+        UCHAR Target1EConfig;   /* 3A - Channel 1 Target E config */
+        UCHAR Target1FConfig;   /* 3B - Channel 1 Target F config */
+        UCHAR reserved[3];      /* 3C - Reserved                */
+        /* ---------- CheckSum ----------       */
+        UCHAR CheckSum;         /* 3F - Checksum of NVRam       */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1                            */
+#define NBC_BIOSENABLE  0x01    /* BIOS enable                    */
+#define NBC_CDROM       0x02    /* Support bootable CDROM */
+#define NBC_REMOVABLE   0x04    /* Support removable drive        */
+
+/* Bios Configuration for nvram->BIOSConfig2                            */
+#define NBB_TARGET_MASK 0x0F    /* Boot SCSI target ID number     */
+#define NBB_CHANL_MASK  0xF0    /* Boot SCSI channel number       */
+
+/* Bit definition for nvram->SCSIConfig                                 */
+#define NCC_BUSRESET    0x01    /* Reset SCSI bus at power up     */
+#define NCC_PARITYCHK   0x02    /* SCSI parity enable             */
+#define NCC_LVDS        0x10    /* Enable LVDS                    */
+#define NCC_ACTTERM1    0x20    /* Enable active terminator 1     */
+#define NCC_ACTTERM2    0x40    /* Enable active terminator 2     */
+#define NCC_AUTOTERM    0x80    /* Enable auto termination        */
+
+/* Bit definition for nvram->TargetxConfig                              */
+#define NTC_PERIOD      0x07    /* Maximum Sync. Speed            */
+#define NTC_1GIGA       0x08    /* 255 head / 63 sectors (64/32) */
+#define NTC_NO_SYNC     0x10    /* NO SYNC. NEGO          */
+#define NTC_NO_WIDESYNC 0x20    /* NO WIDE SYNC. NEGO             */
+#define NTC_DISC_ENABLE 0x40    /* Enable SCSI disconnect */
+#define NTC_SPINUP      0x80    /* Start disk drive               */
+
+/* Default NVRam values                                                 */
+#define NBC_DEFAULT     (NBC_ENABLE)
+#define NCC_DEFAULT     (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK)
+#define NCC_MAX_TAGS    0x20    /* Maximum tags per target        */
+#define NCC_RESET_TIME  0x0A    /* SCSI RESET recovering time     */
+#define NTC_DEFAULT     (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE)
+
+#define ORC_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+#define ORC_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+#define ORC_RDLONG(x,y)         (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+#define ORC_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
+#define ORC_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
+#define ORC_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
new file mode 100644 (file)
index 0000000..b5cfeab
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Adaptec AIC79xx device driver for Linux.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $Id$
+ *
+ */
+#ifndef _AIC79XX_PCI_H_
+#define _AIC79XX_PCI_H_
+
+#define ID_ALL_MASK                    0xFFFFFFFFFFFFFFFFull
+#define ID_ALL_IROC_MASK               0xFF7FFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK             0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK           0xFFF0FFFF00000000ull
+#define ID_9005_GENERIC_IROC_MASK      0xFF70FFFF00000000ull
+
+#define ID_AIC7901                     0x800F9005FFFF9005ull
+#define ID_AHA_29320A                  0x8000900500609005ull
+#define ID_AHA_29320ALP                        0x8017900500449005ull
+
+#define ID_AIC7901A                    0x801E9005FFFF9005ull
+#define ID_AHA_29320                   0x8012900500429005ull
+#define ID_AHA_29320B                  0x8013900500439005ull
+#define ID_AHA_29320LP                 0x8014900500449005ull
+
+#define ID_AIC7902                     0x801F9005FFFF9005ull
+#define ID_AIC7902_B                   0x801D9005FFFF9005ull
+#define ID_AHA_39320                   0x8010900500409005ull
+#define ID_AHA_39320_B                 0x8015900500409005ull
+#define ID_AHA_39320A                  0x8016900500409005ull
+#define ID_AHA_39320D                  0x8011900500419005ull
+#define ID_AHA_39320D_B                        0x801C900500419005ull
+#define ID_AHA_39320D_HP               0x8011900500AC0E11ull
+#define ID_AHA_39320D_B_HP             0x801C900500AC0E11ull
+
+#endif /* _AIC79XX_PCI_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.h b/drivers/scsi/aic7xxx/aic7xxx_pci.h
new file mode 100644 (file)
index 0000000..be27fcb
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $Id$
+ *
+ */
+#ifndef _AIC7XXX_PCI_H_
+#define _AIC7XXX_PCI_H_
+
+#define ID_ALL_MASK                    0xFFFFFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK             0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK           0xFFF0FFFF00000000ull
+#define ID_9005_SISL_MASK              0x000FFFFF00000000ull
+#define ID_9005_SISL_ID                        0x0005900500000000ull
+#define ID_AIC7850                     0x5078900400000000ull
+#define ID_AHA_2902_04_10_15_20C_30C   0x5078900478509004ull
+#define ID_AIC7855                     0x5578900400000000ull
+#define ID_AIC7859                     0x3860900400000000ull
+#define ID_AHA_2930CU                  0x3860900438699004ull
+#define ID_AIC7860                     0x6078900400000000ull
+#define ID_AIC7860C                    0x6078900478609004ull
+#define ID_AHA_1480A                   0x6075900400000000ull
+#define ID_AHA_2940AU_0                        0x6178900400000000ull
+#define ID_AHA_2940AU_1                        0x6178900478619004ull
+#define ID_AHA_2940AU_CN               0x2178900478219004ull
+#define ID_AHA_2930C_VAR               0x6038900438689004ull
+
+#define ID_AIC7870                     0x7078900400000000ull
+#define ID_AHA_2940                    0x7178900400000000ull
+#define ID_AHA_3940                    0x7278900400000000ull
+#define ID_AHA_398X                    0x7378900400000000ull
+#define ID_AHA_2944                    0x7478900400000000ull
+#define ID_AHA_3944                    0x7578900400000000ull
+#define ID_AHA_4944                    0x7678900400000000ull
+
+#define ID_AIC7880                     0x8078900400000000ull
+#define ID_AIC7880_B                   0x8078900478809004ull
+#define ID_AHA_2940U                   0x8178900400000000ull
+#define ID_AHA_3940U                   0x8278900400000000ull
+#define ID_AHA_2944U                   0x8478900400000000ull
+#define ID_AHA_3944U                   0x8578900400000000ull
+#define ID_AHA_398XU                   0x8378900400000000ull
+#define ID_AHA_4944U                   0x8678900400000000ull
+#define ID_AHA_2940UB                  0x8178900478819004ull
+#define ID_AHA_2930U                   0x8878900478889004ull
+#define ID_AHA_2940U_PRO               0x8778900478879004ull
+#define ID_AHA_2940U_CN                        0x0078900478009004ull
+
+#define ID_AIC7895                     0x7895900478959004ull
+#define ID_AIC7895_ARO                 0x7890900478939004ull
+#define ID_AIC7895_ARO_MASK            0xFFF0FFFFFFFFFFFFull
+#define ID_AHA_2940U_DUAL              0x7895900478919004ull
+#define ID_AHA_3940AU                  0x7895900478929004ull
+#define ID_AHA_3944AU                  0x7895900478949004ull
+
+#define ID_AIC7890                     0x001F9005000F9005ull
+#define ID_AIC7890_ARO                 0x00139005000F9005ull
+#define ID_AAA_131U2                   0x0013900500039005ull
+#define ID_AHA_2930U2                  0x0011900501819005ull
+#define ID_AHA_2940U2B                 0x00109005A1009005ull
+#define ID_AHA_2940U2_OEM              0x0010900521809005ull
+#define ID_AHA_2940U2                  0x00109005A1809005ull
+#define ID_AHA_2950U2B                 0x00109005E1009005ull
+
+#define ID_AIC7892                     0x008F9005FFFF9005ull
+#define ID_AIC7892_ARO                 0x00839005FFFF9005ull
+#define ID_AHA_29160                   0x00809005E2A09005ull
+#define ID_AHA_29160_CPQ               0x00809005E2A00E11ull
+#define ID_AHA_29160N                  0x0080900562A09005ull
+#define ID_AHA_29160C                  0x0080900562209005ull
+#define ID_AHA_29160B                  0x00809005E2209005ull
+#define ID_AHA_19160B                  0x0081900562A19005ull
+
+#define ID_AIC7896                     0x005F9005FFFF9005ull
+#define ID_AIC7896_ARO                 0x00539005FFFF9005ull
+#define ID_AHA_3950U2B_0               0x00509005FFFF9005ull
+#define ID_AHA_3950U2B_1               0x00509005F5009005ull
+#define ID_AHA_3950U2D_0               0x00519005FFFF9005ull
+#define ID_AHA_3950U2D_1               0x00519005B5009005ull
+
+#define ID_AIC7899                     0x00CF9005FFFF9005ull
+#define ID_AIC7899_ARO                 0x00C39005FFFF9005ull
+#define ID_AHA_3960D                   0x00C09005F6209005ull
+#define ID_AHA_3960D_CPQ               0x00C09005F6200E11ull
+
+#define ID_AIC7810                     0x1078900400000000ull
+#define ID_AIC7815                     0x7815900400000000ull
+
+#endif /* _AIC7XXX_PCI_H_ */
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
new file mode 100644 (file)
index 0000000..4e247b6
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsic.o
+
+ibmvscsic-y                    += ibmvscsi.o
+ibmvscsic-$(CONFIG_PPC_ISERIES)        += iseries_vscsi.o 
+ibmvscsic-$(CONFIG_PPC_PSERIES)        += rpa_vscsi.o 
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
new file mode 100644 (file)
index 0000000..210ee7d
--- /dev/null
@@ -0,0 +1,1393 @@
+/* ------------------------------------------------------------
+ * ibmvscsi.c
+ * (C) Copyright IBM Corporation 1994, 2004
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *          Dave Boutcher (sleddog@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ * ------------------------------------------------------------
+ * Emulation of a SCSI host adapter for Virtual I/O devices
+ *
+ * This driver supports the SCSI adapter implemented by the IBM
+ * Power5 firmware.  That SCSI adapter is not a physical adapter,
+ * but allows Linux SCSI peripheral drivers to directly
+ * access devices in another logical partition on the physical system.
+ *
+ * The virtual adapter(s) are present in the open firmware device
+ * tree just like real adapters.
+ *
+ * One of the capabilities provided on these systems is the ability
+ * to DMA between partitions.  The architecture states that for VSCSI,
+ * the server side is allowed to DMA to and from the client.  The client
+ * is never trusted to DMA to or from the server directly.
+ *
+ * Messages are sent between partitions on a "Command/Response Queue" 
+ * (CRQ), which is just a buffer of 16 byte entries in the receiver's 
+ * Senders cannot access the buffer directly, but send messages by
+ * making a hypervisor call and passing in the 16 bytes.  The hypervisor
+ * puts the message in the next 16 byte space in round-robbin fashion,
+ * turns on the high order bit of the message (the valid bit), and 
+ * generates an interrupt to the receiver (if interrupts are turned on.) 
+ * The receiver just turns off the valid bit when they have copied out
+ * the message.
+ *
+ * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit
+ * (IU) (as defined in the T10 standard available at www.t10.org), gets 
+ * a DMA address for the message, and sends it to the server as the
+ * payload of a CRQ message.  The server DMAs the SRP IU and processes it,
+ * including doing any additional data transfers.  When it is done, it
+ * DMAs the SRP response back to the same address as the request came from,
+ * and sends a CRQ message back to inform the client that the request has
+ * completed.
+ *
+ * Note that some of the underlying infrastructure is different between
+ * machines conforming to the "RS/6000 Platform Architecture" (RPA) and
+ * the older iSeries hypervisor models.  To support both, some low level
+ * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c.
+ * The Makefile should pick one, not two, not zero, of these.
+ *
+ * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor
+ * interfaces.  It would be really nice to abstract this above an RDMA
+ * layer.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <asm/vio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include "ibmvscsi.h"
+
+/* The values below are somewhat arbitrary default values, but 
+ * OS/400 will use 3 busses (disks, CDs, tapes, I think.)
+ * Note that there are 3 bits of channel value, 6 bits of id, and
+ * 5 bits of LUN.
+ */
+static int max_id = 64;
+static int max_channel = 3;
+static int init_timeout = 5;
+static int max_requests = 50;
+
+#define IBMVSCSI_VERSION "1.5.1"
+
+MODULE_DESCRIPTION("IBM Virtual SCSI");
+MODULE_AUTHOR("Dave Boutcher");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(IBMVSCSI_VERSION);
+
+module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_id, "Largest ID value for each channel");
+module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_channel, "Largest channel value");
+module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
+module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
+
+/* ------------------------------------------------------------
+ * Routines for the event pool and event structs
+ */
+/**
+ * initialize_event_pool: - Allocates and initializes the event pool for a host
+ * @pool:      event_pool to be initialized
+ * @size:      Number of events in pool
+ * @hostdata:  ibmvscsi_host_data who owns the event pool
+ *
+ * Returns zero on success.
+*/
+static int initialize_event_pool(struct event_pool *pool,
+                                int size, struct ibmvscsi_host_data *hostdata)
+{
+       int i;
+
+       pool->size = size;
+       pool->next = 0;
+       pool->events = kmalloc(pool->size * sizeof(*pool->events), GFP_KERNEL);
+       if (!pool->events)
+               return -ENOMEM;
+       memset(pool->events, 0x00, pool->size * sizeof(*pool->events));
+
+       pool->iu_storage =
+           dma_alloc_coherent(hostdata->dev,
+                              pool->size * sizeof(*pool->iu_storage),
+                              &pool->iu_token, 0);
+       if (!pool->iu_storage) {
+               kfree(pool->events);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < pool->size; ++i) {
+               struct srp_event_struct *evt = &pool->events[i];
+               memset(&evt->crq, 0x00, sizeof(evt->crq));
+               atomic_set(&evt->free, 1);
+               evt->crq.valid = 0x80;
+               evt->crq.IU_length = sizeof(*evt->xfer_iu);
+               evt->crq.IU_data_ptr = pool->iu_token + 
+                       sizeof(*evt->xfer_iu) * i;
+               evt->xfer_iu = pool->iu_storage + i;
+               evt->hostdata = hostdata;
+       }
+
+       return 0;
+}
+
+/**
+ * release_event_pool: - Frees memory of an event pool of a host
+ * @pool:      event_pool to be released
+ * @hostdata:  ibmvscsi_host_data who owns the even pool
+ *
+ * Returns zero on success.
+*/
+static void release_event_pool(struct event_pool *pool,
+                              struct ibmvscsi_host_data *hostdata)
+{
+       int i, in_use = 0;
+       for (i = 0; i < pool->size; ++i)
+               if (atomic_read(&pool->events[i].free) != 1)
+                       ++in_use;
+       if (in_use)
+               printk(KERN_WARNING
+                      "ibmvscsi: releasing event pool with %d "
+                      "events still in use?\n", in_use);
+       kfree(pool->events);
+       dma_free_coherent(hostdata->dev,
+                         pool->size * sizeof(*pool->iu_storage),
+                         pool->iu_storage, pool->iu_token);
+}
+
+/**
+ * valid_event_struct: - Determines if event is valid.
+ * @pool:      event_pool that contains the event
+ * @evt:       srp_event_struct to be checked for validity
+ *
+ * Returns zero if event is invalid, one otherwise.
+*/
+static int valid_event_struct(struct event_pool *pool,
+                               struct srp_event_struct *evt)
+{
+       int index = evt - pool->events;
+       if (index < 0 || index >= pool->size)   /* outside of bounds */
+               return 0;
+       if (evt != pool->events + index)        /* unaligned */
+               return 0;
+       return 1;
+}
+
+/**
+ * ibmvscsi_free-event_struct: - Changes status of event to "free"
+ * @pool:      event_pool that contains the event
+ * @evt:       srp_event_struct to be modified
+ *
+*/
+static void free_event_struct(struct event_pool *pool,
+                                      struct srp_event_struct *evt)
+{
+       if (!valid_event_struct(pool, evt)) {
+               printk(KERN_ERR
+                      "ibmvscsi: Freeing invalid event_struct %p "
+                      "(not in pool %p)\n", evt, pool->events);
+               return;
+       }
+       if (atomic_inc_return(&evt->free) != 1) {
+               printk(KERN_ERR
+                      "ibmvscsi: Freeing event_struct %p "
+                      "which is not in use!\n", evt);
+               return;
+       }
+}
+
+/**
+ * get_evt_struct: - Gets the next free event in pool
+ * @pool:      event_pool that contains the events to be searched
+ *
+ * Returns the next event in "free" state, and NULL if none are free.
+ * Note that no synchronization is done here, we assume the host_lock
+ * will syncrhonze things.
+*/
+static struct srp_event_struct *get_event_struct(struct event_pool *pool)
+{
+       int i;
+       int poolsize = pool->size;
+       int offset = pool->next;
+
+       for (i = 0; i < poolsize; i++) {
+               offset = (offset + 1) % poolsize;
+               if (!atomic_dec_if_positive(&pool->events[offset].free)) {
+                       pool->next = offset;
+                       return &pool->events[offset];
+               }
+       }
+
+       printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n");
+       return NULL;
+}
+
+/**
+ * init_event_struct: Initialize fields in an event struct that are always 
+ *                    required.
+ * @evt:        The event
+ * @done:       Routine to call when the event is responded to
+ * @format:     SRP or MAD format
+ * @timeout:    timeout value set in the CRQ
+ */
+static void init_event_struct(struct srp_event_struct *evt_struct,
+                             void (*done) (struct srp_event_struct *),
+                             u8 format,
+                             int timeout)
+{
+       evt_struct->cmnd = NULL;
+       evt_struct->cmnd_done = NULL;
+       evt_struct->crq.format = format;
+       evt_struct->crq.timeout = timeout;
+       evt_struct->done = done;
+}
+
+/* ------------------------------------------------------------
+ * Routines for receiving SCSI responses from the hosting partition
+ */
+
+/**
+ * set_srp_direction: Set the fields in the srp related to data
+ *     direction and number of buffers based on the direction in
+ *     the scsi_cmnd and the number of buffers
+ */
+static void set_srp_direction(struct scsi_cmnd *cmd,
+                             struct srp_cmd *srp_cmd, 
+                             int numbuf)
+{
+       if (numbuf == 0)
+               return;
+       
+       if (numbuf == 1) {
+               if (cmd->sc_data_direction == DMA_TO_DEVICE)
+                       srp_cmd->data_out_format = SRP_DIRECT_BUFFER;
+               else 
+                       srp_cmd->data_in_format = SRP_DIRECT_BUFFER;
+       } else {
+               if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+                       srp_cmd->data_out_format = SRP_INDIRECT_BUFFER;
+                       srp_cmd->data_out_count = numbuf;
+               } else {
+                       srp_cmd->data_in_format = SRP_INDIRECT_BUFFER;
+                       srp_cmd->data_in_count = numbuf;
+               }
+       }
+}
+
+/**
+ * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
+ * @cmd:       srp_cmd whose additional_data member will be unmapped
+ * @dev:       device for which the memory is mapped
+ *
+*/
+static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev)
+{
+       int i;
+
+       if ((cmd->data_out_format == SRP_NO_BUFFER) &&
+           (cmd->data_in_format == SRP_NO_BUFFER))
+               return;
+       else if ((cmd->data_out_format == SRP_DIRECT_BUFFER) ||
+                (cmd->data_in_format == SRP_DIRECT_BUFFER)) {
+               struct memory_descriptor *data =
+                       (struct memory_descriptor *)cmd->additional_data;
+               dma_unmap_single(dev, data->virtual_address, data->length,
+                                DMA_BIDIRECTIONAL);
+       } else {
+               struct indirect_descriptor *indirect =
+                       (struct indirect_descriptor *)cmd->additional_data;
+               int num_mapped = indirect->head.length / 
+                       sizeof(indirect->list[0]);
+               for (i = 0; i < num_mapped; ++i) {
+                       struct memory_descriptor *data = &indirect->list[i];
+                       dma_unmap_single(dev,
+                                        data->virtual_address,
+                                        data->length, DMA_BIDIRECTIONAL);
+               }
+       }
+}
+
+/**
+ * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields
+ * @cmd:       Scsi_Cmnd with the scatterlist
+ * @srp_cmd:   srp_cmd that contains the memory descriptor
+ * @dev:       device for which to map dma memory
+ *
+ * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
+ * Returns 1 on success.
+*/
+static int map_sg_data(struct scsi_cmnd *cmd,
+                      struct srp_cmd *srp_cmd, struct device *dev)
+{
+
+       int i, sg_mapped;
+       u64 total_length = 0;
+       struct scatterlist *sg = cmd->request_buffer;
+       struct memory_descriptor *data =
+           (struct memory_descriptor *)srp_cmd->additional_data;
+       struct indirect_descriptor *indirect =
+           (struct indirect_descriptor *)data;
+
+       sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL);
+
+       if (sg_mapped == 0)
+               return 0;
+
+       set_srp_direction(cmd, srp_cmd, sg_mapped);
+
+       /* special case; we can use a single direct descriptor */
+       if (sg_mapped == 1) {
+               data->virtual_address = sg_dma_address(&sg[0]);
+               data->length = sg_dma_len(&sg[0]);
+               data->memory_handle = 0;
+               return 1;
+       }
+
+       if (sg_mapped > MAX_INDIRECT_BUFS) {
+               printk(KERN_ERR
+                      "ibmvscsi: More than %d mapped sg entries, got %d\n",
+                      MAX_INDIRECT_BUFS, sg_mapped);
+               return 0;
+       }
+
+       indirect->head.virtual_address = 0;
+       indirect->head.length = sg_mapped * sizeof(indirect->list[0]);
+       indirect->head.memory_handle = 0;
+       for (i = 0; i < sg_mapped; ++i) {
+               struct memory_descriptor *descr = &indirect->list[i];
+               struct scatterlist *sg_entry = &sg[i];
+               descr->virtual_address = sg_dma_address(sg_entry);
+               descr->length = sg_dma_len(sg_entry);
+               descr->memory_handle = 0;
+               total_length += sg_dma_len(sg_entry);
+       }
+       indirect->total_length = total_length;
+
+       return 1;
+}
+
+/**
+ * map_single_data: - Maps memory and initializes memory decriptor fields
+ * @cmd:       struct scsi_cmnd with the memory to be mapped
+ * @srp_cmd:   srp_cmd that contains the memory descriptor
+ * @dev:       device for which to map dma memory
+ *
+ * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
+ * Returns 1 on success.
+*/
+static int map_single_data(struct scsi_cmnd *cmd,
+                          struct srp_cmd *srp_cmd, struct device *dev)
+{
+       struct memory_descriptor *data =
+           (struct memory_descriptor *)srp_cmd->additional_data;
+
+       data->virtual_address =
+               dma_map_single(dev, cmd->request_buffer,
+                              cmd->request_bufflen,
+                              DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(data->virtual_address)) {
+               printk(KERN_ERR
+                      "ibmvscsi: Unable to map request_buffer for command!\n");
+               return 0;
+       }
+       data->length = cmd->request_bufflen;
+       data->memory_handle = 0;
+
+       set_srp_direction(cmd, srp_cmd, 1);
+
+       return 1;
+}
+
+/**
+ * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
+ * @cmd:       struct scsi_cmnd with the memory to be mapped
+ * @srp_cmd:   srp_cmd that contains the memory descriptor
+ * @dev:       dma device for which to map dma memory
+ *
+ * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds 
+ * Returns 1 on success.
+*/
+static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
+                               struct srp_cmd *srp_cmd, struct device *dev)
+{
+       switch (cmd->sc_data_direction) {
+       case DMA_FROM_DEVICE:
+       case DMA_TO_DEVICE:
+               break;
+       case DMA_NONE:
+               return 1;
+       case DMA_BIDIRECTIONAL:
+               printk(KERN_ERR
+                      "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n");
+               return 0;
+       default:
+               printk(KERN_ERR
+                      "ibmvscsi: Unknown data direction 0x%02x; can't map!\n",
+                      cmd->sc_data_direction);
+               return 0;
+       }
+
+       if (!cmd->request_buffer)
+               return 1;
+       if (cmd->use_sg)
+               return map_sg_data(cmd, srp_cmd, dev);
+       return map_single_data(cmd, srp_cmd, dev);
+}
+
+/* ------------------------------------------------------------
+ * Routines for sending and receiving SRPs
+ */
+/**
+ * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
+ * @evt_struct:        evt_struct to be sent
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
+ * Note that this routine assumes that host_lock is held for synchronization
+*/
+static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
+                                  struct ibmvscsi_host_data *hostdata)
+{
+       struct scsi_cmnd *cmnd = evt_struct->cmnd;
+       u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
+       int rc;
+
+       /* If we have exhausted our request limit, just fail this request.
+        * Note that there are rare cases involving driver generated requests 
+        * (such as task management requests) that the mid layer may think we
+        * can handle more requests (can_queue) when we actually can't
+        */
+       if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
+           (atomic_dec_if_positive(&hostdata->request_limit) < 0)) {
+               /* See if the adapter is disabled */
+               if (atomic_read(&hostdata->request_limit) < 0) {
+                       if (cmnd)
+                               cmnd->result = DID_ERROR << 16;
+                       if (evt_struct->cmnd_done)
+                               evt_struct->cmnd_done(cmnd);
+                       unmap_cmd_data(&evt_struct->iu.srp.cmd,
+                                      hostdata->dev);
+                       free_event_struct(&hostdata->pool, evt_struct);
+                       return 0;
+               } else {
+                       printk("ibmvscsi: Warning, request_limit exceeded\n");
+                       unmap_cmd_data(&evt_struct->iu.srp.cmd,
+                                      hostdata->dev);
+                       free_event_struct(&hostdata->pool, evt_struct);
+                       return SCSI_MLQUEUE_HOST_BUSY;
+               }
+       }
+
+       /* Copy the IU into the transfer area */
+       *evt_struct->xfer_iu = evt_struct->iu;
+       evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct;
+
+       /* Add this to the sent list.  We need to do this 
+        * before we actually send 
+        * in case it comes back REALLY fast
+        */
+       list_add_tail(&evt_struct->list, &hostdata->sent);
+
+       if ((rc =
+            ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+               list_del(&evt_struct->list);
+
+               cmnd = evt_struct->cmnd;
+               printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n",
+                      rc);
+               unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev);
+               free_event_struct(&hostdata->pool, evt_struct);
+               if (cmnd)
+                       cmnd->result = DID_ERROR << 16;
+               if (evt_struct->cmnd_done)
+                       evt_struct->cmnd_done(cmnd);
+       }
+
+       return 0;
+}
+
+/**
+ * handle_cmd_rsp: -  Handle responses from commands
+ * @evt_struct:        srp_event_struct to be handled
+ *
+ * Used as a callback by when sending scsi cmds.
+ * Gets called by ibmvscsi_handle_crq()
+*/
+static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
+{
+       struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
+       struct scsi_cmnd *cmnd = evt_struct->cmnd;
+
+       if (cmnd) {
+               cmnd->result = rsp->status;
+               if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
+                       memcpy(cmnd->sense_buffer,
+                              rsp->sense_and_response_data,
+                              rsp->sense_data_list_length);
+               unmap_cmd_data(&evt_struct->iu.srp.cmd, 
+                              evt_struct->hostdata->dev);
+
+               if (rsp->doover)
+                       cmnd->resid = rsp->data_out_residual_count;
+               else if (rsp->diover)
+                       cmnd->resid = rsp->data_in_residual_count;
+       }
+
+       if (evt_struct->cmnd_done)
+               evt_struct->cmnd_done(cmnd);
+}
+
+/**
+ * lun_from_dev: - Returns the lun of the scsi device
+ * @dev:       struct scsi_device
+ *
+*/
+static inline u16 lun_from_dev(struct scsi_device *dev)
+{
+       return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;
+}
+
+/**
+ * ibmvscsi_queue: - The queuecommand function of the scsi template 
+ * @cmd:       struct scsi_cmnd to be executed
+ * @done:      Callback function to be called when cmd is completed
+*/
+static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
+                                void (*done) (struct scsi_cmnd *))
+{
+       struct srp_cmd *srp_cmd;
+       struct srp_event_struct *evt_struct;
+       struct ibmvscsi_host_data *hostdata =
+               (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
+       u16 lun = lun_from_dev(cmnd->device);
+
+       evt_struct = get_event_struct(&hostdata->pool);
+       if (!evt_struct)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       init_event_struct(evt_struct,
+                         handle_cmd_rsp,
+                         VIOSRP_SRP_FORMAT,
+                         cmnd->timeout);
+
+       evt_struct->cmnd = cmnd;
+       evt_struct->cmnd_done = done;
+
+       /* Set up the actual SRP IU */
+       srp_cmd = &evt_struct->iu.srp.cmd;
+       memset(srp_cmd, 0x00, sizeof(*srp_cmd));
+       srp_cmd->type = SRP_CMD_TYPE;
+       memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+       srp_cmd->lun = ((u64) lun) << 48;
+
+       if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) {
+               printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
+               free_event_struct(&hostdata->pool, evt_struct);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+
+       /* Fix up dma address of the buffer itself */
+       if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) ||
+           (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) {
+               struct indirect_descriptor *indirect =
+                   (struct indirect_descriptor *)srp_cmd->additional_data;
+               indirect->head.virtual_address = evt_struct->crq.IU_data_ptr +
+                   offsetof(struct srp_cmd, additional_data) +
+                   offsetof(struct indirect_descriptor, list);
+       }
+
+       return ibmvscsi_send_srp_event(evt_struct, hostdata);
+}
+
+/* ------------------------------------------------------------
+ * Routines for driver initialization
+ */
+/**
+ * adapter_info_rsp: - Handle response to MAD adapter info request
+ * @evt_struct:        srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending adapter_info. Gets called
+ * by ibmvscsi_handle_crq()
+*/
+static void adapter_info_rsp(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+       dma_unmap_single(hostdata->dev,
+                        evt_struct->iu.mad.adapter_info.buffer,
+                        evt_struct->iu.mad.adapter_info.common.length,
+                        DMA_BIDIRECTIONAL);
+
+       if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
+               printk("ibmvscsi: error %d getting adapter info\n",
+                      evt_struct->xfer_iu->mad.adapter_info.common.status);
+       } else {
+               printk("ibmvscsi: host srp version: %s, "
+                      "host partition %s (%d), OS %d\n",
+                      hostdata->madapter_info.srp_version,
+                      hostdata->madapter_info.partition_name,
+                      hostdata->madapter_info.partition_number,
+                      hostdata->madapter_info.os_type);
+       }
+}
+
+/**
+ * send_mad_adapter_info: - Sends the mad adapter info request
+ *      and stores the result so it can be retrieved with
+ *      sysfs.  We COULD consider causing a failure if the
+ *      returned SRP version doesn't match ours.
+ * @hostdata:  ibmvscsi_host_data of host
+ * 
+ * Returns zero if successful.
+*/
+static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
+{
+       struct viosrp_adapter_info *req;
+       struct srp_event_struct *evt_struct;
+       
+       memset(&hostdata->madapter_info, 0x00, sizeof(hostdata->madapter_info));
+       
+       evt_struct = get_event_struct(&hostdata->pool);
+       if (!evt_struct) {
+               printk(KERN_ERR "ibmvscsi: couldn't allocate an event "
+                      "for ADAPTER_INFO_REQ!\n");
+               return;
+       }
+
+       init_event_struct(evt_struct,
+                         adapter_info_rsp,
+                         VIOSRP_MAD_FORMAT,
+                         init_timeout * HZ);
+       
+       req = &evt_struct->iu.mad.adapter_info;
+       memset(req, 0x00, sizeof(*req));
+       
+       req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
+       req->common.length = sizeof(hostdata->madapter_info);
+       req->buffer = dma_map_single(hostdata->dev,
+                                    &hostdata->madapter_info,
+                                    sizeof(hostdata->madapter_info),
+                                    DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(req->buffer)) {
+               printk(KERN_ERR
+                      "ibmvscsi: Unable to map request_buffer "
+                      "for adapter_info!\n");
+               free_event_struct(&hostdata->pool, evt_struct);
+               return;
+       }
+       
+       if (ibmvscsi_send_srp_event(evt_struct, hostdata))
+               printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");
+};
+
+/**
+ * login_rsp: - Handle response to SRP login request
+ * @evt_struct:        srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending srp_login. Gets called
+ * by ibmvscsi_handle_crq()
+*/
+static void login_rsp(struct srp_event_struct *evt_struct)
+{
+       struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+       switch (evt_struct->xfer_iu->srp.generic.type) {
+       case SRP_LOGIN_RSP_TYPE:        /* it worked! */
+               break;
+       case SRP_LOGIN_REJ_TYPE:        /* refused! */
+               printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n");
+               /* Login failed.  */
+               atomic_set(&hostdata->request_limit, -1);
+               return;
+       default:
+               printk(KERN_ERR
+                      "ibmvscsi: Invalid login response typecode 0x%02x!\n",
+                      evt_struct->xfer_iu->srp.generic.type);
+               /* Login failed.  */
+               atomic_set(&hostdata->request_limit, -1);
+               return;
+       }
+
+       printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
+
+       if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta >
+           (max_requests - 2))
+               evt_struct->xfer_iu->srp.login_rsp.request_limit_delta =
+                   max_requests - 2;
+
+       /* Now we know what the real request-limit is */
+       atomic_set(&hostdata->request_limit,
+                  evt_struct->xfer_iu->srp.login_rsp.request_limit_delta);
+
+       hostdata->host->can_queue =
+           evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2;
+
+       if (hostdata->host->can_queue < 1) {
+               printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
+               return;
+       }
+
+       send_mad_adapter_info(hostdata);
+       return;
+}
+
+/**
+ * send_srp_login: - Sends the srp login
+ * @hostdata:  ibmvscsi_host_data of host
+ * 
+ * Returns zero if successful.
+*/
+static int send_srp_login(struct ibmvscsi_host_data *hostdata)
+{
+       int rc;
+       unsigned long flags;
+       struct srp_login_req *login;
+       struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
+       if (!evt_struct) {
+               printk(KERN_ERR
+                      "ibmvscsi: couldn't allocate an event for login req!\n");
+               return FAILED;
+       }
+
+       init_event_struct(evt_struct,
+                         login_rsp,
+                         VIOSRP_SRP_FORMAT,
+                         init_timeout * HZ);
+
+       login = &evt_struct->iu.srp.login_req;
+       login->type = SRP_LOGIN_REQ_TYPE;
+       login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu);
+       login->required_buffer_formats = 0x0006;
+       
+       /* Start out with a request limit of 1, since this is negotiated in
+        * the login request we are just sending
+        */
+       atomic_set(&hostdata->request_limit, 1);
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+       return rc;
+};
+
+/**
+ * sync_completion: Signal that a synchronous command has completed
+ * Note that after returning from this call, the evt_struct is freed.
+ * the caller waiting on this completion shouldn't touch the evt_struct
+ * again.
+ */
+static void sync_completion(struct srp_event_struct *evt_struct)
+{
+       complete(&evt_struct->comp);
+}
+
+/**
+ * ibmvscsi_abort: Abort a command...from scsi host template
+ * send this over to the server and wait synchronously for the response
+ */
+static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+       struct srp_tsk_mgmt *tsk_mgmt;
+       struct srp_event_struct *evt;
+       struct srp_event_struct *tmp_evt, *found_evt;
+       u16 lun = lun_from_dev(cmd->device);
+
+       /* First, find this command in our sent list so we can figure
+        * out the correct tag
+        */
+       found_evt = NULL;
+       list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+               if (tmp_evt->cmnd == cmd) {
+                       found_evt = tmp_evt;
+                       break;
+               }
+       }
+
+       if (!found_evt) 
+               return FAILED;
+
+       evt = get_event_struct(&hostdata->pool);
+       if (evt == NULL) {
+               printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n");
+               return FAILED;
+       }
+       
+       init_event_struct(evt,
+                         sync_completion,
+                         VIOSRP_SRP_FORMAT,
+                         init_timeout * HZ);
+
+       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+       
+       /* Set up an abort SRP command */
+       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+       tsk_mgmt->type = SRP_TSK_MGMT_TYPE;
+       tsk_mgmt->lun = ((u64) lun) << 48;
+       tsk_mgmt->task_mgmt_flags = 0x01;       /* ABORT TASK */
+       tsk_mgmt->managed_task_tag = (u64) found_evt;
+
+       printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
+              tsk_mgmt->lun, tsk_mgmt->managed_task_tag);
+
+       init_completion(&evt->comp);
+       if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
+               printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
+               return FAILED;
+       }
+
+       spin_unlock_irq(hostdata->host->host_lock);
+       wait_for_completion(&evt->comp);
+       spin_lock_irq(hostdata->host->host_lock);
+
+       /* Because we dropped the spinlock above, it's possible
+        * The event is no longer in our list.  Make sure it didn't
+        * complete while we were aborting
+        */
+       found_evt = NULL;
+       list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+               if (tmp_evt->cmnd == cmd) {
+                       found_evt = tmp_evt;
+                       break;
+               }
+       }
+
+       printk(KERN_INFO
+              "ibmvscsi: successfully aborted task tag 0x%lx\n",
+              tsk_mgmt->managed_task_tag);
+
+       if (found_evt == NULL)
+               return SUCCESS;
+
+       cmd->result = (DID_ABORT << 16);
+       list_del(&found_evt->list);
+       unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev);
+       free_event_struct(&found_evt->hostdata->pool, found_evt);
+       atomic_inc(&hostdata->request_limit);
+       return SUCCESS;
+}
+
+/**
+ * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host 
+ * template send this over to the server and wait synchronously for the 
+ * response
+ */
+static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
+{
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+
+       struct srp_tsk_mgmt *tsk_mgmt;
+       struct srp_event_struct *evt;
+       struct srp_event_struct *tmp_evt, *pos;
+       u16 lun = lun_from_dev(cmd->device);
+
+       evt = get_event_struct(&hostdata->pool);
+       if (evt == NULL) {
+               printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n");
+               return FAILED;
+       }
+       
+       init_event_struct(evt,
+                         sync_completion,
+                         VIOSRP_SRP_FORMAT,
+                         init_timeout * HZ);
+
+       tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+
+       /* Set up a lun reset SRP command */
+       memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+       tsk_mgmt->type = SRP_TSK_MGMT_TYPE;
+       tsk_mgmt->lun = ((u64) lun) << 48;
+       tsk_mgmt->task_mgmt_flags = 0x08;       /* LUN RESET */
+
+       printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
+              tsk_mgmt->lun);
+
+       init_completion(&evt->comp);
+       if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
+               printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
+               return FAILED;
+       }
+
+       spin_unlock_irq(hostdata->host->host_lock);
+       wait_for_completion(&evt->comp);
+       spin_lock_irq(hostdata->host->host_lock);
+
+       /* We need to find all commands for this LUN that have not yet been
+        * responded to, and fail them with DID_RESET
+        */
+       list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+               if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
+                       if (tmp_evt->cmnd)
+                               tmp_evt->cmnd->result = (DID_RESET << 16);
+                       list_del(&tmp_evt->list);
+                       unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev);
+                       free_event_struct(&tmp_evt->hostdata->pool,
+                                                  tmp_evt);
+                       atomic_inc(&hostdata->request_limit);
+                       if (tmp_evt->cmnd_done)
+                               tmp_evt->cmnd_done(tmp_evt->cmnd);
+                       else if (tmp_evt->done)
+                               tmp_evt->done(tmp_evt);
+               }
+       }
+       return SUCCESS;
+}
+
+/**
+ * purge_requests: Our virtual adapter just shut down.  purge any sent requests
+ * @hostdata:    the adapter
+ */
+static void purge_requests(struct ibmvscsi_host_data *hostdata)
+{
+       struct srp_event_struct *tmp_evt, *pos;
+       unsigned long flags;
+
+       spin_lock_irqsave(hostdata->host->host_lock, flags);
+       list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+               list_del(&tmp_evt->list);
+               if (tmp_evt->cmnd) {
+                       tmp_evt->cmnd->result = (DID_ERROR << 16);
+                       unmap_cmd_data(&tmp_evt->iu.srp.cmd, 
+                                      tmp_evt->hostdata->dev);
+                       if (tmp_evt->cmnd_done)
+                               tmp_evt->cmnd_done(tmp_evt->cmnd);
+               } else {
+                       if (tmp_evt->done) {
+                               tmp_evt->done(tmp_evt);
+                       }
+               }
+               free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+       }
+       spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ
+ * @crq:       Command/Response queue
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+*/
+void ibmvscsi_handle_crq(struct viosrp_crq *crq,
+                        struct ibmvscsi_host_data *hostdata)
+{
+       unsigned long flags;
+       struct srp_event_struct *evt_struct =
+           (struct srp_event_struct *)crq->IU_data_ptr;
+       switch (crq->valid) {
+       case 0xC0:              /* initialization */
+               switch (crq->format) {
+               case 0x01:      /* Initialization message */
+                       printk(KERN_INFO "ibmvscsi: partner initialized\n");
+                       /* Send back a response */
+                       if (ibmvscsi_send_crq(hostdata,
+                                             0xC002000000000000LL, 0) == 0) {
+                               /* Now login */
+                               send_srp_login(hostdata);
+                       } else {
+                               printk(KERN_ERR
+                                      "ibmvscsi: Unable to send init rsp\n");
+                       }
+
+                       break;
+               case 0x02:      /* Initialization response */
+                       printk(KERN_INFO
+                              "ibmvscsi: partner initialization complete\n");
+
+                       /* Now login */
+                       send_srp_login(hostdata);
+                       break;
+               default:
+                       printk(KERN_ERR "ibmvscsi: unknown crq message type\n");
+               }
+               return;
+       case 0xFF:              /* Hypervisor telling us the connection is closed */
+               printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n");
+
+               atomic_set(&hostdata->request_limit, -1);
+               purge_requests(hostdata);
+               ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+               return;
+       case 0x80:              /* real payload */
+               break;
+       default:
+               printk(KERN_ERR
+                      "ibmvscsi: got an invalid message type 0x%02x\n",
+                      crq->valid);
+               return;
+       }
+
+       /* The only kind of payload CRQs we should get are responses to
+        * things we send. Make sure this response is to something we
+        * actually sent
+        */
+       if (!valid_event_struct(&hostdata->pool, evt_struct)) {
+               printk(KERN_ERR
+                      "ibmvscsi: returned correlation_token 0x%p is invalid!\n",
+                      (void *)crq->IU_data_ptr);
+               return;
+       }
+
+       if (crq->format == VIOSRP_SRP_FORMAT)
+               atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta,
+                          &hostdata->request_limit);
+
+       if (evt_struct->done)
+               evt_struct->done(evt_struct);
+       else
+               printk(KERN_ERR
+                      "ibmvscsi: returned done() is NULL; not running it!\n");
+
+       /*
+        * Lock the host_lock before messing with these structures, since we
+        * are running in a task context
+        */
+       spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags);
+       list_del(&evt_struct->list);
+       free_event_struct(&evt_struct->hostdata->pool, evt_struct);
+       spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_get_host_config: Send the command to the server to get host
+ * configuration data.  The data is opaque to us.
+ */
+static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
+                                  unsigned char *buffer, int length)
+{
+       struct viosrp_host_config *host_config;
+       struct srp_event_struct *evt_struct;
+       int rc;
+
+       evt_struct = get_event_struct(&hostdata->pool);
+       if (!evt_struct) {
+               printk(KERN_ERR
+                      "ibmvscsi: could't allocate event for HOST_CONFIG!\n");
+               return -1;
+       }
+
+       init_event_struct(evt_struct,
+                         sync_completion,
+                         VIOSRP_MAD_FORMAT,
+                         init_timeout * HZ);
+
+       host_config = &evt_struct->iu.mad.host_config;
+
+       /* Set up a lun reset SRP command */
+       memset(host_config, 0x00, sizeof(*host_config));
+       host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
+       host_config->common.length = length;
+       host_config->buffer = dma_map_single(hostdata->dev, buffer, length,
+                                           DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(host_config->buffer)) {
+               printk(KERN_ERR
+                      "ibmvscsi: dma_mapping error " "getting host config\n");
+               free_event_struct(&hostdata->pool, evt_struct);
+               return -1;
+       }
+
+       init_completion(&evt_struct->comp);
+       rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+       if (rc == 0) {
+               wait_for_completion(&evt_struct->comp);
+               dma_unmap_single(hostdata->dev, host_config->buffer,
+                                length, DMA_BIDIRECTIONAL);
+       }
+
+       return rc;
+}
+
+/* ------------------------------------------------------------
+ * sysfs attributes
+ */
+static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)shost->hostdata;
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "%s\n",
+                      hostdata->madapter_info.srp_version);
+       return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_srp_version = {
+       .attr = {
+                .name = "srp_version",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_srp_version,
+};
+
+static ssize_t show_host_partition_name(struct class_device *class_dev,
+                                       char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)shost->hostdata;
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "%s\n",
+                      hostdata->madapter_info.partition_name);
+       return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_partition_name = {
+       .attr = {
+                .name = "partition_name",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_partition_name,
+};
+
+static ssize_t show_host_partition_number(struct class_device *class_dev,
+                                         char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)shost->hostdata;
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "%d\n",
+                      hostdata->madapter_info.partition_number);
+       return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_partition_number = {
+       .attr = {
+                .name = "partition_number",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_partition_number,
+};
+
+static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)shost->hostdata;
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "%d\n",
+                      hostdata->madapter_info.mad_version);
+       return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_mad_version = {
+       .attr = {
+                .name = "mad_version",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_mad_version,
+};
+
+static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)shost->hostdata;
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
+       return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_os_type = {
+       .attr = {
+                .name = "os_type",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_os_type,
+};
+
+static ssize_t show_host_config(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)shost->hostdata;
+
+       /* returns null-terminated host config data */
+       if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
+               return strlen(buf);
+       else
+               return 0;
+}
+
+static struct class_device_attribute ibmvscsi_host_config = {
+       .attr = {
+                .name = "config",
+                .mode = S_IRUGO,
+                },
+       .show = show_host_config,
+};
+
+static struct class_device_attribute *ibmvscsi_attrs[] = {
+       &ibmvscsi_host_srp_version,
+       &ibmvscsi_host_partition_name,
+       &ibmvscsi_host_partition_number,
+       &ibmvscsi_host_mad_version,
+       &ibmvscsi_host_os_type,
+       &ibmvscsi_host_config,
+       NULL
+};
+
+/* ------------------------------------------------------------
+ * SCSI driver registration
+ */
+static struct scsi_host_template driver_template = {
+       .module = THIS_MODULE,
+       .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
+       .proc_name = "ibmvscsi",
+       .queuecommand = ibmvscsi_queuecommand,
+       .eh_abort_handler = ibmvscsi_eh_abort_handler,
+       .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+       .cmd_per_lun = 16,
+       .can_queue = 1,         /* Updated after SRP_LOGIN */
+       .this_id = -1,
+       .sg_tablesize = MAX_INDIRECT_BUFS,
+       .use_clustering = ENABLE_CLUSTERING,
+       .shost_attrs = ibmvscsi_attrs,
+};
+
+/**
+ * Called by bus code for each adapter
+ */
+static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
+{
+       struct ibmvscsi_host_data *hostdata;
+       struct Scsi_Host *host;
+       struct device *dev = &vdev->dev;
+       unsigned long wait_switch = 0;
+
+       vdev->dev.driver_data = NULL;
+
+       host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
+       if (!host) {
+               printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
+               goto scsi_host_alloc_failed;
+       }
+
+       hostdata = (struct ibmvscsi_host_data *)host->hostdata;
+       memset(hostdata, 0x00, sizeof(*hostdata));
+       INIT_LIST_HEAD(&hostdata->sent);
+       hostdata->host = host;
+       hostdata->dev = dev;
+       atomic_set(&hostdata->request_limit, -1);
+
+       if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata,
+                                   max_requests) != 0) {
+               printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
+               goto init_crq_failed;
+       }
+       if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
+               printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n");
+               goto init_pool_failed;
+       }
+
+       host->max_lun = 8;
+       host->max_id = max_id;
+       host->max_channel = max_channel;
+
+       if (scsi_add_host(hostdata->host, hostdata->dev))
+               goto add_host_failed;
+
+       /* Try to send an initialization message.  Note that this is allowed
+        * to fail if the other end is not acive.  In that case we don't
+        * want to scan
+        */
+       if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) {
+               /*
+                * Wait around max init_timeout secs for the adapter to finish
+                * initializing. When we are done initializing, we will have a
+                * valid request_limit.  We don't want Linux scanning before
+                * we are ready.
+                */
+               for (wait_switch = jiffies + (init_timeout * HZ);
+                    time_before(jiffies, wait_switch) &&
+                    atomic_read(&hostdata->request_limit) < 0;) {
+
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(HZ / 100);
+               }
+
+               /* if we now have a valid request_limit, initiate a scan */
+               if (atomic_read(&hostdata->request_limit) > 0)
+                       scsi_scan_host(host);
+       }
+
+       vdev->dev.driver_data = hostdata;
+       return 0;
+
+      add_host_failed:
+       release_event_pool(&hostdata->pool, hostdata);
+      init_pool_failed:
+       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+      init_crq_failed:
+       scsi_host_put(host);
+      scsi_host_alloc_failed:
+       return -1;
+}
+
+static int ibmvscsi_remove(struct vio_dev *vdev)
+{
+       struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
+       release_event_pool(&hostdata->pool, hostdata);
+       ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
+                                  max_requests);
+       
+       scsi_remove_host(hostdata->host);
+       scsi_host_put(hostdata->host);
+
+       return 0;
+}
+
+/**
+ * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we 
+ * support.
+ */
+static struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
+       {"vscsi", "IBM,v-scsi"},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
+static struct vio_driver ibmvscsi_driver = {
+       .name = "ibmvscsi",
+       .id_table = ibmvscsi_device_table,
+       .probe = ibmvscsi_probe,
+       .remove = ibmvscsi_remove
+};
+
+int __init ibmvscsi_module_init(void)
+{
+       return vio_register_driver(&ibmvscsi_driver);
+}
+
+void __exit ibmvscsi_module_exit(void)
+{
+       vio_unregister_driver(&ibmvscsi_driver);
+}
+
+module_init(ibmvscsi_module_init);
+module_exit(ibmvscsi_module_exit);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
new file mode 100644 (file)
index 0000000..dbe1735
--- /dev/null
@@ -0,0 +1,108 @@
+/* ------------------------------------------------------------
+ * ibmvscsi.h
+ * (C) Copyright IBM Corporation 1994, 2003
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *          Dave Boutcher (sleddog@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ * ------------------------------------------------------------
+ * Emulation of a SCSI host adapter for Virtual I/O devices
+ *
+ * This driver allows the Linux SCSI peripheral drivers to directly
+ * access devices in the hosting partition, either on an iSeries
+ * hypervisor system or a converged hypervisor system.
+ */
+#ifndef IBMVSCSI_H
+#define IBMVSCSI_H
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include "viosrp.h"
+
+struct scsi_cmnd;
+struct Scsi_Host;
+
+/* Number of indirect bufs...the list of these has to fit in the
+ * additional data of the srp_cmd struct along with the indirect
+ * descriptor
+ */
+#define MAX_INDIRECT_BUFS 10
+
+/* ------------------------------------------------------------
+ * Data Structures
+ */
+/* an RPA command/response transport queue */
+struct crq_queue {
+       struct viosrp_crq *msgs;
+       int size, cur;
+       dma_addr_t msg_token;
+       spinlock_t lock;
+};
+
+/* a unit of work for the hosting partition */
+struct srp_event_struct {
+       union viosrp_iu *xfer_iu;
+       struct scsi_cmnd *cmnd;
+       struct list_head list;
+       void (*done) (struct srp_event_struct *);
+       struct viosrp_crq crq;
+       struct ibmvscsi_host_data *hostdata;
+       atomic_t free;
+       union viosrp_iu iu;
+       void (*cmnd_done) (struct scsi_cmnd *);
+       struct completion comp;
+};
+
+/* a pool of event structs for use */
+struct event_pool {
+       struct srp_event_struct *events;
+       u32 size;
+       int next;
+       union viosrp_iu *iu_storage;
+       dma_addr_t iu_token;
+};
+
+/* all driver data associated with a host adapter */
+struct ibmvscsi_host_data {
+       atomic_t request_limit;
+       struct device *dev;
+       struct event_pool pool;
+       struct crq_queue queue;
+       struct tasklet_struct srp_task;
+       struct list_head sent;
+       struct Scsi_Host *host;
+       struct mad_adapter_info_data madapter_info;
+};
+
+/* routines for managing a command/response queue */
+int ibmvscsi_init_crq_queue(struct crq_queue *queue,
+                           struct ibmvscsi_host_data *hostdata,
+                           int max_requests);
+void ibmvscsi_release_crq_queue(struct crq_queue *queue,
+                               struct ibmvscsi_host_data *hostdata,
+                               int max_requests);
+void ibmvscsi_reset_crq_queue(struct crq_queue *queue,
+                             struct ibmvscsi_host_data *hostdata);
+
+void ibmvscsi_handle_crq(struct viosrp_crq *crq,
+                        struct ibmvscsi_host_data *hostdata);
+int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+                     u64 word1, u64 word2);
+
+#endif                         /* IBMVSCSI_H */
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
new file mode 100644 (file)
index 0000000..e9202f2
--- /dev/null
@@ -0,0 +1,144 @@
+/* ------------------------------------------------------------
+ * iSeries_vscsi.c
+ * (C) Copyright IBM Corporation 1994, 2003
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *          Dave Boutcher (sleddog@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ * ------------------------------------------------------------
+ * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices
+ *
+ * This driver allows the Linux SCSI peripheral drivers to directly
+ * access devices in the hosting partition, either on an iSeries
+ * hypervisor system or a converged hypervisor system.
+ */
+
+#include <asm/iSeries/vio.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/vio.h>
+#include <linux/device.h>
+#include "ibmvscsi.h"
+
+/* global variables */
+static struct ibmvscsi_host_data *single_host_data;
+
+/* ------------------------------------------------------------
+ * Routines for direct interpartition interaction
+ */
+struct srp_lp_event {
+       struct HvLpEvent lpevt; /* 0x00-0x17          */
+       u32 reserved1;          /* 0x18-0x1B; unused  */
+       u16 version;            /* 0x1C-0x1D; unused  */
+       u16 subtype_rc;         /* 0x1E-0x1F; unused  */
+       struct viosrp_crq crq;  /* 0x20-0x3F          */
+};
+
+/** 
+ * standard interface for handling logical partition events.
+ */
+static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
+{
+       struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
+
+       if (!evt) {
+               printk(KERN_ERR "ibmvscsi: received null event\n");
+               return;
+       }
+
+       if (single_host_data == NULL) {
+               printk(KERN_ERR
+                      "ibmvscsi: received event, no adapter present\n");
+               return;
+       }
+
+       ibmvscsi_handle_crq(&evt->crq, single_host_data);
+}
+
+/* ------------------------------------------------------------
+ * Routines for driver initialization
+ */
+int ibmvscsi_init_crq_queue(struct crq_queue *queue,
+                           struct ibmvscsi_host_data *hostdata,
+                           int max_requests)
+{
+       int rc;
+
+       single_host_data = hostdata;
+       rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0);
+       if (rc < 0) {
+               printk("viopath_open failed with rc %d in open_event_path\n",
+                      rc);
+               goto viopath_open_failed;
+       }
+
+       rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
+       if (rc < 0) {
+               printk("vio_setHandler failed with rc %d in open_event_path\n",
+                      rc);
+               goto vio_setHandler_failed;
+       }
+       return 0;
+
+      vio_setHandler_failed:
+       viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
+      viopath_open_failed:
+       return -1;
+}
+
+void ibmvscsi_release_crq_queue(struct crq_queue *queue,
+                               struct ibmvscsi_host_data *hostdata,
+                               int max_requests)
+{
+       vio_clearHandler(viomajorsubtype_scsi);
+       viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
+}
+
+/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ * no-op for iSeries
+ */
+void ibmvscsi_reset_crq_queue(struct crq_queue *queue,
+                             struct ibmvscsi_host_data *hostdata)
+{
+}
+
+/**
+ * ibmvscsi_send_crq: - Send a CRQ
+ * @hostdata:  the adapter
+ * @word1:     the first 64 bits of the data
+ * @word2:     the second 64 bits of the data
+ */
+int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+{
+       single_host_data = hostdata;
+       return HvCallEvent_signalLpEventFast(viopath_hostLp,
+                                            HvLpEvent_Type_VirtualIo,
+                                            viomajorsubtype_scsi,
+                                            HvLpEvent_AckInd_NoAck,
+                                            HvLpEvent_AckType_ImmediateAck,
+                                            viopath_sourceinst(viopath_hostLp),
+                                            viopath_targetinst(viopath_hostLp),
+                                            0,
+                                            VIOVERSION << 16, word1, word2, 0,
+                                            0);
+}
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
new file mode 100644 (file)
index 0000000..b4e8265
--- /dev/null
@@ -0,0 +1,260 @@
+/* ------------------------------------------------------------
+ * rpa_vscsi.c
+ * (C) Copyright IBM Corporation 1994, 2003
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ * ------------------------------------------------------------
+ * RPA-specific functions of the SCSI host adapter for Virtual I/O devices
+ *
+ * This driver allows the Linux SCSI peripheral drivers to directly
+ * access devices in the hosting partition, either on an iSeries
+ * hypervisor system or a converged hypervisor system.
+ */
+
+#include <asm/vio.h>
+#include <asm/iommu.h>
+#include <asm/hvcall.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include "ibmvscsi.h"
+
+/* ------------------------------------------------------------
+ * Routines for managing the command/response queue
+ */
+/**
+ * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * @irq:       number of irq to handle, not used
+ * @dev_instance: ibmvscsi_host_data of host that received interrupt
+ * @regs:      pt_regs with registers
+ *
+ * Disables interrupts and schedules srp_task
+ * Always returns IRQ_HANDLED
+ */
+static irqreturn_t ibmvscsi_handle_event(int irq,
+                                        void *dev_instance,
+                                        struct pt_regs *regs)
+{
+       struct ibmvscsi_host_data *hostdata =
+           (struct ibmvscsi_host_data *)dev_instance;
+       vio_disable_interrupts(to_vio_dev(hostdata->dev));
+       tasklet_schedule(&hostdata->srp_task);
+       return IRQ_HANDLED;
+}
+
+/**
+ * release_crq_queue: - Deallocates data and unregisters CRQ
+ * @queue:     crq_queue to initialize and register
+ * @host_data: ibmvscsi_host_data of host
+ *
+ * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
+ * the crq with the hypervisor.
+ */
+void ibmvscsi_release_crq_queue(struct crq_queue *queue,
+                               struct ibmvscsi_host_data *hostdata,
+                               int max_requests)
+{
+       long rc;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+       free_irq(vdev->irq, (void *)hostdata);
+       tasklet_kill(&hostdata->srp_task);
+       do {
+               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+       } while ((rc == H_Busy) || (H_isLongBusy(rc)));
+       dma_unmap_single(hostdata->dev,
+                        queue->msg_token,
+                        queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+       free_page((unsigned long)queue->msgs);
+}
+
+/**
+ * crq_queue_next_crq: - Returns the next entry in message queue
+ * @queue:     crq_queue to use
+ *
+ * Returns pointer to next entry in queue, or NULL if there are no new 
+ * entried in the CRQ.
+ */
+static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
+{
+       struct viosrp_crq *crq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       crq = &queue->msgs[queue->cur];
+       if (crq->valid & 0x80) {
+               if (++queue->cur == queue->size)
+                       queue->cur = 0;
+       } else
+               crq = NULL;
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       return crq;
+}
+
+/**
+ * ibmvscsi_send_crq: - Send a CRQ
+ * @hostdata:  the adapter
+ * @word1:     the first 64 bits of the data
+ * @word2:     the second 64 bits of the data
+ */
+int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+{
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+       return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
+}
+
+/**
+ * ibmvscsi_task: - Process srps asynchronously
+ * @data:      ibmvscsi_host_data of host
+ */
+static void ibmvscsi_task(void *data)
+{
+       struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+       struct viosrp_crq *crq;
+       int done = 0;
+
+       while (!done) {
+               /* Pull all the valid messages off the CRQ */
+               while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
+                       ibmvscsi_handle_crq(crq, hostdata);
+                       crq->valid = 0x00;
+               }
+
+               vio_enable_interrupts(vdev);
+               if ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
+                       vio_disable_interrupts(vdev);
+                       ibmvscsi_handle_crq(crq, hostdata);
+                       crq->valid = 0x00;
+               } else {
+                       done = 1;
+               }
+       }
+}
+
+/**
+ * initialize_crq_queue: - Initializes and registers CRQ with hypervisor
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ * Allocates a page for messages, maps it for dma, and registers
+ * the crq with the hypervisor.
+ * Returns zero on success.
+ */
+int ibmvscsi_init_crq_queue(struct crq_queue *queue,
+                           struct ibmvscsi_host_data *hostdata,
+                           int max_requests)
+{
+       int rc;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+       queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+
+       if (!queue->msgs)
+               goto malloc_failed;
+       queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+       queue->msg_token = dma_map_single(hostdata->dev, queue->msgs,
+                                         queue->size * sizeof(*queue->msgs),
+                                         DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(queue->msg_token))
+               goto map_failed;
+
+       rc = plpar_hcall_norets(H_REG_CRQ,
+                               vdev->unit_address,
+                               queue->msg_token, PAGE_SIZE);
+       if (rc == 2) {
+               /* Adapter is good, but other end is not ready */
+               printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+       } else if (rc != 0) {
+               printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
+               goto reg_crq_failed;
+       }
+
+       if (request_irq(vdev->irq,
+                       ibmvscsi_handle_event,
+                       0, "ibmvscsi", (void *)hostdata) != 0) {
+               printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n",
+                      vdev->irq);
+               goto req_irq_failed;
+       }
+
+       rc = vio_enable_interrupts(vdev);
+       if (rc != 0) {
+               printk(KERN_ERR "ibmvscsi:  Error %d enabling interrupts!!!\n",
+                      rc);
+               goto req_irq_failed;
+       }
+
+       queue->cur = 0;
+       queue->lock = SPIN_LOCK_UNLOCKED;
+
+       tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
+                    (unsigned long)hostdata);
+
+       return 0;
+
+      req_irq_failed:
+       do {
+               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+       } while ((rc == H_Busy) || (H_isLongBusy(rc)));
+      reg_crq_failed:
+       dma_unmap_single(hostdata->dev,
+                        queue->msg_token,
+                        queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+      map_failed:
+       free_page((unsigned long)queue->msgs);
+      malloc_failed:
+       return -1;
+}
+
+/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ */
+void ibmvscsi_reset_crq_queue(struct crq_queue *queue,
+                             struct ibmvscsi_host_data *hostdata)
+{
+       int rc;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+       /* Close the CRQ */
+       do {
+               rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+       } while ((rc == H_Busy) || (H_isLongBusy(rc)));
+
+       /* Clean out the queue */
+       memset(queue->msgs, 0x00, PAGE_SIZE);
+       queue->cur = 0;
+
+       /* And re-open it again */
+       rc = plpar_hcall_norets(H_REG_CRQ,
+                               vdev->unit_address,
+                               queue->msg_token, PAGE_SIZE);
+       if (rc == 2) {
+               /* Adapter is good, but other end is not ready */
+               printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+       } else if (rc != 0) {
+               printk(KERN_WARNING
+                      "ibmvscsi: couldn't register crq--rc 0x%x\n", rc);
+       }
+}
diff --git a/drivers/scsi/ibmvscsi/srp.h b/drivers/scsi/ibmvscsi/srp.h
new file mode 100644 (file)
index 0000000..e952c1c
--- /dev/null
@@ -0,0 +1,225 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for the SCSI RDMA Protocol  */
+/* (SRP) as defined in the T10 standard available at www.t10.org.  This      */
+/* file was based on the 16a version of the standard                         */
+/*                                                                           */
+/*****************************************************************************/
+#ifndef SRP_H
+#define SRP_H
+
+#define PACKED __attribute__((packed))
+
+enum srp_types {
+       SRP_LOGIN_REQ_TYPE = 0x00,
+       SRP_LOGIN_RSP_TYPE = 0xC0,
+       SRP_LOGIN_REJ_TYPE = 0x80,
+       SRP_I_LOGOUT_TYPE = 0x03,
+       SRP_T_LOGOUT_TYPE = 0x80,
+       SRP_TSK_MGMT_TYPE = 0x01,
+       SRP_CMD_TYPE = 0x02,
+       SRP_RSP_TYPE = 0xC1,
+       SRP_CRED_REQ_TYPE = 0x81,
+       SRP_CRED_RSP_TYPE = 0x41,
+       SRP_AER_REQ_TYPE = 0x82,
+       SRP_AER_RSP_TYPE = 0x42
+};
+
+enum srp_descriptor_formats {
+       SRP_NO_BUFFER = 0x00,
+       SRP_DIRECT_BUFFER = 0x01,
+       SRP_INDIRECT_BUFFER = 0x02
+};
+
+struct memory_descriptor {
+       u64 virtual_address;
+       u32 memory_handle;
+       u32 length;
+};
+
+struct indirect_descriptor {
+       struct memory_descriptor head;
+       u32 total_length;
+       struct memory_descriptor list[1] PACKED;
+};
+
+struct srp_generic {
+       u8 type;
+       u8 reserved1[7];
+       u64 tag;
+};
+
+struct srp_login_req {
+       u8 type;
+       u8 reserved1[7];
+       u64 tag;
+       u32 max_requested_initiator_to_target_iulen;
+       u32 reserved2;
+       u16 required_buffer_formats;
+       u8 reserved3:6;
+       u8 multi_channel_action:2;
+       u8 reserved4;
+       u32 reserved5;
+       u8 initiator_port_identifier[16];
+       u8 target_port_identifier[16];
+};
+
+struct srp_login_rsp {
+       u8 type;
+       u8 reserved1[3];
+       u32 request_limit_delta;
+       u64 tag;
+       u32 max_initiator_to_target_iulen;
+       u32 max_target_to_initiator_iulen;
+       u16 supported_buffer_formats;
+       u8 reserved2:6;
+       u8 multi_channel_result:2;
+       u8 reserved3;
+       u8 reserved4[24];
+};
+
+struct srp_login_rej {
+       u8 type;
+       u8 reserved1[3];
+       u32 reason;
+       u64 tag;
+       u64 reserved2;
+       u16 supported_buffer_formats;
+       u8 reserved3[6];
+};
+
+struct srp_i_logout {
+       u8 type;
+       u8 reserved1[7];
+       u64 tag;
+};
+
+struct srp_t_logout {
+       u8 type;
+       u8 reserved1[3];
+       u32 reason;
+       u64 tag;
+};
+
+struct srp_tsk_mgmt {
+       u8 type;
+       u8 reserved1[7];
+       u64 tag;
+       u32 reserved2;
+       u64 lun PACKED;
+       u8 reserved3;
+       u8 reserved4;
+       u8 task_mgmt_flags;
+       u8 reserved5;
+       u64 managed_task_tag;
+       u64 reserved6;
+};
+
+struct srp_cmd {
+       u8 type;
+       u32 reserved1 PACKED;
+       u8 data_out_format:4;
+       u8 data_in_format:4;
+       u8 data_out_count;
+       u8 data_in_count;
+       u64 tag;
+       u32 reserved2;
+       u64 lun PACKED;
+       u8 reserved3;
+       u8 reserved4:5;
+       u8 task_attribute:3;
+       u8 reserved5;
+       u8 additional_cdb_len;
+       u8 cdb[16];
+       u8 additional_data[0x100 - 0x30];
+};
+
+struct srp_rsp {
+       u8 type;
+       u8 reserved1[3];
+       u32 request_limit_delta;
+       u64 tag;
+       u16 reserved2;
+       u8 reserved3:2;
+       u8 diunder:1;
+       u8 diover:1;
+       u8 dounder:1;
+       u8 doover:1;
+       u8 snsvalid:1;
+       u8 rspvalid:1;
+       u8 status;
+       u32 data_in_residual_count;
+       u32 data_out_residual_count;
+       u32 sense_data_list_length;
+       u32 response_data_list_length;
+       u8 sense_and_response_data[18];
+};
+
+struct srp_cred_req {
+       u8 type;
+       u8 reserved1[3];
+       u32 request_limit_delta;
+       u64 tag;
+};
+
+struct srp_cred_rsp {
+       u8 type;
+       u8 reserved1[7];
+       u64 tag;
+};
+
+struct srp_aer_req {
+       u8 type;
+       u8 reserved1[3];
+       u32 request_limit_delta;
+       u64 tag;
+       u32 reserved2;
+       u64 lun;
+       u32 sense_data_list_length;
+       u32 reserved3;
+       u8 sense_data[20];
+};
+
+struct srp_aer_rsp {
+       u8 type;
+       u8 reserved1[7];
+       u64 tag;
+};
+
+union srp_iu {
+       struct srp_generic generic;
+       struct srp_login_req login_req;
+       struct srp_login_rsp login_rsp;
+       struct srp_login_rej login_rej;
+       struct srp_i_logout i_logout;
+       struct srp_t_logout t_logout;
+       struct srp_tsk_mgmt tsk_mgmt;
+       struct srp_cmd cmd;
+       struct srp_rsp rsp;
+       struct srp_cred_req cred_req;
+       struct srp_cred_rsp cred_rsp;
+       struct srp_aer_req aer_req;
+       struct srp_aer_rsp aer_rsp;
+};
+
+#endif
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
new file mode 100644 (file)
index 0000000..6a6bba8
--- /dev/null
@@ -0,0 +1,126 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef VIOSRP_H
+#define VIOSRP_H
+#include "srp.h"
+
+enum viosrp_crq_formats {
+       VIOSRP_SRP_FORMAT = 0x01,
+       VIOSRP_MAD_FORMAT = 0x02,
+       VIOSRP_OS400_FORMAT = 0x03,
+       VIOSRP_AIX_FORMAT = 0x04,
+       VIOSRP_LINUX_FORMAT = 0x06,
+       VIOSRP_INLINE_FORMAT = 0x07
+};
+
+struct viosrp_crq {
+       u8 valid;               /* used by RPA */
+       u8 format;              /* SCSI vs out-of-band */
+       u8 reserved;
+       u8 status;              /* non-scsi failure? (e.g. DMA failure) */
+       u16 timeout;            /* in seconds */
+       u16 IU_length;          /* in bytes */
+       u64 IU_data_ptr;        /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.  
+ */
+enum viosrp_mad_types {
+       VIOSRP_EMPTY_IU_TYPE = 0x01,
+       VIOSRP_ERROR_LOG_TYPE = 0x02,
+       VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+       VIOSRP_HOST_CONFIG_TYPE = 0x04
+};
+
+/* 
+ * Common MAD header
+ */
+struct mad_common {
+       u32 type;
+       u16 status;
+       u16 length;
+       u64 tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER 
+ */
+struct viosrp_empty_iu {
+       struct mad_common common;
+       u64 buffer;
+       u32 port;
+};
+
+struct viosrp_error_log {
+       struct mad_common common;
+       u64 buffer;
+};
+
+struct viosrp_adapter_info {
+       struct mad_common common;
+       u64 buffer;
+};
+
+struct viosrp_host_config {
+       struct mad_common common;
+       u64 buffer;
+};
+
+union mad_iu {
+       struct viosrp_empty_iu empty_iu;
+       struct viosrp_error_log error_log;
+       struct viosrp_adapter_info adapter_info;
+       struct viosrp_host_config host_config;
+};
+
+union viosrp_iu {
+       union srp_iu srp;
+       union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+       char srp_version[8];
+       char partition_name[96];
+       u32 partition_number;
+       u32 mad_version;
+       u32 os_type;
+       u32 port_max_txu[8];    /* per-port maximum transfer */
+};
+
+#endif
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
new file mode 100644 (file)
index 0000000..a7b74d8
--- /dev/null
@@ -0,0 +1,3184 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ *************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host
+ * adapters
+ *
+ * 08/06/97 hc - v1.01h
+ *             - Support inic-940 and inic-935
+ * 09/26/97 hc - v1.01i
+ *             - Make correction from J.W. Schultz suggestion
+ * 10/13/97 hc - Support reset function
+ * 10/21/97 hc - v1.01j
+ *             - Support 32 LUN (SCSI 3)
+ * 01/14/98 hc - v1.01k
+ *             - Fix memory allocation problem
+ * 03/04/98 hc - v1.01l
+ *             - Fix tape rewind which will hang the system problem
+ *             - Set can_queue to tul_num_scb
+ * 06/25/98 hc - v1.01m
+ *             - Get it work for kernel version >= 2.1.75
+ *             - Dynamic assign SCSI bus reset holding time in init_tulip()
+ * 07/02/98 hc - v1.01n
+ *             - Support 0002134A
+ * 08/07/98 hc  - v1.01o
+ *             - Change the tul_abort_srb routine to use scsi_done. <01>
+ * 09/07/98 hl  - v1.02
+ *              - Change the INI9100U define and proc_dir_entry to
+ *                reflect the newer Kernel 2.1.118, but the v1.o1o
+ *                should work with Kernel 2.1.118.
+ * 09/20/98 wh  - v1.02a
+ *              - Support Abort command.
+ *              - Handle reset routine.
+ * 09/21/98 hl  - v1.03
+ *              - remove comments.
+ * 12/09/98 bv - v1.03a
+ *             - Removed unused code
+ * 12/13/98 bv - v1.03b
+ *             - Remove cli() locking for kernels >= 2.1.95. This uses
+ *               spinlocks to serialize access to the pSRB_head and
+ *               pSRB_tail members of the HCS structure.
+ * 09/01/99 bv - v1.03d
+ *             - Fixed a deadlock problem in SMP.
+ * 21/01/99 bv - v1.03e
+ *             - Add support for the Domex 3192U PCI SCSI
+ *               This is a slightly modified patch by
+ *               Brian Macy <bmacy@sunshinecomputing.com>
+ * 22/02/99 bv - v1.03f
+ *             - Didn't detect the INIC-950 in 2.0.x correctly.
+ *               Now fixed.
+ * 05/07/99 bv - v1.03g
+ *             - Changed the assumption that HZ = 100
+ * 10/17/03 mc - v1.04
+ *             - added new DMA API support
+ * 06/01/04 jmd        - v1.04a
+ *             - Re-add reset_bus support
+ **************************************************************************/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "initio.h"
+
+#define SENSE_SIZE             14
+
+#define i91u_MAXQUEUE          2
+#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
+
+#define INI_VENDOR_ID   0x1101 /* Initio's PCI vendor ID       */
+#define DMX_VENDOR_ID  0x134a  /* Domex's PCI vendor ID        */
+#define I950_DEVICE_ID 0x9500  /* Initio's inic-950 product ID   */
+#define I940_DEVICE_ID 0x9400  /* Initio's inic-940 product ID   */
+#define I935_DEVICE_ID 0x9401  /* Initio's inic-935 product ID   */
+#define I920_DEVICE_ID 0x0002  /* Initio's other product ID      */
+
+#ifdef DEBUG_i91u
+static unsigned int i91u_debug = DEBUG_DEFAULT;
+#endif
+
+#define TULSZ(sz)     (sizeof(sz) / sizeof(sz[0]))
+#define TUL_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+typedef struct PCI_ID_Struc {
+       unsigned short vendor_id;
+       unsigned short device_id;
+} PCI_ID;
+
+static int tul_num_ch = 4;     /* Maximum 4 adapters           */
+static int tul_num_scb;
+static int tul_tag_enable = 1;
+static SCB *tul_scb;
+
+#ifdef DEBUG_i91u
+static int setup_debug = 0;
+#endif
+
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+
+static const PCI_ID i91u_pci_devices[] = {
+       { INI_VENDOR_ID, I950_DEVICE_ID },
+       { INI_VENDOR_ID, I940_DEVICE_ID },
+       { INI_VENDOR_ID, I935_DEVICE_ID },
+       { INI_VENDOR_ID, I920_DEVICE_ID },
+       { DMX_VENDOR_ID, I920_DEVICE_ID },
+};
+
+#define DEBUG_INTERRUPT 0
+#define DEBUG_QUEUE     0
+#define DEBUG_STATE     0
+#define INT_DISC       0
+
+/*--- external functions --*/
+static void tul_se2_wait(void);
+
+/*--- forward refrence ---*/
+static SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun);
+static SCB *tul_find_done_scb(HCS * pCurHcb);
+
+static int tulip_main(HCS * pCurHcb);
+
+static int tul_next_state(HCS * pCurHcb);
+static int tul_state_1(HCS * pCurHcb);
+static int tul_state_2(HCS * pCurHcb);
+static int tul_state_3(HCS * pCurHcb);
+static int tul_state_4(HCS * pCurHcb);
+static int tul_state_5(HCS * pCurHcb);
+static int tul_state_6(HCS * pCurHcb);
+static int tul_state_7(HCS * pCurHcb);
+static int tul_xfer_data_in(HCS * pCurHcb);
+static int tul_xfer_data_out(HCS * pCurHcb);
+static int tul_xpad_in(HCS * pCurHcb);
+static int tul_xpad_out(HCS * pCurHcb);
+static int tul_status_msg(HCS * pCurHcb);
+
+static int tul_msgin(HCS * pCurHcb);
+static int tul_msgin_sync(HCS * pCurHcb);
+static int tul_msgin_accept(HCS * pCurHcb);
+static int tul_msgout_reject(HCS * pCurHcb);
+static int tul_msgin_extend(HCS * pCurHcb);
+
+static int tul_msgout_ide(HCS * pCurHcb);
+static int tul_msgout_abort_targ(HCS * pCurHcb);
+static int tul_msgout_abort_tag(HCS * pCurHcb);
+
+static int tul_bus_device_reset(HCS * pCurHcb);
+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_bad_seq(HCS * pCurHcb);
+static int int_tul_resel(HCS * pCurHcb);
+static int tul_sync_done(HCS * pCurHcb);
+static int wdtr_done(HCS * pCurHcb);
+static int wait_tulip(HCS * pCurHcb);
+static int tul_wait_done_disc(HCS * pCurHcb);
+static int tul_wait_disc(HCS * pCurHcb);
+static void tulip_scsi(HCS * pCurHcb);
+static int tul_post_scsi_rst(HCS * pCurHcb);
+
+static void tul_se2_ew_en(WORD CurBase);
+static void tul_se2_ew_ds(WORD CurBase);
+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 INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
+
+/*NVRAM nvram, *nvramp = &nvram; */
+static NVRAM i91unvram;
+static NVRAM *i91unvramp;
+
+
+
+static UCHAR i91udftNvRam[64] =
+{
+/*----------- header -----------*/
+       0x25, 0xc9,             /* Signature    */
+       0x40,                   /* Size         */
+       0x01,                   /* Revision     */
+       /* -- Host Adapter Structure -- */
+       0x95,                   /* ModelByte0   */
+       0x00,                   /* ModelByte1   */
+       0x00,                   /* ModelInfo    */
+       0x01,                   /* NumOfCh      */
+       NBC1_DEFAULT,           /* BIOSConfig1  */
+       0,                      /* BIOSConfig2  */
+       0,                      /* HAConfig1    */
+       0,                      /* HAConfig2    */
+       /* SCSI channel 0 and target Structure  */
+       7,                      /* SCSIid       */
+       NCC1_DEFAULT,           /* SCSIconfig1  */
+       0,                      /* SCSIconfig2  */
+       0x10,                   /* NumSCSItarget */
+
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+
+       /* SCSI channel 1 and target Structure  */
+       7,                      /* SCSIid       */
+       NCC1_DEFAULT,           /* SCSIconfig1  */
+       0,                      /* SCSIconfig2  */
+       0x10,                   /* NumSCSItarget */
+
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0};                  /*      - CheckSum -            */
+
+
+static UCHAR tul_rate_tbl[8] = /* fast 20      */
+{
+                               /* nanosecond devide by 4 */
+       12,                     /* 50ns,  20M   */
+       18,                     /* 75ns,  13.3M */
+       25,                     /* 100ns, 10M   */
+       31,                     /* 125ns, 8M    */
+       37,                     /* 150ns, 6.6M  */
+       43,                     /* 175ns, 5.7M  */
+       50,                     /* 200ns, 5M    */
+       62                      /* 250ns, 4M    */
+};
+
+static void tul_do_pause(unsigned amount)
+{                              /* Pause for amount jiffies */
+       unsigned long the_time = jiffies + amount;
+
+       while (time_before_eq(jiffies, the_time));
+}
+
+/*-- forward reference --*/
+
+/*******************************************************************
+       Use memeory refresh time        ~ 15us * 2
+********************************************************************/
+void tul_se2_wait(void)
+{
+#if 1
+       udelay(30);
+#else
+       UCHAR readByte;
+
+       readByte = TUL_RD(0, 0x61);
+       if ((readByte & 0x10) == 0x10) {
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) == 0x10)
+                               break;
+               }
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) != 0x10)
+                               break;
+               }
+       } else {
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) == 0x10)
+                               break;
+               }
+               for (;;) {
+                       readByte = TUL_RD(0, 0x61);
+                       if ((readByte & 0x10) != 0x10)
+                               break;
+               }
+       }
+#endif
+}
+
+
+/******************************************************************
+ Input: instruction for  Serial E2PROM
+
+ EX: se2_rd(0 call se2_instr() to send address and read command
+
+        StartBit  OP_Code   Address                Data
+        --------- --------  ------------------     -------
+        1         1 , 0     A5,A4,A3,A2,A1,A0      D15-D0
+
+                +-----------------------------------------------------
+                |
+ CS -----+
+                       +--+  +--+  +--+  +--+  +--+
+                       ^  |  ^  |  ^  |  ^  |  ^  |
+                       |  |  |  |  |  |  |  |  |  |
+ CLK -------+  +--+  +--+  +--+  +--+  +--
+ (leading edge trigger)
+
+                +--1-----1--+
+                | SB    OP  |  OP    A5    A4
+ DI  ----+           +--0------------------
+ (address and cmd sent to nvram)
+
+        -------------------------------------------+
+                                                                                               |
+ DO                                             +---
+ (data sent from nvram)
+
+
+******************************************************************/
+void tul_se2_instr(WORD CurBase, UCHAR instr)
+{
+       int i;
+       UCHAR b;
+
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);     /* cs+start bit */
+       tul_se2_wait();
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK | SE2DO);    /* +CLK */
+       tul_se2_wait();
+
+       for (i = 0; i < 8; i++) {
+               if (instr & 0x80)
+                       b = SE2CS | SE2DO;      /* -CLK+dataBit */
+               else
+                       b = SE2CS;      /* -CLK */
+               TUL_WR(CurBase + TUL_NVRAM, b);
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, b | SE2CLK);        /* +CLK */
+               tul_se2_wait();
+               instr <<= 1;
+       }
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+       tul_se2_wait();
+       return;
+}
+
+
+/******************************************************************
+ Function name  : tul_se2_ew_en
+ Description    : Enable erase/write state of serial EEPROM
+******************************************************************/
+void tul_se2_ew_en(WORD CurBase)
+{
+       tul_se2_instr(CurBase, 0x30);   /* EWEN */
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS  */
+       tul_se2_wait();
+       return;
+}
+
+
+/************************************************************************
+ Disable erase/write state of serial EEPROM
+*************************************************************************/
+void tul_se2_ew_ds(WORD CurBase)
+{
+       tul_se2_instr(CurBase, 0);      /* EWDS */
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS  */
+       tul_se2_wait();
+       return;
+}
+
+
+/******************************************************************
+       Input  :address of Serial E2PROM
+       Output :value stored in  Serial E2PROM
+*******************************************************************/
+USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+{
+       UCHAR instr, readByte;
+       USHORT readWord;
+       int i;
+
+       instr = (UCHAR) (adr | 0x80);
+       tul_se2_instr(CurBase, instr);  /* READ INSTR */
+       readWord = 0;
+
+       for (i = 15; i >= 0; i--) {
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);    /* +CLK */
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+
+               /* sample data after the following edge of clock  */
+               readByte = TUL_RD(CurBase, TUL_NVRAM);
+               readByte &= SE2DI;
+               readWord += (readByte << i);
+               tul_se2_wait(); /* 6/20/95 */
+       }
+
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* no chip select */
+       tul_se2_wait();
+       return readWord;
+}
+
+
+/******************************************************************
+ Input: new value in  Serial E2PROM, address of Serial E2PROM
+*******************************************************************/
+void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+{
+       UCHAR readByte;
+       UCHAR instr;
+       int i;
+
+       instr = (UCHAR) (adr | 0x40);
+       tul_se2_instr(CurBase, instr);  /* WRITE INSTR */
+       for (i = 15; i >= 0; i--) {
+               if (writeWord & 0x8000)
+                       TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);     /* -CLK+dataBit 1 */
+               else
+                       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK+dataBit 0 */
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);    /* +CLK */
+               tul_se2_wait();
+               writeWord <<= 1;
+       }
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+       tul_se2_wait();
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS  */
+       tul_se2_wait();
+
+       TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* +CS  */
+       tul_se2_wait();
+
+       for (;;) {
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);    /* +CLK */
+               tul_se2_wait();
+               TUL_WR(CurBase + TUL_NVRAM, SE2CS);     /* -CLK */
+               tul_se2_wait();
+               if ((readByte = TUL_RD(CurBase, TUL_NVRAM)) & SE2DI)
+                       break;  /* write complete */
+       }
+       TUL_WR(CurBase + TUL_NVRAM, 0);         /* -CS */
+       return;
+}
+
+
+/***********************************************************************
+ Read SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+int tul_se2_rd_all(WORD CurBase)
+{
+       int i;
+       ULONG chksum = 0;
+       USHORT *np;
+
+       i91unvramp = &i91unvram;
+       np = (USHORT *) i91unvramp;
+       for (i = 0; i < 32; i++) {
+               *np++ = tul_se2_rd(CurBase, i);
+       }
+
+/*--------------------Is signature "ini" ok ? ----------------*/
+       if (i91unvramp->NVM_Signature != INI_SIGNATURE)
+               return -1;
+/*---------------------- Is ckecksum ok ? ----------------------*/
+       np = (USHORT *) i91unvramp;
+       for (i = 0; i < 31; i++)
+               chksum += *np++;
+       if (i91unvramp->NVM_CheckSum != (USHORT) chksum)
+               return -1;
+       return 1;
+}
+
+
+/***********************************************************************
+ Update SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+void tul_se2_update_all(WORD CurBase)
+{                              /* setup default pattern */
+       int i;
+       ULONG chksum = 0;
+       USHORT *np, *np1;
+
+       i91unvramp = &i91unvram;
+       /* Calculate checksum first */
+       np = (USHORT *) i91udftNvRam;
+       for (i = 0; i < 31; i++)
+               chksum += *np++;
+       *np = (USHORT) chksum;
+       tul_se2_ew_en(CurBase); /* Enable write  */
+
+       np = (USHORT *) i91udftNvRam;
+       np1 = (USHORT *) i91unvramp;
+       for (i = 0; i < 32; i++, np++, np1++) {
+               if (*np != *np1) {
+                       tul_se2_wr(CurBase, i, *np);
+               }
+       }
+
+       tul_se2_ew_ds(CurBase); /* Disable write   */
+       return;
+}
+
+/*************************************************************************
+ Function name  : read_eeprom
+**************************************************************************/
+void tul_read_eeprom(WORD CurBase)
+{
+       UCHAR gctrl;
+
+       i91unvramp = &i91unvram;
+/*------Enable EEProm programming ---*/
+       gctrl = TUL_RD(CurBase, TUL_GCTRL);
+       TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT);
+       if (tul_se2_rd_all(CurBase) != 1) {
+               tul_se2_update_all(CurBase);    /* setup default pattern */
+               tul_se2_rd_all(CurBase);        /* load again  */
+       }
+/*------ Disable EEProm programming ---*/
+       gctrl = TUL_RD(CurBase, TUL_GCTRL);
+       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)
+{
+       int i, j;
+
+       for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
+               if (i91u_adpt[i].ADPT_BIOS < wBIOS)
+                       continue;
+               if (i91u_adpt[i].ADPT_BIOS == wBIOS) {
+                       if (i91u_adpt[i].ADPT_BASE == wBASE) {
+                               if (i91u_adpt[i].ADPT_Bus != 0xFF)
+                                       return 1;
+                       } else if (i91u_adpt[i].ADPT_BASE < wBASE)
+                                       continue;
+               }
+               for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
+                       i91u_adpt[j].ADPT_BASE = i91u_adpt[j - 1].ADPT_BASE;
+                       i91u_adpt[j].ADPT_INTR = i91u_adpt[j - 1].ADPT_INTR;
+                       i91u_adpt[j].ADPT_BIOS = i91u_adpt[j - 1].ADPT_BIOS;
+                       i91u_adpt[j].ADPT_Bus = i91u_adpt[j - 1].ADPT_Bus;
+                       i91u_adpt[j].ADPT_Device = i91u_adpt[j - 1].ADPT_Device;
+               }
+               i91u_adpt[i].ADPT_BASE = wBASE;
+               i91u_adpt[i].ADPT_INTR = bInterrupt;
+               i91u_adpt[i].ADPT_BIOS = wBIOS;
+               i91u_adpt[i].ADPT_Bus = bBus;
+               i91u_adpt[i].ADPT_Device = bDevice;
+               return 0;
+       }
+       return 1;
+}
+
+void init_i91uAdapter_table(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {  /* Initialize adapter structure */
+               i91u_adpt[i].ADPT_BIOS = 0xffff;
+               i91u_adpt[i].ADPT_BASE = 0xffff;
+               i91u_adpt[i].ADPT_INTR = 0xff;
+               i91u_adpt[i].ADPT_Bus = 0xff;
+               i91u_adpt[i].ADPT_Device = 0xff;
+       }
+       return;
+}
+
+void tul_stop_bm(HCS * pCurHcb)
+{
+
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* if DMA xfer is pending, abort DMA xfer */
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+               /* wait Abort DMA xfer done */
+               while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+}
+
+/***************************************************************************/
+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  */
+       pCurHcb->HCS_Intr = i91u_adpt[ch_idx].ADPT_INTR;        /* Supply interrupt line */
+       return;
+}
+
+/***************************************************************************/
+int tul_reset_scsi(HCS * pCurHcb, int seconds)
+{
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
+
+       while (!((pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt)) & TSS_SCSIRST_INT));
+       /* reset tulip chip */
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, 0);
+
+       /* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
+       /* SONY 5200 tape drive won't work if only stall for 1 sec */
+       tul_do_pause(seconds * HZ);
+
+       TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+       return (SCSI_RESET_SUCCESS);
+}
+
+/***************************************************************************/
+int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds)
+{
+       int i;
+       BYTE *pwFlags;
+       BYTE *pbHeads;
+       SCB *pTmpScb, *pPrevScb = NULL;
+
+       pCurHcb->HCS_NumScbs = tul_num_scb;
+       pCurHcb->HCS_Semaph = 1;
+       spin_lock_init(&pCurHcb->HCS_SemaphLock);
+       pCurHcb->HCS_JSStatus0 = 0;
+       pCurHcb->HCS_Scb = scbp;
+       pCurHcb->HCS_NxtPend = scbp;
+       pCurHcb->HCS_NxtAvail = scbp;
+       for (i = 0, pTmpScb = scbp; i < tul_num_scb; i++, pTmpScb++) {
+               pTmpScb->SCB_TagId = i;
+               if (i != 0)
+                       pPrevScb->SCB_NxtScb = pTmpScb;
+               pPrevScb = pTmpScb;
+       }
+       pPrevScb->SCB_NxtScb = NULL;
+       pCurHcb->HCS_ScbEnd = pTmpScb;
+       pCurHcb->HCS_FirstAvail = scbp;
+       pCurHcb->HCS_LastAvail = pPrevScb;
+       spin_lock_init(&pCurHcb->HCS_AvailLock);
+       pCurHcb->HCS_FirstPend = NULL;
+       pCurHcb->HCS_LastPend = NULL;
+       pCurHcb->HCS_FirstBusy = NULL;
+       pCurHcb->HCS_LastBusy = NULL;
+       pCurHcb->HCS_FirstDone = NULL;
+       pCurHcb->HCS_LastDone = NULL;
+       pCurHcb->HCS_ActScb = NULL;
+       pCurHcb->HCS_ActTcs = NULL;
+
+       tul_read_eeprom(pCurHcb->HCS_Base);
+/*---------- get H/A configuration -------------*/
+       if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
+               pCurHcb->HCS_MaxTar = 8;
+       else
+               pCurHcb->HCS_MaxTar = 16;
+
+       pCurHcb->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
+
+       pCurHcb->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
+       pCurHcb->HCS_IdMask = ~(1 << pCurHcb->HCS_SCSI_ID);
+
+#if CHK_PARITY
+       /* Enable parity error response */
+       TUL_WR(pCurHcb->HCS_Base + TUL_PCMD, TUL_RD(pCurHcb->HCS_Base, TUL_PCMD) | 0x40);
+#endif
+
+       /* Mask all the interrupt       */
+       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+
+       tul_stop_bm(pCurHcb);
+       /* --- Initialize the tulip --- */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP);
+
+       /* program HBA's SCSI ID        */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId, pCurHcb->HCS_SCSI_ID << 4);
+
+       /* Enable Initiator Mode ,phase latch,alternate sync period mode,
+          disable SCSI reset */
+       if (pCurHcb->HCS_Config & HCC_EN_PAR)
+               pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
+       else
+               pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_SConf1);
+
+       /* Enable HW reselect           */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, 0);
+
+       /* selection time out = 250 ms */
+       TUL_WR(pCurHcb->HCS_Base + TUL_STimeOut, 153);
+
+/*--------- Enable SCSI terminator -----*/
+       TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, (pCurHcb->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)));
+       TUL_WR(pCurHcb->HCS_Base + TUL_GCTRL1,
+              ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE));
+
+       for (i = 0,
+            pwFlags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
+            pbHeads = pbBiosAdr + 0x180;
+            i < pCurHcb->HCS_MaxTar;
+            i++, pwFlags++) {
+               pCurHcb->HCS_Tcs[i].TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+               if (pCurHcb->HCS_Tcs[i].TCS_Flags & TCF_EN_255)
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+               else
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
+               pCurHcb->HCS_Tcs[i].TCS_JS_Period = 0;
+               pCurHcb->HCS_Tcs[i].TCS_SConfig0 = pCurHcb->HCS_SConf1;
+               pCurHcb->HCS_Tcs[i].TCS_DrvHead = *pbHeads++;
+               if (pCurHcb->HCS_Tcs[i].TCS_DrvHead == 255)
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+               else
+                       pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
+               pCurHcb->HCS_Tcs[i].TCS_DrvSector = *pbHeads++;
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;
+               pCurHcb->HCS_ActTags[i] = 0;
+               pCurHcb->HCS_MaxTags[i] = 0xFF;
+       }                       /* for                          */
+       printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
+              pCurHcb->HCS_Base, pCurHcb->HCS_Intr,
+              pCurHcb->HCS_BIOS, pCurHcb->HCS_SCSI_ID);
+/*------------------- reset SCSI Bus ---------------------------*/
+       if (pCurHcb->HCS_Config & HCC_SCSI_RESET) {
+               printk("i91u: Reset SCSI Bus ... \n");
+               tul_reset_scsi(pCurHcb, seconds);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCFG1, 0x17);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SIntEnable, 0xE9);
+       return (0);
+}
+
+/***************************************************************************/
+SCB *tul_alloc_scb(HCS * hcsp)
+{
+       SCB *pTmpScb;
+       ULONG flags;
+       spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
+       if ((pTmpScb = hcsp->HCS_FirstAvail) != NULL) {
+#if DEBUG_QUEUE
+               printk("find scb at %08lx\n", (ULONG) pTmpScb);
+#endif
+               if ((hcsp->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL)
+                       hcsp->HCS_LastAvail = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+               pTmpScb->SCB_Status = SCB_RENT;
+       }
+       spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_release_scb(HCS * hcsp, SCB * scbp)
+{
+       ULONG flags;
+
+#if DEBUG_QUEUE
+       printk("Release SCB %lx; ", (ULONG) scbp);
+#endif
+       spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
+       scbp->SCB_Srb = NULL;
+       scbp->SCB_Status = 0;
+       scbp->SCB_NxtScb = NULL;
+       if (hcsp->HCS_LastAvail != NULL) {
+               hcsp->HCS_LastAvail->SCB_NxtScb = scbp;
+               hcsp->HCS_LastAvail = scbp;
+       } else {
+               hcsp->HCS_FirstAvail = scbp;
+               hcsp->HCS_LastAvail = scbp;
+       }
+       spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+}
+
+/***************************************************************************/
+void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("Append pend SCB %lx; ", (ULONG) scbp);
+#endif
+       scbp->SCB_Status = SCB_PEND;
+       scbp->SCB_NxtScb = NULL;
+       if (pCurHcb->HCS_LastPend != NULL) {
+               pCurHcb->HCS_LastPend->SCB_NxtScb = scbp;
+               pCurHcb->HCS_LastPend = scbp;
+       } else {
+               pCurHcb->HCS_FirstPend = scbp;
+               pCurHcb->HCS_LastPend = scbp;
+       }
+}
+
+/***************************************************************************/
+void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("Push pend SCB %lx; ", (ULONG) scbp);
+#endif
+       scbp->SCB_Status = SCB_PEND;
+       if ((scbp->SCB_NxtScb = pCurHcb->HCS_FirstPend) != NULL) {
+               pCurHcb->HCS_FirstPend = scbp;
+       } else {
+               pCurHcb->HCS_FirstPend = scbp;
+               pCurHcb->HCS_LastPend = scbp;
+       }
+}
+
+/***************************************************************************/
+SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+{
+       SCB *pFirstPend;
+
+
+       pFirstPend = pCurHcb->HCS_FirstPend;
+       while (pFirstPend != NULL) {
+               if (pFirstPend->SCB_Opcode != ExecSCSI) {
+                       return (pFirstPend);
+               }
+               if (pFirstPend->SCB_TagMsg == 0) {
+                       if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] == 0) &&
+                           !(pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
+                               return (pFirstPend);
+                       }
+               } else {
+                       if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] >=
+                         pCurHcb->HCS_MaxTags[pFirstPend->SCB_Target]) |
+                           (pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
+                               pFirstPend = pFirstPend->SCB_NxtScb;
+                               continue;
+                       }
+                       return (pFirstPend);
+               }
+               pFirstPend = pFirstPend->SCB_NxtScb;
+       }
+
+
+       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)
+{
+       SCB *pTmpScb, *pPrevScb;
+
+#if DEBUG_QUEUE
+       printk("unlink pend SCB %lx; ", (ULONG) pCurScb);
+#endif
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;
+       while (pTmpScb != NULL) {
+               if (pCurScb == pTmpScb) {       /* Unlink this SCB              */
+                       if (pTmpScb == pCurHcb->HCS_FirstPend) {
+                               if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastPend = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastPend)
+                                       pCurHcb->HCS_LastPend = pPrevScb;
+                       }
+                       pTmpScb->SCB_NxtScb = NULL;
+                       break;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+       return;
+}
+/***************************************************************************/
+void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("append busy SCB %lx; ", (ULONG) scbp);
+#endif
+       if (scbp->SCB_TagMsg)
+               pCurHcb->HCS_ActTags[scbp->SCB_Target]++;
+       else
+               pCurHcb->HCS_Tcs[scbp->SCB_Target].TCS_Flags |= TCF_BUSY;
+       scbp->SCB_Status = SCB_BUSY;
+       scbp->SCB_NxtScb = NULL;
+       if (pCurHcb->HCS_LastBusy != NULL) {
+               pCurHcb->HCS_LastBusy->SCB_NxtScb = scbp;
+               pCurHcb->HCS_LastBusy = scbp;
+       } else {
+               pCurHcb->HCS_FirstBusy = scbp;
+               pCurHcb->HCS_LastBusy = scbp;
+       }
+}
+
+/***************************************************************************/
+SCB *tul_pop_busy_scb(HCS * pCurHcb)
+{
+       SCB *pTmpScb;
+
+
+       if ((pTmpScb = pCurHcb->HCS_FirstBusy) != NULL) {
+               if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                       pCurHcb->HCS_LastBusy = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+               if (pTmpScb->SCB_TagMsg)
+                       pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+               else
+                       pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+       }
+#if DEBUG_QUEUE
+       printk("Pop busy SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+       SCB *pTmpScb, *pPrevScb;
+
+#if DEBUG_QUEUE
+       printk("unlink busy SCB %lx; ", (ULONG) pCurScb);
+#endif
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
+       while (pTmpScb != NULL) {
+               if (pCurScb == pTmpScb) {       /* Unlink this SCB              */
+                       if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+                               if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastBusy = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastBusy)
+                                       pCurHcb->HCS_LastBusy = pPrevScb;
+                       }
+                       pTmpScb->SCB_NxtScb = NULL;
+                       if (pTmpScb->SCB_TagMsg)
+                               pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+                       else
+                               pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+                       break;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+       return;
+}
+
+/***************************************************************************/
+SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
+{
+       SCB *pTmpScb, *pPrevScb;
+       WORD scbp_tarlun;
+
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
+       while (pTmpScb != NULL) {
+               scbp_tarlun = (pTmpScb->SCB_Lun << 8) | (pTmpScb->SCB_Target);
+               if (scbp_tarlun == tarlun) {    /* Unlink this SCB              */
+                       break;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+#if DEBUG_QUEUE
+       printk("find busy SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+       printk("append done SCB %lx; ", (ULONG) scbp);
+#endif
+
+       scbp->SCB_Status = SCB_DONE;
+       scbp->SCB_NxtScb = NULL;
+       if (pCurHcb->HCS_LastDone != NULL) {
+               pCurHcb->HCS_LastDone->SCB_NxtScb = scbp;
+               pCurHcb->HCS_LastDone = scbp;
+       } else {
+               pCurHcb->HCS_FirstDone = scbp;
+               pCurHcb->HCS_LastDone = scbp;
+       }
+}
+
+/***************************************************************************/
+SCB *tul_find_done_scb(HCS * pCurHcb)
+{
+       SCB *pTmpScb;
+
+
+       if ((pTmpScb = pCurHcb->HCS_FirstDone) != NULL) {
+               if ((pCurHcb->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL)
+                       pCurHcb->HCS_LastDone = NULL;
+               pTmpScb->SCB_NxtScb = NULL;
+       }
+#if DEBUG_QUEUE
+       printk("find done SCB %lx; ", (ULONG) pTmpScb);
+#endif
+       return (pTmpScb);
+}
+
+/***************************************************************************/
+int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
+{
+       ULONG flags;
+       SCB *pTmpScb, *pPrevScb;
+
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+       if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+               /* disable Jasmin SCSI Int        */
+
+                spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+               tulip_main(pCurHcb);
+
+               spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+               pCurHcb->HCS_Semaph = 1;
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+
+               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+               return SCSI_ABORT_SNOOZE;
+       }
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;    /* Check Pend queue */
+       while (pTmpScb != NULL) {
+               /* 07/27/98 */
+               if (pTmpScb->SCB_Srb == srbp) {
+                       if (pTmpScb == pCurHcb->HCS_ActScb) {
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+                               return SCSI_ABORT_BUSY;
+                       } else if (pTmpScb == pCurHcb->HCS_FirstPend) {
+                               if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastPend = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastPend)
+                                       pCurHcb->HCS_LastPend = pPrevScb;
+                       }
+                       pTmpScb->SCB_HaStat = HOST_ABORTED;
+                       pTmpScb->SCB_Flags |= SCF_DONE;
+                       if (pTmpScb->SCB_Flags & SCF_POST)
+                               (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+                       return SCSI_ABORT_SUCCESS;
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;    /* Check Busy queue */
+       while (pTmpScb != NULL) {
+
+               if (pTmpScb->SCB_Srb == srbp) {
+
+                       if (pTmpScb == pCurHcb->HCS_ActScb) {
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+                               return SCSI_ABORT_BUSY;
+                       } else if (pTmpScb->SCB_TagMsg == 0) {
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+                               return SCSI_ABORT_BUSY;
+                       } else {
+                               pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+                               if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+                                       if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                                               pCurHcb->HCS_LastBusy = NULL;
+                               } else {
+                                       pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                                       if (pTmpScb == pCurHcb->HCS_LastBusy)
+                                               pCurHcb->HCS_LastBusy = pPrevScb;
+                               }
+                               pTmpScb->SCB_NxtScb = NULL;
+
+
+                               pTmpScb->SCB_HaStat = HOST_ABORTED;
+                               pTmpScb->SCB_Flags |= SCF_DONE;
+                               if (pTmpScb->SCB_Flags & SCF_POST)
+                                       (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
+                               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+                               return SCSI_ABORT_SUCCESS;
+                       }
+               }
+               pPrevScb = pTmpScb;
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+       return (SCSI_ABORT_NOT_RUNNING);
+}
+
+/***************************************************************************/
+int tul_bad_seq(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+
+       printk("tul_bad_seg c=%d\n", pCurHcb->HCS_Index);
+
+       if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
+               tul_unlink_busy_scb(pCurHcb, pCurScb);
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               pCurScb->SCB_TaStat = 0;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       tul_stop_bm(pCurHcb);
+
+       tul_reset_scsi(pCurHcb, 8);     /* 7/29/98 */
+
+       return (tul_post_scsi_rst(pCurHcb));
+}
+
+/************************************************************************/
+int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
+               unsigned int target, unsigned int ResetFlags)
+{
+       ULONG flags;
+       SCB *pScb;
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+       if (ResetFlags & SCSI_RESET_ASYNCHRONOUS) {
+
+               if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+                       /* disable Jasmin SCSI Int        */
+
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+                       tulip_main(pCurHcb);
+
+                       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+                       pCurHcb->HCS_Semaph = 1;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+                       return SCSI_RESET_SNOOZE;
+               }
+               pScb = pCurHcb->HCS_FirstBusy;  /* Check Busy queue */
+               while (pScb != NULL) {
+                       if (pScb->SCB_Srb == pSrb)
+                               break;
+                       pScb = pScb->SCB_NxtScb;
+               }
+               if (pScb == NULL) {
+                       printk("Unable to Reset - No SCB Found\n");
+
+                       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+                       return SCSI_RESET_NOT_RUNNING;
+               }
+       }
+       if ((pScb = tul_alloc_scb(pCurHcb)) == NULL) {
+               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+               return SCSI_RESET_NOT_RUNNING;
+       }
+       pScb->SCB_Opcode = BusDevRst;
+       pScb->SCB_Flags = SCF_POST;
+       pScb->SCB_Target = target;
+       pScb->SCB_Mode = 0;
+
+       pScb->SCB_Srb = NULL;
+       if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
+               pScb->SCB_Srb = pSrb;
+       }
+       tul_push_pend_scb(pCurHcb, pScb);       /* push this SCB to Pending queue */
+
+       if (pCurHcb->HCS_Semaph == 1) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+               /* disable Jasmin SCSI Int        */
+               pCurHcb->HCS_Semaph = 0;
+
+               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+               tulip_main(pCurHcb);
+
+                spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+               pCurHcb->HCS_Semaph = 1;
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+       }
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+       return SCSI_RESET_PENDING;
+}
+
+int tul_reset_scsi_bus(HCS * pCurHcb)
+{
+       ULONG flags;
+
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+       pCurHcb->HCS_Semaph = 0;
+
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+       tul_stop_bm(pCurHcb);
+
+       tul_reset_scsi(pCurHcb, 2);     /* 7/29/98 */
+
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+       tul_post_scsi_rst(pCurHcb);
+
+        spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+       tulip_main(pCurHcb);
+
+        spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+       pCurHcb->HCS_Semaph = 1;
+       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+       return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
+}
+
+/************************************************************************/
+void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+       ULONG flags;
+
+       pCurScb->SCB_Mode = 0;
+
+       pCurScb->SCB_SGIdx = 0;
+       pCurScb->SCB_SGMax = pCurScb->SCB_SGLen;
+
+       spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+       tul_append_pend_scb(pCurHcb, pCurScb);  /* Append this SCB to Pending queue */
+
+/* VVVVV 07/21/98 */
+       if (pCurHcb->HCS_Semaph == 1) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+               /* disable Jasmin SCSI Int        */
+               pCurHcb->HCS_Semaph = 0;
+
+               spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+               tulip_main(pCurHcb);
+
+               spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+               pCurHcb->HCS_Semaph = 1;
+               TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+       }
+       spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+       return;
+}
+
+/***************************************************************************/
+int tul_isr(HCS * pCurHcb)
+{
+       /* Enter critical section       */
+
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_Int) & TSS_INT_PENDING) {
+               if (pCurHcb->HCS_Semaph == 1) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+                       /* Disable Tulip SCSI Int */
+                       pCurHcb->HCS_Semaph = 0;
+
+                       tulip_main(pCurHcb);
+
+                       pCurHcb->HCS_Semaph = 1;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+/***************************************************************************/
+int tulip_main(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+
+       for (;;) {
+
+               tulip_scsi(pCurHcb);    /* Call tulip_scsi              */
+
+               while ((pCurScb = tul_find_done_scb(pCurHcb)) != NULL) {        /* find done entry */
+                       if (pCurScb->SCB_TaStat == INI_QUEUE_FULL) {
+                               pCurHcb->HCS_MaxTags[pCurScb->SCB_Target] =
+                                   pCurHcb->HCS_ActTags[pCurScb->SCB_Target] - 1;
+                               pCurScb->SCB_TaStat = 0;
+                               tul_append_pend_scb(pCurHcb, pCurScb);
+                               continue;
+                       }
+                       if (!(pCurScb->SCB_Mode & SCM_RSENS)) {         /* not in auto req. sense mode */
+                               if (pCurScb->SCB_TaStat == 2) {
+
+                                       /* clr sync. nego flag */
+
+                                       if (pCurScb->SCB_Flags & SCF_SENSE) {
+                                               BYTE len;
+                                               len = pCurScb->SCB_SenseLen;
+                                               if (len == 0)
+                                                       len = 1;
+                                               pCurScb->SCB_BufLen = pCurScb->SCB_SenseLen;
+                                               pCurScb->SCB_BufPtr = pCurScb->SCB_SensePtr;
+                                               pCurScb->SCB_Flags &= ~(SCF_SG | SCF_DIR);      /* for xfer_data_in */
+/*                      pCurScb->SCB_Flags |= SCF_NO_DCHK;      */
+                                               /* so, we won't report worng direction in xfer_data_in,
+                                                  and won't report HOST_DO_DU in state_6 */
+                                               pCurScb->SCB_Mode = SCM_RSENS;
+                                               pCurScb->SCB_Ident &= 0xBF;     /* Disable Disconnect */
+                                               pCurScb->SCB_TagMsg = 0;
+                                               pCurScb->SCB_TaStat = 0;
+                                               pCurScb->SCB_CDBLen = 6;
+                                               pCurScb->SCB_CDB[0] = SCSICMD_RequestSense;
+                                               pCurScb->SCB_CDB[1] = 0;
+                                               pCurScb->SCB_CDB[2] = 0;
+                                               pCurScb->SCB_CDB[3] = 0;
+                                               pCurScb->SCB_CDB[4] = len;
+                                               pCurScb->SCB_CDB[5] = 0;
+                                               tul_push_pend_scb(pCurHcb, pCurScb);
+                                               break;
+                                       }
+                               }
+                       } else {        /* in request sense mode */
+
+                               if (pCurScb->SCB_TaStat == 2) {         /* check contition status again after sending
+                                                                          requset sense cmd 0x3 */
+                                       pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+                               }
+                               pCurScb->SCB_TaStat = 2;
+                       }
+                       pCurScb->SCB_Flags |= SCF_DONE;
+                       if (pCurScb->SCB_Flags & SCF_POST) {
+                               (*pCurScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pCurScb);
+                       }
+               }               /* while */
+
+               /* find_active: */
+               if (TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0) & TSS_INT_PENDING)
+                       continue;
+
+               if (pCurHcb->HCS_ActScb) {      /* return to OS and wait for xfer_done_ISR/Selected_ISR */
+                       return 1;       /* return to OS, enable interrupt */
+               }
+               /* Check pending SCB            */
+               if (tul_find_first_pend_scb(pCurHcb) == NULL) {
+                       return 1;       /* return to OS, enable interrupt */
+               }
+       }                       /* End of for loop */
+       /* statement won't reach here */
+}
+
+
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+/***************************************************************************/
+void tulip_scsi(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       TCS *pCurTcb;
+
+       /* make sure to service interrupt asap */
+
+       if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {
+
+               pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
+               pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+               pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+               if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* SCSI bus reset detected      */
+                       int_tul_scsi_rst(pCurHcb);
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {       /* if selected/reselected interrupt */
+                       if (int_tul_resel(pCurHcb) == 0)
+                               tul_next_state(pCurHcb);
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {
+                       int_tul_busfree(pCurHcb);
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+                       int_tul_busfree(pCurHcb);       /* unexpected bus free or sel timeout */
+                       return;
+               }
+               if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {      /* func complete or Bus service */
+                       if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)
+                               tul_next_state(pCurHcb);
+                       return;
+               }
+       }
+       if (pCurHcb->HCS_ActScb != NULL)
+               return;
+
+       if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)
+               return;
+
+       /* program HBA's SCSI ID & target SCSI ID */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,
+            (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));
+       if (pCurScb->SCB_Opcode == ExecSCSI) {
+               pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+
+               if (pCurScb->SCB_TagMsg)
+                       pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;
+               else
+                       pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
+               if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {        /* do wdtr negotiation          */
+                       tul_select_atn_stop(pCurHcb, pCurScb);
+               } else {
+                       if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {   /* do sync negotiation          */
+                               tul_select_atn_stop(pCurHcb, pCurScb);
+                       } else {
+                               if (pCurScb->SCB_TagMsg)
+                                       tul_select_atn3(pCurHcb, pCurScb);
+                               else
+                                       tul_select_atn(pCurHcb, pCurScb);
+                       }
+               }
+               if (pCurScb->SCB_Flags & SCF_POLL) {
+                       while (wait_tulip(pCurHcb) != -1) {
+                               if (tul_next_state(pCurHcb) == -1)
+                                       break;
+                       }
+               }
+       } else if (pCurScb->SCB_Opcode == BusDevRst) {
+               tul_select_atn_stop(pCurHcb, pCurScb);
+               pCurScb->SCB_NxtStat = 8;
+               if (pCurScb->SCB_Flags & SCF_POLL) {
+                       while (wait_tulip(pCurHcb) != -1) {
+                               if (tul_next_state(pCurHcb) == -1)
+                                       break;
+                       }
+               }
+       } else if (pCurScb->SCB_Opcode == AbortCmd) {
+               if (tul_abort_srb(pCurHcb, pCurScb->SCB_Srb) != 0) {
+
+
+                       tul_unlink_pend_scb(pCurHcb, pCurScb);
+
+                       tul_release_scb(pCurHcb, pCurScb);
+               } else {
+                       pCurScb->SCB_Opcode = BusDevRst;
+                       tul_select_atn_stop(pCurHcb, pCurScb);
+                       pCurScb->SCB_NxtStat = 8;
+               }
+
+/* 08/03/98 */
+       } else {
+               tul_unlink_pend_scb(pCurHcb, pCurScb);
+               pCurScb->SCB_HaStat = 0x16;     /* bad command */
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       return;
+}
+
+
+/***************************************************************************/
+int tul_next_state(HCS * pCurHcb)
+{
+       int next;
+
+       next = pCurHcb->HCS_ActScb->SCB_NxtStat;
+       for (;;) {
+               switch (next) {
+               case 1:
+                       next = tul_state_1(pCurHcb);
+                       break;
+               case 2:
+                       next = tul_state_2(pCurHcb);
+                       break;
+               case 3:
+                       next = tul_state_3(pCurHcb);
+                       break;
+               case 4:
+                       next = tul_state_4(pCurHcb);
+                       break;
+               case 5:
+                       next = tul_state_5(pCurHcb);
+                       break;
+               case 6:
+                       next = tul_state_6(pCurHcb);
+                       break;
+               case 7:
+                       next = tul_state_7(pCurHcb);
+                       break;
+               case 8:
+                       return (tul_bus_device_reset(pCurHcb));
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+               if (next <= 0)
+                       return next;
+       }
+}
+
+
+/***************************************************************************/
+/* sTate after selection with attention & stop */
+int tul_state_1(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+#if DEBUG_STATE
+       printk("-s1-");
+#endif
+
+       tul_unlink_pend_scb(pCurHcb, pCurScb);
+       tul_append_busy_scb(pCurHcb, pCurScb);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+       /* ATN on */
+       if (pCurHcb->HCS_Phase == MSG_OUT) {
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+
+               if (pCurScb->SCB_TagMsg) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+               }
+               if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
+
+                       pCurTcb->TCS_Flags |= TCF_WDTR_DONE;
+
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);       /* Extended msg length */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);       /* Sync request */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);       /* Start from 16 bits */
+               } else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
+
+                       pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);       /* extended msg length */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);       /* sync request */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);      /* REQ/ACK offset */
+               }
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               if (wait_tulip(pCurHcb) == -1)
+                       return (-1);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+       return (3);
+}
+
+
+/***************************************************************************/
+/* state after selection with attention */
+/* state after selection with attention3 */
+int tul_state_2(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+#if DEBUG_STATE
+       printk("-s2-");
+#endif
+
+       tul_unlink_pend_scb(pCurHcb, pCurScb);
+       tul_append_busy_scb(pCurHcb, pCurScb);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+
+       if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {
+               return (4);
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+       return (3);
+}
+
+/***************************************************************************/
+/* state before CDB xfer is done */
+int tul_state_3(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+       int i;
+
+#if DEBUG_STATE
+       printk("-s3-");
+#endif
+       for (;;) {
+               switch (pCurHcb->HCS_Phase) {
+               case CMD_OUT:   /* Command out phase            */
+                       for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       if (wait_tulip(pCurHcb) == -1)
+                               return (-1);
+                       if (pCurHcb->HCS_Phase == CMD_OUT) {
+                               return (tul_bad_seq(pCurHcb));
+                       }
+                       return (4);
+
+               case MSG_IN:    /* Message in phase             */
+                       pCurScb->SCB_NxtStat = 3;
+                       if (tul_msgin(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case STATUS_IN: /* Status phase                 */
+                       if (tul_status_msg(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_OUT:   /* Message out phase            */
+                       if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
+
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);         /* msg nop */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                               if (wait_tulip(pCurHcb) == -1)
+                                       return (-1);
+
+                       } else {
+                               pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);       /* ext. msg len */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);       /* sync request */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);      /* REQ/ACK offset */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                               if (wait_tulip(pCurHcb) == -1)
+                                       return (-1);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));
+
+                       }
+                       break;
+
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+       }
+}
+
+
+/***************************************************************************/
+int tul_state_4(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+#if DEBUG_STATE
+       printk("-s4-");
+#endif
+       if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {
+               return (6);     /* Go to state 6                */
+       }
+       for (;;) {
+               if (pCurScb->SCB_BufLen == 0)
+                       return (6);     /* Go to state 6                */
+
+               switch (pCurHcb->HCS_Phase) {
+
+               case STATUS_IN: /* Status phase                 */
+                       if ((pCurScb->SCB_Flags & SCF_DIR) != 0) {      /* if direction bit set then report data underrun */
+                               pCurScb->SCB_HaStat = HOST_DO_DU;
+                       }
+                       if ((tul_status_msg(pCurHcb)) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_IN:    /* Message in phase             */
+                       pCurScb->SCB_NxtStat = 0x4;
+                       if (tul_msgin(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_OUT:   /* Message out phase            */
+                       if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+                               pCurScb->SCB_BufLen = 0;
+                               pCurScb->SCB_HaStat = HOST_DO_DU;
+                               if (tul_msgout_ide(pCurHcb) == -1)
+                                       return (-1);
+                               return (6);     /* Go to state 6                */
+                       } else {
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);         /* msg nop */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                               if (wait_tulip(pCurHcb) == -1)
+                                       return (-1);
+                       }
+                       break;
+
+               case DATA_IN:   /* Data in phase                */
+                       return (tul_xfer_data_in(pCurHcb));
+
+               case DATA_OUT:  /* Data out phase               */
+                       return (tul_xfer_data_out(pCurHcb));
+
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+       }
+}
+
+
+/***************************************************************************/
+/* state after dma xfer done or phase change before xfer done */
+int tul_state_5(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       long cnt, xcnt;         /* cannot use unsigned !! code: if (xcnt < 0) */
+
+#if DEBUG_STATE
+       printk("-s5-");
+#endif
+/*------ get remaining count -------*/
+
+       cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;
+
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {
+               /* ----------------------- DATA_IN ----------------------------- */
+               /* check scsi parity error */
+               if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+                       pCurScb->SCB_HaStat = HOST_DO_DU;
+               }
+               if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* DMA xfer pending, Send STOP  */
+                       /* tell Hardware  scsi xfer has been terminated */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);
+                       /* wait until DMA xfer not pending */
+                       while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);
+               }
+       } else {
+/*-------- DATA OUT -----------*/
+               if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {
+                       if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)
+                               cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;
+                       else
+                               cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);
+               }
+               if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {   /* if DMA xfer is pending, abort DMA xfer */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);
+                       /* wait Abort DMA xfer done */
+                       while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+               }
+               if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       if (wait_tulip(pCurHcb) == -1) {
+                               return (-1);
+                       }
+                       cnt = 0;
+               } else {
+                       if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+               }
+       }
+
+       if (cnt == 0) {
+               pCurScb->SCB_BufLen = 0;
+               return (6);     /* Go to state 6                */
+       }
+       /* Update active data pointer */
+       xcnt = (long) pCurScb->SCB_BufLen - cnt;        /* xcnt== bytes already xferred */
+       pCurScb->SCB_BufLen = (U32) cnt;        /* cnt == bytes left to be xferred */
+       if (pCurScb->SCB_Flags & SCF_SG) {
+               register SG *sgp;
+               ULONG i;
+
+               sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];
+               for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {
+                       xcnt -= (long) sgp->SG_Len;
+                       if (xcnt < 0) {         /* this sgp xfer half done */
+                               xcnt += (long) sgp->SG_Len;     /* xcnt == bytes xferred in this sgp */
+                               sgp->SG_Ptr += (U32) xcnt;      /* new ptr to be xfer */
+                               sgp->SG_Len -= (U32) xcnt;      /* new len to be xfer */
+                               pCurScb->SCB_BufPtr += ((U32) (i - pCurScb->SCB_SGIdx) << 3);
+                               /* new SG table ptr */
+                               pCurScb->SCB_SGLen = (BYTE) (pCurScb->SCB_SGMax - i);
+                               /* new SG table len */
+                               pCurScb->SCB_SGIdx = (WORD) i;
+                               /* for next disc and come in this loop */
+                               return (4);     /* Go to state 4                */
+                       }
+                       /* else (xcnt >= 0 , i.e. this sgp already xferred */
+               }               /* for */
+               return (6);     /* Go to state 6                */
+       } else {
+               pCurScb->SCB_BufPtr += (U32) xcnt;
+       }
+       return (4);             /* Go to state 4                */
+}
+
+/***************************************************************************/
+/* state after Data phase */
+int tul_state_6(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+#if DEBUG_STATE
+       printk("-s6-");
+#endif
+       for (;;) {
+               switch (pCurHcb->HCS_Phase) {
+               case STATUS_IN: /* Status phase                 */
+                       if ((tul_status_msg(pCurHcb)) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_IN:    /* Message in phase             */
+                       pCurScb->SCB_NxtStat = 6;
+                       if ((tul_msgin(pCurHcb)) == -1)
+                               return (-1);
+                       break;
+
+               case MSG_OUT:   /* Message out phase            */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);         /* msg nop */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       if (wait_tulip(pCurHcb) == -1)
+                               return (-1);
+                       break;
+
+               case DATA_IN:   /* Data in phase                */
+                       return (tul_xpad_in(pCurHcb));
+
+               case DATA_OUT:  /* Data out phase               */
+                       return (tul_xpad_out(pCurHcb));
+
+               default:
+                       return (tul_bad_seq(pCurHcb));
+               }
+       }
+}
+
+/***************************************************************************/
+int tul_state_7(HCS * pCurHcb)
+{
+       int cnt, i;
+
+#if DEBUG_STATE
+       printk("-s7-");
+#endif
+       /* flush SCSI FIFO */
+       cnt = TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F;
+       if (cnt) {
+               for (i = 0; i < cnt; i++)
+                       TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       }
+       switch (pCurHcb->HCS_Phase) {
+       case DATA_IN:           /* Data in phase                */
+       case DATA_OUT:          /* Data out phase               */
+               return (tul_bad_seq(pCurHcb));
+       default:
+               return (6);     /* Go to state 6                */
+       }
+}
+
+/***************************************************************************/
+int tul_xfer_data_in(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DOUT) {
+               return (6);     /* wrong direction */
+       }
+       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_IN);    /* 7/25/95 */
+
+       if (pCurScb->SCB_Flags & SCF_SG) {      /* S/G xfer */
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_IN);
+       } else {
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_IN);
+       }
+       pCurScb->SCB_NxtStat = 0x5;
+       return (0);             /* return to OS, wait xfer done , let jas_isr come in */
+}
+
+
+/***************************************************************************/
+int tul_xfer_data_out(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DIN) {
+               return (6);     /* wrong direction */
+       }
+       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_OUT);
+
+       if (pCurScb->SCB_Flags & SCF_SG) {      /* S/G xfer */
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_OUT);
+       } else {
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_OUT);
+       }
+
+       pCurScb->SCB_NxtStat = 0x5;
+       return (0);             /* return to OS, wait xfer done , let jas_isr come in */
+}
+
+
+/***************************************************************************/
+int tul_xpad_in(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
+               pCurScb->SCB_HaStat = HOST_DO_DU;       /* over run             */
+       }
+       for (;;) {
+               if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+               else
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1) {
+                       return (-1);
+               }
+               if (pCurHcb->HCS_Phase != DATA_IN) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                       return (6);
+               }
+               TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       }
+}
+
+int tul_xpad_out(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+
+       if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
+               pCurScb->SCB_HaStat = HOST_DO_DU;       /* over run             */
+       }
+       for (;;) {
+               if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+               else
+                       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               if ((wait_tulip(pCurHcb)) == -1) {
+                       return (-1);
+               }
+               if (pCurHcb->HCS_Phase != DATA_OUT) {   /* Disable wide CPU to allow read 16 bits */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                       return (6);
+               }
+       }
+}
+
+
+/***************************************************************************/
+int tul_status_msg(HCS * pCurHcb)
+{                              /* status & MSG_IN */
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       BYTE msg;
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_CMD_COMP);
+       if ((wait_tulip(pCurHcb)) == -1) {
+               return (-1);
+       }
+       /* get status */
+       pCurScb->SCB_TaStat = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+
+       if (pCurHcb->HCS_Phase == MSG_OUT) {
+               if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
+               } else {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);
+               }
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               return (wait_tulip(pCurHcb));
+       }
+       if (pCurHcb->HCS_Phase == MSG_IN) {
+               msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+               if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {   /* Parity error                 */
+                       if ((tul_msgin_accept(pCurHcb)) == -1)
+                               return (-1);
+                       if (pCurHcb->HCS_Phase != MSG_OUT)
+                               return (tul_bad_seq(pCurHcb));
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+                       return (wait_tulip(pCurHcb));
+               }
+               if (msg == 0) { /* Command complete             */
+
+                       if ((pCurScb->SCB_TaStat & 0x18) == 0x10) {     /* No link support              */
+                               return (tul_bad_seq(pCurHcb));
+                       }
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+                       return tul_wait_done_disc(pCurHcb);
+
+               }
+               if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) {
+                       if ((pCurScb->SCB_TaStat & 0x18) == 0x10)
+                               return (tul_msgin_accept(pCurHcb));
+               }
+       }
+       return (tul_bad_seq(pCurHcb));
+}
+
+
+/***************************************************************************/
+/* scsi bus free */
+int int_tul_busfree(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+       if (pCurScb != NULL) {
+               if (pCurScb->SCB_Status & SCB_SELECT) {         /* selection timeout */
+                       tul_unlink_pend_scb(pCurHcb, pCurScb);
+                       pCurScb->SCB_HaStat = HOST_SEL_TOUT;
+                       tul_append_done_scb(pCurHcb, pCurScb);
+               } else {        /* Unexpected bus free          */
+                       tul_unlink_busy_scb(pCurHcb, pCurScb);
+                       pCurScb->SCB_HaStat = HOST_BUS_FREE;
+                       tul_append_done_scb(pCurHcb, pCurScb);
+               }
+               pCurHcb->HCS_ActScb = NULL;
+               pCurHcb->HCS_ActTcs = NULL;
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+       return (-1);
+}
+
+
+/***************************************************************************/
+/* scsi bus reset */
+int int_tul_scsi_rst(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       int i;
+
+       /* if DMA xfer is pending, abort DMA xfer */
+       if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & 0x01) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+               /* wait Abort DMA xfer done */
+               while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & 0x04) == 0);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+       }
+       /* Abort all active & disconnected scb */
+       while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       pCurHcb->HCS_ActScb = NULL;
+       pCurHcb->HCS_ActTcs = NULL;
+
+       /* clr sync nego. done flag */
+       for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+       }
+       return (-1);
+}
+
+
+/***************************************************************************/
+/* scsi reselection */
+int int_tul_resel(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       TCS *pCurTcb;
+       BYTE tag, msg = 0;
+       BYTE tar, lun;
+
+       if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
+               if (pCurScb->SCB_Status & SCB_SELECT) {         /* if waiting for selection complete */
+                       pCurScb->SCB_Status &= ~SCB_SELECT;
+               }
+               pCurHcb->HCS_ActScb = NULL;
+       }
+       /* --------- get target id---------------------- */
+       tar = TUL_RD(pCurHcb->HCS_Base, TUL_SBusId);
+       /* ------ get LUN from Identify message----------- */
+       lun = TUL_RD(pCurHcb->HCS_Base, TUL_SIdent) & 0x0F;
+       /* 07/22/98 from 0x1F -> 0x0F */
+       pCurTcb = &pCurHcb->HCS_Tcs[tar];
+       pCurHcb->HCS_ActTcs = pCurTcb;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
+
+
+       /* ------------- tag queueing ? ------------------- */
+       if (pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG) {
+               if ((tul_msgin_accept(pCurHcb)) == -1)
+                       return (-1);
+               if (pCurHcb->HCS_Phase != MSG_IN)
+                       goto no_tag;
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1)
+                       return (-1);
+               msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);     /* Read Tag Message    */
+
+               if ((msg < MSG_STAG) || (msg > MSG_OTAG))       /* Is simple Tag      */
+                       goto no_tag;
+
+               if ((tul_msgin_accept(pCurHcb)) == -1)
+                       return (-1);
+
+               if (pCurHcb->HCS_Phase != MSG_IN)
+                       goto no_tag;
+
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1)
+                       return (-1);
+               tag = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);     /* Read Tag ID       */
+               pCurScb = pCurHcb->HCS_Scb + tag;
+               if ((pCurScb->SCB_Target != tar) || (pCurScb->SCB_Lun != lun)) {
+                       return tul_msgout_abort_tag(pCurHcb);
+               }
+               if (pCurScb->SCB_Status != SCB_BUSY) {  /* 03/24/95             */
+                       return tul_msgout_abort_tag(pCurHcb);
+               }
+               pCurHcb->HCS_ActScb = pCurScb;
+               if ((tul_msgin_accept(pCurHcb)) == -1)
+                       return (-1);
+       } else {                /* No tag               */
+             no_tag:
+               if ((pCurScb = tul_find_busy_scb(pCurHcb, tar | (lun << 8))) == NULL) {
+                       return tul_msgout_abort_targ(pCurHcb);
+               }
+               pCurHcb->HCS_ActScb = pCurScb;
+               if (!(pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG)) {
+                       if ((tul_msgin_accept(pCurHcb)) == -1)
+                               return (-1);
+               }
+       }
+       return 0;
+}
+
+
+/***************************************************************************/
+int int_tul_bad_seq(HCS * pCurHcb)
+{                              /* target wrong phase           */
+       SCB *pCurScb;
+       int i;
+
+       tul_reset_scsi(pCurHcb, 10);
+
+       while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+       }
+       return (-1);
+}
+
+
+/***************************************************************************/
+int tul_msgout_abort_targ(HCS * pCurHcb)
+{
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+       if (tul_msgin_accept(pCurHcb) == -1)
+               return (-1);
+       if (pCurHcb->HCS_Phase != MSG_OUT)
+               return (tul_bad_seq(pCurHcb));
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+       return tul_wait_disc(pCurHcb);
+}
+
+/***************************************************************************/
+int tul_msgout_abort_tag(HCS * pCurHcb)
+{
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+       if (tul_msgin_accept(pCurHcb) == -1)
+               return (-1);
+       if (pCurHcb->HCS_Phase != MSG_OUT)
+               return (tul_bad_seq(pCurHcb));
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT_TAG);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+       return tul_wait_disc(pCurHcb);
+
+}
+
+/***************************************************************************/
+int tul_msgin(HCS * pCurHcb)
+{
+       TCS *pCurTcb;
+
+       for (;;) {
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if ((wait_tulip(pCurHcb)) == -1)
+                       return (-1);
+
+               switch (TUL_RD(pCurHcb->HCS_Base, TUL_SFifo)) {
+               case MSG_DISC:  /* Disconnect msg */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+
+                       return tul_wait_disc(pCurHcb);
+
+               case MSG_SDP:
+               case MSG_RESTORE:
+               case MSG_NOP:
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+               case MSG_REJ:   /* Clear ATN first              */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal,
+                              (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+                       pCurTcb = pCurHcb->HCS_ActTcs;
+                       if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {   /* do sync nego */
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+                       }
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+               case MSG_EXTEND:        /* extended msg */
+                       tul_msgin_extend(pCurHcb);
+                       break;
+
+               case MSG_IGNOREWIDE:
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+                       /* get */
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+                       if (wait_tulip(pCurHcb) == -1)
+                               return -1;
+
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);       /* put pad  */
+                       TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);   /* get IGNORE field */
+                       TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);   /* get pad */
+
+                       tul_msgin_accept(pCurHcb);
+                       break;
+
+               case MSG_COMP:
+                       {
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+                               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+                               return tul_wait_done_disc(pCurHcb);
+                       }
+               default:
+                       tul_msgout_reject(pCurHcb);
+                       break;
+               }
+               if (pCurHcb->HCS_Phase != MSG_IN)
+                       return (pCurHcb->HCS_Phase);
+       }
+       /* statement won't reach here */
+}
+
+
+
+
+/***************************************************************************/
+int tul_msgout_reject(HCS * pCurHcb)
+{
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+
+       if ((tul_msgin_accept(pCurHcb)) == -1)
+               return (-1);
+
+       if (pCurHcb->HCS_Phase == MSG_OUT) {
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_REJ);         /* Msg reject           */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               return (wait_tulip(pCurHcb));
+       }
+       return (pCurHcb->HCS_Phase);
+}
+
+
+
+/***************************************************************************/
+int tul_msgout_ide(HCS * pCurHcb)
+{
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_IDE);         /* Initiator Detected Error */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+       return (wait_tulip(pCurHcb));
+}
+
+
+/***************************************************************************/
+int tul_msgin_extend(HCS * pCurHcb)
+{
+       BYTE len, idx;
+
+       if (tul_msgin_accept(pCurHcb) != MSG_IN)
+               return (pCurHcb->HCS_Phase);
+
+       /* Get extended msg length      */
+       TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+       if (wait_tulip(pCurHcb) == -1)
+               return (-1);
+
+       len = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       pCurHcb->HCS_Msg[0] = len;
+       for (idx = 1; len != 0; len--) {
+
+               if ((tul_msgin_accept(pCurHcb)) != MSG_IN)
+                       return (pCurHcb->HCS_Phase);
+               TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+               if (wait_tulip(pCurHcb) == -1)
+                       return (-1);
+               pCurHcb->HCS_Msg[idx++] = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+       }
+       if (pCurHcb->HCS_Msg[1] == 1) {         /* if it's synchronous data transfer request */
+               if (pCurHcb->HCS_Msg[0] != 3)   /* if length is not right */
+                       return (tul_msgout_reject(pCurHcb));
+               if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) {        /* Set OFFSET=0 to do async, nego back */
+                       pCurHcb->HCS_Msg[3] = 0;
+               } else {
+                       if ((tul_msgin_sync(pCurHcb) == 0) &&
+                           (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) {
+                               tul_sync_done(pCurHcb);
+                               return (tul_msgin_accept(pCurHcb));
+                       }
+               }
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+               if ((tul_msgin_accept(pCurHcb)) != MSG_OUT)
+                       return (pCurHcb->HCS_Phase);
+               /* sync msg out */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+
+               tul_sync_done(pCurHcb);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[3]);
+
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+               return (wait_tulip(pCurHcb));
+       }
+       if ((pCurHcb->HCS_Msg[0] != 2) || (pCurHcb->HCS_Msg[1] != 3))
+               return (tul_msgout_reject(pCurHcb));
+       /* if it's WIDE DATA XFER REQ   */
+       if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) {
+               pCurHcb->HCS_Msg[2] = 0;
+       } else {
+               if (pCurHcb->HCS_Msg[2] > 2)    /* > 32 bits            */
+                       return (tul_msgout_reject(pCurHcb));
+               if (pCurHcb->HCS_Msg[2] == 2) {         /* == 32                */
+                       pCurHcb->HCS_Msg[2] = 1;
+               } else {
+                       if ((pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) {
+                               wdtr_done(pCurHcb);
+                               if ((pCurHcb->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
+                                       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+                               return (tul_msgin_accept(pCurHcb));
+                       }
+               }
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+
+       if (tul_msgin_accept(pCurHcb) != MSG_OUT)
+               return (pCurHcb->HCS_Phase);
+       /* WDTR msg out                 */
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+       return (wait_tulip(pCurHcb));
+}
+
+/***************************************************************************/
+int tul_msgin_sync(HCS * pCurHcb)
+{
+       char default_period;
+
+       default_period = tul_rate_tbl[pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE];
+       if (pCurHcb->HCS_Msg[3] > MAX_OFFSET) {
+               pCurHcb->HCS_Msg[3] = MAX_OFFSET;
+               if (pCurHcb->HCS_Msg[2] < default_period) {
+                       pCurHcb->HCS_Msg[2] = default_period;
+                       return 1;
+               }
+               if (pCurHcb->HCS_Msg[2] >= 59) {        /* Change to async              */
+                       pCurHcb->HCS_Msg[3] = 0;
+               }
+               return 1;
+       }
+       /* offset requests asynchronous transfers ? */
+       if (pCurHcb->HCS_Msg[3] == 0) {
+               return 0;
+       }
+       if (pCurHcb->HCS_Msg[2] < default_period) {
+               pCurHcb->HCS_Msg[2] = default_period;
+               return 1;
+       }
+       if (pCurHcb->HCS_Msg[2] >= 59) {
+               pCurHcb->HCS_Msg[3] = 0;
+               return 1;
+       }
+       return 0;
+}
+
+
+/***************************************************************************/
+int wdtr_done(HCS * pCurHcb)
+{
+       pCurHcb->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE;
+       pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE;
+
+       pCurHcb->HCS_ActTcs->TCS_JS_Period = 0;
+       if (pCurHcb->HCS_Msg[2]) {      /* if 16 bit */
+               pCurHcb->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI;
+       }
+       pCurHcb->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+
+       return 1;
+}
+
+/***************************************************************************/
+int tul_sync_done(HCS * pCurHcb)
+{
+       int i;
+
+       pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE;
+
+       if (pCurHcb->HCS_Msg[3]) {
+               pCurHcb->HCS_ActTcs->TCS_JS_Period |= pCurHcb->HCS_Msg[3];
+               for (i = 0; i < 8; i++) {
+                       if (tul_rate_tbl[i] >= pCurHcb->HCS_Msg[2])     /* pick the big one */
+                               break;
+               }
+               pCurHcb->HCS_ActTcs->TCS_JS_Period |= (i << 4);
+               pCurHcb->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD;
+       }
+       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+
+       return (-1);
+}
+
+
+int tul_post_scsi_rst(HCS * pCurHcb)
+{
+       SCB *pCurScb;
+       TCS *pCurTcb;
+       int i;
+
+       pCurHcb->HCS_ActScb = NULL;
+       pCurHcb->HCS_ActTcs = NULL;
+       pCurHcb->HCS_Flags = 0;
+
+       while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+               pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+               tul_append_done_scb(pCurHcb, pCurScb);
+       }
+       /* clear sync done flag         */
+       pCurTcb = &pCurHcb->HCS_Tcs[0];
+       for (i = 0; i < pCurHcb->HCS_MaxTar; pCurTcb++, i++) {
+               pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+               /* Initialize the sync. xfer register values to an asyn xfer */
+               pCurTcb->TCS_JS_Period = 0;
+               pCurTcb->TCS_SConfig0 = pCurHcb->HCS_SConf1;
+               pCurHcb->HCS_ActTags[0] = 0;    /* 07/22/98 */
+               pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;     /* 07/22/98 */
+       }                       /* for */
+
+       return (-1);
+}
+
+/***************************************************************************/
+void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb)
+{
+       pCurScb->SCB_Status |= SCB_SELECT;
+       pCurScb->SCB_NxtStat = 0x1;
+       pCurHcb->HCS_ActScb = pCurScb;
+       pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SELATNSTOP);
+       return;
+}
+
+
+/***************************************************************************/
+void tul_select_atn(HCS * pCurHcb, SCB * pCurScb)
+{
+       int i;
+
+       pCurScb->SCB_Status |= SCB_SELECT;
+       pCurScb->SCB_NxtStat = 0x2;
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+       for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+       pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+       pCurHcb->HCS_ActScb = pCurScb;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN);
+       return;
+}
+
+/***************************************************************************/
+void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb)
+{
+       int i;
+
+       pCurScb->SCB_Status |= SCB_SELECT;
+       pCurScb->SCB_NxtStat = 0x2;
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+       for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+               TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+       pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+       pCurHcb->HCS_ActScb = pCurScb;
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN3);
+       return;
+}
+
+/***************************************************************************/
+/* SCSI Bus Device Reset */
+int tul_bus_device_reset(HCS * pCurHcb)
+{
+       SCB *pCurScb = pCurHcb->HCS_ActScb;
+       TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+       SCB *pTmpScb, *pPrevScb;
+       BYTE tar;
+
+       if (pCurHcb->HCS_Phase != MSG_OUT) {
+               return (int_tul_bad_seq(pCurHcb));      /* Unexpected phase             */
+       }
+       tul_unlink_pend_scb(pCurHcb, pCurScb);
+       tul_release_scb(pCurHcb, pCurScb);
+
+
+       tar = pCurScb->SCB_Target;      /* target                       */
+       pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
+       /* clr sync. nego & WDTR flags  07/22/98 */
+
+       /* abort all SCB with same target */
+       pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;    /* Check Busy queue */
+       while (pTmpScb != NULL) {
+
+               if (pTmpScb->SCB_Target == tar) {
+                       /* unlink it */
+                       if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+                               if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+                                       pCurHcb->HCS_LastBusy = NULL;
+                       } else {
+                               pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+                               if (pTmpScb == pCurHcb->HCS_LastBusy)
+                                       pCurHcb->HCS_LastBusy = pPrevScb;
+                       }
+                       pTmpScb->SCB_HaStat = HOST_ABORTED;
+                       tul_append_done_scb(pCurHcb, pTmpScb);
+               }
+               /* Previous haven't change      */
+               else {
+                       pPrevScb = pTmpScb;
+               }
+               pTmpScb = pTmpScb->SCB_NxtScb;
+       }
+
+       TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_DEVRST);
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+       return tul_wait_disc(pCurHcb);
+
+}
+
+/***************************************************************************/
+int tul_msgin_accept(HCS * pCurHcb)
+{
+       TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+       return (wait_tulip(pCurHcb));
+}
+
+/***************************************************************************/
+int wait_tulip(HCS * pCurHcb)
+{
+
+       while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+                & TSS_INT_PENDING));
+
+       pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+       pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
+       pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+
+       if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {       /* if SCSI bus reset detected   */
+               return (int_tul_resel(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {     /* if selected/reselected timeout interrupt */
+               return (int_tul_busfree(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* if SCSI bus reset detected   */
+               return (int_tul_scsi_rst(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+               if (pCurHcb->HCS_Flags & HCF_EXPECT_DONE_DISC) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+                       tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+                       pCurHcb->HCS_ActScb->SCB_HaStat = 0;
+                       tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
+                       pCurHcb->HCS_ActScb = NULL;
+                       pCurHcb->HCS_ActTcs = NULL;
+                       pCurHcb->HCS_Flags &= ~HCF_EXPECT_DONE_DISC;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+                       return (-1);
+               }
+               if (pCurHcb->HCS_Flags & HCF_EXPECT_DISC) {
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+                       pCurHcb->HCS_ActScb = NULL;
+                       pCurHcb->HCS_ActTcs = NULL;
+                       pCurHcb->HCS_Flags &= ~HCF_EXPECT_DISC;
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+                       TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+                       return (-1);
+               }
+               return (int_tul_busfree(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {
+               return (pCurHcb->HCS_Phase);
+       }
+       return (pCurHcb->HCS_Phase);
+}
+/***************************************************************************/
+int tul_wait_disc(HCS * pCurHcb)
+{
+
+       while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+                & TSS_INT_PENDING));
+
+
+       pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+       if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* if SCSI bus reset detected   */
+               return (int_tul_scsi_rst(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+               pCurHcb->HCS_ActScb = NULL;
+               return (-1);
+       }
+       return (tul_bad_seq(pCurHcb));
+}
+
+/***************************************************************************/
+int tul_wait_done_disc(HCS * pCurHcb)
+{
+
+
+       while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+                & TSS_INT_PENDING));
+
+       pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+
+       if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {     /* if SCSI bus reset detected   */
+               return (int_tul_scsi_rst(pCurHcb));
+       }
+       if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {        /* BUS disconnection            */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);         /* Flush SCSI FIFO  */
+               TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+               TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);        /* Enable HW reselect       */
+               tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+
+               tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
+               pCurHcb->HCS_ActScb = NULL;
+               return (-1);
+       }
+       return (tul_bad_seq(pCurHcb));
+}
+
+static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs)
+{
+       struct Scsi_Host *dev = dev_id;
+       unsigned long flags;
+       
+       spin_lock_irqsave(dev->host_lock, flags);
+       tul_isr((HCS *)dev->base);
+       spin_unlock_irqrestore(dev->host_lock, flags);
+       return IRQ_HANDLED;
+}
+
+static int tul_NewReturnNumberOfAdapters(void)
+{
+       struct pci_dev *pDev = NULL;    /* Start from none              */
+       int iAdapters = 0;
+       long dRegValue;
+       WORD wBIOS;
+       int i = 0;
+
+       init_i91uAdapter_table();
+
+       for (i = 0; i < TULSZ(i91u_pci_devices); i++)
+       {
+               while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
+                       if (pci_enable_device(pDev))
+                               continue;
+                       pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+                       wBIOS = (UWORD) (dRegValue & 0xFF);
+                       if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+                               dRegValue = 0;
+                       wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+                       if (pci_set_dma_mask(pDev, 0xffffffff)) {
+                               printk(KERN_WARNING 
+                                      "i91u: Could not set 32 bit DMA mask\n");
+                               continue;
+                       }
+
+                       if (Addi91u_into_Adapter_table(wBIOS,
+                                                       (pDev->resource[0].start),
+                                                       pDev->irq,
+                                                       pDev->bus->number,
+                                                       (pDev->devfn >> 3)
+                               ) == 0)
+                               iAdapters++;
+               }
+       }
+
+       return (iAdapters);
+}
+
+static int i91u_detect(struct scsi_host_template * tpnt)
+{
+       HCS *pHCB;
+       struct Scsi_Host *hreg;
+       unsigned long i;        /* 01/14/98                     */
+       int ok = 0, iAdapters;
+       ULONG dBiosAdr;
+       BYTE *pbBiosAdr;
+
+       /* Get total number of adapters in the motherboard */
+       iAdapters = tul_NewReturnNumberOfAdapters();
+       if (iAdapters == 0)     /* If no tulip founded, return */
+               return (0);
+
+       tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
+       /* Update actually channel number */
+       if (tul_tag_enable) {   /* 1.01i                  */
+               tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
+       } else {
+               tul_num_scb = MAX_TARGETS + 3;  /* 1-tape, 1-CD_ROM, 1- extra */
+       }                       /* Update actually SCBs per adapter */
+
+       /* Get total memory needed for HCS */
+       i = tul_num_ch * sizeof(HCS);
+       memset((unsigned char *) &tul_hcs[0], 0, i);    /* Initialize tul_hcs 0 */
+       /* Get total memory needed for SCB */
+
+       for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
+               i = tul_num_ch * tul_num_scb * sizeof(SCB);
+               if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
+                       break;
+       }
+       if (tul_scb == NULL) {
+               printk("i91u: SCB memory allocation error\n");
+               return (0);
+       }
+       memset((unsigned char *) tul_scb, 0, i);
+
+       for (i = 0, pHCB = &tul_hcs[0];         /* Get pointer for control block */
+            i < tul_num_ch;
+            i++, pHCB++) {
+               get_tulipPCIConfig(pHCB, i);
+
+               dBiosAdr = pHCB->HCS_BIOS;
+               dBiosAdr = (dBiosAdr << 4);
+
+               pbBiosAdr = phys_to_virt(dBiosAdr);
+
+               init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
+               request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */ 
+
+               pHCB->HCS_Index = i;    /* 7/29/98 */
+               hreg = scsi_register(tpnt, sizeof(HCS));
+               if(hreg == NULL) {
+                       release_region(pHCB->HCS_Base, 256);
+                       return 0;
+               }
+               hreg->io_port = pHCB->HCS_Base;
+               hreg->n_io_port = 0xff;
+               hreg->can_queue = tul_num_scb;  /* 03/05/98                      */
+               hreg->unique_id = pHCB->HCS_Base;
+               hreg->max_id = pHCB->HCS_MaxTar;
+               hreg->max_lun = 32;     /* 10/21/97                     */
+               hreg->irq = pHCB->HCS_Intr;
+               hreg->this_id = pHCB->HCS_SCSI_ID;      /* Assign HCS index           */
+               hreg->base = (unsigned long)pHCB;
+               hreg->sg_tablesize = TOTAL_SG_ENTRY;    /* Maximun support is 32 */
+
+               /* Initial tulip chip           */
+               ok = request_irq(pHCB->HCS_Intr, i91u_intr, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
+               if (ok < 0) {
+                       printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
+                       return 0;
+               }
+       }
+
+       tpnt->this_id = -1;
+       tpnt->can_queue = 1;
+
+       return 1;
+}
+
+static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, struct scsi_cmnd * SCpnt)
+{                              /* Create corresponding SCB     */
+       struct scatterlist *pSrbSG;
+       SG *pSG;                /* Pointer to SG list           */
+       int i;
+       long TotalLen;
+       dma_addr_t dma_addr;
+
+       pSCB->SCB_Post = i91uSCBPost;   /* i91u's callback routine      */
+       pSCB->SCB_Srb = SCpnt;
+       pSCB->SCB_Opcode = ExecSCSI;
+       pSCB->SCB_Flags = SCF_POST;     /* After SCSI done, call post routine */
+       pSCB->SCB_Target = SCpnt->device->id;
+       pSCB->SCB_Lun = SCpnt->device->lun;
+       pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
+
+       pSCB->SCB_Flags |= SCF_SENSE;   /* Turn on auto request sense   */
+       dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->sense_buffer,
+                                 SENSE_SIZE, DMA_FROM_DEVICE);
+       pSCB->SCB_SensePtr = cpu_to_le32((u32)dma_addr);
+       pSCB->SCB_SenseLen = cpu_to_le32(SENSE_SIZE);
+       SCpnt->SCp.ptr = (char *)(unsigned long)dma_addr;
+
+       pSCB->SCB_CDBLen = SCpnt->cmd_len;
+       pSCB->SCB_HaStat = 0;
+       pSCB->SCB_TaStat = 0;
+       memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
+
+       if (SCpnt->device->tagged_supported) {  /* Tag Support                  */
+               pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;    /* Do simple tag only   */
+       } else {
+               pSCB->SCB_TagMsg = 0;   /* No tag support               */
+       }
+       /* todo handle map_sg error */
+       if (SCpnt->use_sg) {
+               dma_addr = dma_map_single(&pHCB->pci_dev->dev, &pSCB->SCB_SGList[0],
+                                         sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+                                         DMA_BIDIRECTIONAL);
+               pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
+               SCpnt->SCp.dma_handle = dma_addr;
+
+               pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
+               pSCB->SCB_SGLen = dma_map_sg(&pHCB->pci_dev->dev, pSrbSG,
+                                            SCpnt->use_sg, SCpnt->sc_data_direction);
+
+               pSCB->SCB_Flags |= SCF_SG;      /* Turn on SG list flag       */
+               for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0];   /* 1.01g */
+                    i < pSCB->SCB_SGLen; i++, pSG++, pSrbSG++) {
+                       pSG->SG_Ptr = cpu_to_le32((u32)sg_dma_address(pSrbSG));
+                       TotalLen += pSG->SG_Len = cpu_to_le32((u32)sg_dma_len(pSrbSG));
+               }
+
+               pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
+                   TotalLen : SCpnt->request_bufflen;
+       } else if (SCpnt->request_bufflen) {            /* Non SG */
+               dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->request_buffer,
+                                         SCpnt->request_bufflen,
+                                         SCpnt->sc_data_direction);
+               SCpnt->SCp.dma_handle = dma_addr;
+               pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
+               pSCB->SCB_BufLen = cpu_to_le32((u32)SCpnt->request_bufflen);
+               pSCB->SCB_SGLen = 0;
+       } else {
+               pSCB->SCB_BufLen = 0;
+               pSCB->SCB_SGLen = 0;
+       }
+}
+
+static int i91u_queuecommand(struct scsi_cmnd *cmd,
+               void (*done)(struct scsi_cmnd *))
+{
+       HCS *pHCB = (HCS *) cmd->device->host->base;
+       register SCB *pSCB;
+
+       cmd->scsi_done = done;
+
+       pSCB = tul_alloc_scb(pHCB);
+       if (!pSCB)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       i91uBuildSCB(pHCB, pSCB, cmd);
+       tul_exec_scb(pHCB, pSCB);
+       return 0;
+}
+
+#if 0 /* no new EH yet */
+/*
+ *  Abort a queued command
+ *  (commands that are on the bus can't be aborted easily)
+ */
+static int i91u_abort(struct scsi_cmnd * SCpnt)
+{
+       HCS *pHCB;
+
+       pHCB = (HCS *) SCpnt->device->host->base;
+       return tul_abort_srb(pHCB, SCpnt);
+}
+
+/*
+ *  Reset registers, reset a hanging bus and
+ *  kill active and disconnected commands for target w/o soft reset
+ */
+static int i91u_reset(struct scsi_cmnd * SCpnt, unsigned int reset_flags)
+{                              /* I need Host Control Block Information */
+       HCS *pHCB;
+
+       pHCB = (HCS *) SCpnt->device->host->base;
+
+       if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
+               return tul_reset_scsi_bus(pHCB);
+       else
+               return tul_device_reset(pHCB, SCpnt, SCpnt->device->id, reset_flags);
+}
+#endif
+
+static int i91u_bus_reset(struct scsi_cmnd * SCpnt)
+{
+       HCS *pHCB;
+
+       pHCB = (HCS *) SCpnt->device->host->base;
+       tul_reset_scsi(pHCB, 0);
+       return SUCCESS;
+}
+
+/*
+ * Return the "logical geometry"
+ */
+static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
+               sector_t capacity, int *info_array)
+{
+       HCS *pHcb;              /* Point to Host adapter control block */
+       TCS *pTcb;
+
+       pHcb = (HCS *) sdev->host->base;
+       pTcb = &pHcb->HCS_Tcs[sdev->id];
+
+       if (pTcb->TCS_DrvHead) {
+               info_array[0] = pTcb->TCS_DrvHead;
+               info_array[1] = pTcb->TCS_DrvSector;
+               info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+       } else {
+               if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+                       info_array[0] = 255;
+                       info_array[1] = 63;
+                       info_array[2] = (unsigned long)capacity / 255 / 63;
+               } else {
+                       info_array[0] = 64;
+                       info_array[1] = 32;
+                       info_array[2] = (unsigned long)capacity >> 11;
+               }
+       }
+
+#if defined(DEBUG_BIOSPARAM)
+       if (i91u_debug & debug_biosparam) {
+               printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+                      info_array[0], info_array[1], info_array[2]);
+               printk("WARNING: check, if the bios geometry is correct.\n");
+       }
+#endif
+
+       return 0;
+}
+
+static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
+{
+       /* auto sense buffer */
+       if (cmnd->SCp.ptr) {
+               dma_unmap_single(&pci_dev->dev,
+                                (dma_addr_t)((unsigned long)cmnd->SCp.ptr),
+                                SENSE_SIZE, DMA_FROM_DEVICE);
+               cmnd->SCp.ptr = NULL;
+       }
+
+       /* request buffer */
+       if (cmnd->use_sg) {
+               dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
+                                sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+                                DMA_BIDIRECTIONAL);
+
+               dma_unmap_sg(&pci_dev->dev, cmnd->request_buffer,
+                            cmnd->use_sg,
+                            cmnd->sc_data_direction);
+       } else if (cmnd->request_bufflen) {
+               dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
+                                cmnd->request_bufflen,
+                                cmnd->sc_data_direction);
+       }
+}
+
+/*****************************************************************************
+ Function name  : i91uSCBPost
+ Description    : This is callback routine be called when tulip finish one
+                       SCSI command.
+ Input          : pHCB  -       Pointer to host adapter control block.
+                 pSCB  -       Pointer to SCSI control block.
+ Output         : None.
+ Return         : None.
+*****************************************************************************/
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
+{
+       struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
+       HCS *pHCB;
+       SCB *pSCB;
+
+       pHCB = (HCS *) pHcb;
+       pSCB = (SCB *) pScb;
+       if ((pSRB = pSCB->SCB_Srb) == 0) {
+               printk("i91uSCBPost: SRB pointer is empty\n");
+
+               tul_release_scb(pHCB, pSCB);    /* Release SCB for current channel */
+               return;
+       }
+       switch (pSCB->SCB_HaStat) {
+       case 0x0:
+       case 0xa:               /* Linked command complete without error and linked normally */
+       case 0xb:               /* Linked command complete without error interrupt generated */
+               pSCB->SCB_HaStat = 0;
+               break;
+
+       case 0x11:              /* Selection time out-The initiator selection or target
+                                  reselection was not complete within the SCSI Time out period */
+               pSCB->SCB_HaStat = DID_TIME_OUT;
+               break;
+
+       case 0x14:              /* Target bus phase sequence failure-An invalid bus phase or bus
+                                  phase sequence was requested by the target. The host adapter
+                                  will generate a SCSI Reset Condition, notifying the host with
+                                  a SCRD interrupt */
+               pSCB->SCB_HaStat = DID_RESET;
+               break;
+
+       case 0x1a:              /* SCB Aborted. 07/21/98 */
+               pSCB->SCB_HaStat = DID_ABORT;
+               break;
+
+       case 0x12:              /* Data overrun/underrun-The target attempted to transfer more data
+                                  than was allocated by the Data Length field or the sum of the
+                                  Scatter / Gather Data Length fields. */
+       case 0x13:              /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+       case 0x16:              /* Invalid SCB Operation Code. */
+
+       default:
+               printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
+               pSCB->SCB_HaStat = DID_ERROR;   /* Couldn't find any better */
+               break;
+       }
+
+       pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+
+       if (pSRB == NULL) {
+               printk("pSRB is NULL\n");
+       }
+
+       i91u_unmap_cmnd(pHCB->pci_dev, pSRB);
+       pSRB->scsi_done(pSRB);  /* Notify system DONE           */
+
+       tul_release_scb(pHCB, pSCB);    /* Release SCB for current channel */
+}
+
+/*
+ * Release ressources
+ */
+static int i91u_release(struct Scsi_Host *hreg)
+{
+       free_irq(hreg->irq, hreg);
+       release_region(hreg->io_port, 256);
+       return 0;
+}
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct scsi_host_template driver_template = {
+       .proc_name      = "INI9100U",
+       .name           = i91u_REVID,
+       .detect         = i91u_detect,
+       .release        = i91u_release,
+       .queuecommand   = i91u_queuecommand,
+//     .abort          = i91u_abort,
+//     .reset          = i91u_reset,
+       .eh_bus_reset_handler = i91u_bus_reset,
+       .bios_param     = i91u_biosparam,
+       .can_queue      = 1,
+       .this_id        = 1,
+       .sg_tablesize   = SG_ALL,
+       .cmd_per_lun    = 1,
+       .use_clustering = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
+
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
new file mode 100644 (file)
index 0000000..df3ed7c
--- /dev/null
@@ -0,0 +1,739 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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/config.h>
+#include <linux/types.h>
+
+#define ULONG   unsigned long
+#define USHORT  unsigned short
+#define UCHAR   unsigned char
+#define BYTE    unsigned char
+#define WORD    unsigned short
+#define DWORD   unsigned long
+#define UBYTE   unsigned char
+#define UWORD   unsigned short
+#define UDWORD  unsigned long
+#define U32     u32
+
+#define TOTAL_SG_ENTRY         32
+#define MAX_SUPPORTED_ADAPTERS  8
+#define MAX_OFFSET             15
+#define MAX_TARGETS            16
+
+typedef struct {
+       unsigned short base;
+       unsigned short vec;
+} i91u_config;
+
+/***************************************/
+/*  Tulip Configuration Register Set */
+/***************************************/
+#define TUL_PVID        0x00   /* Vendor ID                    */
+#define TUL_PDID        0x02   /* Device ID                    */
+#define TUL_PCMD        0x04   /* Command                      */
+#define TUL_PSTUS       0x06   /* Status                       */
+#define TUL_PRID        0x08   /* Revision number              */
+#define TUL_PPI         0x09   /* Programming interface        */
+#define TUL_PSC         0x0A   /* Sub Class                    */
+#define TUL_PBC         0x0B   /* Base Class                   */
+#define TUL_PCLS        0x0C   /* Cache line size              */
+#define TUL_PLTR        0x0D   /* Latency timer                */
+#define TUL_PHDT        0x0E   /* Header type                  */
+#define TUL_PBIST       0x0F   /* BIST                         */
+#define TUL_PBAD        0x10   /* Base address                 */
+#define TUL_PBAD1       0x14   /* Base address                 */
+#define TUL_PBAD2       0x18   /* Base address                 */
+#define TUL_PBAD3       0x1C   /* Base address                 */
+#define TUL_PBAD4       0x20   /* Base address                 */
+#define TUL_PBAD5       0x24   /* Base address                 */
+#define TUL_PRSVD       0x28   /* Reserved                     */
+#define TUL_PRSVD1      0x2C   /* Reserved                     */
+#define TUL_PRAD        0x30   /* Expansion ROM base address   */
+#define TUL_PRSVD2      0x34   /* Reserved                     */
+#define TUL_PRSVD3      0x38   /* Reserved                     */
+#define TUL_PINTL       0x3C   /* Interrupt line               */
+#define TUL_PINTP       0x3D   /* Interrupt pin                */
+#define TUL_PIGNT       0x3E   /* MIN_GNT                      */
+#define TUL_PMGNT       0x3F   /* MAX_GNT                      */
+
+/************************/
+/*  Jasmin Register Set */
+/************************/
+#define TUL_HACFG0      0x40   /* H/A Configuration Register 0         */
+#define TUL_HACFG1      0x41   /* H/A Configuration Register 1         */
+#define TUL_HACFG2      0x42   /* H/A Configuration Register 2         */
+
+#define TUL_SDCFG0      0x44   /* SCSI Device Configuration 0          */
+#define TUL_SDCFG1      0x45   /* SCSI Device Configuration 1          */
+#define TUL_SDCFG2      0x46   /* SCSI Device Configuration 2          */
+#define TUL_SDCFG3      0x47   /* SCSI Device Configuration 3          */
+
+#define TUL_GINTS       0x50   /* Global Interrupt Status Register     */
+#define TUL_GIMSK       0x52   /* Global Interrupt MASK Register       */
+#define TUL_GCTRL       0x54   /* Global Control Register              */
+#define TUL_GCTRL_EEPROM_BIT    0x04
+#define TUL_GCTRL1      0x55   /* Global Control Register              */
+#define TUL_DMACFG      0x5B   /* DMA configuration                    */
+#define TUL_NVRAM       0x5D   /* Non-volatile RAM port                */
+
+#define TUL_SCnt0       0x80   /* 00 R/W Transfer Counter Low          */
+#define TUL_SCnt1       0x81   /* 01 R/W Transfer Counter Mid          */
+#define TUL_SCnt2       0x82   /* 02 R/W Transfer Count High           */
+#define TUL_SFifoCnt    0x83   /* 03 R   FIFO counter                  */
+#define TUL_SIntEnable  0x84   /* 03 W   Interrupt enble               */
+#define TUL_SInt        0x84   /* 04 R   Interrupt Register            */
+#define TUL_SCtrl0      0x85   /* 05 W   Control 0                     */
+#define TUL_SStatus0    0x85   /* 05 R   Status 0                      */
+#define TUL_SCtrl1      0x86   /* 06 W   Control 1                     */
+#define TUL_SStatus1    0x86   /* 06 R   Status 1                      */
+#define TUL_SConfig     0x87   /* 07 W   Configuration                 */
+#define TUL_SStatus2    0x87   /* 07 R   Status 2                      */
+#define TUL_SPeriod     0x88   /* 08 W   Sync. Transfer Period & Offset */
+#define TUL_SOffset     0x88   /* 08 R   Offset                        */
+#define TUL_SScsiId     0x89   /* 09 W   SCSI ID                       */
+#define TUL_SBusId      0x89   /* 09 R   SCSI BUS ID                   */
+#define TUL_STimeOut    0x8A   /* 0A W   Sel/Resel Time Out Register   */
+#define TUL_SIdent      0x8A   /* 0A R   Identify Message Register     */
+#define TUL_SAvail      0x8A   /* 0A R   Availiable Counter Register   */
+#define TUL_SData       0x8B   /* 0B R/W SCSI data in/out              */
+#define TUL_SFifo       0x8C   /* 0C R/W FIFO                          */
+#define TUL_SSignal     0x90   /* 10 R/W SCSI signal in/out            */
+#define TUL_SCmd        0x91   /* 11 R/W Command                       */
+#define TUL_STest0      0x92   /* 12 R/W Test0                         */
+#define TUL_STest1      0x93   /* 13 R/W Test1                         */
+#define TUL_SCFG1      0x94    /* 14 R/W Configuration                 */
+
+#define TUL_XAddH       0xC0   /*DMA Transfer Physical Address         */
+#define TUL_XAddW       0xC8   /*DMA Current Transfer Physical Address */
+#define TUL_XCntH       0xD0   /*DMA Transfer Counter                  */
+#define TUL_XCntW       0xD4   /*DMA Current Transfer Counter          */
+#define TUL_XCmd        0xD8   /*DMA Command Register                  */
+#define TUL_Int         0xDC   /*Interrupt Register                    */
+#define TUL_XStatus     0xDD   /*DMA status Register                   */
+#define TUL_Mask        0xE0   /*Interrupt Mask Register               */
+#define TUL_XCtrl       0xE4   /*DMA Control Register                  */
+#define TUL_XCtrl1      0xE5   /*DMA Control Register 1                */
+#define TUL_XFifo       0xE8   /*DMA FIFO                              */
+
+#define TUL_WCtrl       0xF7   /*Bus master wait state control         */
+#define TUL_DCtrl       0xFB   /*DMA delay control                     */
+
+/*----------------------------------------------------------------------*/
+/*   bit definition for Command register of Configuration Space Header  */
+/*----------------------------------------------------------------------*/
+#define BUSMS           0x04   /* BUS MASTER Enable                    */
+#define IOSPA           0x01   /* IO Space Enable                      */
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip SCSI Command register                         */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_RESEL    0x80   /* Enable Reselection                   */
+#define TSC_CMD_COMP    0x84   /* Command Complete Sequence            */
+#define TSC_SEL         0x01   /* Select Without ATN Sequence          */
+#define TSC_SEL_ATN     0x11   /* Select With ATN Sequence             */
+#define TSC_SEL_ATN_DMA 0x51   /* Select With ATN Sequence with DMA    */
+#define TSC_SEL_ATN3    0x31   /* Select With ATN3 Sequence            */
+#define TSC_SEL_ATNSTOP 0x12   /* Select With ATN and Stop Sequence    */
+#define TSC_SELATNSTOP  0x1E   /* Select With ATN and Stop Sequence    */
+
+#define TSC_SEL_ATN_DIRECT_IN   0x95   /* Select With ATN Sequence     */
+#define TSC_SEL_ATN_DIRECT_OUT  0x15   /* Select With ATN Sequence     */
+#define TSC_SEL_ATN3_DIRECT_IN  0xB5   /* Select With ATN3 Sequence    */
+#define TSC_SEL_ATN3_DIRECT_OUT 0x35   /* Select With ATN3 Sequence    */
+#define TSC_XF_DMA_OUT_DIRECT   0x06   /* DMA Xfer Infomation out      */
+#define TSC_XF_DMA_IN_DIRECT    0x86   /* DMA Xfer Infomation in       */
+
+#define TSC_XF_DMA_OUT  0x43   /* DMA Xfer Infomation out              */
+#define TSC_XF_DMA_IN   0xC3   /* DMA Xfer Infomation in               */
+#define TSC_XF_FIFO_OUT 0x03   /* FIFO Xfer Infomation out             */
+#define TSC_XF_FIFO_IN  0x83   /* FIFO Xfer Infomation in              */
+
+#define TSC_MSG_ACCEPT  0x0F   /* Message Accept                       */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 0 Register                     */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_SEQ     0x20   /* Reset sequence counter               */
+#define TSC_FLUSH_FIFO  0x10   /* Flush FIFO                           */
+#define TSC_ABT_CMD     0x04   /* Abort command (sequence)             */
+#define TSC_RST_CHIP    0x02   /* Reset SCSI Chip                      */
+#define TSC_RST_BUS     0x01   /* Reset SCSI Bus                       */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 1 Register                     */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_SCAM     0x80   /* Enable SCAM                          */
+#define TSC_TIMER       0x40   /* Select timeout unit                  */
+#define TSC_EN_SCSI2    0x20   /* SCSI-2 mode                          */
+#define TSC_PWDN        0x10   /* Power down mode                      */
+#define TSC_WIDE_CPU    0x08   /* Wide CPU                             */
+#define TSC_HW_RESELECT 0x04   /* Enable HW reselect                   */
+#define TSC_EN_BUS_OUT  0x02   /* Enable SCSI data bus out latch       */
+#define TSC_EN_BUS_IN   0x01   /* Enable SCSI data bus in latch        */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Configuration Register                 */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_LATCH    0x80   /* Enable phase latch                   */
+#define TSC_INITIATOR   0x40   /* Initiator mode                       */
+#define TSC_EN_SCSI_PAR 0x20   /* Enable SCSI parity                   */
+#define TSC_DMA_8BIT    0x10   /* Alternate dma 8-bits mode            */
+#define TSC_DMA_16BIT   0x08   /* Alternate dma 16-bits mode           */
+#define TSC_EN_WDACK    0x04   /* Enable DACK while wide SCSI xfer     */
+#define TSC_ALT_PERIOD  0x02   /* Alternate sync period mode           */
+#define TSC_DIS_SCSIRST 0x01   /* Disable SCSI bus reset us            */
+
+#define TSC_INITDEFAULT (TSC_INITIATOR | TSC_EN_LATCH | TSC_ALT_PERIOD | TSC_DIS_SCSIRST)
+
+#define TSC_WIDE_SCSI   0x80   /* Enable Wide SCSI                     */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI signal Register                        */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_ACK     0x00   /* Release ACK signal                   */
+#define TSC_RST_ATN     0x00   /* Release ATN signal                   */
+#define TSC_RST_BSY     0x00   /* Release BSY signal                   */
+
+#define TSC_SET_ACK     0x40   /* ACK signal                           */
+#define TSC_SET_ATN     0x08   /* ATN signal                           */
+
+#define TSC_REQI        0x80   /* REQ signal                           */
+#define TSC_ACKI        0x40   /* ACK signal                           */
+#define TSC_BSYI        0x20   /* BSY signal                           */
+#define TSC_SELI        0x10   /* SEL signal                           */
+#define TSC_ATNI        0x08   /* ATN signal                           */
+#define TSC_MSGI        0x04   /* MSG signal                           */
+#define TSC_CDI         0x02   /* C/D signal                           */
+#define TSC_IOI         0x01   /* I/O signal                           */
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 0 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_INT_PENDING 0x80   /* Interrupt pending            */
+#define TSS_SEQ_ACTIVE  0x40   /* Sequencer active             */
+#define TSS_XFER_CNT    0x20   /* Transfer counter zero        */
+#define TSS_FIFO_EMPTY  0x10   /* FIFO empty                   */
+#define TSS_PAR_ERROR   0x08   /* SCSI parity error            */
+#define TSS_PH_MASK     0x07   /* SCSI phase mask              */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 1 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_STATUS_RCV  0x08   /* Status received              */
+#define TSS_MSG_SEND    0x40   /* Message sent                 */
+#define TSS_CMD_PH_CMP  0x20   /* command phase done              */
+#define TSS_DATA_PH_CMP 0x10   /* Data phase done              */
+#define TSS_STATUS_SEND 0x08   /* Status sent                  */
+#define TSS_XFER_CMP    0x04   /* Transfer completed           */
+#define TSS_SEL_CMP     0x02   /* Selection completed          */
+#define TSS_ARB_CMP     0x01   /* Arbitration completed        */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 2 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_CMD_ABTED   0x80   /* Command aborted              */
+#define TSS_OFFSET_0    0x40   /* Offset counter zero          */
+#define TSS_FIFO_FULL   0x20   /* FIFO full                    */
+#define TSS_TIMEOUT_0   0x10   /* Timeout counter zero         */
+#define TSS_BUSY_RLS    0x08   /* Busy release                 */
+#define TSS_PH_MISMATCH 0x04   /* Phase mismatch               */
+#define TSS_SCSI_BUS_EN 0x02   /* SCSI data bus enable         */
+#define TSS_SCSIRST     0x01   /* SCSI bus reset in progress   */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Interrupt Register                     */
+/*----------------------------------------------------------------------*/
+#define TSS_RESEL_INT   0x80   /* Reselected interrupt         */
+#define TSS_SEL_TIMEOUT 0x40   /* Selected/reselected timeout  */
+#define TSS_BUS_SERV    0x20
+#define TSS_SCSIRST_INT 0x10   /* SCSI bus reset detected      */
+#define TSS_DISC_INT    0x08   /* Disconnected interrupt       */
+#define TSS_SEL_INT     0x04   /* Select interrupt             */
+#define TSS_SCAM_SEL    0x02   /* SCAM selected                */
+#define TSS_FUNC_COMP   0x01
+
+/*----------------------------------------------------------------------*/
+/* SCSI Phase Codes.                                                    */
+/*----------------------------------------------------------------------*/
+#define DATA_OUT        0
+#define DATA_IN         1      /* 4                            */
+#define CMD_OUT         2
+#define STATUS_IN       3      /* 6                            */
+#define MSG_OUT         6      /* 3                            */
+#define MSG_IN          7
+
+
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip xfer Command register                         */
+/*----------------------------------------------------------------------*/
+#define TAX_X_FORC      0x02
+#define TAX_X_ABT       0x04
+#define TAX_X_CLR_FIFO  0x08
+
+#define TAX_X_IN        0x21
+#define TAX_X_OUT       0x01
+#define TAX_SG_IN       0xA1
+#define TAX_SG_OUT      0x81
+
+/*----------------------------------------------------------------------*/
+/* Tulip Interrupt Register                                             */
+/*----------------------------------------------------------------------*/
+#define XCMP            0x01
+#define FCMP            0x02
+#define XABT            0x04
+#define XERR            0x08
+#define SCMP            0x10
+#define IPEND           0x80
+
+/*----------------------------------------------------------------------*/
+/* Tulip DMA Status Register                                            */
+/*----------------------------------------------------------------------*/
+#define XPEND           0x01   /* Transfer pending             */
+#define FEMPTY          0x02   /* FIFO empty                   */
+
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_GCTRL                                         */
+/*----------------------------------------------------------------------*/
+#define EXTSG           0x80
+#define EXTAD           0x60
+#define SEG4K           0x08
+#define EEPRG           0x04
+#define MRMUL           0x02
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_NVRAM                                         */
+/*----------------------------------------------------------------------*/
+#define SE2CS           0x08
+#define SE2CLK          0x04
+#define SE2DO           0x02
+#define SE2DI           0x01
+
+
+/************************************************************************/
+/*              Scatter-Gather Element Structure                        */
+/************************************************************************/
+typedef struct SG_Struc {
+       U32 SG_Ptr;             /* Data Pointer */
+       U32 SG_Len;             /* Data Length */
+} SG;
+
+/***********************************************************************
+               SCSI Control Block
+************************************************************************/
+typedef struct Scsi_Ctrl_Blk {
+       struct Scsi_Ctrl_Blk *SCB_NxtScb;
+       UBYTE SCB_Status;       /*4 */
+       UBYTE SCB_NxtStat;      /*5 */
+       UBYTE SCB_Mode;         /*6 */
+       UBYTE SCB_Msgin;        /*7 SCB_Res0 */
+       UWORD SCB_SGIdx;        /*8 */
+       UWORD SCB_SGMax;        /*A */
+#ifdef ALPHA
+       U32 SCB_Reserved[2];    /*C */
+#else
+       U32 SCB_Reserved[3];    /*C */
+#endif
+
+       U32 SCB_XferLen;        /*18 Current xfer len           */
+       U32 SCB_TotXLen;        /*1C Total xfer len             */
+       U32 SCB_PAddr;          /*20 SCB phy. Addr. */
+
+       UBYTE SCB_Opcode;       /*24 SCB command code */
+       UBYTE SCB_Flags;        /*25 SCB Flags */
+       UBYTE SCB_Target;       /*26 Target Id */
+       UBYTE SCB_Lun;          /*27 Lun */
+       U32 SCB_BufPtr;         /*28 Data Buffer Pointer */
+       U32 SCB_BufLen;         /*2C Data Allocation Length */
+       UBYTE SCB_SGLen;        /*30 SG list # */
+       UBYTE SCB_SenseLen;     /*31 Sense Allocation Length */
+       UBYTE SCB_HaStat;       /*32 */
+       UBYTE SCB_TaStat;       /*33 */
+       UBYTE SCB_CDBLen;       /*34 CDB Length */
+       UBYTE SCB_Ident;        /*35 Identify */
+       UBYTE SCB_TagMsg;       /*36 Tag Message */
+       UBYTE SCB_TagId;        /*37 Queue Tag */
+       UBYTE SCB_CDB[12];      /*38 */
+       U32 SCB_SGPAddr;        /*44 SG List/Sense Buf phy. Addr. */
+       U32 SCB_SensePtr;       /*48 Sense data pointer */
+       void (*SCB_Post) (BYTE *, BYTE *);      /*4C POST routine */
+       struct scsi_cmnd *SCB_Srb;      /*50 SRB Pointer */
+       SG SCB_SGList[TOTAL_SG_ENTRY];  /*54 Start of SG list */
+} SCB;
+
+/* Bit Definition for SCB_Status */
+#define SCB_RENT        0x01
+#define SCB_PEND        0x02
+#define SCB_CONTIG      0x04   /* Contigent Allegiance */
+#define SCB_SELECT      0x08
+#define SCB_BUSY        0x10
+#define SCB_DONE        0x20
+
+
+/* Opcodes of SCB_Opcode */
+#define ExecSCSI        0x1
+#define BusDevRst       0x2
+#define AbortCmd        0x3
+
+
+/* Bit Definition for SCB_Mode */
+#define SCM_RSENS       0x01   /* request sense mode */
+
+
+/* Bit Definition for SCB_Flags */
+#define SCF_DONE        0x01
+#define SCF_POST        0x02
+#define SCF_SENSE       0x04
+#define SCF_DIR         0x18
+#define SCF_NO_DCHK     0x00
+#define SCF_DIN         0x08
+#define SCF_DOUT        0x10
+#define SCF_NO_XF       0x18
+#define SCF_WR_VF       0x20   /* Write verify turn on         */
+#define SCF_POLL        0x40
+#define SCF_SG          0x80
+
+/* Error Codes for SCB_HaStat */
+#define HOST_SEL_TOUT   0x11
+#define HOST_DO_DU      0x12
+#define HOST_BUS_FREE   0x13
+#define HOST_BAD_PHAS   0x14
+#define HOST_INV_CMD    0x16
+#define HOST_ABORTED    0x1A   /* 07/21/98 */
+#define HOST_SCSI_RST   0x1B
+#define HOST_DEV_RST    0x1C
+
+/* Error Codes for SCB_TaStat */
+#define TARGET_CHKCOND  0x02
+#define TARGET_BUSY     0x08
+#define INI_QUEUE_FULL 0x28
+
+/* SCSI MESSAGE */
+#define MSG_COMP        0x00
+#define MSG_EXTEND      0x01
+#define MSG_SDP         0x02
+#define MSG_RESTORE     0x03
+#define MSG_DISC        0x04
+#define MSG_IDE         0x05
+#define MSG_ABORT       0x06
+#define MSG_REJ         0x07
+#define MSG_NOP         0x08
+#define MSG_PARITY      0x09
+#define MSG_LINK_COMP   0x0A
+#define MSG_LINK_FLAG   0x0B
+#define MSG_DEVRST      0x0C
+#define MSG_ABORT_TAG   0x0D
+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG        0x20
+#define MSG_HTAG        0x21
+#define MSG_OTAG        0x22
+
+#define MSG_IGNOREWIDE  0x23
+
+#define MSG_IDENT   0x80
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+
+typedef struct Tar_Ctrl_Struc {
+       UWORD TCS_Flags;        /* 0 */
+       UBYTE TCS_JS_Period;    /* 2 */
+       UBYTE TCS_SConfig0;     /* 3 */
+
+       UWORD TCS_DrvFlags;     /* 4 */
+       UBYTE TCS_DrvHead;      /* 6 */
+       UBYTE TCS_DrvSector;    /* 7 */
+} TCS;
+
+/***********************************************************************
+               Target Device Control Structure
+**********************************************************************/
+
+/* Bit Definition for TCF_Flags */
+#define TCF_SCSI_RATE           0x0007
+#define TCF_EN_DISC             0x0008
+#define TCF_NO_SYNC_NEGO        0x0010
+#define TCF_NO_WDTR             0x0020
+#define TCF_EN_255              0x0040
+#define TCF_EN_START            0x0080
+#define TCF_WDTR_DONE           0x0100
+#define TCF_SYNC_DONE           0x0200
+#define TCF_BUSY                0x0400
+
+
+/* Bit Definition for TCF_DrvFlags */
+#define TCF_DRV_BUSY            0x01   /* Indicate target busy(driver) */
+#define TCF_DRV_EN_TAG          0x0800
+#define TCF_DRV_255_63          0x0400
+
+typedef struct I91u_Adpt_Struc {
+       UWORD ADPT_BIOS;        /* 0 */
+       UWORD ADPT_BASE;        /* 1 */
+       UBYTE ADPT_Bus;         /* 2 */
+       UBYTE ADPT_Device;      /* 3 */
+       UBYTE ADPT_INTR;        /* 4 */
+} INI_ADPT_STRUCT;
+
+
+/***********************************************************************
+             Host Adapter Control Structure
+************************************************************************/
+typedef struct Ha_Ctrl_Struc {
+       UWORD HCS_Base;         /* 00 */
+       UWORD HCS_BIOS;         /* 02 */
+       UBYTE HCS_Intr;         /* 04 */
+       UBYTE HCS_SCSI_ID;      /* 05 */
+       UBYTE HCS_MaxTar;       /* 06 */
+       UBYTE HCS_NumScbs;      /* 07 */
+
+       UBYTE HCS_Flags;        /* 08 */
+       UBYTE HCS_Index;        /* 09 */
+       UBYTE HCS_HaId;         /* 0A */
+       UBYTE HCS_Config;       /* 0B */
+       UWORD HCS_IdMask;       /* 0C */
+       UBYTE HCS_Semaph;       /* 0E */
+       UBYTE HCS_Phase;        /* 0F */
+       UBYTE HCS_JSStatus0;    /* 10 */
+       UBYTE HCS_JSInt;        /* 11 */
+       UBYTE HCS_JSStatus1;    /* 12 */
+       UBYTE HCS_SConf1;       /* 13 */
+
+       UBYTE HCS_Msg[8];       /* 14 */
+       SCB *HCS_NxtAvail;      /* 1C */
+       SCB *HCS_Scb;           /* 20 */
+       SCB *HCS_ScbEnd;        /* 24 */
+       SCB *HCS_NxtPend;       /* 28 */
+       SCB *HCS_NxtContig;     /* 2C */
+       SCB *HCS_ActScb;        /* 30 */
+       TCS *HCS_ActTcs;        /* 34 */
+
+       SCB *HCS_FirstAvail;    /* 38 */
+       SCB *HCS_LastAvail;     /* 3C */
+       SCB *HCS_FirstPend;     /* 40 */
+       SCB *HCS_LastPend;      /* 44 */
+       SCB *HCS_FirstBusy;     /* 48 */
+       SCB *HCS_LastBusy;      /* 4C */
+       SCB *HCS_FirstDone;     /* 50 */
+       SCB *HCS_LastDone;      /* 54 */
+       UBYTE HCS_MaxTags[16];  /* 58 */
+       UBYTE HCS_ActTags[16];  /* 68 */
+       TCS HCS_Tcs[MAX_TARGETS];       /* 78 */
+       spinlock_t HCS_AvailLock;
+       spinlock_t HCS_SemaphLock;
+       struct pci_dev *pci_dev;
+} HCS;
+
+/* Bit Definition for HCB_Config */
+#define HCC_SCSI_RESET          0x01
+#define HCC_EN_PAR              0x02
+#define HCC_ACT_TERM1           0x04
+#define HCC_ACT_TERM2           0x08
+#define HCC_AUTO_TERM           0x10
+#define HCC_EN_PWR              0x80
+
+/* Bit Definition for HCB_Flags */
+#define HCF_EXPECT_DISC         0x01
+#define HCF_EXPECT_SELECT       0x02
+#define HCF_EXPECT_RESET        0x10
+#define HCF_EXPECT_DONE_DISC    0x20
+
+/******************************************************************
+       Serial EEProm
+*******************************************************************/
+
+typedef struct _NVRAM_SCSI {   /* SCSI channel configuration   */
+       UCHAR NVM_ChSCSIID;     /* 0Ch -> Channel SCSI ID       */
+       UCHAR NVM_ChConfig1;    /* 0Dh -> Channel config 1      */
+       UCHAR NVM_ChConfig2;    /* 0Eh -> Channel config 2      */
+       UCHAR NVM_NumOfTarg;    /* 0Fh -> Number of SCSI target */
+       /* SCSI target configuration    */
+       UCHAR NVM_Targ0Config;  /* 10h -> Target 0 configuration */
+       UCHAR NVM_Targ1Config;  /* 11h -> Target 1 configuration */
+       UCHAR NVM_Targ2Config;  /* 12h -> Target 2 configuration */
+       UCHAR NVM_Targ3Config;  /* 13h -> Target 3 configuration */
+       UCHAR NVM_Targ4Config;  /* 14h -> Target 4 configuration */
+       UCHAR NVM_Targ5Config;  /* 15h -> Target 5 configuration */
+       UCHAR NVM_Targ6Config;  /* 16h -> Target 6 configuration */
+       UCHAR NVM_Targ7Config;  /* 17h -> Target 7 configuration */
+       UCHAR NVM_Targ8Config;  /* 18h -> Target 8 configuration */
+       UCHAR NVM_Targ9Config;  /* 19h -> Target 9 configuration */
+       UCHAR NVM_TargAConfig;  /* 1Ah -> Target A configuration */
+       UCHAR NVM_TargBConfig;  /* 1Bh -> Target B configuration */
+       UCHAR NVM_TargCConfig;  /* 1Ch -> Target C configuration */
+       UCHAR NVM_TargDConfig;  /* 1Dh -> Target D configuration */
+       UCHAR NVM_TargEConfig;  /* 1Eh -> Target E configuration */
+       UCHAR NVM_TargFConfig;  /* 1Fh -> Target F configuration */
+} NVRAM_SCSI;
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+       USHORT NVM_Signature;   /* 0,1: Signature */
+       UCHAR NVM_Size;         /* 2:   Size of data structure */
+       UCHAR NVM_Revision;     /* 3:   Revision of data structure */
+       /* ----Host Adapter Structure ---- */
+       UCHAR NVM_ModelByte0;   /* 4:   Model number (byte 0) */
+       UCHAR NVM_ModelByte1;   /* 5:   Model number (byte 1) */
+       UCHAR NVM_ModelInfo;    /* 6:   Model information         */
+       UCHAR NVM_NumOfCh;      /* 7:   Number of SCSI channel */
+       UCHAR NVM_BIOSConfig1;  /* 8:   BIOS configuration 1  */
+       UCHAR NVM_BIOSConfig2;  /* 9:   BIOS configuration 2  */
+       UCHAR NVM_HAConfig1;    /* A:   Hoat adapter configuration 1 */
+       UCHAR NVM_HAConfig2;    /* B:   Hoat adapter configuration 2 */
+       NVRAM_SCSI NVM_SCSIInfo[2];
+       UCHAR NVM_reserved[10];
+       /* ---------- CheckSum ----------       */
+       USHORT NVM_CheckSum;    /* 0x3E, 0x3F: Checksum of NVRam        */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1                            */
+#define NBC1_ENABLE             0x01   /* BIOS enable                  */
+#define NBC1_8DRIVE             0x02   /* Support more than 2 drives   */
+#define NBC1_REMOVABLE          0x04   /* Support removable drive      */
+#define NBC1_INT19              0x08   /* Intercept int 19h            */
+#define NBC1_BIOSSCAN           0x10   /* Dynamic BIOS scan            */
+#define NBC1_LUNSUPPORT         0x40   /* Support LUN                  */
+
+/* HA Configuration Byte 1                                              */
+#define NHC1_BOOTIDMASK 0x0F   /* Boot ID number               */
+#define NHC1_LUNMASK    0x70   /* Boot LUN number              */
+#define NHC1_CHANMASK   0x80   /* Boot Channel number          */
+
+/* Bit definition for nvram->SCSIconfig1                                */
+#define NCC1_BUSRESET           0x01   /* Reset SCSI bus at power up   */
+#define NCC1_PARITYCHK          0x02   /* SCSI parity enable           */
+#define NCC1_ACTTERM1           0x04   /* Enable active terminator 1   */
+#define NCC1_ACTTERM2           0x08   /* Enable active terminator 2   */
+#define NCC1_AUTOTERM           0x10   /* Enable auto terminator       */
+#define NCC1_PWRMGR             0x80   /* Enable power management      */
+
+/* Bit definition for SCSI Target configuration byte                    */
+#define NTC_DISCONNECT          0x08   /* Enable SCSI disconnect       */
+#define NTC_SYNC                0x10   /* SYNC_NEGO                    */
+#define NTC_NO_WDTR             0x20   /* SYNC_NEGO                    */
+#define NTC_1GIGA               0x40   /* 255 head / 63 sectors (64/32) */
+#define NTC_SPINUP              0x80   /* Start disk drive             */
+
+/*      Default NVRam values                                            */
+#define INI_SIGNATURE           0xC925
+#define NBC1_DEFAULT            (NBC1_ENABLE)
+#define NCC1_DEFAULT            (NCC1_BUSRESET | NCC1_AUTOTERM | NCC1_PARITYCHK)
+#define NTC_DEFAULT             (NTC_NO_WDTR | NTC_1GIGA | NTC_DISCONNECT)
+
+/* SCSI related definition                                              */
+#define DISC_NOT_ALLOW          0x80   /* Disconnect is not allowed    */
+#define DISC_ALLOW              0xC0   /* Disconnect is allowed        */
+#define SCSICMD_RequestSense    0x03
+
+typedef struct _HCSinfo {
+       ULONG base;
+       UCHAR vec;
+       UCHAR bios;             /* High byte of BIOS address */
+       USHORT BaseAndBios;     /* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */
+} HCSINFO;
+
+#define TUL_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)(x+y)) ))
+#define TUL_RDLONG(x,y)         (ULONG)(inl((int)((ULONG)(x+y)) ))
+#define TUL_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
+#define TUL_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
+#define TUL_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS         0x01
+#define SCSI_RESET_ASYNCHRONOUS                0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET   0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET  0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#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[];
diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid
new file mode 100644 (file)
index 0000000..97c7a76
--- /dev/null
@@ -0,0 +1,77 @@
+config MEGARAID_NEWGEN
+       bool "LSI Logic New Generation RAID Device Drivers"
+       depends on PCI && SCSI
+       help
+       LSI Logic RAID Device Drivers
+
+config MEGARAID_MM
+       tristate "LSI Logic Management Module (New Driver)"
+       depends on PCI && SCSI && MEGARAID_NEWGEN
+       help
+       Management Module provides ioctl, sysfs support for LSI Logic
+       RAID controllers.
+       To compile this driver as a module, choose M here: the
+       module will be called megaraid_mm
+
+
+config MEGARAID_MAILBOX
+       tristate "LSI Logic MegaRAID Driver (New Driver)"
+       depends on PCI && SCSI && MEGARAID_MM
+       help
+       List of supported controllers
+
+       OEM     Product Name            VID :DID :SVID:SSID
+       ---     ------------            ---- ---- ---- ----
+       Dell PERC3/QC                   101E:1960:1028:0471
+       Dell PERC3/DC                   101E:1960:1028:0493
+       Dell PERC3/SC                   101E:1960:1028:0475
+       Dell PERC3/Di                   1028:000E:1028:0123
+       Dell PERC4/SC                   1000:1960:1028:0520
+       Dell PERC4/DC                   1000:1960:1028:0518
+       Dell PERC4/QC                   1000:0407:1028:0531
+       Dell PERC4/Di                   1028:000F:1028:014A
+       Dell PERC 4e/Si                 1028:0013:1028:016c
+       Dell PERC 4e/Di                 1028:0013:1028:016d
+       Dell PERC 4e/Di                 1028:0013:1028:016e
+       Dell PERC 4e/Di                 1028:0013:1028:016f
+       Dell PERC 4e/Di                 1028:0013:1028:0170
+       Dell PERC 4e/DC                 1000:0408:1028:0002
+       Dell PERC 4e/SC                 1000:0408:1028:0001
+       LSI MegaRAID SCSI 320-0         1000:1960:1000:A520
+       LSI MegaRAID SCSI 320-1         1000:1960:1000:0520
+       LSI MegaRAID SCSI 320-2         1000:1960:1000:0518
+       LSI MegaRAID SCSI 320-0X        1000:0407:1000:0530
+       LSI MegaRAID SCSI 320-2X        1000:0407:1000:0532
+       LSI MegaRAID SCSI 320-4X        1000:0407:1000:0531
+       LSI MegaRAID SCSI 320-1E        1000:0408:1000:0001
+       LSI MegaRAID SCSI 320-2E        1000:0408:1000:0002
+       LSI MegaRAID SATA 150-4         1000:1960:1000:4523
+       LSI MegaRAID SATA 150-6         1000:1960:1000:0523
+       LSI MegaRAID SATA 300-4X        1000:0409:1000:3004
+       LSI MegaRAID SATA 300-8X        1000:0409:1000:3008
+       INTEL RAID Controller SRCU42X   1000:0407:8086:0532
+       INTEL RAID Controller SRCS16    1000:1960:8086:0523
+       INTEL RAID Controller SRCU42E   1000:0408:8086:0002
+       INTEL RAID Controller SRCZCRX   1000:0407:8086:0530
+       INTEL RAID Controller SRCS28X   1000:0409:8086:3008
+       INTEL RAID Controller SROMBU42E 1000:0408:8086:3431
+       INTEL RAID Controller SROMBU42E 1000:0408:8086:3499
+       INTEL RAID Controller SRCU51L   1000:1960:8086:0520
+       FSC MegaRAID PCI Express ROMB   1000:0408:1734:1065
+       ACER MegaRAID ROMB-2E           1000:0408:1025:004D
+
+       To compile this driver as a module, choose M here: the
+       module will be called megaraid_mbox
+
+if MEGARAID_NEWGEN=n
+config MEGARAID_LEGACY
+       tristate "LSI Logic Legacy MegaRAID Driver"
+       depends on PCI && SCSI
+       help
+       This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490
+       and 467 SCSI host adapters. This driver also support the all U320
+       RAID controllers
+
+       To compile this driver as a module, choose M here: the
+       module will be called megaraid
+endif
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
new file mode 100644 (file)
index 0000000..6dd99f2
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MEGARAID_MM)      += megaraid_mm.o
+obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h
new file mode 100644 (file)
index 0000000..3052869
--- /dev/null
@@ -0,0 +1,790 @@
+/*
+ *
+ *                     Linux MegaRAID Unified device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : mbox_defs.h
+ *
+ */
+#ifndef _MRAID_MBOX_DEFS_H_
+#define _MRAID_MBOX_DEFS_H_
+
+#include <linux/types.h>
+
+/*
+ * Commands and states for mailbox based controllers
+ */
+
+#define MBOXCMD_LREAD          0x01
+#define MBOXCMD_LWRITE         0x02
+#define MBOXCMD_PASSTHRU       0x03
+#define MBOXCMD_ADPEXTINQ      0x04
+#define MBOXCMD_ADAPTERINQ     0x05
+#define MBOXCMD_LREAD64                0xA7
+#define MBOXCMD_LWRITE64       0xA8
+#define MBOXCMD_PASSTHRU64     0xC3
+#define MBOXCMD_EXTPTHRU       0xE3
+
+#define MAIN_MISC_OPCODE       0xA4
+#define GET_MAX_SG_SUPPORT     0x01
+#define SUPPORT_EXT_CDB                0x16
+
+#define FC_NEW_CONFIG          0xA1
+#define NC_SUBOP_PRODUCT_INFO  0x0E
+#define NC_SUBOP_ENQUIRY3      0x0F
+#define ENQ3_GET_SOLICITED_FULL        0x02
+#define OP_DCMD_READ_CONFIG    0x04
+#define NEW_READ_CONFIG_8LD    0x67
+#define READ_CONFIG_8LD                0x07
+#define FLUSH_ADAPTER          0x0A
+#define FLUSH_SYSTEM           0xFE
+
+/*
+ * Command for random deletion of logical drives
+ */
+#define        FC_DEL_LOGDRV           0xA4
+#define        OP_SUP_DEL_LOGDRV       0x2A
+#define OP_GET_LDID_MAP                0x18
+#define OP_DEL_LOGDRV          0x1C
+
+/*
+ * BIOS commands
+ */
+#define IS_BIOS_ENABLED                0x62
+#define GET_BIOS               0x01
+#define CHNL_CLASS             0xA9
+#define GET_CHNL_CLASS         0x00
+#define SET_CHNL_CLASS         0x01
+#define CH_RAID                        0x01
+#define CH_SCSI                        0x00
+#define BIOS_PVT_DATA          0x40
+#define GET_BIOS_PVT_DATA      0x00
+
+
+/*
+ * Commands to support clustering
+ */
+#define GET_TARGET_ID          0x7D
+#define CLUSTER_OP             0x70
+#define GET_CLUSTER_MODE       0x02
+#define CLUSTER_CMD            0x6E
+#define RESERVE_LD             0x01
+#define RELEASE_LD             0x02
+#define RESET_RESERVATIONS     0x03
+#define RESERVATION_STATUS     0x04
+#define RESERVE_PD             0x05
+#define RELEASE_PD             0x06
+
+
+/*
+ * Module battery status
+ */
+#define BATTERY_MODULE_MISSING         0x01
+#define BATTERY_LOW_VOLTAGE            0x02
+#define BATTERY_TEMP_HIGH              0x04
+#define BATTERY_PACK_MISSING           0x08
+#define BATTERY_CHARGE_MASK            0x30
+#define BATTERY_CHARGE_DONE            0x00
+#define BATTERY_CHARGE_INPROG          0x10
+#define BATTERY_CHARGE_FAIL            0x20
+#define BATTERY_CYCLES_EXCEEDED                0x40
+
+/*
+ * Physical drive states.
+ */
+#define PDRV_UNCNF     0
+#define PDRV_ONLINE    3
+#define PDRV_FAILED    4
+#define PDRV_RBLD      5
+#define PDRV_HOTSPARE  6
+
+
+/*
+ * Raid logical drive states.
+ */
+#define RDRV_OFFLINE   0
+#define RDRV_DEGRADED  1
+#define RDRV_OPTIMAL   2
+#define RDRV_DELETED   3
+
+/*
+ * Read, write and cache policies
+ */
+#define NO_READ_AHEAD          0
+#define READ_AHEAD             1
+#define ADAP_READ_AHEAD                2
+#define WRMODE_WRITE_THRU      0
+#define WRMODE_WRITE_BACK      1
+#define CACHED_IO              0
+#define DIRECT_IO              1
+
+#define MAX_LOGICAL_DRIVES_8LD         8
+#define MAX_LOGICAL_DRIVES_40LD                40
+#define FC_MAX_PHYSICAL_DEVICES                256
+#define MAX_MBOX_CHANNELS              5
+#define MAX_MBOX_TARGET                        15
+#define MBOX_MAX_PHYSICAL_DRIVES       MAX_MBOX_CHANNELS*MAX_MBOX_TARGET
+#define MAX_ROW_SIZE_40LD              32
+#define MAX_ROW_SIZE_8LD               8
+#define SPAN_DEPTH_8_SPANS             8
+#define SPAN_DEPTH_4_SPANS             4
+#define MAX_REQ_SENSE_LEN              0x20
+
+
+
+/**
+ * struct mbox_t - Driver and f/w handshake structure.
+ * @cmd                : firmware command
+ * @cmdid      : command id
+ * @numsectors : number of sectors to be transferred
+ * @lba                : Logical Block Address on LD
+ * @xferaddr   : DMA address for data transfer
+ * @logdrv     : logical drive number
+ * @numsge     : number of scatter gather elements in sg list
+ * @resvd      : reserved
+ * @busy       : f/w busy, must wait to issue more commands.
+ * @numstatus  : number of commands completed.
+ * @status     : status of the commands completed
+ * @completed  : array of completed command ids.
+ * @poll       : poll and ack sequence
+ * @ack                : poll and ack sequence
+ *
+ * The central handshake structure between the driver and the firmware. This
+ * structure must be allocated by the driver and aligned at 8-byte boundary.
+ */
+#define MBOX_MAX_FIRMWARE_STATUS       46
+typedef struct {
+       uint8_t         cmd;
+       uint8_t         cmdid;
+       uint16_t        numsectors;
+       uint32_t        lba;
+       uint32_t        xferaddr;
+       uint8_t         logdrv;
+       uint8_t         numsge;
+       uint8_t         resvd;
+       uint8_t         busy;
+       uint8_t         numstatus;
+       uint8_t         status;
+       uint8_t         completed[MBOX_MAX_FIRMWARE_STATUS];
+       uint8_t         poll;
+       uint8_t         ack;
+} __attribute__ ((packed)) mbox_t;
+
+
+/**
+ * mbox64_t - 64-bit extension for the mailbox
+ * @segment_lo : the low 32-bits of the address of the scatter-gather list
+ * @segment_hi : the upper 32-bits of the address of the scatter-gather list
+ * @mbox       : 32-bit mailbox, whose xferadder field must be set to
+ *             0xFFFFFFFF
+ *
+ * This is the extension of the 32-bit mailbox to be able to perform DMA
+ * beyond 4GB address range.
+ */
+typedef struct {
+       uint32_t        xferaddr_lo;
+       uint32_t        xferaddr_hi;
+       mbox_t          mbox32;
+} __attribute__ ((packed)) mbox64_t;
+
+/*
+ * mailbox structure used for internal commands
+ */
+typedef struct {
+       u8      cmd;
+       u8      cmdid;
+       u8      opcode;
+       u8      subopcode;
+       u32     lba;
+       u32     xferaddr;
+       u8      logdrv;
+       u8      rsvd[3];
+       u8      numstatus;
+       u8      status;
+} __attribute__ ((packed)) int_mbox_t;
+
+/**
+ * mraid_passthru_t - passthru structure to issue commands to physical devices
+ * @timeout            : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr
+ * @ars                        : set if ARS required after check condition
+ * @islogical          : set if command meant for logical devices
+ * @logdrv             : logical drive number if command for LD
+ * @channel            : Channel on which physical device is located
+ * @target             : SCSI target of the device
+ * @queuetag           : unused
+ * @queueaction                : unused
+ * @cdb                        : SCSI CDB
+ * @cdblen             : length of the CDB
+ * @reqsenselen                : amount of request sense data to be returned
+ * @reqsensearea       : Sense information buffer
+ * @numsge             : number of scatter-gather elements in the sg list
+ * @scsistatus         : SCSI status of the command completed.
+ * @dataxferaddr       : DMA data transfer address
+ * @dataxferlen                : amount of the data to be transferred.
+ */
+typedef struct {
+       uint8_t         timeout         :3;
+       uint8_t         ars             :1;
+       uint8_t         reserved        :3;
+       uint8_t         islogical       :1;
+       uint8_t         logdrv;
+       uint8_t         channel;
+       uint8_t         target;
+       uint8_t         queuetag;
+       uint8_t         queueaction;
+       uint8_t         cdb[10];
+       uint8_t         cdblen;
+       uint8_t         reqsenselen;
+       uint8_t         reqsensearea[MAX_REQ_SENSE_LEN];
+       uint8_t         numsge;
+       uint8_t         scsistatus;
+       uint32_t        dataxferaddr;
+       uint32_t        dataxferlen;
+} __attribute__ ((packed)) mraid_passthru_t;
+
+typedef struct {
+
+       uint32_t                dataxferaddr_lo;
+       uint32_t                dataxferaddr_hi;
+       mraid_passthru_t        pthru32;
+
+} __attribute__ ((packed)) mega_passthru64_t;
+
+/**
+ * mraid_epassthru_t - passthru structure to issue commands to physical devices
+ * @timeout            : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr
+ * @ars                        : set if ARS required after check condition
+ * @rsvd1              : reserved field
+ * @cd_rom             : (?)
+ * @rsvd2              : reserved field
+ * @islogical          : set if command meant for logical devices
+ * @logdrv             : logical drive number if command for LD
+ * @channel            : Channel on which physical device is located
+ * @target             : SCSI target of the device
+ * @queuetag           : unused
+ * @queueaction                : unused
+ * @cdblen             : length of the CDB
+ * @rsvd3              : reserved field
+ * @cdb                        : SCSI CDB
+ * @numsge             : number of scatter-gather elements in the sg list
+ * @status             : SCSI status of the command completed.
+ * @reqsenselen                : amount of request sense data to be returned
+ * @reqsensearea       : Sense information buffer
+ * @rsvd4              : reserved field
+ * @dataxferaddr       : DMA data transfer address
+ * @dataxferlen                : amount of the data to be transferred.
+ */
+typedef struct {
+       uint8_t         timeout         :3;
+       uint8_t         ars             :1;
+       uint8_t         rsvd1           :1;
+       uint8_t         cd_rom          :1;
+       uint8_t         rsvd2           :1;
+       uint8_t         islogical       :1;
+       uint8_t         logdrv;
+       uint8_t         channel;
+       uint8_t         target;
+       uint8_t         queuetag;
+       uint8_t         queueaction;
+       uint8_t         cdblen;
+       uint8_t         rsvd3;
+       uint8_t         cdb[16];
+       uint8_t         numsge;
+       uint8_t         status;
+       uint8_t         reqsenselen;
+       uint8_t         reqsensearea[MAX_REQ_SENSE_LEN];
+       uint8_t         rsvd4;
+       uint32_t        dataxferaddr;
+       uint32_t        dataxferlen;
+} __attribute__ ((packed)) mraid_epassthru_t;
+
+
+/**
+ * mraid_pinfo_t - product info, static information about the controller
+ * @data_size          : current size in bytes (not including resvd)
+ * @config_signature   : Current value is 0x00282008
+ * @fw_version         : Firmware version
+ * @bios_version       : version of the BIOS
+ * @product_name       : Name given to the controller
+ * @max_commands       : Maximum concurrent commands supported
+ * @nchannels          : Number of SCSI Channels detected
+ * @fc_loop_present    : Number of Fibre Loops detected
+ * @mem_type           : EDO, FPM, SDRAM etc
+ * @signature          :
+ * @dram_size          : In terms of MB
+ * @subsysid           : device PCI subsystem ID
+ * @subsysvid          : device PCI subsystem vendor ID
+ * @notify_counters    :
+ * @pad1k              : 135 + 889 resvd = 1024 total size
+ *
+ * This structures holds the information about the controller which is not
+ * expected to change dynamically.
+ *
+ * The current value of config signature is 0x00282008:
+ * 0x28 = MAX_LOGICAL_DRIVES,
+ * 0x20 = Number of stripes and
+ * 0x08 = Number of spans
+ */
+typedef struct {
+       uint32_t        data_size;
+       uint32_t        config_signature;
+       uint8_t         fw_version[16];
+       uint8_t         bios_version[16];
+       uint8_t         product_name[80];
+       uint8_t         max_commands;
+       uint8_t         nchannels;
+       uint8_t         fc_loop_present;
+       uint8_t         mem_type;
+       uint32_t        signature;
+       uint16_t        dram_size;
+       uint16_t        subsysid;
+       uint16_t        subsysvid;
+       uint8_t         notify_counters;
+       uint8_t         pad1k[889];
+} __attribute__ ((packed)) mraid_pinfo_t;
+
+
+/**
+ * mraid_notify_t - the notification structure
+ * @global_counter             : Any change increments this counter
+ * @param_counter              : Indicates any params changed
+ * @param_id                   : Param modified - defined below
+ * @param_val                  : New val of last param modified
+ * @write_config_counter       : write config occurred
+ * @write_config_rsvd          :
+ * @ldrv_op_counter            : Indicates ldrv op started/completed
+ * @ldrv_opid                  : ldrv num
+ * @ldrv_opcmd                 : ldrv operation - defined below
+ * @ldrv_opstatus              : status of the operation
+ * @ldrv_state_counter         : Indicates change of ldrv state
+ * @ldrv_state_id              : ldrv num
+ * @ldrv_state_new             : New state
+ * @ldrv_state_old             : old state
+ * @pdrv_state_counter         : Indicates change of ldrv state
+ * @pdrv_state_id              : pdrv id
+ * @pdrv_state_new             : New state
+ * @pdrv_state_old             : old state
+ * @pdrv_fmt_counter           : Indicates pdrv format started/over
+ * @pdrv_fmt_id                        : pdrv id
+ * @pdrv_fmt_val               : format started/over
+ * @pdrv_fmt_rsvd              :
+ * @targ_xfer_counter          : Indicates SCSI-2 Xfer rate change
+ * @targ_xfer_id               : pdrv Id
+ * @targ_xfer_val              : new Xfer params of last pdrv
+ * @targ_xfer_rsvd             :
+ * @fcloop_id_chg_counter      : Indicates loopid changed
+ * @fcloopid_pdrvid            : pdrv id
+ * @fcloop_id0                 : loopid on fc loop 0
+ * @fcloop_id1                 : loopid on fc loop 1
+ * @fcloop_state_counter       : Indicates loop state changed
+ * @fcloop_state0              : state of fc loop 0
+ * @fcloop_state1              : state of fc loop 1
+ * @fcloop_state_rsvd          :
+ */
+typedef struct {
+       uint32_t        global_counter;
+       uint8_t         param_counter;
+       uint8_t         param_id;
+       uint16_t        param_val;
+       uint8_t         write_config_counter;
+       uint8_t         write_config_rsvd[3];
+       uint8_t         ldrv_op_counter;
+       uint8_t         ldrv_opid;
+       uint8_t         ldrv_opcmd;
+       uint8_t         ldrv_opstatus;
+       uint8_t         ldrv_state_counter;
+       uint8_t         ldrv_state_id;
+       uint8_t         ldrv_state_new;
+       uint8_t         ldrv_state_old;
+       uint8_t         pdrv_state_counter;
+       uint8_t         pdrv_state_id;
+       uint8_t         pdrv_state_new;
+       uint8_t         pdrv_state_old;
+       uint8_t         pdrv_fmt_counter;
+       uint8_t         pdrv_fmt_id;
+       uint8_t         pdrv_fmt_val;
+       uint8_t         pdrv_fmt_rsvd;
+       uint8_t         targ_xfer_counter;
+       uint8_t         targ_xfer_id;
+       uint8_t         targ_xfer_val;
+       uint8_t         targ_xfer_rsvd;
+       uint8_t         fcloop_id_chg_counter;
+       uint8_t         fcloopid_pdrvid;
+       uint8_t         fcloop_id0;
+       uint8_t         fcloop_id1;
+       uint8_t         fcloop_state_counter;
+       uint8_t         fcloop_state0;
+       uint8_t         fcloop_state1;
+       uint8_t         fcloop_state_rsvd;
+} __attribute__ ((packed)) mraid_notify_t;
+
+
+/**
+ * mraid_inquiry3_t - enquiry for device information
+ *
+ * @data_size          : current size in bytes (not including resvd)
+ * @notify             :
+ * @notify_rsvd                :
+ * @rebuild_rate       : rebuild rate (0% - 100%)
+ * @cache_flush_int    : cache flush interval in seconds
+ * @sense_alert                :
+ * @drive_insert_count : drive insertion count
+ * @battery_status     :
+ * @num_ldrv           : no. of Log Drives configured
+ * @recon_state                : state of reconstruct
+ * @ldrv_op_status     : logdrv Status
+ * @ldrv_size          : size of each log drv
+ * @ldrv_prop          :
+ * @ldrv_state         : state of log drives
+ * @pdrv_state         : state of phys drvs.
+ * @pdrv_format                :
+ * @targ_xfer          : phys device transfer rate
+ * @pad1k              : 761 + 263reserved = 1024 bytes total size
+ */
+#define MAX_NOTIFY_SIZE                0x80
+#define CUR_NOTIFY_SIZE                sizeof(mraid_notify_t)
+
+typedef struct {
+       uint32_t        data_size;
+
+       mraid_notify_t  notify;
+
+       uint8_t         notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
+
+       uint8_t         rebuild_rate;
+       uint8_t         cache_flush_int;
+       uint8_t         sense_alert;
+       uint8_t         drive_insert_count;
+
+       uint8_t         battery_status;
+       uint8_t         num_ldrv;
+       uint8_t         recon_state[MAX_LOGICAL_DRIVES_40LD / 8];
+       uint16_t        ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8];
+
+       uint32_t        ldrv_size[MAX_LOGICAL_DRIVES_40LD];
+       uint8_t         ldrv_prop[MAX_LOGICAL_DRIVES_40LD];
+       uint8_t         ldrv_state[MAX_LOGICAL_DRIVES_40LD];
+       uint8_t         pdrv_state[FC_MAX_PHYSICAL_DEVICES];
+       uint16_t        pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16];
+
+       uint8_t         targ_xfer[80];
+       uint8_t         pad1k[263];
+} __attribute__ ((packed)) mraid_inquiry3_t;
+
+
+/**
+ * mraid_adapinfo_t - information about the adapter
+ * @max_commands               : max concurrent commands supported
+ * @rebuild_rate               : rebuild rate - 0% thru 100%
+ * @max_targ_per_chan          : max targ per channel
+ * @nchannels                  : number of channels on HBA
+ * @fw_version                 : firmware version
+ * @age_of_flash               : number of times FW has been flashed
+ * @chip_set_value             : contents of 0xC0000832
+ * @dram_size                  : in MB
+ * @cache_flush_interval       : in seconds
+ * @bios_version               :
+ * @board_type                 :
+ * @sense_alert                        :
+ * @write_config_count         : increase with every configuration change
+ * @drive_inserted_count       : increase with every drive inserted
+ * @inserted_drive             : channel:Id of inserted drive
+ * @battery_status             : bit 0: battery module missing
+ *                             bit 1: VBAD
+ *                             bit 2: temprature high
+ *                             bit 3: battery pack missing
+ *                             bit 4,5:
+ *                                     00 - charge complete
+ *                                     01 - fast charge in progress
+ *                                     10 - fast charge fail
+ *                                     11 - undefined
+ *                             bit 6: counter > 1000
+ *                             bit 7: Undefined
+ * @dec_fault_bus_info         :
+ */
+typedef struct {
+       uint8_t         max_commands;
+       uint8_t         rebuild_rate;
+       uint8_t         max_targ_per_chan;
+       uint8_t         nchannels;
+       uint8_t         fw_version[4];
+       uint16_t        age_of_flash;
+       uint8_t         chip_set_value;
+       uint8_t         dram_size;
+       uint8_t         cache_flush_interval;
+       uint8_t         bios_version[4];
+       uint8_t         board_type;
+       uint8_t         sense_alert;
+       uint8_t         write_config_count;
+       uint8_t         battery_status;
+       uint8_t         dec_fault_bus_info;
+} __attribute__ ((packed)) mraid_adapinfo_t;
+
+
+/**
+ * mraid_ldrv_info_t - information about the logical drives
+ * @nldrv      : Number of logical drives configured
+ * @rsvd       :
+ * @size       : size of each logical drive
+ * @prop       :
+ * @state      : state of each logical drive
+ */
+typedef struct {
+       uint8_t         nldrv;
+       uint8_t         rsvd[3];
+       uint32_t        size[MAX_LOGICAL_DRIVES_8LD];
+       uint8_t         prop[MAX_LOGICAL_DRIVES_8LD];
+       uint8_t         state[MAX_LOGICAL_DRIVES_8LD];
+} __attribute__ ((packed)) mraid_ldrv_info_t;
+
+
+/**
+ * mraid_pdrv_info_t - information about the physical drives
+ * @pdrv_state : state of each physical drive
+ */
+typedef struct {
+       uint8_t         pdrv_state[MBOX_MAX_PHYSICAL_DRIVES];
+       uint8_t         rsvd;
+} __attribute__ ((packed)) mraid_pdrv_info_t;
+
+
+/**
+ * mraid_inquiry_t - RAID inquiry, mailbox command 0x05
+ * @mraid_adapinfo_t   : adapter information
+ * @mraid_ldrv_info_t  : logical drives information
+ * @mraid_pdrv_info_t  : physical drives information
+ */
+typedef struct {
+       mraid_adapinfo_t        adapter_info;
+       mraid_ldrv_info_t       logdrv_info;
+       mraid_pdrv_info_t       pdrv_info;
+} __attribute__ ((packed)) mraid_inquiry_t;
+
+
+/**
+ * mraid_extinq_t - RAID extended inquiry, mailbox command 0x04
+ *
+ * @raid_inq           : raid inquiry
+ * @phys_drv_format    :
+ * @stack_attn         :
+ * @modem_status       :
+ * @rsvd               :
+ */
+typedef struct {
+       mraid_inquiry_t raid_inq;
+       uint16_t        phys_drv_format[MAX_MBOX_CHANNELS];
+       uint8_t         stack_attn;
+       uint8_t         modem_status;
+       uint8_t         rsvd[2];
+} __attribute__ ((packed)) mraid_extinq_t;
+
+
+/**
+ * adap_device_t - device information
+ * @channel    : channel fpor the device
+ * @target     : target ID of the device
+ */
+typedef struct {
+       uint8_t         channel;
+       uint8_t         target;
+}__attribute__ ((packed)) adap_device_t;
+
+
+/**
+ * adap_span_40ld_t - 40LD span
+ * @start_blk  : starting block
+ * @num_blks   : number of blocks
+ */
+typedef struct {
+       uint32_t        start_blk;
+       uint32_t        num_blks;
+       adap_device_t   device[MAX_ROW_SIZE_40LD];
+}__attribute__ ((packed)) adap_span_40ld_t;
+
+
+/**
+ * adap_span_8ld_t - 8LD span
+ * @start_blk  : starting block
+ * @num_blks   : number of blocks
+ */
+typedef struct {
+       uint32_t        start_blk;
+       uint32_t        num_blks;
+       adap_device_t   device[MAX_ROW_SIZE_8LD];
+}__attribute__ ((packed)) adap_span_8ld_t;
+
+
+/**
+ * logdrv_param_t - logical drives parameters
+ *
+ * @span_depth : total number of spans
+ * @level      : RAID level
+ * @read_ahead : read ahead, no read ahead, adaptive read ahead
+ * @stripe_sz  : encoded stripe size
+ * @status     : status of the logical drive
+ * @write_mode : write mode, write_through/write_back
+ * @direct_io  : direct io or through cache
+ * @row_size   : number of stripes in a row
+ */
+typedef struct {
+       uint8_t         span_depth;
+       uint8_t         level;
+       uint8_t         read_ahead;
+       uint8_t         stripe_sz;
+       uint8_t         status;
+       uint8_t         write_mode;
+       uint8_t         direct_io;
+       uint8_t         row_size;
+} __attribute__ ((packed)) logdrv_param_t;
+
+
+/**
+ * logdrv_40ld_t - logical drive definition for 40LD controllers
+ * @lparam     : logical drives parameters
+ * @span       : span
+ */
+typedef struct {
+       logdrv_param_t          lparam;
+       adap_span_40ld_t        span[SPAN_DEPTH_8_SPANS];
+}__attribute__ ((packed)) logdrv_40ld_t;
+
+
+/**
+ * logdrv_8ld_span8_t - logical drive definition for 8LD controllers
+ * @lparam     : logical drives parameters
+ * @span       : span
+ *
+ * 8-LD logical drive with upto 8 spans
+ */
+typedef struct {
+       logdrv_param_t  lparam;
+       adap_span_8ld_t span[SPAN_DEPTH_8_SPANS];
+}__attribute__ ((packed)) logdrv_8ld_span8_t;
+
+
+/**
+ * logdrv_8ld_span4_t - logical drive definition for 8LD controllers
+ * @lparam     : logical drives parameters
+ * @span       : span
+ *
+ * 8-LD logical drive with upto 4 spans
+ */
+typedef struct {
+       logdrv_param_t  lparam;
+       adap_span_8ld_t span[SPAN_DEPTH_4_SPANS];
+}__attribute__ ((packed)) logdrv_8ld_span4_t;
+
+
+/**
+ * phys_drive_t - physical device information
+ * @type       : Type of the device
+ * @cur_status : current status of the device
+ * @tag_depth  : Level of tagging
+ * @sync_neg   : sync negotiation - ENABLE or DISBALE
+ * @size       : configurable size in terms of 512 byte
+ */
+typedef struct {
+       uint8_t         type;
+       uint8_t         cur_status;
+       uint8_t         tag_depth;
+       uint8_t         sync_neg;
+       uint32_t        size;
+}__attribute__ ((packed)) phys_drive_t;
+
+
+/**
+ * disk_array_40ld_t - disk array for 40LD controllers
+ * @numldrv    : number of logical drives
+ * @resvd      :
+ * @ldrv       : logical drives information
+ * @pdrv       : physical drives information
+ */
+typedef struct {
+       uint8_t         numldrv;
+       uint8_t         resvd[3];
+       logdrv_40ld_t   ldrv[MAX_LOGICAL_DRIVES_40LD];
+       phys_drive_t    pdrv[MBOX_MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_40ld_t;
+
+
+/**
+ * disk_array_8ld_span8_t - disk array for 8LD controllers
+ * @numldrv    : number of logical drives
+ * @resvd      :
+ * @ldrv       : logical drives information
+ * @pdrv       : physical drives information
+ *
+ * Disk array for 8LD logical drives with upto 8 spans
+ */
+typedef struct {
+       uint8_t                 numldrv;
+       uint8_t                 resvd[3];
+       logdrv_8ld_span8_t      ldrv[MAX_LOGICAL_DRIVES_8LD];
+       phys_drive_t            pdrv[MBOX_MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_8ld_span8_t;
+
+
+/**
+ * disk_array_8ld_span4_t - disk array for 8LD controllers
+ * @numldrv    : number of logical drives
+ * @resvd      :
+ * @ldrv       : logical drives information
+ * @pdrv       : physical drives information
+ *
+ * Disk array for 8LD logical drives with upto 4 spans
+ */
+typedef struct {
+       uint8_t                 numldrv;
+       uint8_t                 resvd[3];
+       logdrv_8ld_span4_t      ldrv[MAX_LOGICAL_DRIVES_8LD];
+       phys_drive_t            pdrv[MBOX_MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_8ld_span4_t;
+
+
+/**
+ * private_bios_data - bios private data for boot devices
+ * @geometry   : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB,
+ *             0x1000 - 8GB, Others values are invalid
+ * @unused     : bits 4-7 are unused
+ * @boot_drv   : logical drive set as boot drive, 0..7 - for 8LD cards,
+ *             0..39 - for 40LD cards
+ * @cksum      : 0-(sum of first 13 bytes of this structure)
+ */
+struct private_bios_data {
+       uint8_t         geometry        :4;
+       uint8_t         unused          :4;
+       uint8_t         boot_drv;
+       uint8_t         rsvd[12];
+       uint16_t        cksum;
+} __attribute__ ((packed));
+
+
+/**
+ * mbox_sgl64 - 64-bit scatter list for mailbox based controllers
+ * @address    : address of the buffer
+ * @length     : data transfer length
+ */
+typedef struct {
+       uint64_t        address;
+       uint32_t        length;
+} __attribute__ ((packed)) mbox_sgl64;
+
+/**
+ * mbox_sgl32 - 32-bit scatter list for mailbox based controllers
+ * @address    : address of the buffer
+ * @length     : data transfer length
+ */
+typedef struct {
+       uint32_t        address;
+       uint32_t        length;
+} __attribute__ ((packed)) mbox_sgl32;
+
+#endif         // _MRAID_MBOX_DEFS_H_
+
+/* vim: set ts=8 sw=8 tw=78: */
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
new file mode 100644 (file)
index 0000000..e151175
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *
+ *                     Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : mega_common.h
+ *
+ * Libaray of common routine used by all low-level megaraid drivers
+ */
+
+#ifndef _MEGA_COMMON_H_
+#define _MEGA_COMMON_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <asm/semaphore.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+
+#define LSI_MAX_CHANNELS               16
+#define LSI_MAX_LOGICAL_DRIVES_64LD    (64+1)
+
+
+/**
+ * scb_t - scsi command control block
+ * @param ccb          : command control block for individual driver
+ * @param list         : list of control blocks
+ * @param gp           : general purpose field for LLDs
+ * @param sno          : all SCBs have a serial number
+ * @param scp          : associated scsi command
+ * @param state                : current state of scb
+ * @param dma_dir      : direction of data transfer
+ * @param dma_type     : transfer with sg list, buffer, or no data transfer
+ * @param dev_channel  : actual channel on the device
+ * @param dev_target   : actual target on the device
+ * @param status       : completion status
+ *
+ * This is our central data structure to issue commands the each driver.
+ * Driver specific data structures are maintained in the ccb field.
+ * scb provides a field 'gp', which can be used by LLD for its own purposes
+ *
+ * dev_channel and dev_target must be initialized with the actual channel and
+ * target on the controller.
+ */
+typedef struct {
+       caddr_t                 ccb;
+       struct list_head        list;
+       unsigned long           gp;
+       unsigned int            sno;
+       struct scsi_cmnd        *scp;
+       uint32_t                state;
+       uint32_t                dma_direction;
+       uint32_t                dma_type;
+       uint16_t                dev_channel;
+       uint16_t                dev_target;
+       uint32_t                status;
+} scb_t;
+
+/*
+ * SCB states as it transitions from one state to another
+ */
+#define SCB_FREE       0x0000  /* on the free list */
+#define SCB_ACTIVE     0x0001  /* off the free list */
+#define SCB_PENDQ      0x0002  /* on the pending queue */
+#define SCB_ISSUED     0x0004  /* issued - owner f/w */
+#define SCB_ABORT      0x0008  /* Got an abort for this one */
+#define SCB_RESET      0x0010  /* Got a reset for this one */
+
+/*
+ * DMA types for scb
+ */
+#define MRAID_DMA_NONE 0x0000  /* no data transfer for this command */
+#define MRAID_DMA_WSG  0x0001  /* data transfer using a sg list */
+#define MRAID_DMA_WBUF 0x0002  /* data transfer using a contiguous buffer */
+
+
+/**
+ * struct adapter_t - driver's initialization structure
+ * @param dpc_h                        : tasklet handle
+ * @param pdev                 : pci configuration pointer for kernel
+ * @param host                 : pointer to host structure of mid-layer
+ * @param host_lock            : pointer to appropriate lock
+ * @param lock                 : synchronization lock for mid-layer and driver
+ * @param quiescent            : driver is quiescent for now.
+ * @param outstanding_cmds     : number of commands pending in the driver
+ * @param kscb_list            : pointer to the bulk of SCBs pointers for IO
+ * @param kscb_pool            : pool of free scbs for IO
+ * @param kscb_pool_lock       : lock for pool of free scbs
+ * @param pend_list            : pending commands list
+ * @param pend_list_lock       : exlusion lock for pending commands list
+ * @param completed_list       : list of completed commands
+ * @param completed_list_lock  : exclusion lock for list of completed commands
+ * @param sglen                        : max sg elements supported
+ * @param device_ids           : to convert kernel device addr to our devices.
+ * @param raid_device          : raid adapter specific pointer
+ * @param max_channel          : maximum channel number supported - inclusive
+ * @param max_target           : max target supported - inclusive
+ * @param max_lun              : max lun supported - inclusive
+ * @param unique_id            : unique identifier for each adapter
+ * @param irq                  : IRQ for this adapter
+ * @param ito                  : internal timeout value, (-1) means no timeout
+ * @param ibuf                 : buffer to issue internal commands
+ * @param ibuf_dma_h           : dma handle for the above buffer
+ * @param uscb_list            : SCB pointers for user cmds, common mgmt module
+ * @param uscb_pool            : pool of SCBs for user commands
+ * @param uscb_pool_lock       : exclusion lock for these SCBs
+ * @param max_cmds             : max outstanding commands
+ * @param fw_version           : firmware version
+ * @param bios_version         : bios version
+ * @param max_cdb_sz           : biggest CDB size supported.
+ * @param ha                   : is high availability present - clustering
+ * @param init_id              : initiator ID, the default value should be 7
+ * @param max_sectors          : max sectors per request
+ * @param cmd_per_lun          : max outstanding commands per LUN
+ * @param being_detached       : set when unloading, no more mgmt calls
+ *
+ *
+ * mraid_setup_device_map() can be called anytime after the device map is
+ * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is
+ * required, usually from LLD's queue entry point. The formar API sets up the
+ * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the
+ * device in question is a logical drive.
+ *
+ * quiescent flag should be set by the driver if it is not accepting more
+ * commands
+ *
+ * NOTE: The fields of this structures are placed to minimize cache misses
+ */
+
+// amount of space required to store the bios and firmware version strings
+#define VERSION_SIZE   16
+
+typedef struct {
+       struct tasklet_struct   dpc_h;
+       struct pci_dev          *pdev;
+       struct Scsi_Host        *host;
+       spinlock_t              *host_lock;
+       spinlock_t              lock;
+       uint8_t                 quiescent;
+       int                     outstanding_cmds;
+       scb_t                   *kscb_list;
+       struct list_head        kscb_pool;
+       spinlock_t              kscb_pool_lock;
+       struct list_head        pend_list;
+       spinlock_t              pend_list_lock;
+       struct list_head        completed_list;
+       spinlock_t              completed_list_lock;
+       uint16_t                sglen;
+       int                     device_ids[LSI_MAX_CHANNELS]
+                                       [LSI_MAX_LOGICAL_DRIVES_64LD];
+       caddr_t                 raid_device;
+       uint8_t                 max_channel;
+       uint16_t                max_target;
+       uint8_t                 max_lun;
+
+       uint32_t                unique_id;
+       uint8_t                 irq;
+       uint8_t                 ito;
+       caddr_t                 ibuf;
+       dma_addr_t              ibuf_dma_h;
+       scb_t                   *uscb_list;
+       struct list_head        uscb_pool;
+       spinlock_t              uscb_pool_lock;
+       int                     max_cmds;
+       uint8_t                 fw_version[VERSION_SIZE];
+       uint8_t                 bios_version[VERSION_SIZE];
+       uint8_t                 max_cdb_sz;
+       uint8_t                 ha;
+       uint16_t                init_id;
+       uint16_t                max_sectors;
+       uint16_t                cmd_per_lun;
+       atomic_t                being_detached;
+} adapter_t;
+
+#define SCSI_FREE_LIST_LOCK(adapter)   (&adapter->kscb_pool_lock)
+#define USER_FREE_LIST_LOCK(adapter)   (&adapter->uscb_pool_lock)
+#define PENDING_LIST_LOCK(adapter)     (&adapter->pend_list_lock)
+#define COMPLETED_LIST_LOCK(adapter)   (&adapter->completed_list_lock)
+
+
+// conversion from scsi command
+#define SCP2HOST(scp)                  (scp)->device->host     // to host
+#define SCP2HOSTDATA(scp)              SCP2HOST(scp)->hostdata // to soft state
+#define SCP2CHANNEL(scp)               (scp)->device->channel  // to channel
+#define SCP2TARGET(scp)                        (scp)->device->id       // to target
+#define SCP2LUN(scp)                   (scp)->device->lun      // to LUN
+
+// generic macro to convert scsi command and host to controller's soft state
+#define SCSIHOST2ADAP(host)    (((caddr_t *)(host->hostdata))[0])
+#define SCP2ADAPTER(scp)       (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp))
+
+
+/**
+ * MRAID_GET_DEVICE_MAP - device ids
+ * @param adp          - Adapter's soft state
+ * @param scp          - mid-layer scsi command pointer
+ * @param p_chan       - physical channel on the controller
+ * @param target       - target id of the device or logical drive number
+ * @param islogical    - set if the command is for the logical drive
+ *
+ * Macro to retrieve information about device class, logical or physical and
+ * the corresponding physical channel and target or logical drive number
+ **/
+#define MRAID_IS_LOGICAL(adp, scp)     \
+       (SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0
+
+#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical)      \
+       /*                                                              \
+        * Is the request coming for the virtual channel                \
+        */                                                             \
+       islogical = MRAID_IS_LOGICAL(adp, scp);                         \
+                                                                       \
+       /*                                                              \
+        * Get an index into our table of drive ids mapping             \
+        */                                                             \
+       if (islogical) {                                                \
+               p_chan = 0xFF;                                          \
+               target =                                                \
+               (adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)]; \
+       }                                                               \
+       else {                                                          \
+               p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)]           \
+                                       [SCP2TARGET(scp)] >> 8) & 0xFF; \
+               target = ((adp)->device_ids[SCP2CHANNEL(scp)]           \
+                                       [SCP2TARGET(scp)] & 0xFF);      \
+       }
+
+/*
+ * ### Helper routines ###
+ */
+#define LSI_DBGLVL mraid_debug_level   // each LLD must define a global
+                                       // mraid_debug_level
+
+#ifdef DEBUG
+#if defined (_ASSERT_PANIC)
+#define ASSERT_ACTION  panic
+#else
+#define ASSERT_ACTION  printk
+#endif
+
+#define ASSERT(expression)                                             \
+       if (!(expression)) {                                            \
+       ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \
+                       #expression, __FILE__, __LINE__, __FUNCTION__); \
+       }
+#else
+#define ASSERT(expression)
+#endif
+
+/*
+ * struct mraid_pci_blk - structure holds DMA memory block info
+ * @param vaddr                : virtual address to a memory block
+ * @param dma_addr     : DMA handle to a memory block
+ *
+ * This structure is filled up for the caller. It is the responsibilty of the
+ * caller to allocate this array big enough to store addresses for all
+ * requested elements
+ */
+struct mraid_pci_blk {
+       caddr_t         vaddr;
+       dma_addr_t      dma_addr;
+};
+
+#endif // _MEGA_COMMON_H_
+
+// vim: set ts=8 sw=8 tw=78:
diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h
new file mode 100644 (file)
index 0000000..44584ca
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ *
+ *                     Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : megaraid_ioctl.h
+ *
+ * Definitions to interface with user level applications
+ */
+
+#ifndef _MEGARAID_IOCTL_H_
+#define _MEGARAID_IOCTL_H_
+
+#include <linux/types.h>
+#include <asm/semaphore.h>
+
+#include "mbox_defs.h"
+
+/**
+ * con_log() - console log routine
+ * @param level                : indicates the severity of the message.
+ * @fparam mt          : format string
+ *
+ * con_log displays the error messages on the console based on the current
+ * debug level. Also it attaches the appropriate kernel severity level with
+ * the message.
+ *
+ *
+ * consolge messages debug levels
+ */
+#define        CL_ANN          0       /* print unconditionally, announcements */
+#define CL_DLEVEL1     1       /* debug level 1, informative */
+#define CL_DLEVEL2     2       /* debug level 2, verbose */
+#define CL_DLEVEL3     3       /* debug level 3, very verbose */
+
+#define        con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt;
+
+/*
+ * Definitions & Declarations needed to use common management module
+ */
+
+#define MEGAIOC_MAGIC          'm'
+#define MEGAIOCCMD             _IOWR(MEGAIOC_MAGIC, 0, mimd_t)
+
+#define MEGAIOC_QNADAP         'm'     /* Query # of adapters          */
+#define MEGAIOC_QDRVRVER       'e'     /* Query driver version         */
+#define MEGAIOC_QADAPINFO      'g'     /* Query adapter information    */
+
+#define USCSICMD               0x80
+#define UIOC_RD                        0x00001
+#define UIOC_WR                        0x00002
+
+#define MBOX_CMD               0x00000
+#define GET_DRIVER_VER         0x10000
+#define GET_N_ADAP             0x20000
+#define GET_ADAP_INFO          0x30000
+#define GET_CAP                        0x40000
+#define GET_STATS              0x50000
+#define GET_IOCTL_VERSION      0x01
+
+#define EXT_IOCTL_SIGN_SZ      16
+#define EXT_IOCTL_SIGN         "$$_EXTD_IOCTL_$$"
+
+#define        MBOX_LEGACY             0x00            /* ioctl has legacy mbox*/
+#define MBOX_HPE               0x01            /* ioctl has hpe mbox   */
+
+#define        APPTYPE_MIMD            0x00            /* old existing apps    */
+#define APPTYPE_UIOC           0x01            /* new apps using uioc  */
+
+#define IOCTL_ISSUE            0x00000001      /* Issue ioctl          */
+#define IOCTL_ABORT            0x00000002      /* Abort previous ioctl */
+
+#define DRVRTYPE_MBOX          0x00000001      /* regular mbox driver  */
+#define DRVRTYPE_HPE           0x00000002      /* new hpe driver       */
+
+#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) )
+#define GETADAP(mkadap)        ((mkadap) ^ MEGAIOC_MAGIC << 8)
+
+#define MAX_DMA_POOLS          5               /* 4k, 8k, 16k, 32k, 64k*/
+
+
+/**
+ * struct uioc_t - the common ioctl packet structure
+ *
+ * @signature  : Must be "$$_EXTD_IOCTL_$$"
+ * @mb_type    : Type of the mail box (MB_LEGACY or MB_HPE)
+ * @app_type   : Type of the issuing application (existing or new)
+ * @opcode     : Opcode of the command
+ * @adapno     : Adapter number
+ * @cmdbuf     : Pointer to buffer - can point to mbox or plain data buffer
+ * @xferlen    : xferlen for DCMD and non mailbox commands
+ * @data_dir   : Direction of the data transfer
+ * @status     : Status from the driver
+ * @reserved   : reserved bytes for future expansion
+ *
+ * @user_data  : user data transfer address is saved in this
+ * @user_data_len: length of the data buffer sent by user app
+ * @user_pthru : user passthru address is saves in this (null if DCMD)
+ * @pthru32    : kernel address passthru (allocated per kioc)
+ * @pthru32_h  : physicall address of @pthru32
+ * @list       : for kioc free pool list maintenance
+ * @done       : call back routine for llds to call when kioc is completed
+ * @buf_vaddr  : dma pool buffer attached to kioc for data transfer
+ * @buf_paddr  : physical address of the dma pool buffer
+ * @pool_index : index of the dma pool that @buf_vaddr is taken from
+ * @free_buf   : indicates if buffer needs to be freed after kioc completes
+ *
+ * Note                : All LSI drivers understand only this packet. Any other
+ *             : format sent by applications would be converted to this.
+ */
+typedef struct uioc {
+
+/* User Apps: */
+
+       uint8_t                 signature[EXT_IOCTL_SIGN_SZ];
+       uint16_t                mb_type;
+       uint16_t                app_type;
+       uint32_t                opcode;
+       uint32_t                adapno;
+       uint64_t                cmdbuf;
+       uint32_t                xferlen;
+       uint32_t                data_dir;
+       int32_t                 status;
+       uint8_t                 reserved[128];
+
+/* Driver Data: */
+       void __user *           user_data;
+       uint32_t                user_data_len;
+       mraid_passthru_t        __user *user_pthru;
+
+       mraid_passthru_t        *pthru32;
+       dma_addr_t              pthru32_h;
+
+       struct list_head        list;
+       void                    (*done)(struct uioc*);
+
+       caddr_t                 buf_vaddr;
+       dma_addr_t              buf_paddr;
+       uint8_t                 pool_index;
+       uint8_t                 free_buf;
+
+} __attribute__ ((aligned(1024),packed)) uioc_t;
+
+
+/**
+ * struct mraid_hba_info - information about the controller
+ *
+ * @param pci_vendor_id                : PCI vendor id
+ * @param pci_device_id                : PCI device id
+ * @param subsystem_vendor_id  : PCI subsystem vendor id
+ * @param subsystem_device_id  : PCI subsystem device id
+ * @param baseport             : base port of hba memory
+ * @param pci_bus              : PCI bus
+ * @param pci_dev_fn           : PCI device/function values
+ * @param irq                  : interrupt vector for the device
+ *
+ * Extended information of 256 bytes about the controller. Align on the single
+ * byte boundary so that 32-bit applications can be run on 64-bit platform
+ * drivers withoug re-compilation.
+ * NOTE: reduce the number of reserved bytes whenever new field are added, so
+ * that total size of the structure remains 256 bytes.
+ */
+typedef struct mraid_hba_info {
+
+       uint16_t        pci_vendor_id;
+       uint16_t        pci_device_id;
+       uint16_t        subsys_vendor_id;
+       uint16_t        subsys_device_id;
+
+       uint64_t        baseport;
+       uint8_t         pci_bus;
+       uint8_t         pci_dev_fn;
+       uint8_t         pci_slot;
+       uint8_t         irq;
+
+       uint32_t        unique_id;
+       uint32_t        host_no;
+
+       uint8_t         num_ldrv;
+} __attribute__ ((aligned(256), packed)) mraid_hba_info_t;
+
+
+/**
+ * mcontroller : adapter info structure for old mimd_t apps
+ *
+ * @base       : base address
+ * @irq                : irq number
+ * @numldrv    : number of logical drives
+ * @pcibus     : pci bus
+ * @pcidev     : pci device
+ * @pcifun     : pci function
+ * @pciid      : pci id
+ * @pcivendor  : vendor id
+ * @pcislot    : slot number
+ * @uid                : unique id
+ */
+typedef struct mcontroller {
+
+       uint64_t        base;
+       uint8_t         irq;
+       uint8_t         numldrv;
+       uint8_t         pcibus;
+       uint16_t        pcidev;
+       uint8_t         pcifun;
+       uint16_t        pciid;
+       uint16_t        pcivendor;
+       uint8_t         pcislot;
+       uint32_t        uid;
+
+} __attribute__ ((packed)) mcontroller_t;
+
+
+/**
+ * mm_dmapool_t        : Represents one dma pool with just one buffer
+ *
+ * @vaddr      : Virtual address
+ * @paddr      : DMA physicall address
+ * @bufsize    : In KB - 4 = 4k, 8 = 8k etc.
+ * @handle     : Handle to the dma pool
+ * @lock       : lock to synchronize access to the pool
+ * @in_use     : If pool already in use, attach new block
+ */
+typedef struct mm_dmapool {
+       caddr_t         vaddr;
+       dma_addr_t      paddr;
+       uint32_t        buf_size;
+       struct dma_pool *handle;
+       spinlock_t      lock;
+       uint8_t         in_use;
+} mm_dmapool_t;
+
+
+/**
+ * mraid_mmadp_t: Structure that drivers pass during (un)registration
+ *
+ * @unique_id          : Any unique id (usually PCI bus+dev+fn)
+ * @drvr_type          : megaraid or hpe (DRVRTYPE_MBOX or DRVRTYPE_HPE)
+ * @drv_data           : Driver specific; not touched by the common module
+ * @timeout            : timeout for issued kiocs
+ * @max_kioc           : Maximum ioctl packets acceptable by the lld
+ * @pdev               : pci dev; used for allocating dma'ble memory
+ * @issue_uioc         : Driver supplied routine to issue uioc_t commands
+ *                     : issue_uioc(drvr_data, kioc, ISSUE/ABORT, uioc_done)
+ * @list               : attach with the global list of adapters
+ * @kioc_list          : block of mem for @max_kioc number of kiocs
+ * @kioc_pool          : pool of free kiocs
+ * @kioc_pool_lock     : protection for free pool
+ * @kioc_semaphore     : so as not to exceed @max_kioc parallel ioctls
+ * @mbox_list          : block of mem for @max_kioc number of mboxes
+ * @pthru_dma_pool     : DMA pool to allocate passthru packets
+ * @dma_pool_list      : array of dma pools
+ */
+
+typedef struct mraid_mmadp {
+
+/* Filled by driver */
+
+       uint32_t                unique_id;
+       uint32_t                drvr_type;
+       unsigned long           drvr_data;
+       uint8_t                 timeout;
+       uint8_t                 max_kioc;
+
+       struct pci_dev          *pdev;
+
+       int(*issue_uioc)(unsigned long, uioc_t *, uint32_t);
+
+/* Maintained by common module */
+
+       struct list_head        list;
+       uioc_t                  *kioc_list;
+       struct list_head        kioc_pool;
+       spinlock_t              kioc_pool_lock;
+       struct semaphore        kioc_semaphore;
+
+       mbox64_t                *mbox_list;
+       struct dma_pool         *pthru_dma_pool;
+       mm_dmapool_t            dma_pool_list[MAX_DMA_POOLS];
+
+} mraid_mmadp_t;
+
+int mraid_mm_register_adp(mraid_mmadp_t *);
+int mraid_mm_unregister_adp(uint32_t);
+
+#endif /* _MEGARAID_IOCTL_H_ */
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
new file mode 100644 (file)
index 0000000..7afd6a5
--- /dev/null
@@ -0,0 +1,3891 @@
+/*
+ *
+ *                     Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : megaraid_mbox.c
+ * Version     : v2.20.4 (September 27 2004)
+ *
+ * Authors:
+ *     Atul Mukker             <Atul.Mukker@lsil.com>
+ *     Sreenivas Bagalkote     <Sreenivas.Bagalkote@lsil.com>
+ *     Manoj Jose              <Manoj.Jose@lsil.com>
+ *
+ * List of supported controllers
+ *
+ * OEM Product Name                    VID     DID     SSVID   SSID
+ * --- ------------                    ---     ---     ----    ----
+ * Dell PERC3/QC                       101E    1960    1028    0471
+ * Dell PERC3/DC                       101E    1960    1028    0493
+ * Dell PERC3/SC                       101E    1960    1028    0475
+ * Dell PERC3/Di                       1028    1960    1028    0123
+ * Dell PERC4/SC                       1000    1960    1028    0520
+ * Dell PERC4/DC                       1000    1960    1028    0518
+ * Dell PERC4/QC                       1000    0407    1028    0531
+ * Dell PERC4/Di                       1028    000F    1028    014A
+ * Dell PERC 4e/Si                     1028    0013    1028    016c
+ * Dell PERC 4e/Di                     1028    0013    1028    016d
+ * Dell PERC 4e/Di                     1028    0013    1028    016e
+ * Dell PERC 4e/Di                     1028    0013    1028    016f
+ * Dell PERC 4e/Di                     1028    0013    1028    0170
+ * Dell PERC 4e/DC                     1000    0408    1028    0002
+ * Dell PERC 4e/SC                     1000    0408    1028    0001
+ *
+ *
+ * LSI MegaRAID SCSI 320-0             1000    1960    1000    A520
+ * LSI MegaRAID SCSI 320-1             1000    1960    1000    0520
+ * LSI MegaRAID SCSI 320-2             1000    1960    1000    0518
+ * LSI MegaRAID SCSI 320-0X            1000    0407    1000    0530
+ * LSI MegaRAID SCSI 320-2X            1000    0407    1000    0532
+ * LSI MegaRAID SCSI 320-4X            1000    0407    1000    0531
+ * LSI MegaRAID SCSI 320-1E            1000    0408    1000    0001
+ * LSI MegaRAID SCSI 320-2E            1000    0408    1000    0002
+ * LSI MegaRAID SATA 150-4             1000    1960    1000    4523
+ * LSI MegaRAID SATA 150-6             1000    1960    1000    0523
+ * LSI MegaRAID SATA 300-4X            1000    0409    1000    3004
+ * LSI MegaRAID SATA 300-8X            1000    0409    1000    3008
+ *
+ * INTEL RAID Controller SRCU42X       1000    0407    8086    0532
+ * INTEL RAID Controller SRCS16                1000    1960    8086    0523
+ * INTEL RAID Controller SRCU42E       1000    0408    8086    0002
+ * INTEL RAID Controller SRCZCRX       1000    0407    8086    0530
+ * INTEL RAID Controller SRCS28X       1000    0409    8086    3008
+ * INTEL RAID Controller SROMBU42E     1000    0408    8086    3431
+ * INTEL RAID Controller SROMBU42E     1000    0408    8086    3499
+ * INTEL RAID Controller SRCU51L       1000    1960    8086    0520
+ *
+ *
+ * FSC MegaRAID PCI Express ROMB       1000    0408    1734    1065
+ *
+ *
+ * ACER        MegaRAID ROMB-2E                1000    0408    1025    004D
+ *
+ *
+ * For history of changes, see Documentation/ChangeLog.megaraid
+ */
+
+#include "megaraid_mbox.h"
+
+static int megaraid_init(void);
+static void megaraid_exit(void);
+
+static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *);
+static void megaraid_detach_one(struct pci_dev *);
+static void megaraid_mbox_shutdown(struct device *);
+
+static int megaraid_io_attach(adapter_t *);
+static void megaraid_io_detach(adapter_t *);
+
+static int megaraid_init_mbox(adapter_t *);
+static void megaraid_fini_mbox(adapter_t *);
+
+static int megaraid_alloc_cmd_packets(adapter_t *);
+static void megaraid_free_cmd_packets(adapter_t *);
+
+static int megaraid_mbox_setup_dma_pools(adapter_t *);
+static void megaraid_mbox_teardown_dma_pools(adapter_t *);
+
+static int megaraid_abort_handler(struct scsi_cmnd *);
+static int megaraid_reset_handler(struct scsi_cmnd *);
+
+static int mbox_post_sync_cmd(adapter_t *, uint8_t []);
+static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []);
+static int megaraid_busywait_mbox(mraid_device_t *);
+static int megaraid_mbox_product_info(adapter_t *);
+static int megaraid_mbox_extended_cdb(adapter_t *);
+static int megaraid_mbox_support_ha(adapter_t *, uint16_t *);
+static int megaraid_mbox_support_random_del(adapter_t *);
+static int megaraid_mbox_get_max_sg(adapter_t *);
+static void megaraid_mbox_enum_raid_scsi(adapter_t *);
+static void megaraid_mbox_flush_cache(adapter_t *);
+
+static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
+static void megaraid_mbox_setup_device_map(adapter_t *);
+
+static int megaraid_queue_command(struct scsi_cmnd *,
+               void (*)(struct scsi_cmnd *));
+static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *);
+static void megaraid_mbox_runpendq(adapter_t *, scb_t *);
+static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
+               struct scsi_cmnd *);
+static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
+               struct scsi_cmnd *);
+
+static irqreturn_t megaraid_isr(int, void *, struct pt_regs *);
+
+static void megaraid_mbox_dpc(unsigned long);
+
+static int megaraid_cmm_register(adapter_t *);
+static int megaraid_cmm_unregister(adapter_t *);
+static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t);
+static int megaraid_mbox_mm_command(adapter_t *, uioc_t *);
+static void megaraid_mbox_mm_done(adapter_t *, scb_t *);
+static int gather_hbainfo(adapter_t *, mraid_hba_info_t *);
+static int wait_till_fw_empty(adapter_t *);
+
+
+
+MODULE_AUTHOR("LSI Logic Corporation");
+MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MEGARAID_VERSION);
+
+/*
+ * ### modules parameters for driver ###
+ */
+
+/**
+ * Set to enable driver to expose unconfigured disk to kernel
+ */
+static int megaraid_expose_unconf_disks = 0;
+module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0);
+MODULE_PARM_DESC(unconf_disks,
+       "Set to expose unconfigured disks to kernel (default=0)");
+
+/**
+ * driver wait time if the adapter's mailbox is busy
+ */
+static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT;
+module_param_named(busy_wait, max_mbox_busy_wait, int, 0);
+MODULE_PARM_DESC(busy_wait,
+       "Max wait for mailbox in microseconds if busy (default=10)");
+
+/**
+ * number of sectors per IO command
+ */
+static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS;
+module_param_named(max_sectors, megaraid_max_sectors, int, 0);
+MODULE_PARM_DESC(max_sectors,
+       "Maximum number of sectors per IO command (default=128)");
+
+/**
+ * number of commands per logical unit
+ */
+static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN;
+module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0);
+MODULE_PARM_DESC(cmd_per_lun,
+       "Maximum number of commands per logical unit (default=64)");
+
+
+/**
+ * Fast driver load option, skip scanning for physical devices during load.
+ * This would result in non-disk devices being skipped during driver load
+ * time. These can be later added though, using /proc/scsi/scsi
+ */
+static unsigned int megaraid_fast_load = 0;
+module_param_named(fast_load, megaraid_fast_load, int, 0);
+MODULE_PARM_DESC(fast_load,
+       "Faster loading of the driver, skips physical devices! (default=0)");
+
+
+/**
+ * mraid_debug level - threshold for amount of information to be displayed by
+ * the driver. This level can be changed through modules parameters, ioctl or
+ * sysfs/proc interface. By default, print the announcement messages only.
+ */
+int mraid_debug_level = CL_ANN;
+module_param_named(debug_level, mraid_debug_level, int, 0);
+MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)");
+
+/*
+ * ### global data ###
+ */
+static uint8_t megaraid_mbox_version[8] =
+       { 0x02, 0x20, 0x04, 0x00, 9, 27, 20, 4 };
+
+
+/*
+ * PCI table for all supported controllers.
+ */
+static struct pci_device_id pci_id_table_g[] =  {
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4_DI_DISCOVERY,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4_DI_DISCOVERY,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_PERC4_SC,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4_SC,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_PERC4_DC,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4_DC,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_PERC4_QC,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4_QC,
+       },
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4_DI_EVERGLADES,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4_DI_EVERGLADES,
+       },
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4E_SI_BIGBEND,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_SI_BIGBEND,
+       },
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4E_DI_KOBUK,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_DI_KOBUK,
+       },
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4E_DI_CORVETTE,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_DI_CORVETTE,
+       },
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4E_DI_EXPEDITION,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION,
+       },
+       {
+               PCI_VENDOR_ID_DELL,
+               PCI_DEVICE_ID_PERC4E_DI_GUADALUPE,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_PERC4E_DC_320_2E,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_DC_320_2E,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_PERC4E_SC_320_1E,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC4E_SC_320_1E,
+       },
+       {
+               PCI_VENDOR_ID_AMI,
+               PCI_DEVICE_ID_AMI_MEGARAID3,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC3_QC,
+       },
+       {
+               PCI_VENDOR_ID_AMI,
+               PCI_DEVICE_ID_AMI_MEGARAID3,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC3_DC,
+       },
+       {
+               PCI_VENDOR_ID_AMI,
+               PCI_DEVICE_ID_AMI_MEGARAID3,
+               PCI_VENDOR_ID_DELL,
+               PCI_SUBSYS_ID_PERC3_SC,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_0,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_0,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_1,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_1,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_2,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_2,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_0x,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_2x,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_4x,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_1E,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SCSI_320_2E,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_I4_133_RAID,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_I4_133_RAID,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SATA_150_4,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SATA_150_4,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SATA_150_6,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SATA_150_6,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SATA_300_4x,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SATA_300_4x,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_SATA_300_8x,
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_SUBSYS_ID_MEGARAID_SATA_300_8x,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SRCU42X,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SRCU42X,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SRCS16,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SRCS16,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SRCU42E,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SRCU42E,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SRCZCRX,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SRCS28X,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SRCS28X,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
+               PCI_VENDOR_ID_INTEL,
+               PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB,
+               PCI_SUBSYS_ID_FSC,
+               PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB,
+       },
+       {
+               PCI_VENDOR_ID_LSI_LOGIC,
+               PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E,
+               PCI_VENDOR_ID_AI,
+               PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E,
+       },
+       {0}     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, pci_id_table_g);
+
+
+static struct pci_driver megaraid_pci_driver_g = {
+       .name           = "megaraid",
+       .id_table       = pci_id_table_g,
+       .probe          = megaraid_probe_one,
+       .remove         = __devexit_p(megaraid_detach_one),
+       .driver         = {
+               .shutdown       = megaraid_mbox_shutdown,
+       }
+};
+
+
+/*
+ * Scsi host template for megaraid unified driver
+ */
+static struct scsi_host_template megaraid_template_g = {
+       .module                         = THIS_MODULE,
+       .name                           = "LSI Logic MegaRAID driver",
+       .proc_name                      = "megaraid",
+       .queuecommand                   = megaraid_queue_command,
+       .eh_abort_handler               = megaraid_abort_handler,
+       .eh_device_reset_handler        = megaraid_reset_handler,
+       .eh_bus_reset_handler           = megaraid_reset_handler,
+       .eh_host_reset_handler          = megaraid_reset_handler,
+       .use_clustering                 = ENABLE_CLUSTERING,
+};
+
+
+/**
+ * megaraid_init - module load hook
+ *
+ * We register ourselves as hotplug enabled module and let PCI subsystem
+ * discover our adaters
+ **/
+static int __init
+megaraid_init(void)
+{
+       int     rval;
+
+       // Announce the driver version
+       con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION,
+               MEGARAID_EXT_VERSION));
+
+       // check validity of module parameters
+       if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mailbox: max commands per lun reset to %d\n",
+                       MBOX_MAX_SCSI_CMDS));
+
+               megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS;
+       }
+
+
+       // register as a PCI hot-plug driver module
+       if ((rval = pci_module_init(&megaraid_pci_driver_g))) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: could not register hotplug support.\n"));
+       }
+
+       return rval;
+}
+
+
+/**
+ * megaraid_exit - driver unload entry point
+ *
+ * We simply unwrap the megaraid_init routine here
+ */
+static void __exit
+megaraid_exit(void)
+{
+       con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
+
+       // unregister as PCI hotplug driver
+       pci_unregister_driver(&megaraid_pci_driver_g);
+
+       return;
+}
+
+
+/**
+ * megaraid_probe_one - PCI hotplug entry point
+ * @param pdev : handle to this controller's PCI configuration space
+ * @param id   : pci device id of the class of controllers
+ *
+ * This routine should be called whenever a new adapter is detected by the
+ * PCI hotplug susbsytem.
+ **/
+static int __devinit
+megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       adapter_t       *adapter;
+
+
+       // detected a new controller
+       con_log(CL_ANN, (KERN_INFO
+               "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
+               pdev->vendor, pdev->device, pdev->subsystem_vendor,
+               pdev->subsystem_device));
+
+       con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number,
+               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)));
+
+       if (pci_enable_device(pdev)) {
+               con_log(CL_ANN, (KERN_WARNING
+                               "megaraid: pci_enable_device failed\n"));
+
+               return -ENODEV;
+       }
+
+       // Enable bus-mastering on this controller
+       pci_set_master(pdev);
+
+       // Allocate the per driver initialization structure
+       adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
+
+       if (adapter == NULL) {
+               con_log(CL_ANN, (KERN_WARNING
+               "megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__));
+
+               goto out_probe_one;
+       }
+       memset(adapter, 0, sizeof(adapter_t));
+
+
+       // set up PCI related soft state and other pre-known parameters
+       adapter->unique_id      = pdev->bus->number << 8 | pdev->devfn;
+       adapter->irq            = pdev->irq;
+       adapter->pdev           = pdev;
+
+       atomic_set(&adapter->being_detached, 0);
+
+       // Setup the default DMA mask. This would be changed later on
+       // depending on hardware capabilities
+       if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFF) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: pci_set_dma_mask failed:%d\n", __LINE__));
+
+               goto out_free_adapter;
+       }
+
+
+       // Initialize the synchronization lock for kernel and LLD
+       spin_lock_init(&adapter->lock);
+       adapter->host_lock = &adapter->lock;
+
+
+       // Initialize the command queues: the list of free SCBs and the list
+       // of pending SCBs.
+       INIT_LIST_HEAD(&adapter->kscb_pool);
+       spin_lock_init(SCSI_FREE_LIST_LOCK(adapter));
+
+       INIT_LIST_HEAD(&adapter->pend_list);
+       spin_lock_init(PENDING_LIST_LOCK(adapter));
+
+       INIT_LIST_HEAD(&adapter->completed_list);
+       spin_lock_init(COMPLETED_LIST_LOCK(adapter));
+
+
+       // Start the mailbox based controller
+       if (megaraid_init_mbox(adapter) != 0) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: maibox adapter did not initialize\n"));
+
+               goto out_free_adapter;
+       }
+
+       // Register with LSI Common Management Module
+       if (megaraid_cmm_register(adapter) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING
+               "megaraid: could not register with management module\n"));
+
+               goto out_fini_mbox;
+       }
+
+       // setup adapter handle in PCI soft state
+       pci_set_drvdata(pdev, adapter);
+
+       // attach with scsi mid-layer
+       if (megaraid_io_attach(adapter) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n"));
+
+               goto out_cmm_unreg;
+       }
+
+       return 0;
+
+out_cmm_unreg:
+       pci_set_drvdata(pdev, NULL);
+       megaraid_cmm_unregister(adapter);
+out_fini_mbox:
+       megaraid_fini_mbox(adapter);
+out_free_adapter:
+       kfree(adapter);
+out_probe_one:
+       pci_disable_device(pdev);
+
+       return -ENODEV;
+}
+
+
+/**
+ * megaraid_detach_one - release the framework resources and call LLD release
+ * routine
+ * @param pdev : handle for our PCI cofiguration space
+ *
+ * This routine is called during driver unload. We free all the allocated
+ * resources and call the corresponding LLD so that it can also release all
+ * its resources.
+ *
+ * This routine is also called from the PCI hotplug system
+ **/
+static void
+megaraid_detach_one(struct pci_dev *pdev)
+{
+       adapter_t               *adapter;
+       struct Scsi_Host        *host;
+
+
+       // Start a rollback on this adapter
+       adapter = pci_get_drvdata(pdev);
+
+       if (!adapter) {
+               con_log(CL_ANN, (KERN_CRIT
+               "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
+                       pdev->vendor, pdev->device, pdev->subsystem_vendor,
+                       pdev->subsystem_device));
+
+               return;
+       }
+       else {
+               con_log(CL_ANN, (KERN_NOTICE
+               "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
+                       pdev->vendor, pdev->device, pdev->subsystem_vendor,
+                       pdev->subsystem_device));
+       }
+
+
+       host = adapter->host;
+
+       // do not allow any more requests from the management module for this
+       // adapter.
+       // FIXME: How do we account for the request which might still be
+       // pending with us?
+       atomic_set(&adapter->being_detached, 1);
+
+       // detach from the IO sub-system
+       megaraid_io_detach(adapter);
+
+       // reset the device state in the PCI structure. We check this
+       // condition when we enter here. If the device state is NULL,
+       // that would mean the device has already been removed
+       pci_set_drvdata(pdev, NULL);
+
+       // Unregister from common management module
+       //
+       // FIXME: this must return success or failure for conditions if there
+       // is a command pending with LLD or not.
+       megaraid_cmm_unregister(adapter);
+
+       // finalize the mailbox based controller and release all resources
+       megaraid_fini_mbox(adapter);
+
+       kfree(adapter);
+
+       scsi_host_put(host);
+
+       pci_disable_device(pdev);
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA
+ * @param device       : generice driver model device
+ *
+ * Shutdown notification, perform flush cache
+ */
+static void
+megaraid_mbox_shutdown(struct device *device)
+{
+       adapter_t               *adapter = pci_get_drvdata(to_pci_dev(device));
+       static int              counter;
+
+       if (!adapter) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: null device in shutdown\n"));
+               return;
+       }
+
+       // flush caches now
+       con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...",
+               counter++));
+
+       megaraid_mbox_flush_cache(adapter);
+
+       con_log(CL_ANN, ("done\n"));
+}
+
+
+/**
+ * megaraid_io_attach - attach a device with the IO subsystem
+ * @param adapter      : controller's soft state
+ *
+ * Attach this device with the IO subsystem
+ **/
+static int
+megaraid_io_attach(adapter_t *adapter)
+{
+       struct Scsi_Host        *host;
+
+       // Initialize SCSI Host structure
+       host = scsi_host_alloc(&megaraid_template_g, 8);
+       if (!host) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mbox: scsi_register failed\n"));
+
+               return -1;
+       }
+
+       SCSIHOST2ADAP(host)     = (caddr_t)adapter;
+       adapter->host           = host;
+
+       // export the parameters required by the mid-layer
+       scsi_assign_lock(host, adapter->host_lock);
+       scsi_set_device(host, &adapter->pdev->dev);
+
+       host->irq               = adapter->irq;
+       host->unique_id         = adapter->unique_id;
+       host->can_queue         = adapter->max_cmds;
+       host->this_id           = adapter->init_id;
+       host->sg_tablesize      = adapter->sglen;
+       host->max_sectors       = adapter->max_sectors;
+       host->cmd_per_lun       = adapter->cmd_per_lun;
+       host->max_channel       = adapter->max_channel;
+       host->max_id            = adapter->max_target;
+       host->max_lun           = adapter->max_lun;
+
+
+       // notify mid-layer about the new controller
+       if (scsi_add_host(host, &adapter->pdev->dev)) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mbox: scsi_add_host failed\n"));
+
+               scsi_host_put(host);
+
+               return -1;
+       }
+
+       scsi_scan_host(host);
+
+       return 0;
+}
+
+
+/**
+ * megaraid_io_detach - detach a device from the IO subsystem
+ * @param adapter      : controller's soft state
+ *
+ * Detach this device from the IO subsystem
+ **/
+static void
+megaraid_io_detach(adapter_t *adapter)
+{
+       struct Scsi_Host        *host;
+
+       con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n"));
+
+       host = adapter->host;
+
+       scsi_remove_host(host);
+
+       return;
+}
+
+
+/*
+ * START: Mailbox Low Level Driver
+ *
+ * This is section specific to the single mailbox based controllers
+ */
+
+/**
+ * megaraid_init_mbox - initialize controller
+ * @param adapter      - our soft state
+ *
+ * . Allocate 16-byte aligned mailbox memory for firmware handshake
+ * . Allocate controller's memory resources
+ * . Find out all initialization data
+ * . Allocate memory required for all the commands
+ * . Use internal library of FW routines, build up complete soft state
+ */
+static int __init
+megaraid_init_mbox(adapter_t *adapter)
+{
+       struct pci_dev          *pdev;
+       mraid_device_t          *raid_dev;
+       int                     i;
+
+
+       adapter->ito    = MBOX_TIMEOUT;
+       pdev            = adapter->pdev;
+
+       /*
+        * Allocate and initialize the init data structure for mailbox
+        * controllers
+        */
+       raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
+       if (raid_dev == NULL) return -1;
+
+       memset(raid_dev, 0, sizeof(mraid_device_t));
+
+       /*
+        * Attach the adapter soft state to raid device soft state
+        */
+       adapter->raid_device    = (caddr_t)raid_dev;
+       raid_dev->fast_load     = megaraid_fast_load;
+
+
+       // our baseport
+       raid_dev->baseport = pci_resource_start(pdev, 0);
+
+       if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                               "megaraid: mem region busy\n"));
+
+               goto out_free_raid_dev;
+       }
+
+       raid_dev->baseaddr = (unsigned long)
+                       ioremap_nocache(raid_dev->baseport, 128);
+
+       if (!raid_dev->baseaddr) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: could not map hba memory\n") );
+
+               goto out_release_regions;
+       }
+
+       //
+       // Setup the rest of the soft state using the library of FW routines
+       //
+
+       // request IRQ and register the interrupt service routine
+       if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid",
+               adapter)) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: Couldn't register IRQ %d!\n", adapter->irq));
+
+               goto out_iounmap;
+       }
+
+
+       // initialize the mutual exclusion lock for the mailbox
+       spin_lock_init(&raid_dev->mailbox_lock);
+
+       // allocate memory required for commands
+       if (megaraid_alloc_cmd_packets(adapter) != 0) {
+               goto out_free_irq;
+       }
+
+       // Product info
+       if (megaraid_mbox_product_info(adapter) != 0) {
+               goto out_alloc_cmds;
+       }
+
+       // Do we support extended CDBs
+       adapter->max_cdb_sz = 10;
+       if (megaraid_mbox_extended_cdb(adapter) == 0) {
+               adapter->max_cdb_sz = 16;
+       }
+
+       /*
+        * Do we support cluster environment, if we do, what is the initiator
+        * id.
+        * NOTE: In a non-cluster aware firmware environment, the LLD should
+        * return 7 as initiator id.
+        */
+       adapter->ha             = 0;
+       adapter->init_id        = -1;
+       if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) {
+               adapter->ha = 1;
+       }
+
+       /*
+        * Prepare the device ids array to have the mapping between the kernel
+        * device address and megaraid device address.
+        * We export the physical devices on their actual addresses. The
+        * logical drives are exported on a virtual SCSI channel
+        */
+       megaraid_mbox_setup_device_map(adapter);
+
+       // If the firmware supports random deletion, update the device id map
+       if (megaraid_mbox_support_random_del(adapter)) {
+
+               // Change the logical drives numbers in device_ids array one
+               // slot in device_ids is reserved for target id, that's why
+               // "<=" below
+               for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) {
+                       adapter->device_ids[adapter->max_channel][i] += 0x80;
+               }
+               adapter->device_ids[adapter->max_channel][adapter->init_id] =
+                       0xFF;
+       }
+
+       /*
+        * find out the maximum number of scatter-gather elements supported by
+        * this firmware
+        */
+       adapter->sglen = megaraid_mbox_get_max_sg(adapter);
+
+       // enumerate RAID and SCSI channels so that all devices on SCSI
+       // channels can later be exported, including disk devices
+       megaraid_mbox_enum_raid_scsi(adapter);
+
+       /*
+        * Other parameters required by upper layer
+        *
+        * maximum number of sectors per IO command
+        */
+       adapter->max_sectors = megaraid_max_sectors;
+
+       /*
+        * number of queued commands per LUN.
+        */
+       adapter->cmd_per_lun = megaraid_cmd_per_lun;
+
+       // Set the DMA mask to 64-bit. All supported controllers as capable of
+       // DMA in this range
+       if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFFFFFFFFFFULL) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: could not set DMA mask for 64-bit.\n"));
+
+               goto out_alloc_cmds;
+       }
+
+       // setup tasklet for DPC
+       tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc,
+                       (unsigned long)adapter);
+
+       con_log(CL_DLEVEL1, (KERN_INFO
+               "megaraid mbox hba successfully initialized\n"));
+
+       return 0;
+
+out_alloc_cmds:
+       megaraid_free_cmd_packets(adapter);
+out_free_irq:
+       free_irq(adapter->irq, adapter);
+out_iounmap:
+       iounmap((caddr_t)raid_dev->baseaddr);
+out_release_regions:
+       pci_release_regions(pdev);
+out_free_raid_dev:
+       kfree(raid_dev);
+
+       return -1;
+}
+
+
+/**
+ * megaraid_fini_mbox - undo controller initialization
+ * @param adapter      : our soft state
+ */
+static void
+megaraid_fini_mbox(adapter_t *adapter)
+{
+       mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
+
+       // flush all caches
+       megaraid_mbox_flush_cache(adapter);
+
+       tasklet_kill(&adapter->dpc_h);
+
+       megaraid_free_cmd_packets(adapter);
+
+       free_irq(adapter->irq, adapter);
+
+       iounmap((caddr_t)raid_dev->baseaddr);
+
+       pci_release_regions(adapter->pdev);
+
+       kfree(raid_dev);
+
+       return;
+}
+
+
+/**
+ * megaraid_alloc_cmd_packets - allocate shared mailbox
+ * @param adapter      : soft state of the raid controller
+ *
+ * Allocate and align the shared mailbox. This maibox is used to issue
+ * all the commands. For IO based controllers, the mailbox is also regsitered
+ * with the FW. Allocate memory for all commands as well.
+ * This is our big allocator
+ */
+static int
+megaraid_alloc_cmd_packets(adapter_t *adapter)
+{
+       mraid_device_t          *raid_dev = ADAP2RAIDDEV(adapter);
+       struct pci_dev          *pdev;
+       unsigned long           align;
+       scb_t                   *scb;
+       mbox_ccb_t              *ccb;
+       struct mraid_pci_blk    *epthru_pci_blk;
+       struct mraid_pci_blk    *sg_pci_blk;
+       struct mraid_pci_blk    *mbox_pci_blk;
+       int                     i;
+
+       pdev = adapter->pdev;
+
+       /*
+        * Setup the mailbox
+        * Allocate the common 16-byte aligned memory for the handshake
+        * mailbox.
+        */
+       raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev,
+                       sizeof(mbox64_t), &raid_dev->una_mbox64_dma);
+
+       if (!raid_dev->una_mbox64) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+               return -1;
+       }
+       memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t));
+
+       /*
+        * Align the mailbox at 16-byte boundary
+        */
+       raid_dev->mbox  = &raid_dev->una_mbox64->mbox32;
+
+       raid_dev->mbox  = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) &
+                               (~0UL ^ 0xFUL));
+
+       raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8);
+
+       align = ((void *)raid_dev->mbox -
+                       ((void *)&raid_dev->una_mbox64->mbox32));
+
+       raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 +
+                       align;
+
+       // Allocate memory for commands issued internally
+       adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE,
+                               &adapter->ibuf_dma_h);
+       if (!adapter->ibuf) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+
+               goto out_free_common_mbox;
+       }
+       memset(adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+       // Allocate memory for our SCSI Command Blocks and their associated
+       // memory
+
+       /*
+        * Allocate memory for the base list of scb. Later allocate memory for
+        * CCBs and embedded components of each CCB and point the pointers in
+        * scb to the allocated components
+        * NOTE: The code to allocate SCB will be duplicated in all the LLD
+        * since the calling routine does not yet know the number of available
+        * commands.
+        */
+       adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
+                       GFP_KERNEL);
+
+       if (adapter->kscb_list == NULL) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+               goto out_free_ibuf;
+       }
+       memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
+
+       // memory allocation for our command packets
+       if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+               goto out_free_scb_list;
+       }
+
+       // Adjust the scb pointers and link in the free pool
+       epthru_pci_blk  = raid_dev->epthru_pool;
+       sg_pci_blk      = raid_dev->sg_pool;
+       mbox_pci_blk    = raid_dev->mbox_pool;
+
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+               scb                     = adapter->kscb_list + i;
+               ccb                     = raid_dev->ccb_list + i;
+
+               ccb->mbox       = (mbox_t *)(mbox_pci_blk[i].vaddr + 16);
+               ccb->raw_mbox   = (uint8_t *)ccb->mbox;
+               ccb->mbox64     = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8);
+               ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16;
+
+               // make sure the mailbox is aligned properly
+               if (ccb->mbox_dma_h & 0x0F) {
+                       con_log(CL_ANN, (KERN_CRIT
+                               "megaraid mbox: not aligned on 16-bytes\n"));
+
+                       goto out_teardown_dma_pools;
+               }
+
+               ccb->epthru             = (mraid_epassthru_t *)
+                                               epthru_pci_blk[i].vaddr;
+               ccb->epthru_dma_h       = epthru_pci_blk[i].dma_addr;
+               ccb->pthru              = (mraid_passthru_t *)ccb->epthru;
+               ccb->pthru_dma_h        = ccb->epthru_dma_h;
+
+
+               ccb->sgl64              = (mbox_sgl64 *)sg_pci_blk[i].vaddr;
+               ccb->sgl_dma_h          = sg_pci_blk[i].dma_addr;
+               ccb->sgl32              = (mbox_sgl32 *)ccb->sgl64;
+
+               scb->ccb                = (caddr_t)ccb;
+               scb->gp                 = 0;
+
+               scb->sno                = i;    // command index
+
+               scb->scp                = NULL;
+               scb->state              = SCB_FREE;
+               scb->dma_direction      = PCI_DMA_NONE;
+               scb->dma_type           = MRAID_DMA_NONE;
+               scb->dev_channel        = -1;
+               scb->dev_target         = -1;
+
+               // put scb in the free pool
+               list_add_tail(&scb->list, &adapter->kscb_pool);
+       }
+
+       return 0;
+
+out_teardown_dma_pools:
+       megaraid_mbox_teardown_dma_pools(adapter);
+out_free_scb_list:
+       kfree(adapter->kscb_list);
+out_free_ibuf:
+       pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf,
+               adapter->ibuf_dma_h);
+out_free_common_mbox:
+       pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
+               (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
+
+       return -1;
+}
+
+
+/**
+ * megaraid_free_cmd_packets - free memory
+ * @param adapter      : soft state of the raid controller
+ *
+ * Release memory resources allocated for commands
+ */
+static void
+megaraid_free_cmd_packets(adapter_t *adapter)
+{
+       mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
+
+       megaraid_mbox_teardown_dma_pools(adapter);
+
+       kfree(adapter->kscb_list);
+
+       pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE,
+               (void *)adapter->ibuf, adapter->ibuf_dma_h);
+
+       pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
+               (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
+       return;
+}
+
+
+/**
+ * megaraid_mbox_setup_dma_pools - setup dma pool for command packets
+ * @param adapter      : HBA soft state
+ *
+ * setup the dma pools for mailbox, passthru and extended passthru structures,
+ * and scatter-gather lists
+ */
+static int
+megaraid_mbox_setup_dma_pools(adapter_t *adapter)
+{
+       mraid_device_t          *raid_dev = ADAP2RAIDDEV(adapter);
+       struct mraid_pci_blk    *epthru_pci_blk;
+       struct mraid_pci_blk    *sg_pci_blk;
+       struct mraid_pci_blk    *mbox_pci_blk;
+       int                     i;
+
+
+
+       // Allocate memory for 16-bytes aligned mailboxes
+       raid_dev->mbox_pool_handle = pci_pool_create("megaraid mbox pool",
+                                               adapter->pdev,
+                                               sizeof(mbox64_t) + 16,
+                                               16, 0);
+
+       if (raid_dev->mbox_pool_handle == NULL) {
+               goto fail_setup_dma_pool;
+       }
+
+       mbox_pci_blk = raid_dev->mbox_pool;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+               mbox_pci_blk[i].vaddr = pci_pool_alloc(
+                                               raid_dev->mbox_pool_handle,
+                                               GFP_KERNEL,
+                                               &mbox_pci_blk[i].dma_addr);
+               if (!mbox_pci_blk[i].vaddr) {
+                       goto fail_setup_dma_pool;
+               }
+       }
+
+       /*
+        * Allocate memory for each embedded passthru strucuture pointer
+        * Request for a 128 bytes aligned structure for each passthru command
+        * structure
+        * Since passthru and extended passthru commands are exclusive, they
+        * share common memory pool. Passthru structures piggyback on memory
+        * allocted to extended passthru since passthru is smaller of the two
+        */
+       raid_dev->epthru_pool_handle = pci_pool_create("megaraid mbox pthru",
+                       adapter->pdev, sizeof(mraid_epassthru_t), 128, 0);
+
+       if (raid_dev->epthru_pool_handle == NULL) {
+               goto fail_setup_dma_pool;
+       }
+
+       epthru_pci_blk = raid_dev->epthru_pool;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+               epthru_pci_blk[i].vaddr = pci_pool_alloc(
+                                               raid_dev->epthru_pool_handle,
+                                               GFP_KERNEL,
+                                               &epthru_pci_blk[i].dma_addr);
+               if (!epthru_pci_blk[i].vaddr) {
+                       goto fail_setup_dma_pool;
+               }
+       }
+
+
+       // Allocate memory for each scatter-gather list. Request for 512 bytes
+       // alignment for each sg list
+       raid_dev->sg_pool_handle = pci_pool_create("megaraid mbox sg",
+                                       adapter->pdev,
+                                       sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE,
+                                       512, 0);
+
+       if (raid_dev->sg_pool_handle == NULL) {
+               goto fail_setup_dma_pool;
+       }
+
+       sg_pci_blk = raid_dev->sg_pool;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+               sg_pci_blk[i].vaddr = pci_pool_alloc(
+                                               raid_dev->sg_pool_handle,
+                                               GFP_KERNEL,
+                                               &sg_pci_blk[i].dma_addr);
+               if (!sg_pci_blk[i].vaddr) {
+                       goto fail_setup_dma_pool;
+               }
+       }
+
+       return 0;
+
+fail_setup_dma_pool:
+       megaraid_mbox_teardown_dma_pools(adapter);
+       return -1;
+}
+
+
+/**
+ * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets
+ * @param adapter      : HBA soft state
+ *
+ * teardown the dma pool for mailbox, passthru and extended passthru
+ * structures, and scatter-gather lists
+ */
+static void
+megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
+{
+       mraid_device_t          *raid_dev = ADAP2RAIDDEV(adapter);
+       struct mraid_pci_blk    *epthru_pci_blk;
+       struct mraid_pci_blk    *sg_pci_blk;
+       struct mraid_pci_blk    *mbox_pci_blk;
+       int                     i;
+
+
+       sg_pci_blk = raid_dev->sg_pool;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) {
+               pci_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr,
+                       sg_pci_blk[i].dma_addr);
+       }
+       if (raid_dev->sg_pool_handle)
+               pci_pool_destroy(raid_dev->sg_pool_handle);
+
+
+       epthru_pci_blk = raid_dev->epthru_pool;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) {
+               pci_pool_free(raid_dev->epthru_pool_handle,
+                       epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr);
+       }
+       if (raid_dev->epthru_pool_handle)
+               pci_pool_destroy(raid_dev->epthru_pool_handle);
+
+
+       mbox_pci_blk = raid_dev->mbox_pool;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) {
+               pci_pool_free(raid_dev->mbox_pool_handle,
+                       mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr);
+       }
+       if (raid_dev->mbox_pool_handle)
+               pci_pool_destroy(raid_dev->mbox_pool_handle);
+
+       return;
+}
+
+
+/**
+ * megaraid_alloc_scb - detach and return a scb from the free list
+ * @adapter    : controller's soft state
+ *
+ * return the scb from the head of the free list. NULL if there are none
+ * available
+ **/
+static inline scb_t *
+megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
+{
+       struct list_head        *head = &adapter->kscb_pool;
+       scb_t                   *scb = NULL;
+       unsigned long           flags;
+
+       // detach scb from free pool
+       spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+       if (list_empty(head)) {
+               spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
+               return NULL;
+       }
+
+       scb = list_entry(head->next, scb_t, list);
+       list_del_init(&scb->list);
+
+       spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+       scb->state      = SCB_ACTIVE;
+       scb->scp        = scp;
+       scb->dma_type   = MRAID_DMA_NONE;
+
+       return scb;
+}
+
+
+/**
+ * megaraid_dealloc_scb - return the scb to the free pool
+ * @adapter    : controller's soft state
+ * @scb                : scb to be freed
+ *
+ * return the scb back to the free list of scbs. The caller must 'flush' the
+ * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc.
+ * NOTE NOTE: Make sure the scb is not on any list before calling this
+ * routine.
+ **/
+static inline void
+megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
+{
+       unsigned long           flags;
+
+       // put scb in the free pool
+       scb->state      = SCB_FREE;
+       scb->scp        = NULL;
+       spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+       list_add(&scb->list, &adapter->kscb_pool);
+
+       spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_mksgl - make the scatter-gather list
+ * @adapter    - controller's soft state
+ * @scb                - scsi control block
+ *
+ * prepare the scatter-gather list
+ */
+static inline int
+megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
+{
+       struct scatterlist      *sgl;
+       mbox_ccb_t              *ccb;
+       struct page             *page;
+       unsigned long           offset;
+       struct scsi_cmnd        *scp;
+       int                     sgcnt;
+       int                     i;
+
+
+       scp     = scb->scp;
+       ccb     = (mbox_ccb_t *)scb->ccb;
+
+       // no mapping required if no data to be transferred
+       if (!scp->request_buffer || !scp->request_bufflen)
+               return 0;
+
+       if (!scp->use_sg) {     /* scatter-gather list not used */
+
+               page = virt_to_page(scp->request_buffer);
+
+               offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK);
+
+               ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset,
+                                                 scp->request_bufflen,
+                                                 scb->dma_direction);
+               scb->dma_type = MRAID_DMA_WBUF;
+
+               /*
+                * We need to handle special 64-bit commands that need a
+                * minimum of 1 SG
+                */
+               sgcnt = 1;
+               ccb->sgl64[0].address   = ccb->buf_dma_h;
+               ccb->sgl64[0].length    = scp->request_bufflen;
+
+               return sgcnt;
+       }
+
+       sgl = (struct scatterlist *)scp->request_buffer;
+
+       // The number of sg elements returned must not exceed our limit
+       sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg,
+                       scb->dma_direction);
+
+       if (sgcnt > adapter->sglen) {
+               con_log(CL_ANN, (KERN_CRIT
+                       "megaraid critical: too many sg elements:%d\n",
+                       sgcnt));
+               BUG();
+       }
+
+       scb->dma_type = MRAID_DMA_WSG;
+
+       for (i = 0; i < sgcnt; i++, sgl++) {
+               ccb->sgl64[i].address   = sg_dma_address(sgl);
+               ccb->sgl64[i].length    = sg_dma_len(sgl);
+       }
+
+       // Return count of SG nodes
+       return sgcnt;
+}
+
+
+/**
+ * mbox_post_cmd - issue a mailbox command
+ * @adapter    - controller's soft state
+ * @scb                - command to be issued
+ *
+ * post the command to the controller if mailbox is availble.
+ */
+static inline int
+mbox_post_cmd(adapter_t *adapter, scb_t *scb)
+{
+       mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
+       mbox64_t        *mbox64;
+       mbox_t          *mbox;
+       mbox_ccb_t      *ccb;
+       unsigned long   flags;
+       unsigned int    i = 0;
+
+
+       ccb     = (mbox_ccb_t *)scb->ccb;
+       mbox    = raid_dev->mbox;
+       mbox64  = raid_dev->mbox64;
+
+       /*
+        * Check for busy mailbox. If it is, return failure - the caller
+        * should retry later.
+        */
+       spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
+
+       if (unlikely(mbox->busy)) {
+               do {
+                       udelay(1);
+                       i++;
+                       rmb();
+               } while(mbox->busy && (i < max_mbox_busy_wait));
+
+               if (mbox->busy) {
+
+                       spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
+
+                       return -1;
+               }
+       }
+
+
+       // Copy this command's mailbox data into "adapter's" mailbox
+       memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22);
+       mbox->cmdid = scb->sno;
+
+       adapter->outstanding_cmds++;
+
+       if (scb->dma_direction == PCI_DMA_TODEVICE) {
+               if (!scb->scp->use_sg) {        // sg list not used
+                       pci_dma_sync_single(adapter->pdev, ccb->buf_dma_h,
+                                       scb->scp->request_bufflen,
+                                       PCI_DMA_TODEVICE);
+               }
+               else {
+                       pci_dma_sync_sg(adapter->pdev, scb->scp->request_buffer,
+                               scb->scp->use_sg, PCI_DMA_TODEVICE);
+               }
+       }
+
+       mbox->busy      = 1;    // Set busy
+       mbox->poll      = 0;
+       mbox->ack       = 0;
+       wmb();
+
+       WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+       spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
+
+       return 0;
+}
+
+
+/**
+ * megaraid_queue_command - generic queue entry point for all LLDs
+ * @scp                : pointer to the scsi command to be executed
+ * @done       : callback routine to be called after the cmd has be completed
+ *
+ * Queue entry point for mailbox based controllers.
+ */
+static int
+megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *))
+{
+       adapter_t       *adapter;
+       scb_t           *scb;
+       int             if_busy;
+
+       adapter         = SCP2ADAPTER(scp);
+       scp->scsi_done  = done;
+       scp->result     = 0;
+
+       ASSERT(spin_is_locked(adapter->host_lock));
+
+       spin_unlock(adapter->host_lock);
+
+       /*
+        * Allocate and build a SCB request
+        * if_busy flag will be set if megaraid_mbox_build_cmd() command could
+        * not allocate scb. We will return non-zero status in that case.
+        * NOTE: scb can be null even though certain commands completed
+        * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would
+        * return 0 in that case, and we would do the callback right away.
+        */
+       if_busy = 0;
+       scb     = megaraid_mbox_build_cmd(adapter, scp, &if_busy);
+
+       if (scb) {
+               megaraid_mbox_runpendq(adapter, scb);
+       }
+
+       spin_lock(adapter->host_lock);
+
+       if (!scb) {     // command already completed
+               done(scp);
+       }
+
+       return if_busy;
+}
+
+
+/**
+ * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid
+ * firmware lingua
+ * @adapter    - controller's soft state
+ * @scp                - mid-layer scsi command pointer
+ * @busy       - set if request could not be completed because of lack of
+ *             resources
+ *
+ * convert the command issued by mid-layer to format understood by megaraid
+ * firmware. We also complete certain command without sending them to firmware
+ */
+static scb_t *
+megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
+{
+       mraid_device_t          *rdev = ADAP2RAIDDEV(adapter);
+       int                     channel;
+       int                     target;
+       int                     islogical;
+       mbox_ccb_t              *ccb;
+       mraid_passthru_t        *pthru;
+       mbox64_t                *mbox64;
+       mbox_t                  *mbox;
+       scb_t                   *scb;
+       char                    skip[] = "skipping";
+       char                    scan[] = "scanning";
+       char                    *ss;
+
+
+       /*
+        * Get the appropriate device map for the device this command is
+        * intended for
+        */
+       MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical);
+
+       /*
+        * Logical drive commands
+        */
+       if (islogical) {
+               switch (scp->cmnd[0]) {
+               case TEST_UNIT_READY:
+                       /*
+                        * Do we support clustering and is the support enabled
+                        * If no, return success always
+                        */
+                       if (!adapter->ha) {
+                               scp->result = (DID_OK << 16);
+                               return NULL;
+                       }
+
+                       if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+                               scp->result = (DID_ERROR << 16);
+                               *busy = 1;
+                               return NULL;
+                       }
+
+                       scb->dma_direction      = scp->sc_data_direction;
+                       scb->dev_channel        = 0xFF;
+                       scb->dev_target         = target;
+                       ccb                     = (mbox_ccb_t *)scb->ccb;
+
+                       /*
+                        * The command id will be provided by the command
+                        * issuance routine
+                        */
+                       ccb->raw_mbox[0]        = CLUSTER_CMD;
+                       ccb->raw_mbox[2]        = RESERVATION_STATUS;
+                       ccb->raw_mbox[3]        = target;
+
+                       return scb;
+
+               case MODE_SENSE:
+                       if (scp->use_sg) {
+                               struct scatterlist      *sgl;
+                               caddr_t                 vaddr;
+
+                               sgl = (struct scatterlist *)scp->request_buffer;
+                               if (sgl->page) {
+                                       vaddr = (caddr_t)
+                                               (page_address((&sgl[0])->page)
+                                               + (&sgl[0])->offset);
+
+                                       memset(vaddr, 0, scp->cmnd[4]);
+                               }
+                               else {
+                                       con_log(CL_ANN, (KERN_WARNING
+                                       "megaraid mailbox: invalid sg:%d\n",
+                                       __LINE__));
+                               }
+                       }
+                       else {
+                               memset(scp->request_buffer, 0, scp->cmnd[4]);
+                       }
+                       scp->result = (DID_OK << 16);
+                       return NULL;
+
+               case INQUIRY:
+                       /*
+                        * Display the channel scan for logical drives
+                        * Do not display scan for a channel if already done.
+                        */
+                       if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
+
+                               con_log(CL_ANN, (KERN_INFO
+                                       "scsi[%d]: scanning scsi channel %d",
+                                       adapter->host->host_no,
+                                       SCP2CHANNEL(scp)));
+
+                               con_log(CL_ANN, (
+                                       " [virtual] for logical drives\n"));
+
+                               rdev->last_disp |= (1L << SCP2CHANNEL(scp));
+                       }
+
+                       /* Fall through */
+
+               case READ_CAPACITY:
+                       /*
+                        * Do not allow LUN > 0 for logical drives and
+                        * requests for more than 40 logical drives
+                        */
+                       if (SCP2LUN(scp)) {
+                               scp->result = (DID_BAD_TARGET << 16);
+                               return NULL;
+                       }
+                       if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) {
+                               scp->result = (DID_BAD_TARGET << 16);
+                               return NULL;
+                       }
+
+
+                       /* Allocate a SCB and initialize passthru */
+                       if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+                               scp->result = (DID_ERROR << 16);
+                               *busy = 1;
+                               return NULL;
+                       }
+
+                       ccb                     = (mbox_ccb_t *)scb->ccb;
+                       scb->dev_channel        = 0xFF;
+                       scb->dev_target         = target;
+                       pthru                   = ccb->pthru;
+                       mbox                    = ccb->mbox;
+                       mbox64                  = ccb->mbox64;
+
+                       pthru->timeout          = 0;
+                       pthru->ars              = 1;
+                       pthru->reqsenselen      = 14;
+                       pthru->islogical        = 1;
+                       pthru->logdrv           = target;
+                       pthru->cdblen           = scp->cmd_len;
+                       memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+
+                       mbox->cmd               = MBOXCMD_PASSTHRU64;
+                       scb->dma_direction      = scp->sc_data_direction;
+
+                       pthru->dataxferlen      = scp->request_bufflen;
+                       pthru->dataxferaddr     = ccb->sgl_dma_h;
+                       pthru->numsge           = megaraid_mbox_mksgl(adapter,
+                                                       scb);
+
+                       mbox->xferaddr          = 0xFFFFFFFF;
+                       mbox64->xferaddr_lo     = (uint32_t )ccb->pthru_dma_h;
+                       mbox64->xferaddr_hi     = 0;
+
+                       return scb;
+
+               case READ_6:
+               case WRITE_6:
+               case READ_10:
+               case WRITE_10:
+               case READ_12:
+               case WRITE_12:
+
+                       /*
+                        * Allocate a SCB and initialize mailbox
+                        */
+                       if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+                               scp->result = (DID_ERROR << 16);
+                               *busy = 1;
+                               return NULL;
+                       }
+                       ccb                     = (mbox_ccb_t *)scb->ccb;
+                       scb->dev_channel        = 0xFF;
+                       scb->dev_target         = target;
+                       mbox                    = ccb->mbox;
+                       mbox64                  = ccb->mbox64;
+                       mbox->logdrv            = target;
+
+                       /*
+                        * A little HACK: 2nd bit is zero for all scsi read
+                        * commands and is set for all scsi write commands
+                        */
+                       mbox->cmd = (scp->cmnd[0] & 0x02) ?  MBOXCMD_LWRITE64:
+                                       MBOXCMD_LREAD64 ;
+
+                       /*
+                        * 6-byte READ(0x08) or WRITE(0x0A) cdb
+                        */
+                       if (scp->cmd_len == 6) {
+                               mbox->numsectors = (uint32_t)scp->cmnd[4];
+                               mbox->lba =
+                                       ((uint32_t)scp->cmnd[1] << 16)  |
+                                       ((uint32_t)scp->cmnd[2] << 8)   |
+                                       (uint32_t)scp->cmnd[3];
+
+                               mbox->lba &= 0x1FFFFF;
+                       }
+
+                       /*
+                        * 10-byte READ(0x28) or WRITE(0x2A) cdb
+                        */
+                       else if (scp->cmd_len == 10) {
+                               mbox->numsectors =
+                                       (uint32_t)scp->cmnd[8] |
+                                       ((uint32_t)scp->cmnd[7] << 8);
+                               mbox->lba =
+                                       ((uint32_t)scp->cmnd[2] << 24) |
+                                       ((uint32_t)scp->cmnd[3] << 16) |
+                                       ((uint32_t)scp->cmnd[4] << 8) |
+                                       (uint32_t)scp->cmnd[5];
+                       }
+
+                       /*
+                        * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+                        */
+                       else if (scp->cmd_len == 12) {
+                               mbox->lba =
+                                       ((uint32_t)scp->cmnd[2] << 24) |
+                                       ((uint32_t)scp->cmnd[3] << 16) |
+                                       ((uint32_t)scp->cmnd[4] << 8) |
+                                       (uint32_t)scp->cmnd[5];
+
+                               mbox->numsectors =
+                                       ((uint32_t)scp->cmnd[6] << 24) |
+                                       ((uint32_t)scp->cmnd[7] << 16) |
+                                       ((uint32_t)scp->cmnd[8] << 8) |
+                                       (uint32_t)scp->cmnd[9];
+                       }
+                       else {
+                               con_log(CL_ANN, (KERN_WARNING
+                                       "megaraid: unsupported CDB length\n"));
+
+                               megaraid_dealloc_scb(adapter, scb);
+
+                               scp->result = (DID_ERROR << 16);
+                               return NULL;
+                       }
+
+                       scb->dma_direction = scp->sc_data_direction;
+
+                       // Calculate Scatter-Gather info
+                       mbox64->xferaddr_lo     = (uint32_t )ccb->sgl_dma_h;
+                       mbox->numsge            = megaraid_mbox_mksgl(adapter,
+                                                       scb);
+                       mbox->xferaddr          = 0xFFFFFFFF;
+                       mbox64->xferaddr_hi     = 0;
+
+                       return scb;
+
+               case RESERVE:
+               case RELEASE:
+                       /*
+                        * Do we support clustering and is the support enabled
+                        */
+                       if (!adapter->ha) {
+                               scp->result = (DID_BAD_TARGET << 16);
+                               return NULL;
+                       }
+
+                       /*
+                        * Allocate a SCB and initialize mailbox
+                        */
+                       if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+                               scp->result = (DID_ERROR << 16);
+                               *busy = 1;
+                               return NULL;
+                       }
+
+                       ccb                     = (mbox_ccb_t *)scb->ccb;
+                       scb->dev_channel        = 0xFF;
+                       scb->dev_target         = target;
+                       ccb->raw_mbox[0]        = CLUSTER_CMD;
+                       ccb->raw_mbox[2]        =  (scp->cmnd[0] == RESERVE) ?
+                                               RESERVE_LD : RELEASE_LD;
+
+                       ccb->raw_mbox[3]        = target;
+                       scb->dma_direction      = scp->sc_data_direction;
+
+                       return scb;
+
+               default:
+                       scp->result = (DID_BAD_TARGET << 16);
+                       return NULL;
+               }
+       }
+       else { // Passthru device commands
+
+               // Do not allow access to target id > 15 or LUN > 7
+               if (target > 15 || SCP2LUN(scp) > 7) {
+                       scp->result = (DID_BAD_TARGET << 16);
+                       return NULL;
+               }
+
+               // if fast load option was set and scan for last device is
+               // over, reset the fast_load flag so that during a possible
+               // next scan, devices can be made available
+               if (rdev->fast_load && (target == 15) &&
+                       (SCP2CHANNEL(scp) == adapter->max_channel -1)) {
+
+                       con_log(CL_ANN, (KERN_INFO
+                       "megaraid[%d]: physical device scan re-enabled\n",
+                               adapter->host->host_no));
+                       rdev->fast_load = 0;
+               }
+
+               /*
+                * Display the channel scan for physical devices
+                */
+               if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
+
+                       ss = rdev->fast_load ? skip : scan;
+
+                       con_log(CL_ANN, (KERN_INFO
+                               "scsi[%d]: %s scsi channel %d [Phy %d]",
+                               adapter->host->host_no, ss, SCP2CHANNEL(scp),
+                               channel));
+
+                       con_log(CL_ANN, (
+                               " for non-raid devices\n"));
+
+                       rdev->last_disp |= (1L << SCP2CHANNEL(scp));
+               }
+
+               // disable channel sweep if fast load option given
+               if (rdev->fast_load) {
+                       scp->result = (DID_BAD_TARGET << 16);
+                       return NULL;
+               }
+
+               // Allocate a SCB and initialize passthru
+               if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+                       scp->result = (DID_ERROR << 16);
+                       *busy = 1;
+                       return NULL;
+               }
+
+               ccb                     = (mbox_ccb_t *)scb->ccb;
+               scb->dev_channel        = channel;
+               scb->dev_target         = target;
+               scb->dma_direction      = scp->sc_data_direction;
+               mbox                    = ccb->mbox;
+               mbox64                  = ccb->mbox64;
+
+               // Does this firmware support extended CDBs
+               if (adapter->max_cdb_sz == 16) {
+                       mbox->cmd               = MBOXCMD_EXTPTHRU;
+
+                       megaraid_mbox_prepare_epthru(adapter, scb, scp);
+
+                       mbox64->xferaddr_lo     = (uint32_t)ccb->epthru_dma_h;
+                       mbox64->xferaddr_hi     = 0;
+                       mbox->xferaddr          = 0xFFFFFFFF;
+               }
+               else {
+                       mbox->cmd = MBOXCMD_PASSTHRU64;
+
+                       megaraid_mbox_prepare_pthru(adapter, scb, scp);
+
+                       mbox64->xferaddr_lo     = (uint32_t)ccb->pthru_dma_h;
+                       mbox64->xferaddr_hi     = 0;
+                       mbox->xferaddr          = 0xFFFFFFFF;
+               }
+               return scb;
+       }
+
+       // NOT REACHED
+}
+
+
+/**
+ * megaraid_mbox_runpendq - execute commands queued in the pending queue
+ * @adapter    : controller's soft state
+ * @scb                : SCB to be queued in the pending list
+ *
+ * scan the pending list for commands which are not yet issued and try to
+ * post to the controller. The SCB can be a null pointer, which would indicate
+ * no SCB to be queue, just try to execute the ones in the pending list.
+ *
+ * NOTE: We do not actually traverse the pending list. The SCBs are plucked
+ * out from the head of the pending list. If it is successfully issued, the
+ * next SCB is at the head now.
+ */
+static void
+megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q)
+{
+       scb_t                   *scb;
+       unsigned long           flags;
+
+       spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+
+       if (scb_q) {
+               scb_q->state = SCB_PENDQ;
+               list_add_tail(&scb_q->list, &adapter->pend_list);
+       }
+
+       // if the adapter in not in quiescent mode, post the commands to FW
+       if (adapter->quiescent) {
+               spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+               return;
+       }
+
+       while (!list_empty(&adapter->pend_list)) {
+
+               ASSERT(spin_is_locked(PENDING_LIST_LOCK(adapter)));
+
+               scb = list_entry(adapter->pend_list.next, scb_t, list);
+
+               // remove the scb from the pending list and try to
+               // issue. If we are unable to issue it, put back in
+               // the pending list and return
+
+               list_del_init(&scb->list);
+
+               spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+               // if mailbox was busy, return SCB back to pending
+               // list. Make sure to add at the head, since that's
+               // where it would have been removed from
+
+               scb->state = SCB_ISSUED;
+
+               if (mbox_post_cmd(adapter, scb) != 0) {
+
+                       spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+
+                       scb->state = SCB_PENDQ;
+
+                       list_add(&scb->list, &adapter->pend_list);
+
+                       spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
+                               flags);
+
+                       return;
+               }
+
+               spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+       }
+
+       spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_prepare_pthru - prepare a command for physical devices
+ * @adapter    - pointer to controller's soft state
+ * @scb                - scsi control block
+ * @scp                - scsi command from the mid-layer
+ *
+ * prepare a command for the scsi physical devices
+ */
+static void
+megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
+               struct scsi_cmnd *scp)
+{
+       mbox_ccb_t              *ccb;
+       mraid_passthru_t        *pthru;
+       uint8_t                 channel;
+       uint8_t                 target;
+
+       ccb     = (mbox_ccb_t *)scb->ccb;
+       pthru   = ccb->pthru;
+       channel = scb->dev_channel;
+       target  = scb->dev_target;
+
+       pthru->timeout          = 1;    // 0=6sec, 1=60sec, 2=10min, 3=3hrs
+       pthru->ars              = 1;
+       pthru->islogical        = 0;
+       pthru->channel          = 0;
+       pthru->target           = (channel << 4) | target;
+       pthru->logdrv           = SCP2LUN(scp);
+       pthru->reqsenselen      = 14;
+       pthru->cdblen           = scp->cmd_len;
+
+       memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+
+       if (scp->request_bufflen) {
+               pthru->dataxferlen      = scp->request_bufflen;
+               pthru->dataxferaddr     = ccb->sgl_dma_h;
+               pthru->numsge           = megaraid_mbox_mksgl(adapter, scb);
+       }
+       else {
+               pthru->dataxferaddr     = 0;
+               pthru->dataxferlen      = 0;
+               pthru->numsge           = 0;
+       }
+       return;
+}
+
+
+/**
+ * megaraid_mbox_prepare_epthru - prepare a command for physical devices
+ * @adapter    - pointer to controller's soft state
+ * @scb                - scsi control block
+ * @scp                - scsi command from the mid-layer
+ *
+ * prepare a command for the scsi physical devices. This rountine prepares
+ * commands for devices which can take extended CDBs (>10 bytes)
+ */
+static void
+megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
+               struct scsi_cmnd *scp)
+{
+       mbox_ccb_t              *ccb;
+       mraid_epassthru_t       *epthru;
+       uint8_t                 channel;
+       uint8_t                 target;
+
+       ccb     = (mbox_ccb_t *)scb->ccb;
+       epthru  = ccb->epthru;
+       channel = scb->dev_channel;
+       target  = scb->dev_target;
+
+       epthru->timeout         = 1;    // 0=6sec, 1=60sec, 2=10min, 3=3hrs
+       epthru->ars             = 1;
+       epthru->islogical       = 0;
+       epthru->channel         = 0;
+       epthru->target          = (channel << 4) | target;
+       epthru->logdrv          = SCP2LUN(scp);
+       epthru->reqsenselen     = 14;
+       epthru->cdblen          = scp->cmd_len;
+
+       memcpy(epthru->cdb, scp->cmnd, scp->cmd_len);
+
+       if (scp->request_bufflen) {
+               epthru->dataxferlen     = scp->request_bufflen;
+               epthru->dataxferaddr    = ccb->sgl_dma_h;
+               epthru->numsge          = megaraid_mbox_mksgl(adapter, scb);
+       }
+       else {
+               epthru->dataxferaddr    = 0;
+               epthru->dataxferlen     = 0;
+               epthru->numsge          = 0;
+       }
+       return;
+}
+
+
+/**
+ * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs
+ * @adapter    - controller's soft state
+ *
+ * Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the
+ * completed command and put them on the completed list for later processing.
+ *
+ * Returns:    1 if the interrupt is valid, 0 otherwise
+ */
+static inline int
+megaraid_ack_sequence(adapter_t *adapter)
+{
+       mraid_device_t          *raid_dev = ADAP2RAIDDEV(adapter);
+       mbox_t                  *mbox;
+       scb_t                   *scb;
+       uint8_t                 nstatus;
+       uint8_t                 completed[MBOX_MAX_FIRMWARE_STATUS];
+       struct list_head        clist;
+       int                     handled;
+       uint32_t                dword;
+       unsigned long           flags;
+       int                     i, j;
+
+
+       mbox    = raid_dev->mbox;
+
+       // move the SCBs from the firmware completed array to our local list
+       INIT_LIST_HEAD(&clist);
+
+       // loop till F/W has more commands for us to complete
+       handled = 0;
+       spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
+       do {
+               /*
+                * Check if a valid interrupt is pending. If found, force the
+                * interrupt line low.
+                */
+               dword = RDOUTDOOR(raid_dev);
+               if (dword != 0x10001234) break;
+
+               handled = 1;
+
+               WROUTDOOR(raid_dev, 0x10001234);
+
+               nstatus = 0;
+               // wait for valid numstatus to post
+               for (i = 0; i < 0xFFFFF; i++) {
+                       if (mbox->numstatus != 0xFF) {
+                               nstatus = mbox->numstatus;
+                               break;
+                       }
+                       rmb();
+               }
+               mbox->numstatus = 0xFF;
+
+               adapter->outstanding_cmds -= nstatus;
+
+               for (i = 0; i < nstatus; i++) {
+
+                       // wait for valid command index to post
+                       for (j = 0; j < 0xFFFFF; j++) {
+                               if (mbox->completed[i] != 0xFF) break;
+                               rmb();
+                       }
+                       completed[i]            = mbox->completed[i];
+                       mbox->completed[i]      = 0xFF;
+
+                       if (completed[i] == 0xFF) {
+                               con_log(CL_ANN, (KERN_CRIT
+                               "megaraid: command posting timed out\n"));
+
+                               BUG();
+                               continue;
+                       }
+
+                       // Get SCB associated with this command id
+                       if (completed[i] >= MBOX_MAX_SCSI_CMDS) {
+                               // a cmm command
+                               scb = adapter->uscb_list + (completed[i] -
+                                               MBOX_MAX_SCSI_CMDS);
+                       }
+                       else {
+                               // an os command
+                               scb = adapter->kscb_list + completed[i];
+                       }
+
+                       scb->status = mbox->status;
+                       list_add_tail(&scb->list, &clist);
+               }
+
+               // Acknowledge interrupt
+               WRINDOOR(raid_dev, 0x02);
+
+       } while(1);
+
+       spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
+
+
+       // put the completed commands in the completed list. DPC would
+       // complete these commands later
+       spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
+
+       list_splice(&clist, &adapter->completed_list);
+
+       spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
+
+
+       // schedule the DPC if there is some work for it
+       if (handled)
+               tasklet_schedule(&adapter->dpc_h);
+
+       return handled;
+}
+
+
+/**
+ * megaraid_isr - isr for memory based mailbox based controllers
+ * @irq                - irq
+ * @devp       - pointer to our soft state
+ * @regs       - unused
+ *
+ * Interrupt service routine for memory-mapped mailbox controllers.
+ */
+static irqreturn_t
+megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+{
+       adapter_t       *adapter = devp;
+       int             handled;
+
+       handled = megaraid_ack_sequence(adapter);
+
+       /* Loop through any pending requests */
+       if (!adapter->quiescent) {
+               megaraid_mbox_runpendq(adapter, NULL);
+       }
+
+       return IRQ_RETVAL(handled);
+}
+
+
+/**
+ * megaraid_mbox_sync_scb - sync kernel buffers
+ * @adapter    : controller's soft state
+ * @scb                : pointer to the resource packet
+ *
+ * DMA sync if required.
+ */
+static inline void
+megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
+{
+       mbox_ccb_t      *ccb;
+
+       ccb     = (mbox_ccb_t *)scb->ccb;
+
+       switch (scb->dma_type) {
+
+       case MRAID_DMA_WBUF:
+               if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
+                       pci_dma_sync_single(adapter->pdev,
+                                       ccb->buf_dma_h,
+                                       scb->scp->request_bufflen,
+                                       PCI_DMA_FROMDEVICE);
+               }
+
+               pci_unmap_page(adapter->pdev, ccb->buf_dma_h,
+                       scb->scp->request_bufflen, scb->dma_direction);
+
+               break;
+
+       case MRAID_DMA_WSG:
+               if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
+                       pci_dma_sync_sg(adapter->pdev,
+                                       scb->scp->request_buffer,
+                                       scb->scp->use_sg, PCI_DMA_FROMDEVICE);
+               }
+
+               pci_unmap_sg(adapter->pdev, scb->scp->request_buffer,
+                       scb->scp->use_sg, scb->dma_direction);
+
+               break;
+
+       default:
+               break;
+       }
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_dpc - the tasklet to complete the commands from completed list
+ * @devp       : pointer to HBA soft state
+ *
+ * Pick up the commands from the completed list and send back to the owners.
+ * This is a reentrant function and does not assume any locks are held while
+ * it is being called.
+ */
+static void
+megaraid_mbox_dpc(unsigned long devp)
+{
+       adapter_t               *adapter = (adapter_t *)devp;
+       mraid_device_t          *raid_dev;
+       struct list_head        clist;
+       struct scatterlist      *sgl;
+       scb_t                   *scb;
+       scb_t                   *tmp;
+       struct scsi_cmnd        *scp;
+       mraid_passthru_t        *pthru;
+       mraid_epassthru_t       *epthru;
+       mbox_ccb_t              *ccb;
+       int                     islogical;
+       int                     pdev_index;
+       int                     pdev_state;
+       mbox_t                  *mbox;
+       unsigned long           flags;
+       uint8_t                 c;
+       int                     status;
+
+
+       if (!adapter) return;
+
+       raid_dev = ADAP2RAIDDEV(adapter);
+
+       // move the SCBs from the completed list to our local list
+       INIT_LIST_HEAD(&clist);
+
+       spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
+
+       list_splice_init(&adapter->completed_list, &clist);
+
+       spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
+
+
+       list_for_each_entry_safe(scb, tmp, &clist, list) {
+
+               status          = scb->status;
+               scp             = scb->scp;
+               ccb             = (mbox_ccb_t *)scb->ccb;
+               pthru           = ccb->pthru;
+               epthru          = ccb->epthru;
+               mbox            = ccb->mbox;
+
+               // Make sure f/w has completed a valid command
+               if (scb->state != SCB_ISSUED) {
+                       con_log(CL_ANN, (KERN_CRIT
+                       "megaraid critical err: invalid command %d:%d:%p\n",
+                               scb->sno, scb->state, scp));
+                       BUG();
+                       continue;       // Must never happen!
+               }
+
+               // check for the management command and complete it right away
+               if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
+                       scb->state      = SCB_FREE;
+                       scb->status     = status;
+
+                       // remove from local clist
+                       list_del_init(&scb->list);
+
+                       megaraid_mbox_mm_done(adapter, scb);
+
+                       continue;
+               }
+
+               // Was an abort issued for this command earlier
+               if (scb->state & SCB_ABORT) {
+                       con_log(CL_ANN, (KERN_NOTICE
+                       "megaraid: aborted cmd %lx[%x] completed\n",
+                               scp->serial_number, scb->sno));
+               }
+
+               /*
+                * If the inquiry came of a disk drive which is not part of
+                * any RAID array, expose it to the kernel. For this to be
+                * enabled, user must set the "megaraid_expose_unconf_disks"
+                * flag to 1 by specifying it on module parameter list.
+                * This would enable data migration off drives from other
+                * configurations.
+                */
+               islogical = MRAID_IS_LOGICAL(adapter, scp);
+               if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0
+                               && IS_RAID_CH(raid_dev, scb->dev_channel)) {
+
+                       if (scp->use_sg) {
+                               sgl = (struct scatterlist *)
+                                       scp->request_buffer;
+
+                               if (sgl->page) {
+                                       c = *(unsigned char *)
+                                       (page_address((&sgl[0])->page) +
+                                               (&sgl[0])->offset);
+                               }
+                               else {
+                                       con_log(CL_ANN, (KERN_WARNING
+                                       "megaraid mailbox: invalid sg:%d\n",
+                                       __LINE__));
+                                       c = 0;
+                               }
+                       }
+                       else {
+                               c = *(uint8_t *)scp->request_buffer;
+                       }
+
+                       if ((c & 0x1F ) == TYPE_DISK) {
+                               pdev_index = (scb->dev_channel * 16) +
+                                       scb->dev_target;
+                               pdev_state =
+                                       raid_dev->pdrv_state[pdev_index] & 0x0F;
+
+                               if (pdev_state == PDRV_ONLINE           ||
+                                       pdev_state == PDRV_FAILED       ||
+                                       pdev_state == PDRV_RBLD         ||
+                                       pdev_state == PDRV_HOTSPARE     ||
+                                       megaraid_expose_unconf_disks == 0) {
+
+                                       status = 0xF0;
+                               }
+                       }
+               }
+
+               // Convert MegaRAID status to Linux error code
+               switch (status) {
+
+               case 0x00:
+
+                       scp->result = (DID_OK << 16);
+                       break;
+
+               case 0x02:
+
+                       /* set sense_buffer and result fields */
+                       if (mbox->cmd == MBOXCMD_PASSTHRU ||
+                               mbox->cmd == MBOXCMD_PASSTHRU64) {
+
+                               memcpy(scp->sense_buffer, pthru->reqsensearea,
+                                               14);
+
+                               scp->result = DRIVER_SENSE << 24 |
+                                       DID_OK << 16 | CHECK_CONDITION << 1;
+                       }
+                       else {
+                               if (mbox->cmd == MBOXCMD_EXTPTHRU) {
+
+                                       memcpy(scp->sense_buffer,
+                                               epthru->reqsensearea, 14);
+
+                                       scp->result = DRIVER_SENSE << 24 |
+                                               DID_OK << 16 |
+                                               CHECK_CONDITION << 1;
+                               } else {
+                                       scp->sense_buffer[0] = 0x70;
+                                       scp->sense_buffer[2] = ABORTED_COMMAND;
+                                       scp->result = CHECK_CONDITION << 1;
+                               }
+                       }
+                       break;
+
+               case 0x08:
+
+                       scp->result = DID_BUS_BUSY << 16 | status;
+                       break;
+
+               default:
+
+                       /*
+                        * If TEST_UNIT_READY fails, we know RESERVATION_STATUS
+                        * failed
+                        */
+                       if (scp->cmnd[0] == TEST_UNIT_READY) {
+                               scp->result = DID_ERROR << 16 |
+                                       RESERVATION_CONFLICT << 1;
+                       }
+                       else
+                       /*
+                        * Error code returned is 1 if Reserve or Release
+                        * failed or the input parameter is invalid
+                        */
+                       if (status == 1 && (scp->cmnd[0] == RESERVE ||
+                                        scp->cmnd[0] == RELEASE)) {
+
+                               scp->result = DID_ERROR << 16 |
+                                       RESERVATION_CONFLICT << 1;
+                       }
+                       else {
+                               scp->result = DID_BAD_TARGET << 16 | status;
+                       }
+               }
+
+               // print a debug message for all failed commands
+               if (status) {
+                       megaraid_mbox_display_scb(adapter, scb);
+               }
+
+               // Free our internal resources and call the mid-layer callback
+               // routine
+               megaraid_mbox_sync_scb(adapter, scb);
+
+               // remove from local clist
+               list_del_init(&scb->list);
+
+               // put back in free list
+               megaraid_dealloc_scb(adapter, scb);
+
+               // send the scsi packet back to kernel
+               spin_lock(adapter->host_lock);
+               scp->scsi_done(scp);
+               spin_unlock(adapter->host_lock);
+       }
+
+       return;
+}
+
+
+/**
+ * megaraid_abort_handler - abort the scsi command
+ * @scp                : command to be aborted
+ *
+ * Abort a previous SCSI request. Only commands on the pending list can be
+ * aborted. All the commands issued to the F/W must complete.
+ **/
+static int
+megaraid_abort_handler(struct scsi_cmnd *scp)
+{
+       adapter_t               *adapter;
+       mraid_device_t          *raid_dev;
+       scb_t                   *scb;
+       scb_t                   *tmp;
+       int                     found;
+       unsigned long           flags;
+       int                     i;
+
+
+       adapter         = SCP2ADAPTER(scp);
+       raid_dev        = ADAP2RAIDDEV(adapter);
+
+       ASSERT(spin_is_locked(adapter->host_lock));
+
+       con_log(CL_ANN, (KERN_WARNING
+               "megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
+               scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp),
+               SCP2TARGET(scp), SCP2LUN(scp)));
+
+       // If FW has stopped responding, simply return failure
+       if (raid_dev->hw_error) {
+               con_log(CL_ANN, (KERN_NOTICE
+                       "megaraid: hw error, not aborting\n"));
+               return FAILED;
+       }
+
+       // There might a race here, where the command was completed by the
+       // firmware and now it is on the completed list. Before we could
+       // complete the command to the kernel in dpc, the abort came.
+       // Find out if this is the case to avoid the race.
+       scb = NULL;
+       spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
+       list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) {
+
+               if (scb->scp == scp) {  // Found command
+
+                       list_del_init(&scb->list);      // from completed list
+
+                       con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: %ld:%d[%d:%d], abort from completed list\n",
+                               scp->serial_number, scb->sno,
+                               scb->dev_channel, scb->dev_target));
+
+                       scp->result = (DID_ABORT << 16);
+                       scp->scsi_done(scp);
+
+                       megaraid_dealloc_scb(adapter, scb);
+
+                       spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter),
+                               flags);
+
+                       return SUCCESS;
+               }
+       }
+       spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
+
+
+       // Find out if this command is still on the pending list. If it is and
+       // was never issued, abort and return success. If the command is owned
+       // by the firmware, we must wait for it to complete by the FW.
+       spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+       list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
+
+               if (scb->scp == scp) {  // Found command
+
+                       list_del_init(&scb->list);      // from pending list
+
+                       ASSERT(!(scb->state & SCB_ISSUED));
+
+                       con_log(CL_ANN, (KERN_WARNING
+                               "megaraid abort: %ld[%d:%d], driver owner\n",
+                               scp->serial_number, scb->dev_channel,
+                               scb->dev_target));
+
+                       scp->result = (DID_ABORT << 16);
+                       scp->scsi_done(scp);
+
+                       megaraid_dealloc_scb(adapter, scb);
+
+                       spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
+                               flags);
+
+                       return SUCCESS;
+               }
+       }
+       spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+
+       // Check do we even own this command, in which case this would be
+       // owned by the firmware. The only way to locate the FW scb is to
+       // traverse through the list of all SCB, since driver does not
+       // maintain these SCBs on any list
+       found = 0;
+       for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+               scb = adapter->kscb_list + i;
+
+               if (scb->scp == scp) {
+
+                       found = 1;
+
+                       if (!(scb->state & SCB_ISSUED)) {
+                               con_log(CL_ANN, (KERN_WARNING
+                               "megaraid abort: %ld%d[%d:%d], invalid state\n",
+                               scp->serial_number, scb->sno, scb->dev_channel,
+                               scb->dev_target));
+                               BUG();
+                       }
+                       else {
+                               con_log(CL_ANN, (KERN_WARNING
+                               "megaraid abort: %ld:%d[%d:%d], fw owner\n",
+                               scp->serial_number, scb->sno, scb->dev_channel,
+                               scb->dev_target));
+                       }
+               }
+       }
+
+       if (!found) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid abort: scsi cmd:%ld, do now own\n",
+                       scp->serial_number));
+
+               // FIXME: Should there be a callback for this command?
+               return SUCCESS;
+       }
+
+       // We cannot actually abort a command owned by firmware, return
+       // failure and wait for reset. In host reset handler, we will find out
+       // if the HBA is still live
+       return FAILED;
+}
+
+
+/**
+ * megaraid_reset_handler - device reset hadler for mailbox based driver
+ * @scp                : reference command
+ *
+ * Reset handler for the mailbox based controller. First try to find out if
+ * the FW is still live, in which case the outstanding commands counter mut go
+ * down to 0. If that happens, also issue the reservation reset command to
+ * relinquish (possible) reservations on the logical drives connected to this
+ * host
+ **/
+static int
+megaraid_reset_handler(struct scsi_cmnd *scp)
+{
+       adapter_t       *adapter;
+       scb_t           *scb;
+       scb_t           *tmp;
+       mraid_device_t  *raid_dev;
+       unsigned long   flags;
+       uint8_t         raw_mbox[sizeof(mbox_t)];
+       int             rval;
+       int             recovery_window;
+       int             recovering;
+       int             i;
+
+       adapter         = SCP2ADAPTER(scp);
+       raid_dev        = ADAP2RAIDDEV(adapter);
+
+       ASSERT(spin_is_locked(adapter->host_lock));
+
+       con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n"));
+
+       // return failure if adapter is not responding
+       if (raid_dev->hw_error) {
+               con_log(CL_ANN, (KERN_NOTICE
+                       "megaraid: hw error, cannot reset\n"));
+               return FAILED;
+       }
+
+
+       // Under exceptional conditions, FW can take up to 3 minutes to
+       // complete command processing. Wait for additional 2 minutes for the
+       // pending commands counter to go down to 0. If it doesn't, let the
+       // controller be marked offline
+       // Also, reset all the commands currently owned by the driver
+       spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+       list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
+
+               list_del_init(&scb->list);      // from pending list
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: %ld:%d[%d:%d], reset from pending list\n",
+                               scp->serial_number, scb->sno,
+                               scb->dev_channel, scb->dev_target));
+
+               scp->result = (DID_RESET << 16);
+               scp->scsi_done(scp);
+
+               megaraid_dealloc_scb(adapter, scb);
+       }
+       spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+       if (adapter->outstanding_cmds) {
+               con_log(CL_ANN, (KERN_NOTICE
+                       "megaraid: %d outstanding commands. Max wait %d sec\n",
+                       adapter->outstanding_cmds, MBOX_RESET_WAIT));
+       }
+
+       spin_unlock(adapter->host_lock);
+
+       recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
+
+       recovering = adapter->outstanding_cmds;
+
+       for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) {
+
+               megaraid_ack_sequence(adapter);
+
+               // print a message once every 5 seconds only
+               if (!(i % 5)) {
+                       con_log(CL_ANN, (
+                       "megaraid mbox: Wait for %d commands to complete:%d\n",
+                               adapter->outstanding_cmds,
+                               MBOX_RESET_WAIT - i));
+               }
+
+               // bailout if no recovery happended in reset time
+               if ((i == MBOX_RESET_WAIT) &&
+                       (recovering == adapter->outstanding_cmds)) {
+                       break;
+               }
+
+               msleep(1000);
+       }
+
+       spin_lock(adapter->host_lock);
+
+       // If still outstanding commands, bail out
+       if (adapter->outstanding_cmds) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mbox: critical hardware error!\n"));
+
+               raid_dev->hw_error = 1;
+
+               return FAILED;
+       }
+       else {
+               con_log(CL_ANN, (KERN_NOTICE
+               "megaraid mbox: reset sequence completed sucessfully\n"));
+       }
+
+
+       // If the controller supports clustering, reset reservations
+       if (!adapter->ha) return SUCCESS;
+
+       // clear reservations if any
+       raw_mbox[0] = CLUSTER_CMD;
+       raw_mbox[2] = RESET_RESERVATIONS;
+
+       rval = SUCCESS;
+       if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) {
+               con_log(CL_ANN,
+                       (KERN_INFO "megaraid: reservation reset\n"));
+       }
+       else {
+               rval = FAILED;
+               con_log(CL_ANN, (KERN_WARNING
+                               "megaraid: reservation reset failed\n"));
+       }
+
+       return rval;
+}
+
+
+/*
+ * START: internal commands library
+ *
+ * This section of the driver has the common routine used by the driver and
+ * also has all the FW routines
+ */
+
+/**
+ * mbox_post_sync_cmd() - blocking command to the mailbox based controllers
+ * @adapter    - controller's soft state
+ * @raw_mbox   - the mailbox
+ *
+ * Issue a scb in synchronous and non-interrupt mode for mailbox based
+ * controllers
+ */
+static int
+mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[])
+{
+       mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
+       mbox64_t        *mbox64;
+       mbox_t          *mbox;
+       uint8_t         status;
+       int             i;
+
+
+       mbox64  = raid_dev->mbox64;
+       mbox    = raid_dev->mbox;
+
+       /*
+        * Wait until mailbox is free
+        */
+       if (megaraid_busywait_mbox(raid_dev) != 0)
+               goto blocked_mailbox;
+
+       /*
+        * Copy mailbox data into host structure
+        */
+       memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
+       mbox->cmdid             = 0xFE;
+       mbox->busy              = 1;
+       mbox->poll              = 0;
+       mbox->ack               = 0;
+       mbox->numstatus         = 0xFF;
+       mbox->status            = 0xFF;
+
+       wmb();
+       WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+       // wait for maximum 1 second for status to post. If the status is not
+       // available within 1 second, assume FW is initializing and wait
+       // for an extended amount of time
+       if (mbox->numstatus == 0xFF) {  // status not yet available
+               udelay(25);;
+
+               for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) {
+                       rmb();
+                       msleep(1);
+               }
+
+
+               if (i == 1000) {
+                       con_log(CL_ANN, (KERN_NOTICE
+                               "megaraid mailbox: wait for FW to boot      "));
+
+                       for (i = 0; (mbox->numstatus == 0xFF) &&
+                                       (i < MBOX_RESET_WAIT); i++) {
+                               rmb();
+                               con_log(CL_ANN, ("\b\b\b\b\b[%03d]",
+                                                       MBOX_RESET_WAIT - i));
+                               msleep(1000);
+                       }
+
+                       if (i == MBOX_RESET_WAIT) {
+
+                               con_log(CL_ANN, (
+                               "\nmegaraid mailbox: status not available\n"));
+
+                               return -1;
+                       }
+                       con_log(CL_ANN, ("\b\b\b\b\b[ok] \n"));
+               }
+       }
+
+       // wait for maximum 1 second for poll semaphore
+       if (mbox->poll != 0x77) {
+               udelay(25);
+
+               for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) {
+                       rmb();
+                       msleep(1);
+               }
+
+               if (i == 1000) {
+                       con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mailbox: could not get poll semaphore\n"));
+                       return -1;
+               }
+       }
+
+       WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
+       wmb();
+
+       // wait for maximum 1 second for acknowledgement
+       if (RDINDOOR(raid_dev) & 0x2) {
+               udelay(25);
+
+               for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) {
+                       rmb();
+                       msleep(1);
+               }
+
+               if (i == 1000) {
+                       con_log(CL_ANN, (KERN_WARNING
+                               "megaraid mailbox: could not acknowledge\n"));
+                       return -1;
+               }
+       }
+       mbox->poll      = 0;
+       mbox->ack       = 0x77;
+
+       status = mbox->status;
+
+       // invalidate the completed command id array. After command
+       // completion, firmware would write the valid id.
+       mbox->numstatus = 0xFF;
+       mbox->status    = 0xFF;
+       for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) {
+               mbox->completed[i] = 0xFF;
+       }
+
+       return status;
+
+blocked_mailbox:
+
+       con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") );
+       return -1;
+}
+
+
+/**
+ * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers
+ * @adapter    - controller's soft state
+ * @raw_mbox   - the mailbox
+ *
+ * Issue a scb in synchronous and non-interrupt mode for mailbox based
+ * controllers. This is a faster version of the synchronous command and
+ * therefore can be called in interrupt-context as well
+ */
+static int
+mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
+{
+       mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
+       mbox_t          *mbox;
+       long            i;
+
+
+       mbox    = raid_dev->mbox;
+
+       // return immediately if the mailbox is busy
+       if (mbox->busy) return -1;
+
+       // Copy mailbox data into host structure
+       memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14);
+       mbox->cmdid             = 0xFE;
+       mbox->busy              = 1;
+       mbox->poll              = 0;
+       mbox->ack               = 0;
+       mbox->numstatus         = 0xFF;
+       mbox->status            = 0xFF;
+
+       wmb();
+       WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+       for (i = 0; i < 0xFFFFF; i++) {
+               if (mbox->numstatus != 0xFF) break;
+       }
+
+       if (i == 0xFFFFF) {
+               // We may need to re-calibrate the counter
+               con_log(CL_ANN, (KERN_CRIT
+                       "megaraid: fast sync command timed out\n"));
+       }
+
+       WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
+       wmb();
+
+       return mbox->status;
+}
+
+
+/**
+ * megaraid_busywait_mbox() - Wait until the controller's mailbox is available
+ * @raid_dev   - RAID device (HBA) soft state
+ *
+ * wait until the controller's mailbox is available to accept more commands.
+ * wait for at most 1 second
+ */
+static int
+megaraid_busywait_mbox(mraid_device_t *raid_dev)
+{
+       mbox_t  *mbox = raid_dev->mbox;
+       int     i = 0;
+
+       if (mbox->busy) {
+               udelay(25);
+               for (i = 0; mbox->busy && i < 1000; i++)
+                       msleep(1);
+       }
+
+       if (i < 1000) return 0;
+       else return -1;
+}
+
+
+/**
+ * megaraid_mbox_product_info - some static information about the controller
+ * @adapter    - our soft state
+ *
+ * issue commands to the controller to grab some parameters required by our
+ * caller.
+ */
+static int
+megaraid_mbox_product_info(adapter_t *adapter)
+{
+       mraid_device_t          *raid_dev = ADAP2RAIDDEV(adapter);
+       mbox_t                  *mbox;
+       uint8_t                 raw_mbox[sizeof(mbox_t)];
+       mraid_pinfo_t           *pinfo;
+       dma_addr_t              pinfo_dma_h;
+       mraid_inquiry3_t        *mraid_inq3;
+       int                     i;
+
+
+       memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+       mbox = (mbox_t *)raw_mbox;
+
+       /*
+        * Issue an ENQUIRY3 command to find out certain adapter parameters,
+        * e.g., max channels, max commands etc.
+        */
+       pinfo = pci_alloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+                       &pinfo_dma_h);
+
+       if (pinfo == NULL) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+
+               return -1;
+       }
+       memset(pinfo, 0, sizeof(mraid_pinfo_t));
+
+       mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+       memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+       raw_mbox[0] = FC_NEW_CONFIG;
+       raw_mbox[2] = NC_SUBOP_ENQUIRY3;
+       raw_mbox[3] = ENQ3_GET_SOLICITED_FULL;
+
+       // Issue the command
+       if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n"));
+
+               pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+                       pinfo, pinfo_dma_h);
+
+               return -1;
+       }
+
+       /*
+        * Collect information about state of each physical drive
+        * attached to the controller. We will expose all the disks
+        * which are not part of RAID
+        */
+       mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf;
+       for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) {
+               raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i];
+       }
+
+       /*
+        * Get product info for information like number of channels,
+        * maximum commands supported.
+        */
+       memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+       mbox->xferaddr = (uint32_t)pinfo_dma_h;
+
+       raw_mbox[0] = FC_NEW_CONFIG;
+       raw_mbox[2] = NC_SUBOP_PRODUCT_INFO;
+
+       if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: product info failed\n"));
+
+               pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+                       pinfo, pinfo_dma_h);
+
+               return -1;
+       }
+
+       /*
+        * Setup some parameters for host, as required by our caller
+        */
+       adapter->max_channel = pinfo->nchannels;
+
+       /*
+        * we will export all the logical drives on a single channel.
+        * Add 1 since inquires do not come for inititor ID
+        */
+       adapter->max_target     = MAX_LOGICAL_DRIVES_40LD + 1;
+       adapter->max_lun        = 8;    // up to 8 LUNs for non-disk devices
+
+       /*
+        * These are the maximum outstanding commands for the scsi-layer
+        */
+       adapter->max_cmds       = MBOX_MAX_SCSI_CMDS;
+
+       memset(adapter->fw_version, 0, VERSION_SIZE);
+       memset(adapter->bios_version, 0, VERSION_SIZE);
+
+       memcpy(adapter->fw_version, pinfo->fw_version, 4);
+       adapter->fw_version[4] = 0;
+
+       memcpy(adapter->bios_version, pinfo->bios_version, 4);
+       adapter->bios_version[4] = 0;
+
+       con_log(CL_ANN, (KERN_NOTICE
+               "megaraid: fw version:[%s] bios version:[%s]\n",
+               adapter->fw_version, adapter->bios_version));
+
+       pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo,
+                       pinfo_dma_h);
+
+       return 0;
+}
+
+
+
+/**
+ * megaraid_mbox_extended_cdb - check for support for extended CDBs
+ * @adapter    - soft state for the controller
+ *
+ * this routine check whether the controller in question supports extended
+ * ( > 10 bytes ) CDBs
+ */
+static int
+megaraid_mbox_extended_cdb(adapter_t *adapter)
+{
+       mbox_t          *mbox;
+       uint8_t         raw_mbox[sizeof(mbox_t)];
+       int             rval;
+
+       mbox = (mbox_t *)raw_mbox;
+
+       memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+       mbox->xferaddr  = (uint32_t)adapter->ibuf_dma_h;
+
+       memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+       raw_mbox[0] = MAIN_MISC_OPCODE;
+       raw_mbox[2] = SUPPORT_EXT_CDB;
+
+       /*
+        * Issue the command
+        */
+       rval = 0;
+       if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+               rval = -1;
+       }
+
+       return rval;
+}
+
+
+/**
+ * megaraid_mbox_support_ha - Do we support clustering
+ * @adapter    - soft state for the controller
+ * @init_id    - ID of the initiator
+ *
+ * Determine if the firmware supports clustering and the ID of the initiator.
+ */
+static int
+megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id)
+{
+       mbox_t          *mbox;
+       uint8_t         raw_mbox[sizeof(mbox_t)];
+       int             rval;
+
+
+       mbox = (mbox_t *)raw_mbox;
+
+       memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+
+       mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+
+       memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+       raw_mbox[0] = GET_TARGET_ID;
+
+       // Issue the command
+       *init_id = 7;
+       rval =  -1;
+       if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+
+               *init_id = *(uint8_t *)adapter->ibuf;
+
+               con_log(CL_ANN, (KERN_INFO
+                       "megaraid: cluster firmware, initiator ID: %d\n",
+                       *init_id));
+
+               rval =  0;
+       }
+
+       return rval;
+}
+
+
+/**
+ * megaraid_mbox_support_random_del - Do we support random deletion
+ * @adapter    - soft state for the controller
+ *
+ * Determine if the firmware supports random deletion
+ * Return:     1 is operation supported, 0 otherwise
+ */
+static int
+megaraid_mbox_support_random_del(adapter_t *adapter)
+{
+       mbox_t          *mbox;
+       uint8_t         raw_mbox[sizeof(mbox_t)];
+       int             rval;
+
+
+       mbox = (mbox_t *)raw_mbox;
+
+       memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+       raw_mbox[0] = FC_DEL_LOGDRV;
+       raw_mbox[0] = OP_SUP_DEL_LOGDRV;
+
+       // Issue the command
+       rval = 0;
+       if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+
+               con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n"));
+
+               rval =  1;
+       }
+
+       return rval;
+}
+
+
+/**
+ * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware
+ * @adapter    - soft state for the controller
+ *
+ * Find out the maximum number of scatter-gather elements supported by the
+ * firmware
+ */
+static int
+megaraid_mbox_get_max_sg(adapter_t *adapter)
+{
+       mbox_t          *mbox;
+       uint8_t         raw_mbox[sizeof(mbox_t)];
+       int             nsg;
+
+
+       mbox = (mbox_t *)raw_mbox;
+
+       memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+       mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+
+       memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+       raw_mbox[0] = MAIN_MISC_OPCODE;
+       raw_mbox[2] = GET_MAX_SG_SUPPORT;
+
+       // Issue the command
+       if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+               nsg =  *(uint8_t *)adapter->ibuf;
+       }
+       else {
+               nsg =  MBOX_DEFAULT_SG_SIZE;
+       }
+
+       if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE;
+
+       return nsg;
+}
+
+
+/**
+ * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels
+ * @adapter    - soft state for the controller
+ *
+ * Enumerate the RAID and SCSI channels for ROMB platoforms so that channels
+ * can be exported as regular SCSI channels
+ */
+static void
+megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
+{
+       mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
+       mbox_t          *mbox;
+       uint8_t         raw_mbox[sizeof(mbox_t)];
+
+
+       mbox = (mbox_t *)raw_mbox;
+
+       memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+       mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+
+       memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+       raw_mbox[0] = CHNL_CLASS;
+       raw_mbox[2] = GET_CHNL_CLASS;
+
+       // Issue the command. If the command fails, all channels are RAID
+       // channels
+       raid_dev->channel_class = 0xFF;
+       if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+               raid_dev->channel_class =  *(uint8_t *)adapter->ibuf;
+       }
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_flush_cache - flush adapter and disks cache
+ * @param adapter      : soft state for the controller
+ *
+ * Flush adapter cache followed by disks cache
+ */
+static void
+megaraid_mbox_flush_cache(adapter_t *adapter)
+{
+       mbox_t  *mbox;
+       uint8_t raw_mbox[sizeof(mbox_t)];
+
+
+       mbox = (mbox_t *)raw_mbox;
+
+       memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+       raw_mbox[0] = FLUSH_ADAPTER;
+
+       if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+               con_log(CL_ANN, ("megaraid: flush adapter failed\n"));
+       }
+
+       raw_mbox[0] = FLUSH_SYSTEM;
+
+       if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+               con_log(CL_ANN, ("megaraid: flush disks cache failed\n"));
+       }
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_display_scb - display SCB information, mostly debug purposes
+ * @param adapter      : controllers' soft state
+ * @param scb          : SCB to be displayed
+ * @param level        : debug level for console print
+ *
+ * Diplay information about the given SCB iff the current debug level is
+ * verbose
+ */
+static void
+megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb)
+{
+       mbox_ccb_t              *ccb;
+       struct scsi_cmnd        *scp;
+       mbox_t                  *mbox;
+       int                     level;
+       int                     i;
+
+
+       ccb     = (mbox_ccb_t *)scb->ccb;
+       scp     = scb->scp;
+       mbox    = ccb->mbox;
+
+       level = CL_DLEVEL3;
+
+       con_log(level, (KERN_NOTICE
+               "megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status,
+               mbox->cmd, scb->sno));
+
+       con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n",
+               mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv,
+               mbox->numsge));
+
+       if (!scp) return;
+
+       con_log(level, (KERN_NOTICE "scsi cmnd: "));
+
+       for (i = 0; i < scp->cmd_len; i++) {
+               con_log(level, ("%#2.02x ", scp->cmnd[i]));
+       }
+
+       con_log(level, ("\n"));
+
+       return;
+}
+
+
+/**
+ * megaraid_mbox_setup_device_map - manage device ids
+ * @adapter    : Driver's soft state
+ *
+ * Manange the device ids to have an appropraite mapping between the kernel
+ * scsi addresses and megaraid scsi and logical drive addresses. We export
+ * scsi devices on their actual addresses, whereas the logical drives are
+ * exported on a virtual scsi channel.
+ **/
+static void
+megaraid_mbox_setup_device_map(adapter_t *adapter)
+{
+       uint8_t         c;
+       uint8_t         t;
+
+       /*
+        * First fill the values on the logical drive channel
+        */
+       for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
+               adapter->device_ids[adapter->max_channel][t] =
+                       (t < adapter->init_id) ?  t : t - 1;
+
+       adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF;
+
+       /*
+        * Fill the values on the physical devices channels
+        */
+       for (c = 0; c < adapter->max_channel; c++)
+               for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
+                       adapter->device_ids[c][t] = (c << 8) | t;
+}
+
+
+/*
+ * END: internal commands library
+ */
+
+/*
+ * START: Interface for the common management module
+ *
+ * This is the module, which interfaces with the common mangement module to
+ * provide support for ioctl and sysfs
+ */
+
+/**
+ * megaraid_cmm_register - register with the mangement module
+ * @param adapter      : HBA soft state
+ *
+ * Register with the management module, which allows applications to issue
+ * ioctl calls to the drivers. This interface is used by the management module
+ * to setup sysfs support as well.
+ */
+static int
+megaraid_cmm_register(adapter_t *adapter)
+{
+       mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
+       mraid_mmadp_t   adp;
+       scb_t           *scb;
+       mbox_ccb_t      *ccb;
+       int             rval;
+       int             i;
+
+       // Allocate memory for the base list of scb for management module.
+       adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
+                       GFP_KERNEL);
+
+       if (adapter->uscb_list == NULL) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+               return -1;
+       }
+       memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
+
+
+       // Initialize the synchronization parameters for resources for
+       // commands for management module
+       INIT_LIST_HEAD(&adapter->uscb_pool);
+
+       spin_lock_init(USER_FREE_LIST_LOCK(adapter));
+
+
+
+       // link all the packets. Note, CCB for commands, coming from the
+       // commom management module, mailbox physical address are already
+       // setup by it. We just need placeholder for that in our local command
+       // control blocks
+       for (i = 0; i < MBOX_MAX_USER_CMDS; i++) {
+
+               scb                     = adapter->uscb_list + i;
+               ccb                     = raid_dev->uccb_list + i;
+
+               scb->ccb                = (caddr_t)ccb;
+               ccb->mbox64             = raid_dev->umbox64 + i;
+               ccb->mbox               = &ccb->mbox64->mbox32;
+               ccb->raw_mbox           = (uint8_t *)ccb->mbox;
+
+               scb->gp                 = 0;
+
+               // COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR
+               // COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER)
+               scb->sno                = i + MBOX_MAX_SCSI_CMDS;
+
+               scb->scp                = NULL;
+               scb->state              = SCB_FREE;
+               scb->dma_direction      = PCI_DMA_NONE;
+               scb->dma_type           = MRAID_DMA_NONE;
+               scb->dev_channel        = -1;
+               scb->dev_target         = -1;
+
+               // put scb in the free pool
+               list_add_tail(&scb->list, &adapter->uscb_pool);
+       }
+
+       adp.unique_id           = adapter->unique_id;
+       adp.drvr_type           = DRVRTYPE_MBOX;
+       adp.drvr_data           = (unsigned long)adapter;
+       adp.pdev                = adapter->pdev;
+       adp.issue_uioc          = megaraid_mbox_mm_handler;
+       adp.timeout             = 30;
+       adp.max_kioc            = MBOX_MAX_USER_CMDS;
+
+       if ((rval = mraid_mm_register_adp(&adp)) != 0) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mbox: did not register with CMM\n"));
+
+               kfree(adapter->uscb_list);
+       }
+
+       return rval;
+}
+
+
+/**
+ * megaraid_cmm_unregister - un-register with the mangement module
+ * @param adapter      : HBA soft state
+ *
+ * Un-register with the management module.
+ * FIXME: mgmt module must return failure for unregister if it has pending
+ * commands in LLD
+ */
+static int
+megaraid_cmm_unregister(adapter_t *adapter)
+{
+       kfree(adapter->uscb_list);
+       mraid_mm_unregister_adp(adapter->unique_id);
+       return 0;
+}
+
+
+/**
+ * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD
+ * @param drvr_data    : LLD specific data
+ * @param kioc         : CMM interface packet
+ * @param action       : command action
+ *
+ * This routine is invoked whenever the Common Mangement Module (CMM) has a
+ * command for us. The 'action' parameter specifies if this is a new command
+ * or otherwise.
+ */
+static int
+megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action)
+{
+       adapter_t *adapter;
+
+       if (action != IOCTL_ISSUE) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: unsupported management action:%#2x\n",
+                       action));
+               return (-ENOTSUPP);
+       }
+
+       adapter = (adapter_t *)drvr_data;
+
+       // make sure this adapter is not being detached right now.
+       if (atomic_read(&adapter->being_detached)) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid: reject management request, detaching\n"));
+               return (-ENODEV);
+       }
+
+       switch (kioc->opcode) {
+
+       case GET_ADAP_INFO:
+
+               kioc->status =  gather_hbainfo(adapter, (mraid_hba_info_t *)
+                                       (unsigned long)kioc->buf_vaddr);
+
+               kioc->done(kioc);
+
+               return kioc->status;
+
+       case MBOX_CMD:
+
+               return megaraid_mbox_mm_command(adapter, kioc);
+
+       default:
+               kioc->status = (-EINVAL);
+               kioc->done(kioc);
+               return (-EINVAL);
+       }
+
+       return 0;       // not reached
+}
+
+/**
+ * megaraid_mbox_mm_command - issues commands routed through CMM
+ * @param adapter      : HBA soft state
+ * @param kioc         : management command packet
+ *
+ * Issues commands, which are routed through the management module.
+ */
+static int
+megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc)
+{
+       struct list_head        *head = &adapter->uscb_pool;
+       mbox64_t                *mbox64;
+       uint8_t                 *raw_mbox;
+       scb_t                   *scb;
+       mbox_ccb_t              *ccb;
+       unsigned long           flags;
+
+       // detach one scb from free pool
+       spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
+
+       if (list_empty(head)) { // should never happen because of CMM
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid mbox: bug in cmm handler, lost resources\n"));
+
+               spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
+
+               return (-EINVAL);
+       }
+
+       scb = list_entry(head->next, scb_t, list);
+       list_del_init(&scb->list);
+
+       spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
+
+       scb->state      = SCB_ACTIVE;
+       scb->dma_type   = MRAID_DMA_NONE;
+
+       ccb             = (mbox_ccb_t *)scb->ccb;
+       mbox64          = (mbox64_t *)(unsigned long)kioc->cmdbuf;
+       raw_mbox        = (uint8_t *)&mbox64->mbox32;
+
+       memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t));
+
+       scb->gp         = (unsigned long)kioc;
+
+       /*
+        * If it is a logdrv random delete operation, we have to wait till
+        * there are no outstanding cmds at the fw and then issue it directly
+        */
+       if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
+
+               if (wait_till_fw_empty(adapter)) {
+                       con_log(CL_ANN, (KERN_NOTICE
+                               "megaraid mbox: LD delete, timed out\n"));
+
+                       kioc->status = -ETIME;
+
+                       scb->status = -1;
+
+                       megaraid_mbox_mm_done(adapter, scb);
+
+                       return (-ETIME);
+               }
+
+               INIT_LIST_HEAD(&scb->list);
+
+               scb->state = SCB_ISSUED;
+               if (mbox_post_cmd(adapter, scb) != 0) {
+
+                       con_log(CL_ANN, (KERN_NOTICE
+                               "megaraid mbox: LD delete, mailbox busy\n"));
+
+                       kioc->status = -EBUSY;
+
+                       scb->status = -1;
+
+                       megaraid_mbox_mm_done(adapter, scb);
+
+                       return (-EBUSY);
+               }
+
+               return 0;
+       }
+
+       // put the command on the pending list and execute
+       megaraid_mbox_runpendq(adapter, scb);
+
+       return 0;
+}
+
+
+static int
+wait_till_fw_empty(adapter_t *adapter)
+{
+       unsigned long   flags = 0;
+       int             i;
+
+
+       /*
+        * Set the quiescent flag to stop issuing cmds to FW.
+        */
+       spin_lock_irqsave(adapter->host_lock, flags);
+       adapter->quiescent++;
+       spin_unlock_irqrestore(adapter->host_lock, flags);
+
+       /*
+        * Wait till there are no more cmds outstanding at FW. Try for at most
+        * 60 seconds
+        */
+       for (i = 0; i < 60 && adapter->outstanding_cmds; i++) {
+               con_log(CL_DLEVEL1, (KERN_INFO
+                       "megaraid: FW has %d pending commands\n",
+                       adapter->outstanding_cmds));
+
+               msleep(1000);
+       }
+
+       return adapter->outstanding_cmds;
+}
+
+
+/**
+ * megaraid_mbox_mm_done - callback for CMM commands
+ * @adapter    : HBA soft state
+ * @scb                : completed command
+ *
+ * Callback routine for internal commands originated from the management
+ * module.
+ */
+static void
+megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
+{
+       uioc_t                  *kioc;
+       mbox64_t                *mbox64;
+       uint8_t                 *raw_mbox;
+       unsigned long           flags;
+
+       kioc                    = (uioc_t *)scb->gp;
+       kioc->status            = 0;
+       mbox64                  = (mbox64_t *)(unsigned long)kioc->cmdbuf;
+       mbox64->mbox32.status   = scb->status;
+       raw_mbox                = (uint8_t *)&mbox64->mbox32;
+
+
+       // put scb in the free pool
+       scb->state      = SCB_FREE;
+       scb->scp        = NULL;
+
+       spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
+
+       list_add(&scb->list, &adapter->uscb_pool);
+
+       spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
+
+       // if a delete logical drive operation succeeded, restart the
+       // controller
+       if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
+
+               adapter->quiescent--;
+
+               megaraid_mbox_runpendq(adapter, NULL);
+       }
+
+       kioc->done(kioc);
+
+       return;
+}
+
+
+/**
+ * gather_hbainfo - HBA characteristics for the applications
+ * @param adapter      : HBA soft state
+ * @param hinfo                : pointer to the caller's host info strucuture
+ */
+static int
+gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
+{
+       uint8_t dmajor;
+
+       dmajor                  = megaraid_mbox_version[0];
+
+       hinfo->pci_vendor_id    = adapter->pdev->vendor;
+       hinfo->pci_device_id    = adapter->pdev->device;
+       hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor;
+       hinfo->subsys_device_id = adapter->pdev->subsystem_device;
+
+       hinfo->pci_bus          = adapter->pdev->bus->number;
+       hinfo->pci_dev_fn       = adapter->pdev->devfn;
+       hinfo->pci_slot         = PCI_SLOT(adapter->pdev->devfn);
+       hinfo->irq              = adapter->host->irq;
+       hinfo->baseport         = ADAP2RAIDDEV(adapter)->baseport;
+
+       hinfo->unique_id        = (hinfo->pci_bus << 8) | adapter->pdev->devfn;
+       hinfo->host_no          = adapter->host->host_no;
+
+       return 0;
+}
+
+/*
+ * END: Interface for the common management module
+ */
+
+
+/*
+ * END: Mailbox Low Level Driver
+ */
+module_init(megaraid_init);
+module_exit(megaraid_exit);
+
+/* vim: set ts=8 sw=8 tw=78 ai si: */
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
new file mode 100644 (file)
index 0000000..2f195ab
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *
+ *                     Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : megaraid_mbox.h
+ */
+
+#ifndef _MEGARAID_H_
+#define _MEGARAID_H_
+
+
+#include "mega_common.h"
+#include "mbox_defs.h"
+#include "megaraid_ioctl.h"
+
+
+#define MEGARAID_VERSION       "2.20.4.0"
+#define MEGARAID_EXT_VERSION   "(Release Date: Mon Sep 27 22:15:07 EDT 2004)"
+
+
+/*
+ * Define some PCI values here until they are put in the kernel
+ */
+#define PCI_DEVICE_ID_PERC4_DI_DISCOVERY               0x000E
+#define PCI_SUBSYS_ID_PERC4_DI_DISCOVERY               0x0123
+
+#define PCI_DEVICE_ID_PERC4_SC                         0x1960
+#define PCI_SUBSYS_ID_PERC4_SC                         0x0520
+
+#define PCI_DEVICE_ID_PERC4_DC                         0x1960
+#define PCI_SUBSYS_ID_PERC4_DC                         0x0518
+
+#define PCI_DEVICE_ID_PERC4_QC                         0x0407
+#define PCI_SUBSYS_ID_PERC4_QC                         0x0531
+
+#define PCI_DEVICE_ID_PERC4_DI_EVERGLADES              0x000F
+#define PCI_SUBSYS_ID_PERC4_DI_EVERGLADES              0x014A
+
+#define PCI_DEVICE_ID_PERC4E_SI_BIGBEND                        0x0013
+#define PCI_SUBSYS_ID_PERC4E_SI_BIGBEND                        0x016c
+
+#define PCI_DEVICE_ID_PERC4E_DI_KOBUK                  0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_KOBUK                  0x016d
+
+#define PCI_DEVICE_ID_PERC4E_DI_CORVETTE               0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_CORVETTE               0x016e
+
+#define PCI_DEVICE_ID_PERC4E_DI_EXPEDITION             0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION             0x016f
+
+#define PCI_DEVICE_ID_PERC4E_DI_GUADALUPE              0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE              0x0170
+
+#define PCI_DEVICE_ID_PERC4E_DC_320_2E                 0x0408
+#define PCI_SUBSYS_ID_PERC4E_DC_320_2E                 0x0002
+
+#define PCI_DEVICE_ID_PERC4E_SC_320_1E                 0x0408
+#define PCI_SUBSYS_ID_PERC4E_SC_320_1E                 0x0001
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0              0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0              0xA520
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1              0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1              0x0520
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2              0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2              0x0518
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0x             0x0407
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x             0x0530
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2x             0x0407
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x             0x0532
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_4x             0x0407
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x             0x0531
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1E             0x0408
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E             0x0001
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2E             0x0408
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E             0x0002
+
+#define PCI_DEVICE_ID_MEGARAID_I4_133_RAID             0x1960
+#define PCI_SUBSYS_ID_MEGARAID_I4_133_RAID             0x0522
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_150_4              0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SATA_150_4              0x4523
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_150_6              0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SATA_150_6              0x0523
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_300_4x             0x0409
+#define PCI_SUBSYS_ID_MEGARAID_SATA_300_4x             0x3004
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_300_8x             0x0409
+#define PCI_SUBSYS_ID_MEGARAID_SATA_300_8x             0x3008
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCU42X               0x0407
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42X               0x0532
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCS16                        0x1960
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCS16                        0x0523
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCU42E               0x0408
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42E               0x0002
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCZCRX               0x0407
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX               0x0530
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCS28X               0x0409
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCS28X               0x3008
+
+#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF       0x0408
+#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF       0x3431
+
+#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH     0x0408
+#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH     0x3499
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK   0x1960
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK   0x0520
+
+#define PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB    0x0408
+#define PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB    0x1065
+
+#define PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E            0x0408
+#define PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E            0x004D
+
+#define PCI_SUBSYS_ID_PERC3_QC                         0x0471
+#define PCI_SUBSYS_ID_PERC3_DC                         0x0493
+#define PCI_SUBSYS_ID_PERC3_SC                         0x0475
+
+#ifndef PCI_SUBSYS_ID_FSC
+#define PCI_SUBSYS_ID_FSC                              0x1734
+#endif
+
+#define MBOX_MAX_SCSI_CMDS     128     // number of cmds reserved for kernel
+#define MBOX_MAX_USER_CMDS     32      // number of cmds for applications
+#define MBOX_DEF_CMD_PER_LUN   64      // default commands per lun
+#define MBOX_DEFAULT_SG_SIZE   26      // default sg size supported by all fw
+#define MBOX_MAX_SG_SIZE       32      // maximum scatter-gather list size
+#define MBOX_MAX_SECTORS       128     // maximum sectors per IO
+#define MBOX_TIMEOUT           30      // timeout value for internal cmds
+#define MBOX_BUSY_WAIT         10      // max usec to wait for busy mailbox
+#define MBOX_RESET_WAIT                180     // wait these many seconds in reset
+#define MBOX_RESET_EXT_WAIT    120     // extended wait reset
+
+/*
+ * maximum transfer that can happen through the firmware commands issued
+ * internnaly from the driver.
+ */
+#define MBOX_IBUF_SIZE         4096
+
+
+/**
+ * mbox_ccb_t - command control block specific to mailbox based controllers
+ * @raw_mbox           : raw mailbox pointer
+ * @mbox               : mailbox
+ * @mbox64             : extended mailbox
+ * @mbox_dma_h         : maibox dma address
+ * @sgl64              : 64-bit scatter-gather list
+ * @sgl32              : 32-bit scatter-gather list
+ * @sgl_dma_h          : dma handle for the scatter-gather list
+ * @pthru              : passthru structure
+ * @pthru_dma_h                : dma handle for the passthru structure
+ * @epthru             : extended passthru structure
+ * @epthru_dma_h       : dma handle for extended passthru structure
+ * @buf_dma_h          : dma handle for buffers w/o sg list
+ *
+ * command control block specific to the mailbox based controllers
+ */
+typedef struct {
+       uint8_t                 *raw_mbox;
+       mbox_t                  *mbox;
+       mbox64_t                *mbox64;
+       dma_addr_t              mbox_dma_h;
+       mbox_sgl64              *sgl64;
+       mbox_sgl32              *sgl32;
+       dma_addr_t              sgl_dma_h;
+       mraid_passthru_t        *pthru;
+       dma_addr_t              pthru_dma_h;
+       mraid_epassthru_t       *epthru;
+       dma_addr_t              epthru_dma_h;
+       dma_addr_t              buf_dma_h;
+} mbox_ccb_t;
+
+
+/**
+ * mraid_device_t - adapter soft state structure for mailbox controllers
+ * @param una_mbox64           : 64-bit mbox - unaligned
+ * @param una_mbox64_dma       : mbox dma addr - unaligned
+ * @param mbox                 : 32-bit mbox - aligned
+ * @param mbox64               : 64-bit mbox - aligned
+ * @param mbox_dma             : mbox dma addr - aligned
+ * @param mailbox_lock         : exclusion lock for the mailbox
+ * @param baseport             : base port of hba memory
+ * @param baseaddr             : mapped addr of hba memory
+ * @param mbox_pool            : pool of mailboxes
+ * @param mbox_pool_handle     : handle for the mailbox pool memory
+ * @param epthru_pool          : a pool for extended passthru commands
+ * @param epthru_pool_handle   : handle to the pool above
+ * @param sg_pool              : pool of scatter-gather lists for this driver
+ * @param sg_pool_handle       : handle to the pool above
+ * @param ccb_list             : list of our command control blocks
+ * @param uccb_list            : list of cmd control blocks for mgmt module
+ * @param umbox64              : array of mailbox for user commands (cmm)
+ * @param pdrv_state           : array for state of each physical drive.
+ * @param last_disp            : flag used to show device scanning
+ * @param hw_error             : set if FW not responding
+ * @param fast_load            : If set, skip physical device scanning
+ * @channel_class              : channel class, RAID or SCSI
+ *
+ * Initialization structure for mailbox controllers: memory based and IO based
+ * All the fields in this structure are LLD specific and may be discovered at
+ * init() or start() time.
+ *
+ * NOTE: The fields of this structures are placed to minimize cache misses
+ */
+typedef struct {
+       mbox64_t                        *una_mbox64;
+       dma_addr_t                      una_mbox64_dma;
+       mbox_t                          *mbox;
+       mbox64_t                        *mbox64;
+       dma_addr_t                      mbox_dma;
+       spinlock_t                      mailbox_lock;
+       unsigned long                   baseport;
+       unsigned long                   baseaddr;
+       struct mraid_pci_blk            mbox_pool[MBOX_MAX_SCSI_CMDS];
+       struct dma_pool                 *mbox_pool_handle;
+       struct mraid_pci_blk            epthru_pool[MBOX_MAX_SCSI_CMDS];
+       struct dma_pool                 *epthru_pool_handle;
+       struct mraid_pci_blk            sg_pool[MBOX_MAX_SCSI_CMDS];
+       struct dma_pool                 *sg_pool_handle;
+       mbox_ccb_t                      ccb_list[MBOX_MAX_SCSI_CMDS];
+       mbox_ccb_t                      uccb_list[MBOX_MAX_USER_CMDS];
+       mbox64_t                        umbox64[MBOX_MAX_USER_CMDS];
+
+       uint8_t                         pdrv_state[MBOX_MAX_PHYSICAL_DRIVES];
+       uint32_t                        last_disp;
+       int                             hw_error;
+       int                             fast_load;
+       uint8_t                         channel_class;
+} mraid_device_t;
+
+// route to raid device from adapter
+#define ADAP2RAIDDEV(adp)      ((mraid_device_t *)((adp)->raid_device))
+
+#define MAILBOX_LOCK(rdev)     (&(rdev)->mailbox_lock)
+
+// Find out if this channel is a RAID or SCSI
+#define IS_RAID_CH(rdev, ch)   (((rdev)->channel_class >> (ch)) & 0x01)
+
+
+#define RDINDOOR(rdev)         readl((rdev)->baseaddr + 0x20)
+#define RDOUTDOOR(rdev)                readl((rdev)->baseaddr + 0x2C)
+#define WRINDOOR(rdev, value)  writel(value, (rdev)->baseaddr + 0x20)
+#define WROUTDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x2C)
+
+#endif // _MEGARAID_H_
+
+// vim: set ts=8 sw=8 tw=78:
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
new file mode 100644 (file)
index 0000000..8a6bc93
--- /dev/null
@@ -0,0 +1,1160 @@
+/*
+ *
+ *                     Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : megaraid_mm.c
+ * Version     : v2.20.2.0 (August 19 2004)
+ *
+ * Common management module
+ */
+
+#include "megaraid_mm.h"
+
+
+// Entry points for char node driver
+static int mraid_mm_open(struct inode *, struct file *);
+static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long);
+
+
+// routines to convert to and from the old the format
+static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *);
+static int kioc_to_mimd(uioc_t *, mimd_t __user *);
+
+
+// Helper functions
+static int handle_drvrcmd(void __user *, uint8_t, int *);
+static int lld_ioctl(mraid_mmadp_t *, uioc_t *);
+static void ioctl_done(uioc_t *);
+static void lld_timedout(unsigned long);
+static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *);
+static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *);
+static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *);
+static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *);
+static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int);
+static int mraid_mm_setup_dma_pools(mraid_mmadp_t *);
+static void mraid_mm_free_adp_resources(mraid_mmadp_t *);
+static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *);
+
+#ifdef CONFIG_COMPAT
+static int mraid_mm_compat_ioctl(unsigned int, unsigned int, unsigned long,
+               struct file *);
+#endif
+
+MODULE_AUTHOR("LSI Logic Corporation");
+MODULE_DESCRIPTION("LSI Logic Management Module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(LSI_COMMON_MOD_VERSION);
+
+static int dbglevel = CL_ANN;
+module_param_named(dlevel, dbglevel, int, 0);
+MODULE_PARM_DESC(dlevel, "Debug level (default=0)");
+
+EXPORT_SYMBOL(mraid_mm_register_adp);
+EXPORT_SYMBOL(mraid_mm_unregister_adp);
+
+static int majorno;
+static uint32_t drvr_ver       = 0x02200100;
+
+static int adapters_count_g;
+static struct list_head adapters_list_g;
+
+wait_queue_head_t wait_q;
+
+static struct file_operations lsi_fops = {
+       .open   = mraid_mm_open,
+       .ioctl  = mraid_mm_ioctl,
+       .owner  = THIS_MODULE,
+};
+
+/**
+ * mraid_mm_open - open routine for char node interface
+ * @inod       : unused
+ * @filep      : unused
+ *
+ * allow ioctl operations by apps only if they superuser privilege
+ */
+static int
+mraid_mm_open(struct inode *inode, struct file *filep)
+{
+       /*
+        * Only allow superuser to access private ioctl interface
+        */
+       if (!capable(CAP_SYS_ADMIN)) return (-EACCES);
+
+       return 0;
+}
+
+/**
+ * mraid_mm_ioctl - module entry-point for ioctls
+ * @inode      : inode (ignored)
+ * @filep      : file operations pointer (ignored)
+ * @cmd                : ioctl command
+ * @arg                : user ioctl packet
+ */
+static int
+mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       uioc_t          *kioc;
+       char            signature[EXT_IOCTL_SIGN_SZ]    = {0};
+       int             rval;
+       mraid_mmadp_t   *adp;
+       uint8_t         old_ioctl;
+       int             drvrcmd_rval;
+       void __user *argp = (void __user *)arg;
+
+       /*
+        * Make sure only USCSICMD are issued through this interface.
+        * MIMD application would still fire different command.
+        */
+
+       if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) {
+               return (-EINVAL);
+       }
+
+       /*
+        * Look for signature to see if this is the new or old ioctl format.
+        */
+       if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid cmm: copy from usr addr failed\n"));
+               return (-EFAULT);
+       }
+
+       if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0)
+               old_ioctl = 0;
+       else
+               old_ioctl = 1;
+
+       /*
+        * At present, we don't support the new ioctl packet
+        */
+       if (!old_ioctl )
+               return (-EINVAL);
+
+       /*
+        * If it is a driver ioctl (as opposed to fw ioctls), then we can
+        * handle the command locally. rval > 0 means it is not a drvr cmd
+        */
+       rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval);
+
+       if (rval < 0)
+               return rval;
+       else if (rval == 0)
+               return drvrcmd_rval;
+
+       rval = 0;
+       if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) {
+               return rval;
+       }
+
+       /*
+        * The following call will block till a kioc is available
+        */
+       kioc = mraid_mm_alloc_kioc(adp);
+
+       /*
+        * User sent the old mimd_t ioctl packet. Convert it to uioc_t.
+        */
+       if ((rval = mimd_to_kioc(argp, adp, kioc))) {
+               mraid_mm_dealloc_kioc(adp, kioc);
+               return rval;
+       }
+
+       kioc->done = ioctl_done;
+
+       /*
+        * Issue the IOCTL to the low level driver
+        */
+       if ((rval = lld_ioctl(adp, kioc))) {
+               mraid_mm_dealloc_kioc(adp, kioc);
+               return rval;
+       }
+
+       /*
+        * Convert the kioc back to user space
+        */
+       rval = kioc_to_mimd(kioc, argp);
+
+       /*
+        * Return the kioc to free pool
+        */
+       mraid_mm_dealloc_kioc(adp, kioc);
+
+       return rval;
+}
+
+
+/**
+ * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet
+ * @umimd      : User space mimd_t ioctl packet
+ * @adapter    : pointer to the adapter (OUT)
+ */
+static mraid_mmadp_t *
+mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
+{
+       mraid_mmadp_t   *adapter;
+       mimd_t          mimd;
+       uint32_t        adapno;
+       int             iterator;
+
+
+       if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) {
+               *rval = -EFAULT;
+               return NULL;
+       }
+
+       adapno = GETADAP(mimd.ui.fcs.adapno);
+
+       if (adapno >= adapters_count_g) {
+               *rval = -ENODEV;
+               return NULL;
+       }
+
+       adapter = NULL;
+       iterator = 0;
+
+       list_for_each_entry(adapter, &adapters_list_g, list) {
+               if (iterator++ == adapno) break;
+       }
+
+       if (!adapter) {
+               *rval = -ENODEV;
+               return NULL;
+       }
+
+       return adapter;
+}
+
+/*
+ * handle_drvrcmd - This routine checks if the opcode is a driver
+ *                       cmd and if it is, handles it.
+ * @arg                : packet sent by the user app
+ * @old_ioctl  : mimd if 1; uioc otherwise
+ */
+static int
+handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval)
+{
+       mimd_t          __user *umimd;
+       mimd_t          kmimd;
+       uint8_t         opcode;
+       uint8_t         subopcode;
+
+       if (old_ioctl)
+               goto old_packet;
+       else
+               goto new_packet;
+
+new_packet:
+       return (-ENOTSUPP);
+
+old_packet:
+       *rval = 0;
+       umimd = arg;
+
+       if (copy_from_user(&kmimd, umimd, sizeof(mimd_t)))
+               return (-EFAULT);
+
+       opcode          = kmimd.ui.fcs.opcode;
+       subopcode       = kmimd.ui.fcs.subopcode;
+
+       /*
+        * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or
+        * GET_NUMADP, then we can handle. Otherwise we should return 1 to
+        * indicate that we cannot handle this.
+        */
+       if (opcode != 0x82)
+               return 1;
+
+       switch (subopcode) {
+
+       case MEGAIOC_QDRVRVER:
+
+               if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t)))
+                       return (-EFAULT);
+
+               return 0;
+
+       case MEGAIOC_QNADAP:
+
+               *rval = adapters_count_g;
+
+               if (copy_to_user(kmimd.data, &adapters_count_g,
+                               sizeof(uint32_t)))
+                       return (-EFAULT);
+
+               return 0;
+
+       default:
+               /* cannot handle */
+               return 1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * mimd_to_kioc        - Converter from old to new ioctl format
+ *
+ * @umimd      : user space old MIMD IOCTL
+ * @kioc       : kernel space new format IOCTL
+ *
+ * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The
+ * new packet is in kernel space so that driver can perform operations on it
+ * freely.
+ */
+
+static int
+mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
+{
+       mbox64_t                *mbox64;
+       mbox_t                  *mbox;
+       mraid_passthru_t        *pthru32;
+       uint32_t                adapno;
+       uint8_t                 opcode;
+       uint8_t                 subopcode;
+       mimd_t                  mimd;
+
+       if (copy_from_user(&mimd, umimd, sizeof(mimd_t)))
+               return (-EFAULT);
+
+       /*
+        * Applications are not allowed to send extd pthru
+        */
+       if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) ||
+                       (mimd.mbox[0] == MBOXCMD_EXTPTHRU))
+               return (-EINVAL);
+
+       opcode          = mimd.ui.fcs.opcode;
+       subopcode       = mimd.ui.fcs.subopcode;
+       adapno          = GETADAP(mimd.ui.fcs.adapno);
+
+       if (adapno >= adapters_count_g)
+               return (-ENODEV);
+
+       kioc->adapno    = adapno;
+       kioc->mb_type   = MBOX_LEGACY;
+       kioc->app_type  = APPTYPE_MIMD;
+
+       switch (opcode) {
+
+       case 0x82:
+
+               if (subopcode == MEGAIOC_QADAPINFO) {
+
+                       kioc->opcode    = GET_ADAP_INFO;
+                       kioc->data_dir  = UIOC_RD;
+                       kioc->xferlen   = sizeof(mraid_hba_info_t);
+
+                       if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
+                               return (-ENOMEM);
+               }
+               else {
+                       con_log(CL_ANN, (KERN_WARNING
+                                       "megaraid cmm: Invalid subop\n"));
+                       return (-EINVAL);
+               }
+
+               break;
+
+       case 0x81:
+
+               kioc->opcode            = MBOX_CMD;
+               kioc->xferlen           = mimd.ui.fcs.length;
+               kioc->user_data_len     = kioc->xferlen;
+               kioc->user_data         = mimd.ui.fcs.buffer;
+
+               if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
+                       return (-ENOMEM);
+
+               if (mimd.outlen) kioc->data_dir  = UIOC_RD;
+               if (mimd.inlen) kioc->data_dir |= UIOC_WR;
+
+               break;
+
+       case 0x80:
+
+               kioc->opcode            = MBOX_CMD;
+               kioc->xferlen           = (mimd.outlen > mimd.inlen) ?
+                                               mimd.outlen : mimd.inlen;
+               kioc->user_data_len     = kioc->xferlen;
+               kioc->user_data         = mimd.data;
+
+               if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
+                       return (-ENOMEM);
+
+               if (mimd.outlen) kioc->data_dir  = UIOC_RD;
+               if (mimd.inlen) kioc->data_dir |= UIOC_WR;
+
+               break;
+
+       default:
+               return (-EINVAL);
+       }
+
+       /*
+        * If driver command, nothing else to do
+        */
+       if (opcode == 0x82)
+               return 0;
+
+       /*
+        * This is a mailbox cmd; copy the mailbox from mimd
+        */
+       mbox64  = (mbox64_t *)((unsigned long)kioc->cmdbuf);
+       mbox    = &mbox64->mbox32;
+       memcpy(mbox, mimd.mbox, 14);
+
+       if (mbox->cmd != MBOXCMD_PASSTHRU) {    // regular DCMD
+
+               mbox->xferaddr  = (uint32_t)kioc->buf_paddr;
+
+               if (kioc->data_dir & UIOC_WR) {
+                       if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
+                                                       kioc->xferlen)) {
+                               return (-EFAULT);
+                       }
+               }
+
+               return 0;
+       }
+
+       /*
+        * This is a regular 32-bit pthru cmd; mbox points to pthru struct.
+        * Just like in above case, the beginning for memblk is treated as
+        * a mailbox. The passthru will begin at next 1K boundary. And the
+        * data will start 1K after that.
+        */
+       pthru32                 = kioc->pthru32;
+       kioc->user_pthru        = &umimd->pthru;
+       mbox->xferaddr          = (uint32_t)kioc->pthru32_h;
+
+       if (copy_from_user(pthru32, kioc->user_pthru,
+                       sizeof(mraid_passthru_t))) {
+               return (-EFAULT);
+       }
+
+       pthru32->dataxferaddr   = kioc->buf_paddr;
+       if (kioc->data_dir & UIOC_WR) {
+               if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
+                                               pthru32->dataxferlen)) {
+                       return (-EFAULT);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * mraid_mm_attch_buf - Attach a free dma buffer for required size
+ *
+ * @adp                : Adapter softstate
+ * @kioc       : kioc that the buffer needs to be attached to
+ * @xferlen    : required length for buffer
+ *
+ * First we search for a pool with smallest buffer that is >= @xferlen. If
+ * that pool has no free buffer, we will try for the next bigger size. If none
+ * is available, we will try to allocate the smallest buffer that is >=
+ * @xferlen and attach it the pool.
+ */
+static int
+mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen)
+{
+       mm_dmapool_t    *pool;
+       int             right_pool = -1;
+       unsigned long   flags;
+       int             i;
+
+       kioc->pool_index        = -1;
+       kioc->buf_vaddr         = NULL;
+       kioc->buf_paddr         = 0;
+       kioc->free_buf          = 0;
+
+       /*
+        * We need xferlen amount of memory. See if we can get it from our
+        * dma pools. If we don't get exact size, we will try bigger buffer
+        */
+
+       for (i = 0; i < MAX_DMA_POOLS; i++) {
+
+               pool = &adp->dma_pool_list[i];
+
+               if (xferlen > pool->buf_size)
+                       continue;
+
+               if (right_pool == -1)
+                       right_pool = i;
+
+               spin_lock_irqsave(&pool->lock, flags);
+
+               if (!pool->in_use) {
+
+                       pool->in_use            = 1;
+                       kioc->pool_index        = i;
+                       kioc->buf_vaddr         = pool->vaddr;
+                       kioc->buf_paddr         = pool->paddr;
+
+                       spin_unlock_irqrestore(&pool->lock, flags);
+                       return 0;
+               }
+               else {
+                       spin_unlock_irqrestore(&pool->lock, flags);
+                       continue;
+               }
+       }
+
+       /*
+        * If xferlen doesn't match any of our pools, return error
+        */
+       if (right_pool == -1)
+               return -EINVAL;
+
+       /*
+        * We did not get any buffer from the preallocated pool. Let us try
+        * to allocate one new buffer. NOTE: This is a blocking call.
+        */
+       pool = &adp->dma_pool_list[right_pool];
+
+       spin_lock_irqsave(&pool->lock, flags);
+
+       kioc->pool_index        = right_pool;
+       kioc->free_buf          = 1;
+       kioc->buf_vaddr         = pci_pool_alloc(pool->handle, GFP_KERNEL,
+                                                       &kioc->buf_paddr);
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       if (!kioc->buf_vaddr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/**
+ * mraid_mm_alloc_kioc - Returns a uioc_t from free list
+ * @adp        : Adapter softstate for this module
+ *
+ * The kioc_semaphore is initialized with number of kioc nodes in the
+ * free kioc pool. If the kioc pool is empty, this function blocks till
+ * a kioc becomes free.
+ */
+static uioc_t *
+mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
+{
+       uioc_t                  *kioc;
+       struct list_head*       head;
+       unsigned long           flags;
+
+       down(&adp->kioc_semaphore);
+
+       spin_lock_irqsave(&adp->kioc_pool_lock, flags);
+
+       head = &adp->kioc_pool;
+
+       if (list_empty(head)) {
+               up(&adp->kioc_semaphore);
+               spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
+
+               con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n"));
+               return NULL;
+       }
+
+       kioc = list_entry(head->next, uioc_t, list);
+       list_del_init(&kioc->list);
+
+       spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
+
+       memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t));
+       memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t));
+
+       kioc->buf_vaddr         = NULL;
+       kioc->buf_paddr         = 0;
+       kioc->pool_index        =-1;
+       kioc->free_buf          = 0;
+       kioc->user_data         = NULL;
+       kioc->user_data_len     = 0;
+       kioc->user_pthru        = NULL;
+
+       return kioc;
+}
+
+/**
+ * mraid_mm_dealloc_kioc - Return kioc to free pool
+ *
+ * @adp                : Adapter softstate
+ * @kioc       : uioc_t node to be returned to free pool
+ */
+static void
+mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc)
+{
+       mm_dmapool_t    *pool;
+       unsigned long   flags;
+
+       pool = &adp->dma_pool_list[kioc->pool_index];
+
+       /* This routine may be called in non-isr context also */
+       spin_lock_irqsave(&pool->lock, flags);
+
+       /*
+        * While attaching the dma buffer, if we didn't get the required
+        * buffer from the pool, we would have allocated it at the run time
+        * and set the free_buf flag. We must free that buffer. Otherwise,
+        * just mark that the buffer is not in use
+        */
+       if (kioc->free_buf == 1)
+               pci_pool_free(pool->handle, kioc->buf_vaddr, kioc->buf_paddr);
+       else
+               pool->in_use = 0;
+
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       /* Return the kioc to the free pool */
+       spin_lock_irqsave(&adp->kioc_pool_lock, flags);
+       list_add(&kioc->list, &adp->kioc_pool);
+       spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
+
+       /* increment the free kioc count */
+       up(&adp->kioc_semaphore);
+
+       return;
+}
+
+/**
+ * lld_ioctl - Routine to issue ioctl to low level drvr
+ *
+ * @adp                : The adapter handle
+ * @kioc       : The ioctl packet with kernel addresses
+ */
+static int
+lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
+{
+       int                     rval;
+       struct timer_list       timer;
+       struct timer_list       *tp = NULL;
+
+       kioc->status    = -ENODATA;
+       rval            = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE);
+
+       if (rval) return rval;
+
+       /*
+        * Start the timer
+        */
+       if (adp->timeout > 0) {
+               tp              = &timer;
+               init_timer(tp);
+
+               tp->function    = lld_timedout;
+               tp->data        = (unsigned long)kioc;
+               tp->expires     = jiffies + adp->timeout * HZ;
+
+               add_timer(tp);
+       }
+
+       /*
+        * Wait till the low level driver completes the ioctl. After this
+        * call, the ioctl either completed successfully or timedout.
+        */
+       wait_event(wait_q, (kioc->status != -ENODATA));
+       if (tp) {
+               del_timer_sync(tp);
+       }
+
+       return kioc->status;
+}
+
+
+/**
+ * ioctl_done - callback from the low level driver
+ *
+ * @kioc       : completed ioctl packet
+ */
+static void
+ioctl_done(uioc_t *kioc)
+{
+       /*
+        * When the kioc returns from driver, make sure it still doesn't
+        * have ENODATA in status. Otherwise, driver will hang on wait_event
+        * forever
+        */
+       if (kioc->status == -ENODATA) {
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid cmm: lld didn't change status!\n"));
+
+               kioc->status = -EINVAL;
+       }
+
+       wake_up(&wait_q);
+}
+
+
+/*
+ * lld_timedout        : callback from the expired timer
+ *
+ * @ptr                : ioctl packet that timed out
+ */
+static void
+lld_timedout(unsigned long ptr)
+{
+       uioc_t *kioc    = (uioc_t *)ptr;
+
+       kioc->status    = -ETIME;
+
+       con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n"));
+
+       wake_up(&wait_q);
+}
+
+
+/**
+ * kioc_to_mimd        : Converter from new back to old format
+ *
+ * @kioc       : Kernel space IOCTL packet (successfully issued)
+ * @mimd       : User space MIMD packet
+ */
+static int
+kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd)
+{
+       mimd_t                  kmimd;
+       uint8_t                 opcode;
+       uint8_t                 subopcode;
+
+       mbox64_t                *mbox64;
+       mraid_passthru_t        __user *upthru32;
+       mraid_passthru_t        *kpthru32;
+       mcontroller_t           cinfo;
+       mraid_hba_info_t        *hinfo;
+
+
+       if (copy_from_user(&kmimd, mimd, sizeof(mimd_t)))
+               return (-EFAULT);
+
+       opcode          = kmimd.ui.fcs.opcode;
+       subopcode       = kmimd.ui.fcs.subopcode;
+
+       if (opcode == 0x82) {
+               switch (subopcode) {
+
+               case MEGAIOC_QADAPINFO:
+
+                       hinfo = (mraid_hba_info_t *)(unsigned long)
+                                       kioc->buf_vaddr;
+
+                       hinfo_to_cinfo(hinfo, &cinfo);
+
+                       if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo)))
+                               return (-EFAULT);
+
+                       return 0;
+
+               default:
+                       return (-EINVAL);
+               }
+
+               return 0;
+       }
+
+       mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
+
+       if (kioc->user_pthru) {
+
+               upthru32 = kioc->user_pthru;
+               kpthru32 = kioc->pthru32;
+
+               if (copy_to_user(&upthru32->scsistatus,
+                                       &kpthru32->scsistatus,
+                                       sizeof(uint8_t))) {
+                       return (-EFAULT);
+               }
+       }
+
+       if (kioc->user_data) {
+               if (copy_to_user(kioc->user_data, kioc->buf_vaddr,
+                                       kioc->user_data_len)) {
+                       return (-EFAULT);
+               }
+       }
+
+       if (copy_to_user(&mimd->mbox[17],
+                       &mbox64->mbox32.status, sizeof(uint8_t))) {
+               return (-EFAULT);
+       }
+
+       return 0;
+}
+
+
+/**
+ * hinfo_to_cinfo - Convert new format hba info into old format
+ *
+ * @hinfo      : New format, more comprehensive adapter info
+ * @cinfo      : Old format adapter info to support mimd_t apps
+ */
+static void
+hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo)
+{
+       if (!hinfo || !cinfo)
+               return;
+
+       cinfo->base             = hinfo->baseport;
+       cinfo->irq              = hinfo->irq;
+       cinfo->numldrv          = hinfo->num_ldrv;
+       cinfo->pcibus           = hinfo->pci_bus;
+       cinfo->pcidev           = hinfo->pci_slot;
+       cinfo->pcifun           = PCI_FUNC(hinfo->pci_dev_fn);
+       cinfo->pciid            = hinfo->pci_device_id;
+       cinfo->pcivendor        = hinfo->pci_vendor_id;
+       cinfo->pcislot          = hinfo->pci_slot;
+       cinfo->uid              = hinfo->unique_id;
+}
+
+
+/*
+ * mraid_mm_register_adp - Registration routine for low level drvrs
+ *
+ * @adp        : Adapter objejct
+ */
+int
+mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
+{
+       mraid_mmadp_t   *adapter;
+       mbox64_t        *mbox_list;
+       uioc_t          *kioc;
+       uint32_t        rval;
+       int             i;
+
+
+       if (lld_adp->drvr_type != DRVRTYPE_MBOX)
+               return (-EINVAL);
+
+       adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
+
+       if (!adapter) {
+               rval = -ENOMEM;
+               goto memalloc_error;
+       }
+
+       memset(adapter, 0, sizeof(mraid_mmadp_t));
+
+       adapter->unique_id      = lld_adp->unique_id;
+       adapter->drvr_type      = lld_adp->drvr_type;
+       adapter->drvr_data      = lld_adp->drvr_data;
+       adapter->pdev           = lld_adp->pdev;
+       adapter->issue_uioc     = lld_adp->issue_uioc;
+       adapter->timeout        = lld_adp->timeout;
+       adapter->max_kioc       = lld_adp->max_kioc;
+
+       /*
+        * Allocate single blocks of memory for all required kiocs,
+        * mailboxes and passthru structures.
+        */
+       adapter->kioc_list      = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc,
+                                               GFP_KERNEL);
+       adapter->mbox_list      = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc,
+                                               GFP_KERNEL);
+       adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool",
+                                               adapter->pdev,
+                                               sizeof(mraid_passthru_t),
+                                               16, 0);
+
+       if (!adapter->kioc_list || !adapter->mbox_list ||
+                       !adapter->pthru_dma_pool) {
+
+               con_log(CL_ANN, (KERN_WARNING
+                       "megaraid cmm: out of memory, %s %d\n", __FUNCTION__,
+                       __LINE__));
+
+               rval = (-ENOMEM);
+
+               goto memalloc_error;
+       }
+
+       /*
+        * Slice kioc_list and make a kioc_pool with the individiual kiocs
+        */
+       INIT_LIST_HEAD(&adapter->kioc_pool);
+       spin_lock_init(&adapter->kioc_pool_lock);
+       sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc);
+
+       mbox_list       = (mbox64_t *)adapter->mbox_list;
+
+       for (i = 0; i < lld_adp->max_kioc; i++) {
+
+               kioc            = adapter->kioc_list + i;
+               kioc->cmdbuf    = (uint64_t)(unsigned long)(mbox_list + i);
+               kioc->pthru32   = pci_pool_alloc(adapter->pthru_dma_pool,
+                                               GFP_KERNEL, &kioc->pthru32_h);
+
+               if (!kioc->pthru32) {
+
+                       con_log(CL_ANN, (KERN_WARNING
+                               "megaraid cmm: out of memory, %s %d\n",
+                                       __FUNCTION__, __LINE__));
+
+                       rval = (-ENOMEM);
+
+                       goto pthru_dma_pool_error;
+               }
+
+               list_add_tail(&kioc->list, &adapter->kioc_pool);
+       }
+
+       // Setup the dma pools for data buffers
+       if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) {
+               goto dma_pool_error;
+       }
+
+       list_add_tail(&adapter->list, &adapters_list_g);
+
+       adapters_count_g++;
+
+       return 0;
+
+dma_pool_error:
+       /* Do nothing */
+
+pthru_dma_pool_error:
+
+       for (i = 0; i < lld_adp->max_kioc; i++) {
+               kioc = adapter->kioc_list + i;
+               if (kioc->pthru32) {
+                       pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32,
+                               kioc->pthru32_h);
+               }
+       }
+
+memalloc_error:
+
+       if (adapter->kioc_list)
+               kfree(adapter->kioc_list);
+
+       if (adapter->mbox_list)
+               kfree(adapter->mbox_list);
+
+       if (adapter->pthru_dma_pool)
+               pci_pool_destroy(adapter->pthru_dma_pool);
+
+       if (adapter)
+               kfree(adapter);
+
+       return rval;
+}
+
+/**
+ * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter
+ *
+ * @adp        : Adapter softstate
+ *
+ * We maintain a pool of dma buffers per each adapter. Each pool has one
+ * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers.
+ * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We
+ * dont' want to waste too much memory by allocating more buffers per each
+ * pool.
+ */
+static int
+mraid_mm_setup_dma_pools(mraid_mmadp_t *adp)
+{
+       mm_dmapool_t    *pool;
+       int             bufsize;
+       int             i;
+
+       /*
+        * Create MAX_DMA_POOLS number of pools
+        */
+       bufsize = MRAID_MM_INIT_BUFF_SIZE;
+
+       for (i = 0; i < MAX_DMA_POOLS; i++){
+
+               pool = &adp->dma_pool_list[i];
+
+               pool->buf_size = bufsize;
+               spin_lock_init(&pool->lock);
+
+               pool->handle = pci_pool_create("megaraid mm data buffer",
+                                               adp->pdev, bufsize, 16, 0);
+
+               if (!pool->handle) {
+                       goto dma_pool_setup_error;
+               }
+
+               pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL,
+                                                       &pool->paddr);
+
+               if (!pool->vaddr)
+                       goto dma_pool_setup_error;
+
+               bufsize = bufsize * 2;
+       }
+
+       return 0;
+
+dma_pool_setup_error:
+
+       mraid_mm_teardown_dma_pools(adp);
+       return (-ENOMEM);
+}
+
+
+/*
+ * mraid_mm_unregister_adp - Unregister routine for low level drivers
+ *                               Assume no outstanding ioctls to llds.
+ *
+ * @unique_id  : UID of the adpater
+ */
+int
+mraid_mm_unregister_adp(uint32_t unique_id)
+{
+       mraid_mmadp_t   *adapter;
+       mraid_mmadp_t   *tmp;
+
+       list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) {
+
+
+               if (adapter->unique_id == unique_id) {
+
+                       adapters_count_g--;
+
+                       list_del_init(&adapter->list);
+
+                       mraid_mm_free_adp_resources(adapter);
+
+                       kfree(adapter);
+
+                       con_log(CL_ANN, (
+                               "megaraid cmm: Unregistered one adapter:%#x\n",
+                               unique_id));
+
+                       return 0;
+               }
+       }
+
+       return (-ENODEV);
+}
+
+/**
+ * mraid_mm_free_adp_resources - Free adapter softstate
+ *
+ * @adp        : Adapter softstate
+ */
+static void
+mraid_mm_free_adp_resources(mraid_mmadp_t *adp)
+{
+       uioc_t  *kioc;
+       int     i;
+
+       mraid_mm_teardown_dma_pools(adp);
+
+       for (i = 0; i < adp->max_kioc; i++) {
+
+               kioc = adp->kioc_list + i;
+
+               pci_pool_free(adp->pthru_dma_pool, kioc->pthru32,
+                               kioc->pthru32_h);
+       }
+
+       kfree(adp->kioc_list);
+
+       kfree(adp->mbox_list);
+
+       pci_pool_destroy(adp->pthru_dma_pool);
+
+
+       return;
+}
+
+
+/**
+ * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers
+ *
+ * @adp        : Adapter softstate
+ */
+static void
+mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp)
+{
+       int             i;
+       mm_dmapool_t    *pool;
+
+       for (i = 0; i < MAX_DMA_POOLS; i++) {
+
+               pool = &adp->dma_pool_list[i];
+
+               if (pool->handle) {
+
+                       if (pool->vaddr)
+                               pci_pool_free(pool->handle, pool->vaddr,
+                                                       pool->paddr);
+
+                       pci_pool_destroy(pool->handle);
+                       pool->handle = NULL;
+               }
+       }
+
+       return;
+}
+
+/**
+ * mraid_mm_init       : Module entry point
+ */
+static int __init
+mraid_mm_init(void)
+{
+       // Announce the driver version
+       con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n",
+               LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION));
+
+       majorno = register_chrdev(0, "megadev", &lsi_fops);
+
+       if (majorno < 0) {
+               con_log(CL_ANN, ("megaraid cmm: cannot get major\n"));
+               return majorno;
+       }
+
+       init_waitqueue_head(&wait_q);
+
+       INIT_LIST_HEAD(&adapters_list_g);
+
+#ifdef CONFIG_COMPAT
+       register_ioctl32_conversion(MEGAIOCCMD, mraid_mm_compat_ioctl);
+#endif
+
+       return 0;
+}
+
+
+/**
+ * mraid_mm_compat_ioctl       : 32bit to 64bit ioctl conversion routine
+ */
+#ifdef CONFIG_COMPAT
+static int
+mraid_mm_compat_ioctl(unsigned int fd, unsigned int cmd,
+                       unsigned long arg, struct file *filep)
+{
+       struct inode *inode = filep->f_dentry->d_inode;
+
+       return mraid_mm_ioctl(inode, filep, cmd, arg);
+}
+#endif
+
+/**
+ * mraid_mm_exit       : Module exit point
+ */
+static void __exit
+mraid_mm_exit(void)
+{
+       con_log(CL_DLEVEL1 , ("exiting common mod\n"));
+
+       unregister_chrdev(majorno, "megadev");
+       unregister_ioctl32_conversion(MEGAIOCCMD);
+}
+
+module_init(mraid_mm_init);
+module_exit(mraid_mm_exit);
+
+/* vi: set ts=8 sw=8 tw=78: */
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
new file mode 100644 (file)
index 0000000..effc23a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *
+ *                     Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *        This program is free software; you can redistribute it and/or
+ *        modify it under the terms of the GNU General Public License
+ *        as published by the Free Software Foundation; either version
+ *        2 of the License, or (at your option) any later version.
+ *
+ * FILE                : megaraid_mm.h
+ */
+
+#ifndef MEGARAID_MM_H
+#define MEGARAID_MM_H
+
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/ioctl32.h>
+
+#include "mbox_defs.h"
+#include "megaraid_ioctl.h"
+
+
+#define LSI_COMMON_MOD_VERSION "2.20.2.0"
+#define LSI_COMMON_MOD_EXT_VERSION     \
+               "(Release Date: Thu Aug 19 09:58:33 EDT 2004)"
+
+
+#define LSI_DBGLVL                     dbglevel
+
+// The smallest dma pool
+#define MRAID_MM_INIT_BUFF_SIZE                4096
+
+/**
+ * mimd_t      : Old style ioctl packet structure (deprecated)
+ *
+ * @inlen      :
+ * @outlen     :
+ * @fca                :
+ * @opcode     :
+ * @subopcode  :
+ * @adapno     :
+ * @buffer     :
+ * @pad                :
+ * @length     :
+ * @mbox       :
+ * @pthru      :
+ * @data       :
+ * @pad                :
+ *
+ * Note                : This structure is DEPRECATED. New applications must use
+ *             : uioc_t structure instead. All new hba drivers use the new
+ *             : format. If we get this mimd packet, we will convert it into
+ *             : new uioc_t format and send it to the hba drivers.
+ */
+
+typedef struct mimd {
+
+       uint32_t inlen;
+       uint32_t outlen;
+
+       union {
+               uint8_t fca[16];
+               struct {
+                       uint8_t opcode;
+                       uint8_t subopcode;
+                       uint16_t adapno;
+#if BITS_PER_LONG == 32
+                       uint8_t __user *buffer;
+                       uint8_t pad[4];
+#endif
+#if BITS_PER_LONG == 64
+                       uint8_t __user *buffer;
+#endif
+                       uint32_t length;
+               } __attribute__ ((packed)) fcs;
+       } __attribute__ ((packed)) ui;
+
+       uint8_t mbox[18];               /* 16 bytes + 2 status bytes */
+       mraid_passthru_t pthru;
+
+#if BITS_PER_LONG == 32
+       char __user *data;              /* buffer <= 4096 for 0x80 commands */
+       char pad[4];
+#endif
+#if BITS_PER_LONG == 64
+       char __user *data;
+#endif
+
+} __attribute__ ((packed))mimd_t;
+
+#endif // MEGARAID_MM_H
+
+// vi: set ts=8 sw=8 tw=78:
diff --git a/drivers/scsi/ql1040_fw.h b/drivers/scsi/ql1040_fw.h
new file mode 100644 (file)
index 0000000..89d8e09
--- /dev/null
@@ -0,0 +1,2099 @@
+/**************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * Copyright (C) 2004 QLogic Corporation
+ * (www.qlogic.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, 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.
+ *
+ *************************************************************************/
+
+/************************************************************************
+ *                                                                     *
+ *             --- ISP1040 Initiator/Target Firmware ---               *
+ *                         32 LUN Support                              *
+ *                                                                     *
+ ************************************************************************
+ */
+
+/*
+ *     Firmware Version 7.65.00 (14:17 Jul 20, 1999)
+ */
+
+static unsigned char firmware_version[] = {7,65,0};
+
+#define FW_VERSION_STRING "7.65.0"
+
+static unsigned short risc_code_addr01 = 0x1000 ;
+
+static unsigned short risc_code01[] = { 
+       0x0078, 0x103a, 0x0000, 0x4057, 0x0000, 0x2043, 0x4f50, 0x5952,
+       0x4947, 0x4854, 0x2031, 0x3939, 0x3520, 0x514c, 0x4f47, 0x4943,
+       0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350,
+       0x3130, 0x3230, 0x2049, 0x2f54, 0x2046, 0x6972, 0x6d77, 0x6172,
+       0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x372e, 0x3635,
+       0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20,
+       0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020,
+       0x3031, 0x2024, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048,
+       0x1045, 0x0038, 0x104b, 0x0078, 0x1047, 0x0028, 0x104b, 0x20b9,
+       0x1212, 0x0078, 0x104d, 0x20b9, 0x2222, 0x20c1, 0x0008, 0x2071,
+       0x0010, 0x70c3, 0x0004, 0x20c9, 0x77ff, 0x2089, 0x1186, 0x70c7,
+       0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0007, 0x3f00,
+       0x70d6, 0x20c1, 0x0008, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100,
+       0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc,
+       0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040,
+       0x10bf, 0xa386, 0x000f, 0x0040, 0x1085, 0x2c6a, 0x2a5a, 0x20c1,
+       0x0000, 0x2019, 0x000f, 0x0078, 0x1065, 0x2c6a, 0x2a5a, 0x20c1,
+       0x0008, 0x2009, 0x7fff, 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc,
+       0x3fff, 0x2734, 0x203b, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040,
+       0x10a9, 0x284a, 0x263a, 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134,
+       0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x10aa, 0x0078,
+       0x118e, 0x284a, 0x263a, 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b,
+       0xa5a5, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10bc, 0x250a, 0xa18a,
+       0x1000, 0x98c1, 0x0078, 0x10c1, 0x250a, 0x0078, 0x10c1, 0x2c6a,
+       0x2a5a, 0x2130, 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x5100, 0x8424,
+       0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0xa192, 0x7800, 0x2009,
+       0x0000, 0x2001, 0x0031, 0x1078, 0x1cba, 0x2218, 0x2079, 0x5100,
+       0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109,
+       0x00c0, 0x10dc, 0x7ef2, 0x8528, 0x7de6, 0x7cea, 0x7bee, 0x7883,
+       0x0000, 0x2031, 0x0030, 0x78cf, 0x0101, 0x780b, 0x0002, 0x780f,
+       0x0002, 0x784f, 0x0003, 0x2069, 0x5140, 0x2001, 0x04fd, 0x2004,
+       0xa082, 0x0005, 0x0048, 0x1104, 0x0038, 0x1100, 0x0078, 0x1108,
+       0x681b, 0x003c, 0x0078, 0x110a, 0x00a8, 0x1108, 0x681b, 0x003c,
+       0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008,
+       0x6813, 0x0005, 0x6823, 0x0000, 0x6827, 0x0006, 0x6817, 0x0008,
+       0x682b, 0x0000, 0x681f, 0x0019, 0x2069, 0x5380, 0x2011, 0x0020,
+       0x2009, 0x0010, 0x680b, 0x080c, 0x680f, 0x0019, 0x6803, 0xfd00,
+       0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004,
+       0x8109, 0x00c0, 0x1122, 0x2069, 0x5400, 0x2009, 0x0002, 0x20a9,
+       0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bf0, 0xa386, 0xfeff,
+       0x00c0, 0x1148, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x114c,
+       0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, 0x1152,
+       0x0078, 0x1139, 0x8109, 0x00c0, 0x1137, 0x1078, 0x220a, 0x1078,
+       0x482c, 0x1078, 0x1963, 0x1078, 0x4d22, 0x3200, 0xa085, 0x000d,
+       0x2090, 0x70c3, 0x0000, 0x0090, 0x116c, 0x70c0, 0xa086, 0x0002,
+       0x00c0, 0x116c, 0x1078, 0x1284, 0x1078, 0x1196, 0x78cc, 0xa005,
+       0x00c0, 0x117a, 0x1078, 0x1ce3, 0x0010, 0x1180, 0x0068, 0x1180,
+       0x1078, 0x20e9, 0x0010, 0x1180, 0x0068, 0x1180, 0x1078, 0x1a48,
+       0x00e0, 0x116c, 0x1078, 0x4ba9, 0x0078, 0x116c, 0x118e, 0x1190,
+       0x240b, 0x240b, 0x48ad, 0x48ad, 0x240b, 0x240b, 0x0078, 0x118e,
+       0x0078, 0x1190, 0x0078, 0x1192, 0x0078, 0x1194, 0x0068, 0x1201,
+       0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1201, 0x7814,
+       0xa005, 0x00c0, 0x11a7, 0x0010, 0x1202, 0x0078, 0x1201, 0x2009,
+       0x515b, 0x2104, 0xa005, 0x00c0, 0x1201, 0x2009, 0x5164, 0x200b,
+       0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11cc, 0x7816, 0x2009,
+       0x5162, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca,
+       0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce,
+       0x1078, 0x1948, 0x0078, 0x11ff, 0x7814, 0xa086, 0x0018, 0x00c0,
+       0x11d3, 0x1078, 0x165a, 0x7817, 0x0000, 0x2009, 0x5162, 0x2104,
+       0xa065, 0x0040, 0x11ef, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x19b3,
+       0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c, 0x6007,
+       0x0103, 0x1078, 0x1924, 0x00c0, 0x11fb, 0x1078, 0x1948, 0x2009,
+       0x5162, 0x200b, 0x0000, 0x2009, 0x515c, 0x2104, 0x200b, 0x0000,
+       0xa005, 0x0040, 0x11ff, 0x2001, 0x4005, 0x0078, 0x1286, 0x0078,
+       0x1284, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000,
+       0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1252, 0x2038,
+       0x0079, 0x1212, 0x1284, 0x12e5, 0x12a9, 0x12fe, 0x130d, 0x1313,
+       0x12a0, 0x1748, 0x1317, 0x1298, 0x12ad, 0x12af, 0x12b1, 0x12b3,
+       0x174d, 0x1298, 0x1329, 0x1360, 0x1672, 0x1742, 0x12b5, 0x1591,
+       0x15ad, 0x15c9, 0x15f4, 0x154a, 0x1558, 0x156c, 0x1580, 0x13df,
+       0x1298, 0x138d, 0x1393, 0x1398, 0x139d, 0x13a3, 0x13a8, 0x13ad,
+       0x13b2, 0x13b7, 0x13bb, 0x13d0, 0x13dc, 0x1298, 0x1298, 0x1298,
+       0x1298, 0x13eb, 0x13f4, 0x1403, 0x1429, 0x1433, 0x143a, 0x1480,
+       0x148f, 0x149e, 0x14b0, 0x152a, 0x153a, 0x1298, 0x1298, 0x1298,
+       0x1298, 0x153f, 0xa0bc, 0xffa0, 0x00c0, 0x1298, 0x2038, 0xa084,
+       0x001f, 0x0079, 0x125b, 0x1786, 0x1789, 0x1799, 0x1298, 0x1298,
+       0x18df, 0x18fc, 0x1298, 0x1298, 0x1298, 0x1900, 0x1908, 0x1298,
+       0x1298, 0x1298, 0x1298, 0x12db, 0x12f4, 0x131f, 0x1356, 0x1668,
+       0x1764, 0x1778, 0x1298, 0x1829, 0x190e, 0x18bb, 0x18c5, 0x18c9,
+       0x18d7, 0x1298, 0x1298, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078,
+       0x1286, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068,
+       0x1287, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x00e0,
+       0x128f, 0x00e0, 0x1291, 0x0068, 0x1291, 0x2091, 0x4080, 0x007c,
+       0x70c3, 0x4001, 0x0078, 0x1287, 0x70c3, 0x4006, 0x0078, 0x1287,
+       0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
+       0x1284, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1284, 0x0078,
+       0x1284, 0x0078, 0x1284, 0x0078, 0x1284, 0x2091, 0x8000, 0x70c3,
+       0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+       0x0007, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031,
+       0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061,
+       0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091,
+       0x4080, 0x0078, 0x0455, 0x1078, 0x1b53, 0x00c0, 0x129c, 0x75d8,
+       0x74dc, 0x75da, 0x74de, 0x0078, 0x12e8, 0x2029, 0x0000, 0x2520,
+       0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1a8d, 0x0040, 0x1284,
+       0x70c3, 0x4002, 0x0078, 0x1284, 0x1078, 0x1b53, 0x00c0, 0x129c,
+       0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1301, 0x2029, 0x0000,
+       0x2520, 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1aed, 0x0040,
+       0x1284, 0x70c3, 0x4002, 0x0078, 0x1284, 0x71c4, 0x70c8, 0x2114,
+       0x200a, 0x0078, 0x1282, 0x71c4, 0x2114, 0x0078, 0x1282, 0x70c7,
+       0x0007, 0x70cb, 0x0041, 0x70cf, 0x0000, 0x0078, 0x1284, 0x1078,
+       0x1b53, 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078,
+       0x132c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0,
+       0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1350, 0x8001,
+       0x7892, 0xa084, 0xfc00, 0x0040, 0x1345, 0x78cc, 0xa085, 0x0001,
+       0x78ce, 0x2001, 0x4005, 0x0078, 0x1286, 0x7a9a, 0x7b9e, 0x7da2,
+       0x7ea6, 0x7c96, 0x78cc, 0xa084, 0xfffc, 0x78ce, 0x0078, 0x1354,
+       0x78cc, 0xa085, 0x0001, 0x78ce, 0x0078, 0x1284, 0x1078, 0x1b53,
+       0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1363,
+       0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6,
+       0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1387, 0x8001, 0x78ae,
+       0xa084, 0xfc00, 0x0040, 0x137c, 0x78cc, 0xa085, 0x0100, 0x78ce,
+       0x2001, 0x4005, 0x0078, 0x1286, 0x7ab6, 0x7bba, 0x7dbe, 0x7ec2,
+       0x7cb2, 0x78cc, 0xa084, 0xfcff, 0x78ce, 0x0078, 0x138b, 0x78cc,
+       0xa085, 0x0100, 0x78ce, 0x0078, 0x1284, 0x2009, 0x5161, 0x210c,
+       0x7aec, 0x0078, 0x1282, 0x2009, 0x5141, 0x210c, 0x0078, 0x1283,
+       0x2009, 0x5142, 0x210c, 0x0078, 0x1283, 0x2061, 0x5140, 0x610c,
+       0x6210, 0x0078, 0x1282, 0x2009, 0x5145, 0x210c, 0x0078, 0x1283,
+       0x2009, 0x5146, 0x210c, 0x0078, 0x1283, 0x2009, 0x5148, 0x210c,
+       0x0078, 0x1283, 0x2009, 0x5149, 0x210c, 0x0078, 0x1283, 0x7908,
+       0x7a0c, 0x0078, 0x1282, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003,
+       0x8003, 0x8003, 0xa0e8, 0x5380, 0x6a00, 0x6804, 0xa084, 0x0008,
+       0x0040, 0x13cd, 0x6b08, 0x0078, 0x13ce, 0x6b0c, 0x0078, 0x1281,
+       0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091,
+       0x8001, 0x2708, 0x0078, 0x1281, 0x794c, 0x0078, 0x1283, 0x77c4,
+       0x1078, 0x1973, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091,
+       0x8001, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x127c,
+       0x1078, 0x22e2, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8,
+       0x127c, 0x2011, 0x5141, 0x2204, 0x007e, 0x2112, 0x1078, 0x229b,
+       0x017f, 0x0078, 0x1283, 0x71c4, 0x2011, 0x1421, 0x20a9, 0x0008,
+       0x2204, 0xa106, 0x0040, 0x1413, 0x8210, 0x0070, 0x1411, 0x0078,
+       0x1408, 0x0078, 0x127c, 0xa292, 0x1421, 0x027e, 0x2011, 0x5142,
+       0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x22a7, 0x017f, 0x0078,
+       0x1283, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032,
+       0x004b, 0x2061, 0x5140, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8,
+       0x6012, 0x0078, 0x1282, 0x2061, 0x5140, 0x6114, 0x70c4, 0x6016,
+       0x0078, 0x1283, 0x2061, 0x5140, 0x71c4, 0x2011, 0x0004, 0x601f,
+       0x0019, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x145b, 0x2011,
+       0x0005, 0x601f, 0x0019, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040,
+       0x145b, 0x2011, 0x0006, 0x601f, 0x000c, 0x2019, 0x2222, 0xa186,
+       0x003c, 0x00c0, 0x127c, 0x6018, 0x007e, 0x611a, 0x7800, 0xa084,
+       0x0001, 0x00c0, 0x1476, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+       0x0048, 0x146e, 0x0038, 0x1472, 0x0078, 0x1476, 0x0028, 0x1472,
+       0x0078, 0x1476, 0x2019, 0x2222, 0x0078, 0x1478, 0x2019, 0x1212,
+       0x23b8, 0x1078, 0x22b8, 0x1078, 0x4d22, 0x017f, 0x0078, 0x1283,
+       0x71c4, 0xa184, 0xffcf, 0x00c0, 0x127c, 0x2011, 0x5148, 0x2204,
+       0x2112, 0x007e, 0x1078, 0x22da, 0x017f, 0x0078, 0x1283, 0x71c4,
+       0xa182, 0x0010, 0x00c8, 0x127c, 0x2011, 0x5149, 0x2204, 0x007e,
+       0x2112, 0x1078, 0x22c9, 0x017f, 0x0078, 0x1283, 0x71c4, 0x72c8,
+       0xa184, 0xfffd, 0x00c0, 0x127b, 0xa284, 0xfffd, 0x00c0, 0x127b,
+       0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1282,
+       0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8,
+       0x5380, 0x2019, 0x0000, 0x72c8, 0xa284, 0x0080, 0x0040, 0x14c6,
+       0x6c14, 0x84ff, 0x00c0, 0x14c6, 0x6817, 0x0040, 0xa284, 0x0040,
+       0x0040, 0x14d0, 0x6c10, 0x84ff, 0x00c0, 0x14d0, 0x6813, 0x0001,
+       0x6800, 0x007e, 0xa226, 0x0040, 0x14f3, 0x6a02, 0xa484, 0x2000,
+       0x0040, 0x14dc, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14e2,
+       0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14f3, 0x810f, 0xa284,
+       0x4000, 0x0040, 0x14ef, 0x1078, 0x22fc, 0x0078, 0x14f3, 0x1078,
+       0x22ee, 0x0078, 0x14f3, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1522,
+       0xa2a4, 0x00ff, 0x2061, 0x5140, 0x6118, 0xa186, 0x0028, 0x0040,
+       0x1509, 0xa186, 0x0032, 0x0040, 0x150f, 0xa186, 0x003c, 0x0040,
+       0x1515, 0xa482, 0x0064, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482,
+       0x0050, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482, 0x0043, 0x0048,
+       0x151f, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x127d, 0x6a0a,
+       0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4,
+       0x0078, 0x1281, 0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6a14,
+       0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708,
+       0x0078, 0x1281, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1283, 0x71c4,
+       0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x127c, 0x1078, 0x230a,
+       0x0078, 0x1281, 0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6a08,
+       0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
+       0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9,
+       0x6a0a, 0x6804, 0xa005, 0x0040, 0x1567, 0x1078, 0x21d2, 0x2091,
+       0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x1078, 0x1973, 0x2091,
+       0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040,
+       0x157b, 0x1078, 0x21d2, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
+       0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091,
+       0x8000, 0x1078, 0x1980, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078,
+       0x1282, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078,
+       0x19e1, 0x00c0, 0x15a9, 0x6818, 0xa005, 0x0040, 0x15a9, 0x2708,
+       0x1078, 0x231a, 0x00c0, 0x15a9, 0x7817, 0x0015, 0x2091, 0x8001,
+       0x007c, 0x2091, 0x8001, 0x0078, 0x1284, 0x77c4, 0x77c6, 0x2041,
+       0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078,
+       0x1980, 0x2061, 0x5140, 0x606f, 0x0003, 0x6782, 0x6093, 0x000f,
+       0x6073, 0x0000, 0x7817, 0x0016, 0x1078, 0x21d2, 0x2091, 0x8001,
+       0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091,
+       0x8000, 0x2061, 0x5140, 0x606f, 0x0002, 0x6073, 0x0000, 0x6782,
+       0x6093, 0x000f, 0x7817, 0x0017, 0x1078, 0x21d2, 0x2091, 0x8001,
+       0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000,
+       0x1078, 0x1980, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0,
+       0x15e8, 0x2091, 0x8001, 0x007c, 0x78cc, 0xa084, 0x0003, 0x00c0,
+       0x1618, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051,
+       0x0008, 0x1078, 0x1973, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a,
+       0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1601, 0xa7bc,
+       0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1601,
+       0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040,
+       0x1641, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004,
+       0x0040, 0x162e, 0x0070, 0x162e, 0x0078, 0x1625, 0x684b, 0x0009,
+       0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x163b, 0x0070,
+       0x163b, 0x0078, 0x1632, 0x20a9, 0x00fa, 0x0070, 0x1641, 0x0078,
+       0x163d, 0x2079, 0x5100, 0x7817, 0x0018, 0x2061, 0x5140, 0x606f,
+       0x0001, 0x6073, 0x0000, 0x6093, 0x000f, 0x78cc, 0xa085, 0x0002,
+       0x78ce, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2091,
+       0x8001, 0x007c, 0x78cc, 0xa084, 0xfffd, 0x78ce, 0xa084, 0x0001,
+       0x00c0, 0x1664, 0x1078, 0x1a2b, 0x71c4, 0x71c6, 0x794a, 0x007c,
+       0x1078, 0x1b53, 0x00c0, 0x129c, 0x75d8, 0x74dc, 0x75da, 0x74de,
+       0x0078, 0x1675, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc,
+       0x71c6, 0x73ca, 0x72ce, 0x2079, 0x5100, 0x2091, 0x8000, 0x1078,
+       0x192e, 0x2091, 0x8001, 0x0040, 0x172c, 0x20a9, 0x0005, 0x20a1,
+       0x5118, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0020,
+       0x1078, 0x1929, 0x0040, 0x1698, 0x1078, 0x1948, 0x0078, 0x172c,
+       0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x16fb, 0x0c7e,
+       0x2c68, 0x2091, 0x8000, 0x1078, 0x192e, 0x2091, 0x8001, 0x0040,
+       0x16cc, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x16a0, 0x609f, 0x0000,
+       0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c,
+       0xa065, 0x0040, 0x16fa, 0x2009, 0x0020, 0x1078, 0x1929, 0x00c0,
+       0x16e3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x16cc,
+       0x2d00, 0x6002, 0x0078, 0x16b2, 0x0c7f, 0x0c7e, 0x609c, 0x2060,
+       0x1078, 0x19b3, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009,
+       0x000c, 0x6008, 0xa085, 0x0200, 0x600a, 0x1078, 0x1924, 0x1078,
+       0x1948, 0x0078, 0x172c, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078,
+       0x19b3, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c,
+       0x6007, 0x0103, 0x601b, 0x0003, 0x1078, 0x1924, 0x1078, 0x1948,
+       0x0078, 0x172c, 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091,
+       0x8000, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x5140, 0x706f, 0x0005,
+       0x7073, 0x0000, 0x7376, 0x727a, 0x747e, 0x7082, 0x7087, 0x0000,
+       0x2c00, 0x708a, 0x708f, 0x0000, 0xa02e, 0x2530, 0x611c, 0x61a2,
+       0xa184, 0x0060, 0x0040, 0x171e, 0x1078, 0x47c2, 0x0e7f, 0x6596,
+       0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078,
+       0x21d2, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287,
+       0x20a9, 0x0005, 0x2099, 0x5118, 0x2091, 0x8000, 0x530a, 0x2091,
+       0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+       0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x1284,
+       0x71c4, 0x71c6, 0x2168, 0x0078, 0x174f, 0x2069, 0x1000, 0x690c,
+       0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1751, 0xa285,
+       0x0000, 0x00c0, 0x175f, 0x70c3, 0x4000, 0x0078, 0x1761, 0x70c3,
+       0x4003, 0x70ca, 0x0078, 0x1287, 0x2011, 0x5167, 0x220c, 0x70c4,
+       0x8003, 0x0048, 0x1771, 0x1078, 0x3b7f, 0xa184, 0x7fff, 0x0078,
+       0x1775, 0x1078, 0x3b72, 0xa185, 0x8000, 0x2012, 0x0078, 0x1283,
+       0x71c4, 0x1078, 0x3b69, 0x6100, 0x2001, 0x5167, 0x2004, 0xa084,
+       0x8000, 0xa10d, 0x6204, 0x6308, 0x0078, 0x1281, 0x79e4, 0x0078,
+       0x1283, 0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004,
+       0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078,
+       0x1284, 0x70c4, 0x2068, 0x2079, 0x5100, 0x2091, 0x8000, 0x1078,
+       0x192e, 0x2091, 0x8001, 0x0040, 0x1825, 0x6007, 0x0001, 0x600b,
+       0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x000f,
+       0xa284, 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016,
+       0xa284, 0x0800, 0x0040, 0x17c0, 0x601b, 0x000a, 0x0078, 0x17c6,
+       0xa284, 0x1000, 0x0040, 0x17c6, 0x601b, 0x000c, 0xa284, 0x0300,
+       0x0040, 0x17cf, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085,
+       0x0001, 0x601e, 0x6023, 0x0000, 0x6027, 0x0000, 0xa284, 0x0400,
+       0x0040, 0x17dc, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b,
+       0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0,
+       0x17f1, 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078,
+       0x17fb, 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c,
+       0x6552, 0x6596, 0x669a, 0x6014, 0x2091, 0x8000, 0x7817, 0x0042,
+       0x2c08, 0x2061, 0x5140, 0x606f, 0x0005, 0x6073, 0x0000, 0x6077,
+       0x0000, 0x607b, 0x0000, 0x607f, 0x0000, 0x6082, 0x618a, 0xa284,
+       0x0400, 0x608e, 0x2091, 0x8001, 0x0e7e, 0x2071, 0x0020, 0x7007,
+       0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x2091, 0x8000,
+       0x1078, 0x21d2, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078,
+       0x1287, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2091, 0x8000, 0x2071,
+       0x5140, 0x2079, 0x0100, 0x2061, 0x0010, 0x70a0, 0xa06d, 0x0040,
+       0x18b1, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0007, 0x0040, 0x1844,
+       0xa286, 0x000f, 0x00c0, 0x18b1, 0x691c, 0xa184, 0x0080, 0x00c0,
+       0x18b1, 0x6824, 0xa18c, 0xff00, 0xa085, 0x0019, 0x6826, 0x71b0,
+       0x81ff, 0x0040, 0x1867, 0x0d7e, 0x2069, 0x0020, 0x6807, 0x0010,
+       0x6908, 0x6808, 0xa106, 0x00c0, 0x1858, 0x690c, 0x680c, 0xa106,
+       0x00c0, 0x185d, 0xa184, 0x00ff, 0x00c0, 0x185d, 0x0d7f, 0x78b8,
+       0xa084, 0x801f, 0x00c0, 0x1867, 0x7848, 0xa085, 0x000c, 0x784a,
+       0x71b0, 0x81ff, 0x0040, 0x188a, 0x70b3, 0x0000, 0x0d7e, 0x2069,
+       0x0020, 0x6807, 0x0018, 0x6804, 0xa084, 0x0008, 0x00c0, 0x187b,
+       0x6807, 0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, 0x1882, 0x6807,
+       0x0002, 0x0d7f, 0x61c4, 0x62c8, 0x63cc, 0x61c6, 0x62ca, 0x63ce,
+       0x0e7e, 0x2071, 0x5100, 0x7266, 0x736a, 0xae80, 0x0019, 0x0e7f,
+       0x7848, 0xa084, 0x000c, 0x00c0, 0x1898, 0x1078, 0x46db, 0x78a3,
+       0x0000, 0x7858, 0xa084, 0xedff, 0x785a, 0x70b4, 0xa080, 0x00df,
+       0x781a, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001, 0x0078,
+       0x1284, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001, 0x2001,
+       0x4005, 0x0078, 0x1286, 0x7980, 0x71c6, 0x71c4, 0xa182, 0x0003,
+       0x00c8, 0x127c, 0x7982, 0x0078, 0x1284, 0x7980, 0x71c6, 0x0078,
+       0x1284, 0x7974, 0x71c6, 0x71c4, 0x7976, 0x7978, 0x71ca, 0x71c8,
+       0x797a, 0x797c, 0x71ce, 0x71cc, 0x797e, 0x0078, 0x1284, 0x7974,
+       0x71c6, 0x7978, 0x71ca, 0x797c, 0x71ce, 0x0078, 0x1284, 0x7900,
+       0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+       0x0048, 0x18ee, 0x0038, 0x18f0, 0x0078, 0x18fa, 0x00a8, 0x18fa,
+       0xa18c, 0x0001, 0x00c0, 0x18f8, 0x20b9, 0x2222, 0x0078, 0x18fa,
+       0x20b9, 0x1212, 0x0078, 0x1284, 0x7900, 0x71c6, 0x0078, 0x1284,
+       0x2009, 0x5174, 0x2104, 0x70c6, 0x70c4, 0x200a, 0x0078, 0x1284,
+       0x2009, 0x5174, 0x2104, 0x70c6, 0x0078, 0x1284, 0x71c4, 0x8107,
+       0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x5380, 0x6a14,
+       0xd2b4, 0x0040, 0x191f, 0x2011, 0x0001, 0x0078, 0x1921, 0x2011,
+       0x0000, 0x6b0c, 0x0078, 0x1281, 0xac80, 0x0001, 0x1078, 0x1b0f,
+       0x007c, 0xac80, 0x0001, 0x1078, 0x1aaf, 0x007c, 0x7850, 0xa065,
+       0x0040, 0x1936, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e,
+       0x2079, 0x5100, 0x7850, 0xa06d, 0x0040, 0x1946, 0x2d04, 0x7852,
+       0x6803, 0x0000, 0x6807, 0x0000, 0x680b, 0x0000, 0x0f7f, 0x007c,
+       0x2091, 0x8000, 0x0f7e, 0x2079, 0x5100, 0x7850, 0x2062, 0x2c00,
+       0xa005, 0x00c0, 0x1955, 0x1078, 0x23eb, 0x7852, 0x0f7f, 0x2091,
+       0x8001, 0x007c, 0x0f7e, 0x2079, 0x5100, 0x7850, 0x206a, 0x2d00,
+       0x7852, 0x0f7f, 0x007c, 0x2011, 0x7800, 0x7a52, 0x7bec, 0x8319,
+       0x0040, 0x1970, 0xa280, 0x0031, 0x2012, 0x2010, 0x0078, 0x1967,
+       0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f,
+       0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x5400, 0x007c,
+       0x1078, 0x1973, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084,
+       0xffef, 0xa80d, 0x690a, 0x2009, 0x5152, 0x210c, 0x6804, 0xa005,
+       0x0040, 0x19b2, 0xa116, 0x00c0, 0x199d, 0x2060, 0x6000, 0x6806,
+       0x017e, 0x200b, 0x0000, 0x0078, 0x19a0, 0x2009, 0x0000, 0x017e,
+       0x6804, 0xa065, 0x0040, 0x19af, 0x6000, 0x6806, 0x1078, 0x19c0,
+       0x1078, 0x1c5f, 0x6810, 0x8001, 0x6812, 0x00c0, 0x19a0, 0x017f,
+       0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x19bf, 0x609c, 0x609f,
+       0x0000, 0x2008, 0x1078, 0x1948, 0x2100, 0x0078, 0x19b3, 0x007c,
+       0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005,
+       0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022,
+       0x007c, 0x0e7e, 0x2071, 0x5140, 0x704c, 0xa08c, 0x0200, 0x00c0,
+       0x19df, 0xa088, 0x5180, 0x2d0a, 0x8000, 0x704e, 0xa006, 0x0e7f,
+       0x007c, 0x1078, 0x1973, 0x2091, 0x8000, 0x6804, 0x781e, 0xa065,
+       0x0040, 0x1a2a, 0x0078, 0x19f2, 0x2c00, 0x781e, 0x6000, 0xa065,
+       0x0040, 0x1a2a, 0x600c, 0xa306, 0x00c0, 0x19ec, 0x6010, 0xa206,
+       0x00c0, 0x19ec, 0x2c28, 0x2001, 0x5152, 0x2004, 0xac06, 0x00c0,
+       0x1a03, 0x0078, 0x1a28, 0x6804, 0xac06, 0x00c0, 0x1a10, 0x6000,
+       0xa065, 0x6806, 0x00c0, 0x1a1a, 0x6803, 0x0000, 0x0078, 0x1a1a,
+       0x6400, 0x781c, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1a1a,
+       0x2c00, 0x6802, 0x2560, 0x1078, 0x19c0, 0x601b, 0x0005, 0x6023,
+       0x0020, 0x1078, 0x1c5f, 0x6810, 0x8001, 0x1050, 0x23eb, 0x6812,
+       0xa085, 0xffff, 0x007c, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049,
+       0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x1980, 0x8738,
+       0xa784, 0x001f, 0x00c0, 0x1a35, 0xa7bc, 0xff00, 0x873f, 0x8738,
+       0x873f, 0xa784, 0x0f00, 0x00c0, 0x1a35, 0x2091, 0x8001, 0x007c,
+       0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1a59, 0x2091,
+       0x8000, 0x78e0, 0x78e3, 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0,
+       0x1a5a, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1a60, 0x1078, 0x23eb,
+       0x0079, 0x1a62, 0x1a72, 0x1a75, 0x1a7b, 0x1a7f, 0x1a73, 0x1a83,
+       0x1a89, 0x1a73, 0x1a73, 0x1c29, 0x1c4d, 0x1c51, 0x1a73, 0x1a73,
+       0x1a73, 0x1a73, 0x007c, 0x1078, 0x23eb, 0x1078, 0x1a2b, 0x2001,
+       0x8001, 0x0078, 0x1c57, 0x2001, 0x8003, 0x0078, 0x1c57, 0x2001,
+       0x8004, 0x0078, 0x1c57, 0x1078, 0x1a2b, 0x2001, 0x8006, 0x0078,
+       0x1c57, 0x2001, 0x8007, 0x0078, 0x1c57, 0x2030, 0x2138, 0xa782,
+       0x0021, 0x0048, 0x1a95, 0x2009, 0x0020, 0x2600, 0x1078, 0x1aaf,
+       0x00c0, 0x1aae, 0xa7ba, 0x0020, 0x0048, 0x1aad, 0x0040, 0x1aad,
+       0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1,
+       0x0000, 0xa5a9, 0x0000, 0x0078, 0x1a8f, 0xa006, 0x007c, 0x81ff,
+       0x0040, 0x1aea, 0x2099, 0x0030, 0x20a0, 0x700c, 0xa084, 0x00ff,
+       0x0040, 0x1ac1, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+       0x1abc, 0x21a8, 0x7017, 0x0000, 0x810b, 0x7112, 0x721a, 0x731e,
+       0x7422, 0x7526, 0x780c, 0xa085, 0x0001, 0x7002, 0x7007, 0x0001,
+       0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x1ade, 0x2009,
+       0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1ad0, 0x7008, 0x800b,
+       0x00c8, 0x1ad0, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x1aea,
+       0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x2030, 0x2138, 0xa782,
+       0x0021, 0x0048, 0x1af5, 0x2009, 0x0020, 0x2600, 0x1078, 0x1b0f,
+       0x00c0, 0x1b0e, 0xa7ba, 0x0020, 0x0048, 0x1b0d, 0x0040, 0x1b0d,
+       0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1,
+       0x0000, 0xa5a9, 0x0000, 0x0078, 0x1aef, 0xa006, 0x007c, 0x81ff,
+       0x0040, 0x1b50, 0x2098, 0x20a1, 0x0030, 0x700c, 0xa084, 0x00ff,
+       0x0040, 0x1b21, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+       0x1b1c, 0x21a8, 0x7017, 0x0000, 0x810b, 0x7112, 0x721a, 0x731e,
+       0x7422, 0x7526, 0x780c, 0xa085, 0x0000, 0x7002, 0x53a6, 0x7007,
+       0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x1b3f,
+       0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1b31, 0x7010,
+       0xa084, 0xf000, 0x0040, 0x1b48, 0x7007, 0x0008, 0x0078, 0x1b4c,
+       0x7108, 0x8103, 0x00c8, 0x1b31, 0x7007, 0x0002, 0xa184, 0x01e0,
+       0x7003, 0x0000, 0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0004,
+       0x00c8, 0x1b5c, 0x0078, 0x1b5f, 0xa006, 0x0078, 0x1b61, 0xa085,
+       0x0001, 0x007c, 0x0e7e, 0x2071, 0x5100, 0x2d08, 0x7058, 0x6802,
+       0xa005, 0x00c0, 0x1b6c, 0x715e, 0x715a, 0x0e7f, 0x007c, 0x2c08,
+       0x7858, 0x6002, 0xa005, 0x00c0, 0x1b76, 0x795e, 0x795a, 0x007c,
+       0x2091, 0x8000, 0x6003, 0x0000, 0x2c08, 0x785c, 0xa065, 0x00c0,
+       0x1b84, 0x795a, 0x0078, 0x1b85, 0x6102, 0x795e, 0x2091, 0x8001,
+       0x1078, 0x21ef, 0x007c, 0x0e7e, 0x2071, 0x5100, 0x7058, 0xa06d,
+       0x0040, 0x1b99, 0x6800, 0x705a, 0xa005, 0x00c0, 0x1b98, 0x705e,
+       0x8dff, 0x0e7f, 0x007c, 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5100,
+       0xaf80, 0x0016, 0x2060, 0x6000, 0xa005, 0x0040, 0x1bc9, 0x2068,
+       0x6814, 0xa306, 0x00c0, 0x1bb2, 0x6828, 0xa084, 0x00ff, 0xa406,
+       0x0040, 0x1bb5, 0x2d60, 0x0078, 0x1ba3, 0x6800, 0xa005, 0x6002,
+       0x00c0, 0x1bc1, 0xaf80, 0x0016, 0xac06, 0x0040, 0x1bc0, 0x2c00,
+       0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bc8, 0x1078, 0x19b3,
+       0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x0d7e, 0x0c7e,
+       0x0f7e, 0x2079, 0x5100, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa005,
+       0x0040, 0x1bf8, 0x2068, 0x6814, 0xa084, 0x00ff, 0xa306, 0x0040,
+       0x1be4, 0x2d60, 0x0078, 0x1bd6, 0x6800, 0xa005, 0x6002, 0x00c0,
+       0x1bf0, 0xaf80, 0x0016, 0xac06, 0x0040, 0x1bef, 0x2c00, 0x785e,
+       0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bf7, 0x1078, 0x19b3, 0x007f,
+       0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x0d7e, 0x0c7e, 0x0f7e,
+       0x2079, 0x5100, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa06d, 0x0040,
+       0x1c24, 0x6814, 0xa306, 0x0040, 0x1c10, 0x2d60, 0x0078, 0x1c05,
+       0x6800, 0xa005, 0x6002, 0x00c0, 0x1c1c, 0xaf80, 0x0016, 0xac06,
+       0x0040, 0x1c1b, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040,
+       0x1c23, 0x1078, 0x19b3, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005,
+       0x007c, 0x2091, 0x8000, 0x2069, 0x5140, 0x6800, 0xa086, 0x0000,
+       0x0040, 0x1c37, 0x2091, 0x8001, 0x78e3, 0x0009, 0x007c, 0x6880,
+       0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010,
+       0x1078, 0x1980, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1c40, 0x2091,
+       0x8001, 0x2001, 0x800a, 0x0078, 0x1c57, 0x2001, 0x800c, 0x0078,
+       0x1c57, 0x1078, 0x1a2b, 0x2001, 0x800d, 0x0078, 0x1c57, 0x70c2,
+       0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, 0x6004,
+       0x2c08, 0x2063, 0x0000, 0x7884, 0x8000, 0x7886, 0x7888, 0xa005,
+       0x798a, 0x0040, 0x1c6e, 0x2c02, 0x0078, 0x1c6f, 0x798e, 0x007c,
+       0x6807, 0x0103, 0x0c7e, 0x2061, 0x5100, 0x2d08, 0x206b, 0x0000,
+       0x6084, 0x8000, 0x6086, 0x6088, 0xa005, 0x618a, 0x0040, 0x1c83,
+       0x2d02, 0x0078, 0x1c84, 0x618e, 0x0c7f, 0x007c, 0x1078, 0x1c97,
+       0x0040, 0x1c96, 0x0c7e, 0x609c, 0xa065, 0x0040, 0x1c91, 0x1078,
+       0x19b3, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1948, 0x007c, 0x788c,
+       0xa065, 0x0040, 0x1ca9, 0x2091, 0x8000, 0x7884, 0x8001, 0x7886,
+       0x2c04, 0x788e, 0xa005, 0x00c0, 0x1ca7, 0x788a, 0x8000, 0x2091,
+       0x8001, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e,
+       0x00c8, 0x1cb3, 0xa200, 0x0070, 0x1cb7, 0x0078, 0x1cae, 0x8086,
+       0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x1cdd,
+       0xa11a, 0x00c8, 0x1cdd, 0x8213, 0x818d, 0x0048, 0x1cce, 0xa11a,
+       0x00c8, 0x1ccf, 0x0070, 0x1cd5, 0x0078, 0x1cc3, 0xa11a, 0x2308,
+       0x8210, 0x0070, 0x1cd5, 0x0078, 0x1cc3, 0x007e, 0x3200, 0xa084,
+       0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085,
+       0x0800, 0x0078, 0x1cd9, 0x7994, 0x70d0, 0xa106, 0x0040, 0x1d51,
+       0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1d51,
+       0x7008, 0x7208, 0xa206, 0x00c0, 0x1d51, 0xa286, 0x0008, 0x00c0,
+       0x1d51, 0x2071, 0x0010, 0x1078, 0x192e, 0x0040, 0x1d51, 0x7a9c,
+       0x7b98, 0x7ca4, 0x7da0, 0xa184, 0xff00, 0x0040, 0x1d1f, 0x2031,
+       0x0000, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b,
+       0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x2100, 0xa210, 0x2600,
+       0xa319, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1d29, 0x8107,
+       0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+       0x0000, 0x2009, 0x0020, 0x1078, 0x1929, 0x2091, 0x8001, 0x0040,
+       0x1d48, 0x1078, 0x1948, 0x78a8, 0x8000, 0x78aa, 0xa086, 0x0002,
+       0x00c0, 0x1d51, 0x2091, 0x8000, 0x78e3, 0x0002, 0x78ab, 0x0000,
+       0x78cc, 0xa085, 0x0003, 0x78ce, 0x2091, 0x8001, 0x0078, 0x1d51,
+       0x78ab, 0x0000, 0x1078, 0x20ac, 0x6004, 0xa084, 0x000f, 0x0079,
+       0x1d56, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x1d66, 0x1d88,
+       0x1dae, 0x1d66, 0x1dcb, 0x1d75, 0x1f2c, 0x1f47, 0x1d66, 0x1d82,
+       0x1da8, 0x1e13, 0x1e82, 0x1ed2, 0x1ee4, 0x1f43, 0x2039, 0x0400,
+       0x78dc, 0xa705, 0x78de, 0x6008, 0xa705, 0x600a, 0x1078, 0x1fc7,
+       0x609c, 0x78da, 0x1078, 0x2094, 0x007c, 0x78dc, 0xa084, 0x0100,
+       0x0040, 0x1d7c, 0x0078, 0x1d66, 0x601c, 0xa085, 0x0080, 0x601e,
+       0x0078, 0x1d8f, 0x1078, 0x1b53, 0x00c0, 0x1d66, 0x1078, 0x20c6,
+       0x78dc, 0xa084, 0x0100, 0x0040, 0x1d8f, 0x0078, 0x1d66, 0x78df,
+       0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f,
+       0x0000, 0x0040, 0x1da5, 0x1078, 0x1fc7, 0x0040, 0x1da5, 0x78dc,
+       0xa085, 0x0100, 0x78de, 0x0078, 0x1da7, 0x1078, 0x1feb, 0x007c,
+       0x1078, 0x1b53, 0x00c0, 0x1d66, 0x1078, 0x20c2, 0x78dc, 0xa08c,
+       0x0e00, 0x00c0, 0x1db7, 0xa084, 0x0100, 0x00c0, 0x1db9, 0x0078,
+       0x1d66, 0x1078, 0x1fc7, 0x00c0, 0x1dca, 0x6104, 0xa18c, 0x00ff,
+       0xa186, 0x0007, 0x0040, 0x1f84, 0xa186, 0x000f, 0x0040, 0x1f84,
+       0x1078, 0x1feb, 0x007c, 0x78dc, 0xa084, 0x0100, 0x0040, 0x1dd2,
+       0x0078, 0x1d66, 0x78df, 0x0000, 0x6714, 0x2011, 0x0001, 0x20a9,
+       0x0001, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x1df5, 0x2011,
+       0x0001, 0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040,
+       0x1df5, 0x2039, 0x0000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e,
+       0x0002, 0x0040, 0x1df5, 0x0078, 0x1e10, 0x1078, 0x1973, 0x2091,
+       0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde,
+       0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x0070, 0x1e09, 0x0078,
+       0x1df7, 0x8211, 0x0040, 0x1e10, 0x20a9, 0x0100, 0x0078, 0x1df7,
+       0x1078, 0x1948, 0x007c, 0x2001, 0x5167, 0x2004, 0xa084, 0x8000,
+       0x0040, 0x1fac, 0x6114, 0x1078, 0x20e3, 0x6900, 0xa184, 0x0001,
+       0x0040, 0x1e34, 0x6028, 0xa084, 0x00ff, 0x00c0, 0x1fa4, 0x6800,
+       0xa084, 0x0001, 0x0040, 0x1fac, 0x6803, 0x0000, 0x680b, 0x0000,
+       0x6807, 0x0000, 0x0078, 0x1fb4, 0x2011, 0x0001, 0x6020, 0xd0f4,
+       0x0040, 0x1e3c, 0xa295, 0x0002, 0xd0c4, 0x0040, 0x1e41, 0xa295,
+       0x0008, 0xd0cc, 0x0040, 0x1e46, 0xa295, 0x0400, 0x601c, 0xa084,
+       0x0002, 0x0040, 0x1e4d, 0xa295, 0x0004, 0x602c, 0xa08c, 0x00ff,
+       0xa182, 0x0002, 0x0048, 0x1fb0, 0xa182, 0x001b, 0x00c8, 0x1fb0,
+       0x0040, 0x1fb0, 0x690e, 0x602c, 0x8007, 0xa08c, 0x00ff, 0xa182,
+       0x0002, 0x0048, 0x1fb0, 0xa182, 0x001b, 0x00c8, 0x1fb0, 0x0040,
+       0x1fb0, 0x6912, 0x6030, 0xa005, 0x00c0, 0x1e70, 0x2001, 0x001e,
+       0x8000, 0x6816, 0x6028, 0xa084, 0x00ff, 0x0040, 0x1fac, 0x6806,
+       0x6028, 0x8007, 0xa084, 0x00ff, 0x0040, 0x1fac, 0x680a, 0x6a02,
+       0x0078, 0x1fb4, 0x2001, 0x5167, 0x2004, 0xa084, 0x8000, 0x0040,
+       0x1fac, 0x6114, 0x1078, 0x20e3, 0x2091, 0x8000, 0x6a04, 0x6b08,
+       0x6418, 0xa484, 0x0003, 0x0040, 0x1ea8, 0x6128, 0xa18c, 0x00ff,
+       0x8001, 0x00c0, 0x1ea1, 0x2100, 0xa210, 0x0048, 0x1ece, 0x0078,
+       0x1ea8, 0x8001, 0x00c0, 0x1ece, 0x2100, 0xa212, 0x0048, 0x1ece,
+       0xa484, 0x000c, 0x0040, 0x1ec2, 0x6128, 0x810f, 0xa18c, 0x00ff,
+       0xa082, 0x0004, 0x00c0, 0x1eba, 0x2100, 0xa318, 0x0048, 0x1ece,
+       0x0078, 0x1ec2, 0xa082, 0x0004, 0x00c0, 0x1ece, 0x2100, 0xa31a,
+       0x0048, 0x1ece, 0x6030, 0xa005, 0x0040, 0x1ec8, 0x8000, 0x6816,
+       0x6a06, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1fb4, 0x2091, 0x8001,
+       0x0078, 0x1fb0, 0x6114, 0x1078, 0x20e3, 0x2091, 0x8000, 0x6b08,
+       0x8318, 0x0048, 0x1ee0, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1fc3,
+       0x2091, 0x8001, 0x0078, 0x1fb0, 0x6024, 0x8007, 0xa084, 0x00ff,
+       0x0040, 0x1f02, 0xa086, 0x0080, 0x00c0, 0x1f2a, 0x20a9, 0x0008,
+       0x2069, 0x7510, 0x2091, 0x8000, 0x6800, 0xa084, 0xfcff, 0x6802,
+       0xade8, 0x0008, 0x0070, 0x1efe, 0x0078, 0x1ef4, 0x2091, 0x8001,
+       0x0078, 0x1fb4, 0x6028, 0xa015, 0x0040, 0x1f2a, 0x6114, 0x1078,
+       0x20e3, 0x0d7e, 0xade8, 0x0007, 0x2091, 0x8000, 0x6800, 0xa00d,
+       0x0040, 0x1f27, 0xa206, 0x0040, 0x1f18, 0x2168, 0x0078, 0x1f0e,
+       0x0c7e, 0x2160, 0x6000, 0x6802, 0x1078, 0x1948, 0x0c7f, 0x0d7f,
+       0x6808, 0x8000, 0x680a, 0x2091, 0x8001, 0x0078, 0x1fc3, 0x2091,
+       0x8001, 0x0d7f, 0x0078, 0x1fac, 0x6114, 0x1078, 0x20e3, 0x6800,
+       0xa084, 0x0001, 0x0040, 0x1f9c, 0x2091, 0x8000, 0x6a04, 0x8210,
+       0x0048, 0x1f3f, 0x6a06, 0x2091, 0x8001, 0x0078, 0x1fc3, 0x2091,
+       0x8001, 0x0078, 0x1fb0, 0x1078, 0x1b53, 0x00c0, 0x1d66, 0x6114,
+       0x1078, 0x20e3, 0x60be, 0x60bb, 0x0000, 0x6900, 0xa184, 0x0008,
+       0x0040, 0x1f56, 0x6020, 0xa085, 0x0100, 0x6022, 0xa184, 0x0001,
+       0x0040, 0x1fac, 0xa184, 0x0100, 0x00c0, 0x1f98, 0xa184, 0x0200,
+       0x00c0, 0x1f94, 0x681c, 0xa005, 0x00c0, 0x1fa0, 0x6004, 0xa084,
+       0x00ff, 0xa086, 0x000f, 0x00c0, 0x1f6f, 0x1078, 0x20c6, 0x78df,
+       0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f,
+       0x0000, 0x0040, 0x1f84, 0x1078, 0x1fc7, 0x0040, 0x1f84, 0x78dc,
+       0xa085, 0x0100, 0x78de, 0x007c, 0x78d7, 0x0000, 0x78db, 0x0000,
+       0x6024, 0xa084, 0xff00, 0x6026, 0x1078, 0x39de, 0x0040, 0x1ce3,
+       0x1078, 0x1b78, 0x0078, 0x1ce3, 0x2009, 0x0017, 0x0078, 0x1fb6,
+       0x2009, 0x000e, 0x0078, 0x1fb6, 0x2009, 0x0007, 0x0078, 0x1fb6,
+       0x2009, 0x0035, 0x0078, 0x1fb6, 0x2009, 0x003e, 0x0078, 0x1fb6,
+       0x2009, 0x0004, 0x0078, 0x1fb6, 0x2009, 0x0006, 0x0078, 0x1fb6,
+       0x2009, 0x0016, 0x0078, 0x1fb6, 0x2009, 0x0001, 0x6024, 0xa084,
+       0xff00, 0xa105, 0x6026, 0x2091, 0x8000, 0x1078, 0x1c5f, 0x2091,
+       0x8001, 0x0078, 0x1ce3, 0x1078, 0x1948, 0x0078, 0x1ce3, 0x78d4,
+       0xa06d, 0x00c0, 0x1fd2, 0x2c00, 0x78d6, 0x78da, 0x609f, 0x0000,
+       0x0078, 0x1fde, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78d6, 0x2d00,
+       0x6002, 0x78d8, 0xad06, 0x00c0, 0x1fde, 0x6002, 0x78d0, 0x8001,
+       0x78d2, 0x00c0, 0x1fea, 0x78dc, 0xa084, 0xfeff, 0x78de, 0x78d8,
+       0x2060, 0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184,
+       0xe1ff, 0x601e, 0xa184, 0x0060, 0x0040, 0x1ffa, 0x0e7e, 0x1078,
+       0x47c2, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000,
+       0x60b3, 0x0000, 0x6714, 0x1078, 0x1973, 0x2091, 0x8000, 0x60a0,
+       0xa084, 0x8000, 0x00c0, 0x2021, 0x6808, 0xa084, 0x0001, 0x0040,
+       0x2021, 0x2091, 0x8001, 0x1078, 0x19c0, 0x2091, 0x8000, 0x1078,
+       0x1c5f, 0x2091, 0x8001, 0x78d7, 0x0000, 0x78db, 0x0000, 0x0078,
+       0x2093, 0x6024, 0xa096, 0x0001, 0x00c0, 0x2028, 0x8000, 0x6026,
+       0x6a10, 0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x2037, 0x0040,
+       0x2037, 0x2039, 0x0200, 0x1078, 0x2094, 0x0078, 0x2093, 0x2c08,
+       0x2091, 0x8000, 0x60a0, 0xa084, 0x8000, 0x0040, 0x2064, 0x6800,
+       0xa065, 0x0040, 0x2069, 0x6a04, 0x0e7e, 0x2071, 0x5140, 0x7000,
+       0xa084, 0x0001, 0x0040, 0x205e, 0x7048, 0xa206, 0x00c0, 0x205e,
+       0x6b04, 0x231c, 0x2160, 0x6302, 0x2300, 0xa005, 0x00c0, 0x2059,
+       0x6902, 0x2260, 0x6102, 0x0e7f, 0x0078, 0x2070, 0x2160, 0x6202,
+       0x6906, 0x0e7f, 0x0078, 0x2070, 0x6800, 0xa065, 0x0040, 0x2069,
+       0x6102, 0x6902, 0x00c0, 0x206d, 0x6906, 0x2160, 0x6003, 0x0000,
+       0x2160, 0x60a0, 0xa084, 0x8000, 0x0040, 0x207a, 0x6808, 0xa084,
+       0xfffc, 0x680a, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808,
+       0xa08c, 0x0040, 0x0040, 0x2089, 0xa086, 0x0040, 0x680a, 0x1078,
+       0x19d1, 0x2091, 0x8000, 0x1078, 0x21d2, 0x2091, 0x8001, 0x78db,
+       0x0000, 0x78d7, 0x0000, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091,
+       0x8000, 0x1078, 0x1c5f, 0x2091, 0x8001, 0x78d8, 0xa065, 0x0040,
+       0x20a7, 0x609c, 0x78da, 0x609f, 0x0000, 0x0078, 0x2097, 0x78d7,
+       0x0000, 0x78db, 0x0000, 0x007c, 0x7990, 0x7894, 0x8000, 0xa10a,
+       0x00c8, 0x20b3, 0xa006, 0x7896, 0x70d2, 0x7804, 0xa005, 0x0040,
+       0x20c1, 0x8001, 0x7806, 0x00c0, 0x20c1, 0x0068, 0x20c1, 0x2091,
+       0x4080, 0x007c, 0x2039, 0x20da, 0x0078, 0x20c8, 0x2039, 0x20e0,
+       0x2704, 0xa005, 0x0040, 0x20d9, 0xac00, 0x2068, 0x6b08, 0x6c0c,
+       0x6910, 0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, 0x8738, 0x0078,
+       0x20c8, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000,
+       0x0015, 0x001b, 0x0000, 0x0c7e, 0x1078, 0x3b69, 0x2c68, 0x0c7f,
+       0x007c, 0x0010, 0x215a, 0x0068, 0x215a, 0x2029, 0x0000, 0x78cb,
+       0x0000, 0x788c, 0xa065, 0x0040, 0x2153, 0x2009, 0x5174, 0x2104,
+       0xa084, 0x0001, 0x0040, 0x2121, 0x6004, 0xa086, 0x0103, 0x00c0,
+       0x2121, 0x6018, 0xa005, 0x00c0, 0x2121, 0x6014, 0xa005, 0x00c0,
+       0x2121, 0x0d7e, 0x2069, 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0,
+       0x2120, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b,
+       0x0001, 0x2091, 0x4080, 0x0d7f, 0x1078, 0x1c86, 0x0078, 0x2158,
+       0x0d7f, 0x1078, 0x215b, 0x0040, 0x2153, 0x6204, 0xa294, 0x00ff,
+       0xa296, 0x0003, 0x0040, 0x2133, 0x6204, 0xa296, 0x0110, 0x00c0,
+       0x2141, 0x78cb, 0x0001, 0x6204, 0xa294, 0xff00, 0x8217, 0x8211,
+       0x0040, 0x2141, 0x85ff, 0x00c0, 0x2153, 0x8210, 0xa202, 0x00c8,
+       0x2153, 0x057e, 0x1078, 0x216a, 0x057f, 0x0040, 0x214e, 0x78e0,
+       0xa086, 0x0003, 0x0040, 0x2153, 0x0078, 0x2141, 0x8528, 0x78c8,
+       0xa005, 0x0040, 0x20f1, 0x85ff, 0x0040, 0x215a, 0x2091, 0x4080,
+       0x78b0, 0x70d6, 0x007c, 0x7bac, 0x79b0, 0x70d4, 0xa102, 0x00c0,
+       0x2164, 0x2300, 0xa005, 0x007c, 0x0048, 0x2168, 0xa302, 0x007c,
+       0x8002, 0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8,
+       0x2184, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0,
+       0x21b9, 0x7008, 0x7208, 0xa206, 0x00c0, 0x21b9, 0xa286, 0x0008,
+       0x00c0, 0x21b9, 0x2071, 0x0010, 0x1078, 0x21be, 0x2009, 0x0020,
+       0x6004, 0xa086, 0x0103, 0x00c0, 0x2193, 0x6028, 0xa005, 0x00c0,
+       0x2193, 0x2009, 0x000c, 0x1078, 0x1924, 0x0040, 0x21ac, 0x78c4,
+       0x8000, 0x78c6, 0xa086, 0x0002, 0x00c0, 0x21b9, 0x2091, 0x8000,
+       0x78e3, 0x0003, 0x78c7, 0x0000, 0x78cc, 0xa085, 0x0300, 0x78ce,
+       0x2091, 0x8001, 0x0078, 0x21b9, 0x78c7, 0x0000, 0x1078, 0x1c86,
+       0x79ac, 0x78b0, 0x8000, 0xa10a, 0x00c8, 0x21b7, 0xa006, 0x78b2,
+       0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x8107, 0x8004,
+       0x8004, 0x7ab8, 0x7bb4, 0x7cc0, 0x7dbc, 0xa210, 0xa399, 0x0000,
+       0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, 0x515b, 0x2091,
+       0x8000, 0x200a, 0x0f7e, 0x0e7e, 0x2071, 0x5140, 0x7000, 0xa086,
+       0x0000, 0x00c0, 0x21ec, 0x2009, 0x5112, 0x2104, 0xa005, 0x00c0,
+       0x21ec, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21ec,
+       0x0018, 0x21ec, 0x781b, 0x004b, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e,
+       0x0e7e, 0x2071, 0x5140, 0x2091, 0x8000, 0x7000, 0xa086, 0x0000,
+       0x00c0, 0x2205, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0,
+       0x2205, 0x0018, 0x2205, 0x781b, 0x004d, 0x2091, 0x8001, 0x0e7f,
+       0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x5140, 0x2079,
+       0x0100, 0x784b, 0x000f, 0x0098, 0x2218, 0x7838, 0x0078, 0x2211,
+       0x20a9, 0x0040, 0x7800, 0xa082, 0x0004, 0x0048, 0x2221, 0x20a9,
+       0x0060, 0x789b, 0x0000, 0x78af, 0x0000, 0x78af, 0x0000, 0x0070,
+       0x222b, 0x0078, 0x2223, 0x7800, 0xa082, 0x0004, 0x0048, 0x223a,
+       0x70b7, 0x0096, 0x2019, 0x4ee7, 0x1078, 0x2276, 0x702f, 0x8001,
+       0x0078, 0x2246, 0x70b7, 0x0000, 0x2019, 0x4d5f, 0x1078, 0x2276,
+       0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f, 0x8000, 0x7003, 0x0000,
+       0x1078, 0x237f, 0x7004, 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd,
+       0x210c, 0xa18a, 0x0005, 0x0048, 0x225b, 0x0038, 0x2261, 0xa085,
+       0x6280, 0x0078, 0x2263, 0x0028, 0x2261, 0xa085, 0x6280, 0x0078,
+       0x2263, 0xa085, 0x62c0, 0x017f, 0x7806, 0x780f, 0xb204, 0x7843,
+       0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x0008, 0x7053,
+       0x517f, 0x704f, 0x0000, 0x127f, 0x2000, 0x007c, 0x137e, 0x147e,
+       0x157e, 0x047e, 0x20a1, 0x012b, 0x2304, 0xa005, 0x789a, 0x0040,
+       0x2296, 0x8318, 0x2324, 0x8318, 0x2398, 0x24a8, 0xa484, 0xff00,
+       0x0040, 0x228e, 0xa482, 0x0100, 0x20a9, 0x0100, 0x2020, 0x53a6,
+       0xa005, 0x00c0, 0x2285, 0x3318, 0x0078, 0x227c, 0x047f, 0x157f,
+       0x147f, 0x137f, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204,
+       0xa084, 0xfff0, 0xa105, 0x2012, 0x1078, 0x237f, 0x007c, 0x2011,
+       0x0101, 0x20a9, 0x0009, 0x810b, 0x0070, 0x22b0, 0x0078, 0x22ab,
+       0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c,
+       0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x22c1, 0x0078,
+       0x22bc, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a,
+       0x007c, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x22d2,
+       0x0078, 0x22cd, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105,
+       0x2012, 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105,
+       0x2012, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061,
+       0x0100, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003,
+       0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084,
+       0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022,
+       0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae,
+       0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061,
+       0x0100, 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018,
+       0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005,
+       0x0040, 0x235d, 0x2061, 0x7500, 0x1078, 0x2365, 0x0040, 0x2349,
+       0x20a9, 0x0000, 0x2061, 0x7400, 0x0c7e, 0x1078, 0x2365, 0x0040,
+       0x2339, 0x0c7f, 0x8c60, 0x0070, 0x2337, 0x0078, 0x232c, 0x0078,
+       0x235d, 0x007f, 0xa082, 0x7400, 0x2071, 0x5140, 0x7086, 0x7182,
+       0x2001, 0x0004, 0x706e, 0x7093, 0x000f, 0x1078, 0x21cd, 0x0078,
+       0x2359, 0x60c0, 0xa005, 0x00c0, 0x235d, 0x2071, 0x5140, 0x7182,
+       0x2c00, 0x708a, 0x2001, 0x0006, 0x706e, 0x7093, 0x000f, 0x1078,
+       0x21cd, 0x2001, 0x0000, 0x0078, 0x235f, 0x2001, 0x0001, 0x2091,
+       0x8001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040,
+       0x237c, 0x2060, 0x600c, 0xa306, 0x00c0, 0x2379, 0x6010, 0xa206,
+       0x00c0, 0x2379, 0x6014, 0xa106, 0x00c0, 0x2379, 0xa006, 0x0078,
+       0x237e, 0x6000, 0x0078, 0x2366, 0xa085, 0x0001, 0x007c, 0x2011,
+       0x5141, 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084,
+       0x0100, 0x0040, 0x2395, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b,
+       0x810b, 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4,
+       0xa08c, 0x0020, 0x0040, 0x23e9, 0xa084, 0x0006, 0x00c0, 0x23e9,
+       0x6014, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0,
+       0x5380, 0x7004, 0xa084, 0x000a, 0x00c0, 0x23e9, 0x7108, 0xa194,
+       0xff00, 0x0040, 0x23e9, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106,
+       0x0040, 0x23d0, 0x2001, 0x0012, 0xa106, 0x0040, 0x23d4, 0x2001,
+       0x0014, 0xa106, 0x0040, 0x23d8, 0x2001, 0x0019, 0xa106, 0x0040,
+       0x23dc, 0x2001, 0x0032, 0xa106, 0x0040, 0x23e0, 0x0078, 0x23e4,
+       0x2009, 0x0012, 0x0078, 0x23e6, 0x2009, 0x0014, 0x0078, 0x23e6,
+       0x2009, 0x0019, 0x0078, 0x23e6, 0x2009, 0x0020, 0x0078, 0x23e6,
+       0x2009, 0x003f, 0x0078, 0x23e6, 0x2011, 0x0000, 0x2100, 0xa205,
+       0x700a, 0x0e7f, 0x007c, 0x0068, 0x23eb, 0x2091, 0x8000, 0x2071,
+       0x0000, 0x007e, 0x7018, 0xa084, 0x0001, 0x00c0, 0x23f2, 0x007f,
+       0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db,
+       0x0741, 0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091,
+       0x4080, 0x0078, 0x2409, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300,
+       0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x77c2, 0x74c6, 0x76ca, 0x75ce,
+       0xa594, 0x003f, 0xa49c, 0x0003, 0xa484, 0x000f, 0x0079, 0x2420,
+       0x2432, 0x2432, 0x2432, 0x276c, 0x393b, 0x2430, 0x2461, 0x246b,
+       0x2430, 0x2430, 0x2430, 0x2430, 0x2430, 0x2430, 0x2430, 0x2430,
+       0x1078, 0x23eb, 0x8507, 0xa084, 0x001f, 0x0079, 0x2437, 0x2475,
+       0x276c, 0x2926, 0x2a23, 0x2a4b, 0x2ced, 0x2f98, 0x2fdb, 0x3026,
+       0x30ab, 0x3163, 0x320c, 0x2461, 0x2848, 0x2f6d, 0x2457, 0x3cc8,
+       0x3ce8, 0x3eae, 0x3eba, 0x3f8f, 0x2457, 0x2457, 0x4062, 0x4066,
+       0x3cc6, 0x2457, 0x3e19, 0x2457, 0x3b8c, 0x246b, 0x2457, 0x1078,
+       0x23eb, 0x0018, 0x2410, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f,
+       0x007c, 0x2019, 0x4e3b, 0x1078, 0x2276, 0x702f, 0x0001, 0x781b,
+       0x004f, 0x0078, 0x2459, 0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f,
+       0x8000, 0x781b, 0x00d0, 0x0078, 0x2459, 0x7242, 0x2009, 0x510f,
+       0x200b, 0x0000, 0xa584, 0x0001, 0x00c0, 0x3ba0, 0x0040, 0x2492,
+       0x1078, 0x23eb, 0x7003, 0x0000, 0x704b, 0x0000, 0x7043, 0x0000,
+       0x7037, 0x0000, 0x1078, 0x3912, 0x0018, 0x2410, 0x2009, 0x510f,
+       0x200b, 0x0000, 0x7068, 0xa005, 0x00c0, 0x255d, 0x706c, 0xa084,
+       0x0007, 0x0079, 0x249b, 0x2594, 0x24a3, 0x24af, 0x24cc, 0x24ee,
+       0x253b, 0x2514, 0x24a3, 0x1078, 0x38fa, 0x2009, 0x0048, 0x1078,
+       0x2e39, 0x00c0, 0x24ad, 0x7003, 0x0004, 0x0078, 0x2459, 0x1078,
+       0x38fa, 0x00c0, 0x24ca, 0x7080, 0x8007, 0x7882, 0x789b, 0x0010,
+       0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004,
+       0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x24ca, 0x7003, 0x0004,
+       0x7093, 0x000f, 0x0078, 0x2459, 0x1078, 0x38fa, 0x00c0, 0x24ec,
+       0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d,
+       0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002,
+       0x785b, 0x0004, 0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x24ec,
+       0x7003, 0x0004, 0x7093, 0x000f, 0x0078, 0x2459, 0x1078, 0x38fa,
+       0x00c0, 0x2512, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c,
+       0x001f, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x7184, 0x79aa,
+       0x78ab, 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004,
+       0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x2512, 0x7003, 0x0004,
+       0x7093, 0x000f, 0x0078, 0x2459, 0x1078, 0x38fa, 0x00c0, 0x2539,
+       0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d,
+       0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002,
+       0x785b, 0x0004, 0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x2539,
+       0x7088, 0x708b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0002, 0x7093,
+       0x000f, 0x0078, 0x2459, 0x1078, 0x38fa, 0x00c0, 0x2459, 0x7088,
+       0x2068, 0x6f14, 0x1078, 0x37ef, 0x2c50, 0x1078, 0x39ac, 0x789b,
+       0x0010, 0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x6e1c,
+       0x2041, 0x0001, 0x708c, 0xa084, 0x0400, 0x2001, 0x0004, 0x0040,
+       0x255b, 0x2001, 0x0006, 0x0078, 0x267c, 0x1078, 0x38fa, 0x00c0,
+       0x2459, 0x789b, 0x0010, 0x7068, 0x2068, 0x6f14, 0x1078, 0x37ef,
+       0x2c50, 0x1078, 0x39ac, 0x6008, 0xa085, 0x0010, 0x600a, 0x6824,
+       0xa005, 0x0040, 0x257b, 0xa082, 0x0006, 0x0048, 0x2579, 0x0078,
+       0x257b, 0x6827, 0x0005, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0,
+       0x7058, 0xa084, 0x8000, 0x0040, 0x2589, 0xa684, 0x0001, 0x0040,
+       0x258b, 0xa39c, 0xffbf, 0x7baa, 0x2031, 0x0020, 0x2041, 0x0001,
+       0x2001, 0x0003, 0x0078, 0x267c, 0x0018, 0x2410, 0x744c, 0xa485,
+       0x0000, 0x0040, 0x25ae, 0xa080, 0x5180, 0x2030, 0x7150, 0x8108,
+       0xa12a, 0x0048, 0x25a5, 0x2009, 0x5180, 0x2164, 0x6504, 0x85ff,
+       0x00c0, 0x25bf, 0x8421, 0x00c0, 0x259f, 0x7152, 0x7003, 0x0000,
+       0x704b, 0x0000, 0x7040, 0xa005, 0x0040, 0x3ba0, 0x0078, 0x2459,
+       0x764c, 0xa6b0, 0x5180, 0x7150, 0x2600, 0x0078, 0x25aa, 0x7152,
+       0x2568, 0x2558, 0x754a, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0,
+       0x25bc, 0x6708, 0x773a, 0xa784, 0x033f, 0x0040, 0x25f5, 0xa784,
+       0x0021, 0x00c0, 0x25bc, 0xa784, 0x0002, 0x0040, 0x25de, 0xa784,
+       0x0004, 0x0040, 0x25bc, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008,
+       0x00c0, 0x25bc, 0xa784, 0x0010, 0x00c0, 0x25bc, 0xa784, 0x0200,
+       0x00c0, 0x25bc, 0xa784, 0x0100, 0x0040, 0x25f5, 0x6018, 0xa005,
+       0x00c0, 0x25bc, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, 0x6e1c,
+       0xa684, 0x000e, 0x6118, 0x0040, 0x2605, 0x601c, 0xa102, 0x0048,
+       0x2608, 0x0040, 0x2608, 0x0078, 0x25b8, 0x81ff, 0x00c0, 0x25b8,
+       0x68c3, 0x0000, 0xa784, 0x0080, 0x00c0, 0x2610, 0x700c, 0x6022,
+       0xa7bc, 0xff7f, 0x670a, 0x1078, 0x39ac, 0x0018, 0x2410, 0x789b,
+       0x0010, 0xa046, 0x1078, 0x38fa, 0x00c0, 0x2459, 0x6b14, 0xa39c,
+       0x001f, 0xa39d, 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, 0x262c,
+       0xa684, 0x0001, 0x0040, 0x262e, 0xa39c, 0xffbf, 0xa684, 0x0010,
+       0x0040, 0x2634, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e,
+       0x00c0, 0x263f, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x267a, 0x7158,
+       0xa18c, 0x0800, 0x0040, 0x3401, 0x2011, 0x0020, 0xa684, 0x0008,
+       0x00c0, 0x2650, 0x8210, 0xa684, 0x0002, 0x00c0, 0x2650, 0x8210,
+       0x7aaa, 0x8840, 0x1078, 0x3912, 0x6a14, 0x610c, 0x8108, 0xa18c,
+       0x00ff, 0xa1e0, 0x7400, 0x2c64, 0x8cff, 0x0040, 0x2671, 0x6014,
+       0xa206, 0x00c0, 0x265b, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2656,
+       0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078,
+       0x2594, 0x1078, 0x38fa, 0x00c0, 0x2459, 0x2a60, 0x610e, 0x79aa,
+       0x8840, 0x7132, 0x2001, 0x0001, 0x007e, 0x715c, 0xa184, 0x0018,
+       0x0040, 0x2697, 0xa184, 0x0010, 0x0040, 0x268a, 0x1078, 0x3604,
+       0x00c0, 0x26ba, 0xa184, 0x0008, 0x0040, 0x2697, 0x69a0, 0xa184,
+       0x0600, 0x00c0, 0x2697, 0x1078, 0x34f1, 0x0078, 0x26ba, 0x69a0,
+       0xa184, 0x0800, 0x0040, 0x26ae, 0x0c7e, 0x027e, 0x2960, 0x6000,
+       0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f,
+       0x0c7f, 0x1078, 0x3604, 0x00c0, 0x26ba, 0x69a0, 0xa184, 0x0200,
+       0x0040, 0x26b6, 0x1078, 0x3540, 0x0078, 0x26ba, 0xa184, 0x0400,
+       0x00c0, 0x2693, 0x69a0, 0xa184, 0x1000, 0x0040, 0x26c5, 0x6914,
+       0xa18c, 0xff00, 0x810f, 0x1078, 0x22ee, 0x007f, 0x7002, 0xa68c,
+       0x00e0, 0xa684, 0x0060, 0x0040, 0x26d3, 0xa086, 0x0060, 0x00c0,
+       0x26d3, 0xa18d, 0x4000, 0x88ff, 0x0040, 0x26d8, 0xa18d, 0x0004,
+       0x795a, 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061,
+       0x6818, 0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, 0xa68c, 0x0080,
+       0x0040, 0x26f7, 0x7097, 0x0000, 0xa08a, 0x000d, 0x0050, 0x26f5,
+       0xa08a, 0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x78aa,
+       0x8008, 0x810c, 0x0040, 0x3407, 0xa18c, 0x00f8, 0x00c0, 0x3407,
+       0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000,
+       0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f,
+       0x6814, 0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2,
+       0x7eda, 0x1078, 0x38fa, 0x00c0, 0x272e, 0x702c, 0x8003, 0x0048,
+       0x2727, 0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f, 0x8000, 0x7830,
+       0xa084, 0x00c0, 0x00c0, 0x272e, 0x0098, 0x2736, 0x6008, 0xa084,
+       0xffef, 0x600a, 0x1078, 0x3912, 0x0078, 0x2482, 0x7200, 0xa284,
+       0x0007, 0xa086, 0x0001, 0x00c0, 0x2743, 0x781b, 0x004f, 0x1078,
+       0x3912, 0x0078, 0x2754, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b,
+       0x004f, 0x1078, 0x3912, 0x7200, 0x2500, 0xa605, 0x0040, 0x2754,
+       0xa284, 0x0007, 0x1079, 0x2762, 0xad80, 0x0009, 0x7036, 0xa284,
+       0x0007, 0xa086, 0x0001, 0x00c0, 0x2459, 0x6018, 0x8000, 0x601a,
+       0x0078, 0x2459, 0x276a, 0x4a3a, 0x4a3a, 0x4a29, 0x4a3a, 0x276a,
+       0x4a29, 0x276a, 0x1078, 0x23eb, 0x1078, 0x38fa, 0x0f7e, 0x2079,
+       0x5100, 0x78cc, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x2790, 0x706c,
+       0xa086, 0x0001, 0x00c0, 0x277f, 0x706e, 0x0078, 0x2823, 0x706c,
+       0xa086, 0x0005, 0x00c0, 0x278e, 0x7088, 0x2068, 0x681b, 0x0004,
+       0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x706f, 0x0000,
+       0x2011, 0x0004, 0x716c, 0xa186, 0x0001, 0x0040, 0x27b1, 0xa186,
+       0x0007, 0x00c0, 0x27a1, 0x2009, 0x5138, 0x200b, 0x0005, 0x0078,
+       0x27b1, 0x2009, 0x5113, 0x2104, 0x2009, 0x5112, 0x200a, 0x2009,
+       0x5138, 0x200b, 0x0001, 0x706f, 0x0000, 0x7073, 0x0001, 0x0078,
+       0x27b3, 0x706f, 0x0000, 0x1078, 0x4776, 0x157e, 0x20a9, 0x0010,
+       0x2039, 0x0000, 0x1078, 0x36e2, 0xa7b8, 0x0100, 0x0070, 0x27c2,
+       0x0078, 0x27ba, 0x157f, 0x7000, 0x0079, 0x27c6, 0x27f4, 0x27db,
+       0x27db, 0x27ce, 0x27f4, 0x27f4, 0x27f4, 0x27f4, 0x2021, 0x515a,
+       0x2404, 0xa005, 0x0040, 0x27f4, 0xad06, 0x00c0, 0x27db, 0x6800,
+       0x2022, 0x0078, 0x27eb, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27e7,
+       0x6f14, 0x1078, 0x37ef, 0x1078, 0x33d8, 0x0078, 0x27eb, 0x7060,
+       0x2060, 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085,
+       0x0008, 0x6822, 0x1078, 0x1c70, 0x2021, 0x7500, 0x1078, 0x2830,
+       0x2021, 0x515a, 0x1078, 0x2830, 0x157e, 0x20a9, 0x0000, 0x2021,
+       0x7400, 0x1078, 0x2830, 0x8420, 0x0070, 0x2808, 0x0078, 0x2801,
+       0x2061, 0x5400, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6018, 0x6110,
+       0x81ff, 0x0040, 0x2817, 0xa102, 0x0050, 0x2817, 0x6012, 0x601b,
+       0x0000, 0xace0, 0x0010, 0x0070, 0x281f, 0x0078, 0x280e, 0x8421,
+       0x00c0, 0x280c, 0x157f, 0x709c, 0xa084, 0x8000, 0x0040, 0x282a,
+       0x1078, 0x3a00, 0x7003, 0x0000, 0x704b, 0x0000, 0x0078, 0x2459,
+       0x047e, 0x2404, 0xa005, 0x0040, 0x2844, 0x2068, 0x6800, 0x007e,
+       0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078,
+       0x1c70, 0x007f, 0x0078, 0x2832, 0x047f, 0x2023, 0x0000, 0x007c,
+       0xa282, 0x0003, 0x0050, 0x284e, 0x1078, 0x23eb, 0x2300, 0x0079,
+       0x2851, 0x2854, 0x28c7, 0x28e4, 0xa282, 0x0002, 0x0040, 0x285a,
+       0x1078, 0x23eb, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, 0x0079,
+       0x2861, 0x2869, 0x2869, 0x286b, 0x289f, 0x340d, 0x2869, 0x289f,
+       0x2869, 0x1078, 0x23eb, 0x7780, 0x1078, 0x36e2, 0x7780, 0xa7bc,
+       0x0f00, 0x1078, 0x37ef, 0x6018, 0xa005, 0x0040, 0x2896, 0x2021,
+       0x7500, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x28ff, 0x0040,
+       0x2896, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7400, 0x047e, 0x2009,
+       0x0004, 0x2011, 0x0010, 0x1078, 0x28ff, 0x047f, 0x0040, 0x2895,
+       0x8420, 0x0070, 0x2895, 0x0078, 0x2886, 0x157f, 0x8738, 0xa784,
+       0x001f, 0x00c0, 0x2871, 0x0078, 0x2482, 0x0078, 0x2482, 0x7780,
+       0x1078, 0x37ef, 0x6018, 0xa005, 0x0040, 0x28c5, 0x2021, 0x7500,
+       0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x28ff, 0x0040, 0x28c5,
+       0x157e, 0x20a9, 0x0000, 0x2021, 0x7400, 0x047e, 0x2009, 0x0005,
+       0x2011, 0x0020, 0x1078, 0x28ff, 0x047f, 0x0040, 0x28c4, 0x8420,
+       0x0070, 0x28c4, 0x0078, 0x28b5, 0x157f, 0x0078, 0x2482, 0x2200,
+       0x0079, 0x28ca, 0x28cd, 0x28cf, 0x28cf, 0x1078, 0x23eb, 0x2009,
+       0x0012, 0x706c, 0xa086, 0x0002, 0x0040, 0x28d8, 0x2009, 0x000e,
+       0x6818, 0xa084, 0x8000, 0x0040, 0x28de, 0x691a, 0x706f, 0x0000,
+       0x7073, 0x0001, 0x0078, 0x3888, 0x2200, 0x0079, 0x28e7, 0x28ec,
+       0x28cf, 0x28ea, 0x1078, 0x23eb, 0x1078, 0x4776, 0x7000, 0xa086,
+       0x0001, 0x00c0, 0x339d, 0x1078, 0x33ee, 0x6008, 0xa084, 0xffef,
+       0x600a, 0x1078, 0x3390, 0x0040, 0x339d, 0x0078, 0x2594, 0x2404,
+       0xa005, 0x0040, 0x2922, 0x2068, 0x2d04, 0x007e, 0x6814, 0xa706,
+       0x0040, 0x290e, 0x2d20, 0x007f, 0x0078, 0x2900, 0x007f, 0x2022,
+       0x691a, 0x6817, 0x0000, 0x6820, 0xa205, 0x6822, 0x1078, 0x1c70,
+       0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+       0x33ee, 0x007c, 0xa085, 0x0001, 0x0078, 0x2921, 0x2300, 0x0079,
+       0x2929, 0x292e, 0x292c, 0x29c7, 0x1078, 0x23eb, 0x78ec, 0xa084,
+       0x0001, 0x00c0, 0x2942, 0x7000, 0xa086, 0x0004, 0x00c0, 0x293a,
+       0x0078, 0x2965, 0x1078, 0x33ee, 0x6008, 0xa084, 0xffef, 0x600a,
+       0x0078, 0x339d, 0x78e4, 0xa005, 0x00d0, 0x2965, 0x0018, 0x2459,
+       0x2008, 0xa084, 0x0030, 0x00c0, 0x2951, 0x781b, 0x004f, 0x0078,
+       0x2459, 0x78ec, 0xa084, 0x0003, 0x0040, 0x294d, 0x2100, 0xa084,
+       0x0007, 0x0079, 0x295b, 0x299e, 0x29a9, 0x298f, 0x2963, 0x38ed,
+       0x38ed, 0x2963, 0x29b8, 0x1078, 0x23eb, 0x7000, 0xa086, 0x0004,
+       0x00c0, 0x297f, 0x706c, 0xa086, 0x0002, 0x00c0, 0x2975, 0x2011,
+       0x0002, 0x2019, 0x0000, 0x0078, 0x2848, 0x706c, 0xa086, 0x0006,
+       0x0040, 0x296f, 0x706c, 0xa086, 0x0004, 0x0040, 0x296f, 0x79e4,
+       0xa184, 0x0030, 0x0040, 0x2989, 0x78ec, 0xa084, 0x0003, 0x00c0,
+       0x298b, 0x0078, 0x2f6d, 0x2001, 0x0003, 0x0078, 0x2d01, 0x6818,
+       0xa084, 0x8000, 0x0040, 0x2996, 0x681b, 0x001d, 0x1078, 0x36c1,
+       0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x6818, 0xa084,
+       0x8000, 0x0040, 0x29a5, 0x681b, 0x001d, 0x1078, 0x36c1, 0x0078,
+       0x38b8, 0x6818, 0xa084, 0x8000, 0x0040, 0x29b0, 0x681b, 0x001d,
+       0x1078, 0x36c1, 0x782b, 0x3008, 0x781b, 0x00cd, 0x0078, 0x2459,
+       0x6818, 0xa084, 0x8000, 0x0040, 0x29bf, 0x681b, 0x001d, 0x1078,
+       0x36c1, 0x782b, 0x3008, 0x781b, 0x008e, 0x0078, 0x2459, 0xa584,
+       0x000f, 0x00c0, 0x29e4, 0x7000, 0x0079, 0x29ce, 0x2482, 0x29d8,
+       0x29d6, 0x339d, 0x339d, 0x339d, 0x339d, 0x29d6, 0x1078, 0x23eb,
+       0x1078, 0x33ee, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x3390,
+       0x0040, 0x339d, 0x0078, 0x2594, 0x78e4, 0xa005, 0x00d0, 0x2965,
+       0x0018, 0x2965, 0x2008, 0xa084, 0x0030, 0x00c0, 0x29f3, 0x781b,
+       0x004f, 0x0078, 0x2459, 0x78ec, 0xa084, 0x0003, 0x0040, 0x29ef,
+       0x2100, 0xa184, 0x0007, 0x0079, 0x29fd, 0x2a0f, 0x2a13, 0x2a07,
+       0x2a05, 0x38ed, 0x38ed, 0x2a05, 0x38e3, 0x1078, 0x23eb, 0x1078,
+       0x36c9, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x1078,
+       0x36c9, 0x0078, 0x38b8, 0x1078, 0x36c9, 0x782b, 0x3008, 0x781b,
+       0x00cd, 0x0078, 0x2459, 0x1078, 0x36c9, 0x782b, 0x3008, 0x781b,
+       0x008e, 0x0078, 0x2459, 0x2300, 0x0079, 0x2a26, 0x2a2b, 0x2a29,
+       0x2a2d, 0x1078, 0x23eb, 0x0078, 0x30ab, 0x681b, 0x0008, 0x78a3,
+       0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x30ab, 0x78ec, 0xa084,
+       0x0003, 0x0040, 0x30ab, 0xa184, 0x0007, 0x0079, 0x2a3f, 0x2a47,
+       0x2a13, 0x298f, 0x3888, 0x38ed, 0x38ed, 0x2a47, 0x38e3, 0x1078,
+       0x389c, 0x0078, 0x2459, 0xa282, 0x0005, 0x0050, 0x2a51, 0x1078,
+       0x23eb, 0x2300, 0x0079, 0x2a54, 0x2a57, 0x2cae, 0x2cbc, 0x2200,
+       0x0079, 0x2a5a, 0x2a74, 0x2a61, 0x2a74, 0x2a5f, 0x2c93, 0x1078,
+       0x23eb, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020,
+       0x0048, 0x369d, 0xa08a, 0x0004, 0x00c8, 0x369d, 0x0079, 0x2a70,
+       0x369d, 0x369d, 0x369d, 0x364b, 0x789b, 0x0018, 0x79a8, 0xa184,
+       0x0080, 0x0040, 0x2a85, 0x0078, 0x369d, 0x7000, 0xa005, 0x00c0,
+       0x2a7b, 0x2011, 0x0004, 0x0078, 0x321f, 0xa184, 0x00ff, 0xa08a,
+       0x0010, 0x00c8, 0x369d, 0x0079, 0x2a8d, 0x2a9f, 0x2a9d, 0x2ab7,
+       0x2abb, 0x2b78, 0x369d, 0x369d, 0x2b7a, 0x369d, 0x369d, 0x2c8f,
+       0x2c8f, 0x369d, 0x369d, 0x369d, 0x2c91, 0x1078, 0x23eb, 0xa684,
+       0x1000, 0x0040, 0x2aac, 0x2001, 0x0500, 0x8000, 0x8000, 0x783a,
+       0x781b, 0x008c, 0x0078, 0x2459, 0x6818, 0xa084, 0x8000, 0x0040,
+       0x2ab5, 0x681b, 0x001d, 0x0078, 0x2aa3, 0x0078, 0x3888, 0x681b,
+       0x001d, 0x0078, 0x36ad, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0,
+       0x2afc, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2b04, 0x6818, 0xa086,
+       0x0008, 0x00c0, 0x2acd, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040,
+       0x2b74, 0xa684, 0x0080, 0x0040, 0x2af8, 0x7097, 0x0000, 0x6818,
+       0xa084, 0x003f, 0xa08a, 0x000d, 0x0050, 0x2af8, 0xa08a, 0x000c,
+       0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x789b, 0x0061, 0x78aa,
+       0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000,
+       0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f,
+       0x781b, 0x0058, 0x0078, 0x2459, 0xa684, 0x1000, 0x0040, 0x2b04,
+       0x781b, 0x0065, 0x0078, 0x2459, 0xa684, 0x0060, 0x0040, 0x2b70,
+       0xa684, 0x0800, 0x0040, 0x2b70, 0xa684, 0x8000, 0x00c0, 0x2b12,
+       0x0078, 0x2b2c, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0076,
+       0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8, 0x2b1f, 0x8000, 0xa084,
+       0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2,
+       0x6b94, 0x2200, 0xa303, 0x68ae, 0xa684, 0x4000, 0x0040, 0x2b34,
+       0xa6b4, 0xbfff, 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003, 0x00c0,
+       0x2b41, 0x1078, 0x482c, 0x1078, 0x4a29, 0x781b, 0x0064, 0x0078,
+       0x2459, 0xa006, 0x1078, 0x4b30, 0x6ab0, 0x69ac, 0x6c98, 0x6b94,
+       0x2200, 0xa105, 0x0040, 0x2b50, 0x2200, 0xa422, 0x2100, 0xa31b,
+       0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405,
+       0x00c0, 0x2b62, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0064,
+       0x0078, 0x2459, 0x781b, 0x0064, 0x2200, 0xa115, 0x00c0, 0x2b6c,
+       0x1078, 0x4a3a, 0x0078, 0x2459, 0x1078, 0x4a85, 0x0078, 0x2459,
+       0x781b, 0x0065, 0x0078, 0x2459, 0x781b, 0x0058, 0x0078, 0x2459,
+       0x1078, 0x23eb, 0x0078, 0x2bdb, 0x6920, 0xa184, 0x0100, 0x0040,
+       0x2b92, 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000,
+       0xa084, 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f,
+       0x0078, 0x2bca, 0xa184, 0x0200, 0x0040, 0x2bca, 0xa18c, 0xfdff,
+       0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0xdfff, 0x6002,
+       0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184,
+       0x0008, 0x0040, 0x2bca, 0x1078, 0x37eb, 0x1078, 0x34f1, 0x88ff,
+       0x0040, 0x2bca, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5,
+       0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2bc4, 0x782b, 0x3008,
+       0x781b, 0x0056, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b, 0x0065,
+       0x0078, 0x2459, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2bd3, 0x781b,
+       0x0058, 0x0078, 0x2459, 0x781b, 0x0065, 0x0078, 0x2459, 0x0078,
+       0x36a5, 0x0078, 0x36a5, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007,
+       0x00c0, 0x2be9, 0x6820, 0xa084, 0x0100, 0x0040, 0x2bd9, 0x2009,
+       0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001,
+       0x00c0, 0x2c20, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040,
+       0x2c18, 0x0048, 0x2bfd, 0x0078, 0x2c1a, 0xa380, 0x0002, 0xa102,
+       0x00c8, 0x2c18, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0c7e, 0x7054,
+       0x2060, 0x6000, 0xa084, 0xefef, 0x6002, 0x6004, 0xa084, 0xffe5,
+       0x6006, 0x0c7f, 0x7e58, 0xa6b4, 0xfffb, 0x7e5a, 0x0078, 0x2bcb,
+       0x0078, 0x2b7c, 0x24a8, 0x7aa8, 0x00f0, 0x2c1a, 0x0078, 0x2beb,
+       0xa284, 0x00f0, 0xa086, 0x0020, 0x00c0, 0x2c80, 0x8318, 0x8318,
+       0x2300, 0xa102, 0x0040, 0x2c30, 0x0048, 0x2c30, 0x0078, 0x2c7d,
+       0xa286, 0x0023, 0x0040, 0x2bd9, 0x681c, 0xa084, 0xfff1, 0x681e,
+       0x7e58, 0xa684, 0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008,
+       0xa085, 0x0010, 0x600a, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008,
+       0x2c48, 0x0c7f, 0xa184, 0x0010, 0x0040, 0x2c54, 0x1078, 0x37eb,
+       0x1078, 0x3604, 0x0078, 0x2c63, 0x0c7e, 0x7054, 0x2060, 0x6004,
+       0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2bca, 0x1078,
+       0x37eb, 0x1078, 0x34f1, 0x88ff, 0x0040, 0x2bca, 0x789b, 0x0060,
+       0x2800, 0x78aa, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0,
+       0x2c77, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x782b,
+       0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x7aa8, 0x0078, 0x2beb,
+       0x8318, 0x2300, 0xa102, 0x0040, 0x2c89, 0x0048, 0x2c89, 0x0078,
+       0x2beb, 0xa284, 0x0080, 0x00c0, 0x36ad, 0x0078, 0x36a5, 0x0078,
+       0x36ad, 0x0078, 0x369d, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff,
+       0xa08e, 0x0001, 0x0040, 0x2c9e, 0x1078, 0x23eb, 0x7aa8, 0xa294,
+       0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x369d,
+       0x0079, 0x2caa, 0x369d, 0x343e, 0x369d, 0x3599, 0xa282, 0x0000,
+       0x00c0, 0x2cb4, 0x1078, 0x23eb, 0x1078, 0x36c1, 0x782b, 0x3008,
+       0x781b, 0x0065, 0x0078, 0x2459, 0xa282, 0x0003, 0x00c0, 0x2cc2,
+       0x1078, 0x23eb, 0xa484, 0x8000, 0x00c0, 0x2ce5, 0x706c, 0xa005,
+       0x0040, 0x2ccc, 0x1078, 0x23eb, 0x6f14, 0x7782, 0xa7bc, 0x0f00,
+       0x1078, 0x37ef, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784,
+       0x001f, 0x00c0, 0x2cd0, 0x1078, 0x36c5, 0x706f, 0x0002, 0x2009,
+       0x5138, 0x200b, 0x0009, 0x0078, 0x2ce7, 0x1078, 0x36d1, 0x782b,
+       0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0xa282, 0x0004, 0x0050,
+       0x2cf3, 0x1078, 0x23eb, 0x2300, 0x0079, 0x2cf6, 0x2cf9, 0x2de2,
+       0x2e15, 0xa286, 0x0003, 0x0040, 0x2cff, 0x1078, 0x23eb, 0x2001,
+       0x0000, 0x007e, 0x68c0, 0xa005, 0x0040, 0x2d08, 0x7003, 0x0003,
+       0x68a0, 0xa084, 0x2000, 0x0040, 0x2d11, 0x6008, 0xa085, 0x0002,
+       0x600a, 0x007f, 0x703e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2d18,
+       0x2482, 0x2d22, 0x2d22, 0x2f17, 0x2f53, 0x2482, 0x2f53, 0x2d20,
+       0x1078, 0x23eb, 0xa684, 0x1000, 0x00c0, 0x2d2a, 0x1078, 0x4776,
+       0x0040, 0x2dbc, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2d72, 0xa186,
+       0x0008, 0x00c0, 0x2d41, 0x1078, 0x33ee, 0x6008, 0xa084, 0xffef,
+       0x600a, 0x1078, 0x3390, 0x0040, 0x2d72, 0x1078, 0x4776, 0x0078,
+       0x2d59, 0xa186, 0x0028, 0x00c0, 0x2d72, 0x1078, 0x4776, 0x6008,
+       0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2d59, 0x8001,
+       0x601a, 0xa005, 0x0040, 0x2d59, 0x8001, 0xa005, 0x0040, 0x2d59,
+       0x601e, 0x6820, 0xa084, 0x0001, 0x0040, 0x2482, 0x6820, 0xa084,
+       0xfffe, 0x6822, 0x7060, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f,
+       0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2d6f, 0x6002, 0x6006,
+       0x0078, 0x2482, 0x017e, 0x1078, 0x2e46, 0x017f, 0xa684, 0xdf00,
+       0x681e, 0x682b, 0x0000, 0x6f14, 0x81ff, 0x0040, 0x2dbc, 0xa186,
+       0x0002, 0x00c0, 0x2dbc, 0xa684, 0x0800, 0x00c0, 0x2d8f, 0xa684,
+       0x0060, 0x0040, 0x2d8f, 0x78d8, 0x7adc, 0x682e, 0x6a32, 0x6820,
+       0xa084, 0x0800, 0x00c0, 0x2dbc, 0x8717, 0xa294, 0x000f, 0x8213,
+       0x8213, 0x8213, 0xa290, 0x5380, 0xa290, 0x0000, 0x221c, 0xa384,
+       0x0100, 0x00c0, 0x2da5, 0x0078, 0x2dab, 0x8210, 0x2204, 0xa085,
+       0x0018, 0x2012, 0x8211, 0xa384, 0x0400, 0x0040, 0x2db8, 0x68a0,
+       0xa084, 0x0100, 0x00c0, 0x2db8, 0x1078, 0x2eca, 0x0078, 0x2482,
+       0x6008, 0xa085, 0x0002, 0x600a, 0x6916, 0x6818, 0xa084, 0x8000,
+       0x0040, 0x2dc4, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078,
+       0x33df, 0x1078, 0x33ee, 0x00c0, 0x2dd1, 0x6008, 0xa084, 0xffef,
+       0x600a, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2dda, 0x1078, 0x33d8,
+       0x0078, 0x2dde, 0x7060, 0x2060, 0x6800, 0x6002, 0x1078, 0x1c70,
+       0x0078, 0x2482, 0xa282, 0x0004, 0x0048, 0x2de8, 0x1078, 0x23eb,
+       0x2200, 0x0079, 0x2deb, 0x2de6, 0x2def, 0x2dfc, 0x2def, 0x7000,
+       0xa086, 0x0005, 0x0040, 0x2df8, 0x1078, 0x36c1, 0x782b, 0x3008,
+       0x781b, 0x0065, 0x0078, 0x2459, 0x7890, 0x8007, 0x8001, 0xa084,
+       0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186,
+       0x0003, 0x0040, 0x2e11, 0xa186, 0x0000, 0x0040, 0x2e11, 0x0078,
+       0x369d, 0x781b, 0x0065, 0x0078, 0x2459, 0x6820, 0xa085, 0x0004,
+       0x6822, 0x82ff, 0x00c0, 0x2e20, 0x1078, 0x36c1, 0x0078, 0x2e27,
+       0x8211, 0x0040, 0x2e25, 0x1078, 0x23eb, 0x1078, 0x36d1, 0x782b,
+       0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x702c, 0x8003, 0x0048,
+       0x2e37, 0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f, 0x8000, 0x1078,
+       0x3912, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2e43, 0x0018, 0x2e43,
+       0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060,
+       0x00c0, 0x2e50, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2ec9,
+       0xa684, 0x0800, 0x00c0, 0x2e72, 0x68b4, 0xa084, 0x4800, 0xa635,
+       0xa684, 0x0800, 0x00c0, 0x2e72, 0x6998, 0x6a94, 0x692e, 0x6a32,
+       0x703c, 0xa005, 0x00c0, 0x2e6a, 0x2200, 0xa105, 0x0040, 0x2e71,
+       0x703f, 0x0015, 0x7000, 0xa086, 0x0006, 0x0040, 0x2e71, 0x1078,
+       0x4776, 0x007c, 0xa684, 0x0020, 0x0040, 0x2e94, 0xa684, 0x4000,
+       0x0040, 0x2e80, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e6a,
+       0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e7a,
+       0x703c, 0xa005, 0x00c0, 0x2e8e, 0x703f, 0x0015, 0x79d8, 0x7adc,
+       0x692e, 0x6a32, 0x0078, 0x2e6a, 0xa684, 0x4000, 0x0040, 0x2e9e,
+       0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e6a, 0x68b4, 0xa084,
+       0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e98, 0x703c, 0xa005,
+       0x00c0, 0x2eac, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb,
+       0x00c8, 0x2eb3, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+       0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x2ec0, 0x0078, 0x2e6a,
+       0x7000, 0xa086, 0x0006, 0x0040, 0x2ec9, 0x1078, 0x4b30, 0x0078,
+       0x2e6a, 0x007c, 0x6008, 0xa085, 0x0200, 0x600a, 0xa384, 0x0200,
+       0x0040, 0x2ed6, 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006,
+       0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942,
+       0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000,
+       0x689b, 0x0020, 0x68b3, 0x0000, 0x68af, 0x0000, 0x7000, 0x0079,
+       0x2ef1, 0x2482, 0x2efb, 0x2f04, 0x2ef9, 0x2ef9, 0x2ef9, 0x2ef9,
+       0x2ef9, 0x1078, 0x23eb, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2f04,
+       0x1078, 0x33d8, 0x0078, 0x2f0a, 0x7060, 0x2c50, 0x2060, 0x6800,
+       0x6002, 0x2a60, 0x2021, 0x515a, 0x2404, 0xa005, 0x0040, 0x2f13,
+       0x2020, 0x0078, 0x2f0c, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078,
+       0x33df, 0x1078, 0x33ee, 0x6008, 0xa084, 0xfdff, 0x600a, 0x682b,
+       0x0000, 0x789b, 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x4b78,
+       0xa684, 0x0800, 0x0040, 0x2f30, 0x691c, 0xa18d, 0x2000, 0x691e,
+       0x6818, 0xa084, 0x8000, 0x0040, 0x2f40, 0x7868, 0xa08c, 0x00ff,
+       0x0040, 0x2f3e, 0x681b, 0x001e, 0x0078, 0x2f40, 0x681b, 0x0000,
+       0x2021, 0x515a, 0x2404, 0xad06, 0x0040, 0x2f47, 0x7460, 0x6800,
+       0x2022, 0x68c3, 0x0000, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078,
+       0x1c70, 0x0078, 0x2482, 0x1078, 0x2e46, 0x682b, 0x0000, 0x2001,
+       0x000e, 0x6f14, 0x1078, 0x3918, 0xa08c, 0x00ff, 0x6916, 0x6818,
+       0xa084, 0x8000, 0x0040, 0x2f66, 0x703c, 0x681a, 0xa68c, 0xdf00,
+       0x691e, 0x706f, 0x0000, 0x0078, 0x2482, 0x7000, 0xa005, 0x00c0,
+       0x2f73, 0x0078, 0x2482, 0xa006, 0x1078, 0x4776, 0x6817, 0x0000,
+       0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820,
+       0xa085, 0x00ff, 0x6822, 0x7000, 0x0079, 0x2f86, 0x2482, 0x2f90,
+       0x2f90, 0x2f92, 0x2f92, 0x2f92, 0x2f92, 0x2f8e, 0x1078, 0x23eb,
+       0x1078, 0x33ee, 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x33a8,
+       0x2300, 0x0079, 0x2f9b, 0x2f9e, 0x2fa0, 0x2fd9, 0x1078, 0x23eb,
+       0x7000, 0x0079, 0x2fa3, 0x2482, 0x2fad, 0x2fad, 0x2fc8, 0x2fad,
+       0x2fd5, 0x2fc8, 0x2fab, 0x1078, 0x23eb, 0xa684, 0x0060, 0xa086,
+       0x0060, 0x00c0, 0x2fc4, 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5,
+       0x2000, 0x7e5a, 0x681c, 0xa084, 0xffdf, 0x681e, 0x1078, 0x4776,
+       0x1078, 0x4a3a, 0x0078, 0x3888, 0xa684, 0x2000, 0x0040, 0x2fb7,
+       0x6818, 0xa084, 0x8000, 0x0040, 0x2fd5, 0x681b, 0x0015, 0xa684,
+       0x4000, 0x0040, 0x2fd5, 0x681b, 0x0007, 0x1078, 0x389c, 0x0078,
+       0x2459, 0x1078, 0x23eb, 0x2300, 0x0079, 0x2fde, 0x2fe1, 0x2fe3,
+       0x3016, 0x1078, 0x23eb, 0x7000, 0x0079, 0x2fe6, 0x2482, 0x2ff0,
+       0x2ff0, 0x300b, 0x2ff0, 0x3012, 0x300b, 0x2fee, 0x1078, 0x23eb,
+       0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x3007, 0xa6b4, 0xffbf,
+       0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf,
+       0x681e, 0x1078, 0x4776, 0x1078, 0x4a3a, 0x0078, 0x3888, 0xa684,
+       0x2000, 0x0040, 0x2ffa, 0x6818, 0xa084, 0x8000, 0x0040, 0x3012,
+       0x681b, 0x0007, 0x781b, 0x00cd, 0x0078, 0x2459, 0x6820, 0xa085,
+       0x0004, 0x6822, 0x1078, 0x3853, 0xa6b5, 0x0800, 0x1078, 0x36c1,
+       0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x2300, 0x0079,
+       0x3029, 0x302c, 0x302e, 0x3030, 0x1078, 0x23eb, 0x0078, 0x36ad,
+       0xa684, 0x0400, 0x00c0, 0x3059, 0x79e4, 0xa184, 0x0020, 0x0040,
+       0x3040, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3040, 0x782b, 0x3009,
+       0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4,
+       0xa184, 0x0020, 0x0040, 0x3051, 0x78ec, 0xa084, 0x0003, 0x00c0,
+       0x3055, 0x2001, 0x0014, 0x0078, 0x2d01, 0xa184, 0x0007, 0x0079,
+       0x3091, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff,
+       0x0040, 0x308f, 0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0,
+       0x3080, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, 0x3073, 0x2009,
+       0xfff7, 0x0078, 0x3079, 0xa386, 0x0003, 0x00c0, 0x3080, 0x2009,
+       0xffef, 0x0c7e, 0x7054, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f,
+       0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b,
+       0x3009, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078,
+       0x3888, 0x299e, 0x29a9, 0x309b, 0x30a3, 0x3099, 0x3099, 0x3888,
+       0x3888, 0x1078, 0x23eb, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff,
+       0x6922, 0x0078, 0x3892, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff,
+       0x6922, 0x0078, 0x3888, 0x79e4, 0xa184, 0x0030, 0x0040, 0x30b5,
+       0x78ec, 0xa084, 0x0003, 0x00c0, 0x30dc, 0x7000, 0xa086, 0x0004,
+       0x00c0, 0x30cf, 0x706c, 0xa086, 0x0002, 0x00c0, 0x30c5, 0x2011,
+       0x0002, 0x2019, 0x0000, 0x0078, 0x2848, 0x706c, 0xa086, 0x0006,
+       0x0040, 0x30bf, 0x706c, 0xa086, 0x0004, 0x0040, 0x30bf, 0x7000,
+       0xa086, 0x0000, 0x0040, 0x2459, 0x6818, 0xa085, 0x8000, 0x681a,
+       0x2001, 0x0014, 0x0078, 0x2d01, 0xa184, 0x0007, 0x0079, 0x30e0,
+       0x3888, 0x3888, 0x30e8, 0x3888, 0x38ed, 0x38ed, 0x3888, 0x3888,
+       0xa684, 0x0080, 0x0040, 0x3117, 0x7194, 0x81ff, 0x0040, 0x3117,
+       0xa182, 0x000d, 0x00d0, 0x30f8, 0x7097, 0x0000, 0x0078, 0x30fd,
+       0xa182, 0x000c, 0x7096, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa,
+       0x157e, 0x137e, 0x147e, 0x7098, 0x8114, 0xa210, 0x729a, 0xa080,
+       0x000b, 0xad00, 0x2098, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108,
+       0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x3892, 0xa684,
+       0x0400, 0x00c0, 0x3158, 0x6820, 0xa084, 0x0001, 0x0040, 0x3892,
+       0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x312c, 0xa086, 0x0060,
+       0x00c0, 0x312c, 0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6,
+       0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xa085,
+       0x8000, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x3407, 0xa18c,
+       0x00f8, 0x00c0, 0x3407, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b,
+       0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6,
+       0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x0078, 0x3892,
+       0x6818, 0xa084, 0x8000, 0x0040, 0x315f, 0x681b, 0x0008, 0x781b,
+       0x00c3, 0x0078, 0x2459, 0x2300, 0x0079, 0x3166, 0x316b, 0x320a,
+       0x3169, 0x1078, 0x23eb, 0x7000, 0xa084, 0x0007, 0x0079, 0x3170,
+       0x2482, 0x317a, 0x31af, 0x3185, 0x3178, 0x2482, 0x3178, 0x3178,
+       0x1078, 0x23eb, 0x681c, 0xa084, 0x2000, 0x0040, 0x3193, 0x6008,
+       0xa085, 0x0002, 0x600a, 0x0078, 0x3193, 0x68c0, 0xa005, 0x00c0,
+       0x31af, 0x6920, 0xa18d, 0x0001, 0x6922, 0x68c3, 0x0001, 0x6800,
+       0x706a, 0x0078, 0x31a9, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800,
+       0x6006, 0xa005, 0x00c0, 0x319d, 0x6002, 0x681c, 0xa084, 0x000e,
+       0x0040, 0x31a9, 0x7014, 0x68ba, 0x7130, 0xa188, 0x7400, 0x0078,
+       0x31ab, 0x2009, 0x7500, 0x2104, 0x6802, 0x2d0a, 0x7162, 0x6eb6,
+       0xa684, 0x0060, 0x0040, 0x3208, 0xa684, 0x0800, 0x00c0, 0x31c3,
+       0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078,
+       0x4776, 0x0078, 0x3208, 0xa684, 0x0020, 0x0040, 0x31d8, 0x68c0,
+       0xa005, 0x0040, 0x31cf, 0x1078, 0x4b78, 0x0078, 0x31d2, 0xa006,
+       0x1078, 0x4b30, 0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x31de,
+       0x1078, 0x37fc, 0x69aa, 0x6aa6, 0x1078, 0x4b30, 0xa684, 0x8000,
+       0x0040, 0x3208, 0xa684, 0x7fff, 0x68b6, 0x2001, 0x0076, 0x1078,
+       0x3918, 0x2010, 0x2001, 0x0078, 0x1078, 0x3918, 0x2008, 0xa684,
+       0x0020, 0x00c0, 0x3200, 0x2001, 0x007a, 0x1078, 0x3918, 0x801b,
+       0x00c8, 0x31fb, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+       0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae,
+       0x0078, 0x2482, 0x0078, 0x36ad, 0x7037, 0x0000, 0xa282, 0x0006,
+       0x0050, 0x3214, 0x1078, 0x23eb, 0x7000, 0xa084, 0x0007, 0x10c0,
+       0x39be, 0x2300, 0x0079, 0x321c, 0x321f, 0x3248, 0x325c, 0x2200,
+       0x0079, 0x3222, 0x3246, 0x36ad, 0x3228, 0x3246, 0x3278, 0x32ba,
+       0x7003, 0x0005, 0x2001, 0x7610, 0x2068, 0x704a, 0x157e, 0x20a9,
+       0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x3238, 0x0078, 0x3231,
+       0x157f, 0xad80, 0x0009, 0x7036, 0x6817, 0x0000, 0x68b7, 0x0700,
+       0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x369d, 0x1078, 0x23eb,
+       0x7003, 0x0005, 0x2001, 0x7610, 0x2068, 0x704a, 0xad80, 0x0009,
+       0x7036, 0x2200, 0x0079, 0x3254, 0x36ad, 0x325a, 0x325a, 0x3278,
+       0x325a, 0x36ad, 0x1078, 0x23eb, 0x7003, 0x0005, 0x2001, 0x7610,
+       0x2068, 0x704a, 0xad80, 0x0009, 0x7036, 0x2200, 0x0079, 0x3268,
+       0x3270, 0x326e, 0x326e, 0x3270, 0x326e, 0x3270, 0x1078, 0x23eb,
+       0x1078, 0x36d1, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2459,
+       0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8,
+       0xa484, 0x001f, 0xa215, 0x2069, 0x7500, 0x2d04, 0x2d08, 0x7162,
+       0x2068, 0xa005, 0x0040, 0x3293, 0x6814, 0xa206, 0x0040, 0x32af,
+       0x6800, 0x0078, 0x3286, 0x7003, 0x0005, 0x2001, 0x7610, 0x2068,
+       0x704a, 0x7036, 0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000,
+       0x0070, 0x32a4, 0x0078, 0x329d, 0x157f, 0xad80, 0x0009, 0x7036,
+       0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4,
+       0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x3309, 0x1078, 0x36c9,
+       0x0078, 0x3309, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b,
+       0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x79a8, 0x79a8, 0xa18c,
+       0x00ff, 0xa1e8, 0x7400, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005,
+       0x0040, 0x32d9, 0x6814, 0xa206, 0x0040, 0x32f4, 0x6800, 0x0078,
+       0x32cc, 0x7003, 0x0005, 0x2001, 0x7610, 0x2068, 0x704a, 0x157e,
+       0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x32e9, 0x0078,
+       0x32e2, 0x157f, 0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7, 0x0700,
+       0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084,
+       0x0c00, 0x0040, 0x3309, 0xa084, 0x0800, 0x0040, 0x3303, 0x1078,
+       0x36cd, 0x0078, 0x3309, 0x1078, 0x36c9, 0x708b, 0x0000, 0x0078,
+       0x3309, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+       0xa080, 0x5380, 0x2060, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e,
+       0xa684, 0x0060, 0x0040, 0x3361, 0x6b98, 0x6c94, 0x69ac, 0x68b0,
+       0xa105, 0x00c0, 0x3343, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4,
+       0xb7ff, 0x7e5a, 0xa684, 0x0060, 0xa086, 0x0060, 0x0040, 0x3361,
+       0x68c0, 0xa005, 0x0040, 0x333c, 0x7003, 0x0003, 0x682b, 0x0000,
+       0x1078, 0x4a29, 0x0078, 0x333e, 0x1078, 0x4a3a, 0xa6b5, 0x2000,
+       0x7e5a, 0x0078, 0x3361, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400,
+       0xa305, 0x0040, 0x3361, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0,
+       0xa6b4, 0xbfff, 0x7e5a, 0x007e, 0x68c0, 0xa005, 0x007f, 0x0040,
+       0x335f, 0x7003, 0x0003, 0x1078, 0x4a29, 0x0078, 0x3361, 0x1078,
+       0x4a85, 0x077f, 0x1078, 0x37ef, 0x2009, 0x0065, 0xa684, 0x0004,
+       0x0040, 0x3382, 0x78e4, 0xa084, 0x0030, 0x0040, 0x337a, 0x78ec,
+       0xa084, 0x0003, 0x0040, 0x337a, 0x782b, 0x3008, 0x2009, 0x0065,
+       0x0078, 0x3382, 0x0f7e, 0x2079, 0x5100, 0x1078, 0x4776, 0x0f7f,
+       0x0040, 0x2482, 0x791a, 0x2d00, 0x704a, 0x8207, 0xa084, 0x000f,
+       0x8003, 0x8003, 0x8003, 0xa080, 0x5380, 0x2048, 0x0078, 0x2459,
+       0x6020, 0xa005, 0x0040, 0x339c, 0x8001, 0x6022, 0x6008, 0xa085,
+       0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x4776,
+       0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100,
+       0x7000, 0xa084, 0x0007, 0x0079, 0x33ad, 0x2482, 0x33b7, 0x33b7,
+       0x33d4, 0x33bf, 0x33bd, 0x33bf, 0x33b5, 0x1078, 0x23eb, 0x1078,
+       0x33df, 0x1078, 0x33d8, 0x1078, 0x1c70, 0x0078, 0x2482, 0x706c,
+       0x706f, 0x0000, 0x7093, 0x0000, 0x0079, 0x33c6, 0x33d0, 0x33d0,
+       0x33ce, 0x33ce, 0x33ce, 0x33d0, 0x33ce, 0x33d0, 0x0079, 0x2861,
+       0x706f, 0x0000, 0x0078, 0x2482, 0x681b, 0x0000, 0x0078, 0x2f17,
+       0x6800, 0xa005, 0x00c0, 0x33dd, 0x6002, 0x6006, 0x007c, 0x6010,
+       0xa005, 0x0040, 0x33e8, 0x8001, 0x00d0, 0x33e8, 0x1078, 0x23eb,
+       0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005,
+       0x0040, 0x33f4, 0x8001, 0x601a, 0x007c, 0x1078, 0x3912, 0x681b,
+       0x0018, 0x0078, 0x342b, 0x1078, 0x3912, 0x681b, 0x0019, 0x0078,
+       0x342b, 0x1078, 0x3912, 0x681b, 0x001a, 0x0078, 0x342b, 0x1078,
+       0x3912, 0x681b, 0x0003, 0x0078, 0x342b, 0x7780, 0x1078, 0x37ef,
+       0x7184, 0xa18c, 0x00ff, 0xa1e8, 0x7400, 0x2d04, 0x2d08, 0x2068,
+       0xa005, 0x00c0, 0x341d, 0x0078, 0x2482, 0x6814, 0x7280, 0xa206,
+       0x0040, 0x3425, 0x6800, 0x0078, 0x3416, 0x6800, 0x200a, 0x681b,
+       0x0005, 0x708b, 0x0000, 0x1078, 0x33df, 0x6820, 0xa084, 0x0001,
+       0x00c0, 0x3434, 0x1078, 0x33d8, 0x1078, 0x33ee, 0x681f, 0x0000,
+       0x6823, 0x0020, 0x1078, 0x1c70, 0x0078, 0x2482, 0xa282, 0x0003,
+       0x00c0, 0x369d, 0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff,
+       0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0100, 0x0040, 0x34a2,
+       0xa18c, 0xfeff, 0x6922, 0xa4a4, 0x00ff, 0x0040, 0x348c, 0xa482,
+       0x000c, 0x0048, 0x345f, 0x0040, 0x345f, 0x2021, 0x000c, 0x852b,
+       0x852b, 0x1078, 0x3760, 0x0040, 0x3469, 0x1078, 0x355b, 0x0078,
+       0x3495, 0x1078, 0x371b, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5,
+       0x6006, 0x1078, 0x3586, 0x0c7f, 0x6920, 0xa18d, 0x0100, 0x6922,
+       0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x3486,
+       0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x782b, 0x3008,
+       0x781b, 0x0065, 0x0078, 0x2459, 0x0c7e, 0x2960, 0x6004, 0xa084,
+       0xfff5, 0x6006, 0x1078, 0x3586, 0x0c7f, 0x7e58, 0xa684, 0x0400,
+       0x00c0, 0x349e, 0x781b, 0x0058, 0x0078, 0x2459, 0x781b, 0x0065,
+       0x0078, 0x2459, 0x0c7e, 0x7054, 0x2060, 0x6100, 0xa18c, 0x1000,
+       0x0040, 0x34e2, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c,
+       0x0048, 0x34b6, 0x0040, 0x34b6, 0x2011, 0x000c, 0x2400, 0xa202,
+       0x00c8, 0x34bb, 0x2220, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086,
+       0x0028, 0x00c0, 0x34cb, 0xa282, 0x0019, 0x00c8, 0x34d1, 0x2011,
+       0x0019, 0x0078, 0x34d1, 0xa282, 0x000c, 0x00c8, 0x34d1, 0x2011,
+       0x000c, 0x2200, 0xa502, 0x00c8, 0x34d6, 0x2228, 0x1078, 0x371f,
+       0x852b, 0x852b, 0x1078, 0x3760, 0x0040, 0x34e2, 0x1078, 0x355b,
+       0x0078, 0x34e6, 0x1078, 0x371b, 0x1078, 0x3586, 0x7858, 0xa085,
+       0x0004, 0x785a, 0x0c7f, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078,
+       0x2459, 0x0c7e, 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x3509,
+       0x6010, 0xa084, 0x000f, 0x00c0, 0x3503, 0x6104, 0xa18c, 0xfff5,
+       0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078,
+       0x3530, 0x68a0, 0xa084, 0x0200, 0x00c0, 0x3503, 0x6208, 0xa294,
+       0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, 0x351e, 0xa282, 0x0019,
+       0x00c8, 0x3524, 0x2011, 0x0019, 0x0078, 0x3524, 0xa282, 0x000c,
+       0x00c8, 0x3524, 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff,
+       0xa382, 0x000c, 0x0048, 0x3530, 0x0040, 0x3530, 0x2019, 0x000c,
+       0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa,
+       0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c,
+       0x0c7e, 0x2960, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019,
+       0x0000, 0x0078, 0x354b, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+       0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100,
+       0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7154, 0x2160, 0x1078, 0x3562,
+       0x0c7f, 0x007c, 0x2008, 0xa084, 0xfff0, 0xa425, 0x7c86, 0x6018,
+       0x789a, 0x7cae, 0x6412, 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007,
+       0xa105, 0x78a6, 0x6016, 0x788a, 0xa4a4, 0x000f, 0x8427, 0x8204,
+       0x8004, 0xa084, 0x00ff, 0xa405, 0x600e, 0x78ec, 0xd08c, 0x00c0,
+       0x3585, 0x6004, 0xa084, 0xfff5, 0x6006, 0x007c, 0x0c7e, 0x7054,
+       0x2060, 0x1078, 0x358d, 0x0c7f, 0x007c, 0x6018, 0x789a, 0x78a4,
+       0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886,
+       0x007c, 0xa282, 0x0002, 0x00c0, 0x369d, 0x7aa8, 0x6920, 0xa18d,
+       0x0080, 0x6922, 0xa184, 0x0200, 0x0040, 0x35e2, 0xa18c, 0xfdff,
+       0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, 0x369d, 0x1078,
+       0x362b, 0x1078, 0x3586, 0xa980, 0x0001, 0x200c, 0x1078, 0x37eb,
+       0x1078, 0x34f1, 0x88ff, 0x0040, 0x35d5, 0x789b, 0x0060, 0x2800,
+       0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0,
+       0x35cf, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x782b,
+       0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x7e58, 0xa684, 0x0400,
+       0x00c0, 0x35de, 0x781b, 0x0058, 0x0078, 0x2459, 0x781b, 0x0065,
+       0x0078, 0x2459, 0xa282, 0x0002, 0x00c8, 0x35ea, 0xa284, 0x0001,
+       0x0040, 0x35f4, 0x7154, 0xa188, 0x0000, 0x210c, 0xa18c, 0x2000,
+       0x00c0, 0x35f4, 0x2011, 0x0000, 0x1078, 0x370d, 0x1078, 0x362b,
+       0x1078, 0x3586, 0x7858, 0xa085, 0x0004, 0x785a, 0x782b, 0x3008,
+       0x781b, 0x0065, 0x0078, 0x2459, 0x0c7e, 0x027e, 0x2960, 0x6000,
+       0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x361b, 0x6014, 0xa084,
+       0x0040, 0x00c0, 0x3619, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078,
+       0x3628, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab,
+       0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822,
+       0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7054, 0x2060, 0x1078, 0x3632,
+       0x0c7f, 0x007c, 0x82ff, 0x0040, 0x3637, 0x2011, 0x0040, 0x6018,
+       0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xffbf, 0xa205, 0x78a6,
+       0x788a, 0x6016, 0x78ec, 0xd08c, 0x00c0, 0x364a, 0x6004, 0xa084,
+       0xffef, 0x6006, 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040,
+       0x3654, 0x007f, 0x0078, 0x3657, 0x007f, 0x0078, 0x3699, 0xa684,
+       0x0020, 0x0040, 0x3699, 0x7888, 0xa084, 0x0040, 0x0040, 0x3699,
+       0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, 0x3667, 0x8000, 0xa005,
+       0x0040, 0x367d, 0x831b, 0x00c8, 0x3670, 0x8001, 0x0040, 0x3695,
+       0xa684, 0x4000, 0x0040, 0x367d, 0x78b8, 0x801b, 0x00c8, 0x3679,
+       0x8000, 0xa084, 0x003f, 0x00c0, 0x3695, 0xa6b4, 0xbfff, 0x7e5a,
+       0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x3689, 0xa291,
+       0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x4b30, 0x781b,
+       0x0064, 0x1078, 0x49b5, 0x0078, 0x2459, 0x781b, 0x0064, 0x0078,
+       0x2459, 0x781b, 0x0065, 0x0078, 0x2459, 0x1078, 0x36d5, 0x782b,
+       0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x1078, 0x36c1, 0x782b,
+       0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x6827, 0x0002, 0x1078,
+       0x36c9, 0x78e4, 0xa084, 0x0030, 0x0040, 0x2482, 0x78ec, 0xa084,
+       0x0003, 0x0040, 0x2482, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078,
+       0x2459, 0x2001, 0x0005, 0x0078, 0x36d7, 0x2001, 0x000c, 0x0078,
+       0x36d7, 0x2001, 0x0006, 0x0078, 0x36d7, 0x2001, 0x000d, 0x0078,
+       0x36d7, 0x2001, 0x0009, 0x0078, 0x36d7, 0x2001, 0x0007, 0x789b,
+       0x0010, 0x78aa, 0x789b, 0x0060, 0x78ab, 0x0001, 0xa6b5, 0x0004,
+       0x7e5a, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b,
+       0x8703, 0xa0e0, 0x5380, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184,
+       0x000f, 0x0040, 0x36fb, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004,
+       0xa085, 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184,
+       0x0040, 0x0040, 0x370b, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004,
+       0xa085, 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab,
+       0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060,
+       0x78ab, 0x0004, 0x007c, 0x2021, 0x0000, 0x2029, 0x0032, 0x789b,
+       0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa,
+       0x7caa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007,
+       0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4,
+       0xa18c, 0xfff0, 0x2001, 0x5146, 0x2004, 0xa082, 0x0028, 0x0040,
+       0x3749, 0x2021, 0x37d2, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078,
+       0x374f, 0x2021, 0x37de, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011,
+       0x0064, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x375e, 0x8420,
+       0x2300, 0xa210, 0x0070, 0x375e, 0x0078, 0x3751, 0x157f, 0x007c,
+       0x157e, 0x2009, 0x5146, 0x210c, 0xa182, 0x0032, 0x0048, 0x3774,
+       0x0040, 0x3778, 0x2009, 0x37c4, 0x2019, 0x0011, 0x20a9, 0x000e,
+       0x2011, 0x0032, 0x0078, 0x378a, 0xa182, 0x0028, 0x0040, 0x3782,
+       0x2009, 0x37d2, 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064,
+       0x0078, 0x378a, 0x2009, 0x37de, 0x2019, 0x0019, 0x20a9, 0x000d,
+       0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x379a, 0x0048, 0x379a,
+       0x8108, 0x2300, 0xa210, 0x0070, 0x3797, 0x0078, 0x378a, 0x157f,
+       0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, 0x37a9, 0x7808,
+       0xa085, 0x0070, 0x780a, 0x7044, 0xa085, 0x0070, 0x7046, 0x0078,
+       0x37a9, 0x78ec, 0xa084, 0x0300, 0x0040, 0x37b1, 0x2104, 0x0078,
+       0x37c2, 0x2104, 0xa09e, 0x1102, 0x00c0, 0x37c2, 0x2001, 0x04fd,
+       0x2004, 0xa082, 0x0005, 0x0048, 0x37c1, 0x2001, 0x1201, 0x0078,
+       0x37c2, 0x2104, 0xa005, 0x007c, 0x1102, 0x3002, 0x3202, 0x4203,
+       0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07,
+       0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605,
+       0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202,
+       0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04,
+       0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784,
+       0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003,
+       0xa105, 0xa0e0, 0x5400, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b,
+       0x00c8, 0x3803, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+       0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x5140, 0x2091, 0x8000,
+       0x2104, 0x0079, 0x3813, 0x3849, 0x381d, 0x381d, 0x381d, 0x381d,
+       0x381d, 0x381d, 0x384d, 0x1078, 0x23eb, 0x784b, 0x0004, 0x7848,
+       0xa084, 0x0004, 0x00c0, 0x381f, 0x784b, 0x0008, 0x7848, 0xa084,
+       0x0008, 0x00c0, 0x3826, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858,
+       0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x3849,
+       0x0018, 0x3849, 0x681c, 0xa084, 0x0020, 0x00c0, 0x3847, 0x0e7e,
+       0x2071, 0x5140, 0x1078, 0x389c, 0x0e7f, 0x0078, 0x3849, 0x781b,
+       0x00cd, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x70b3, 0x0000, 0x1078,
+       0x3a76, 0x0078, 0x3849, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f,
+       0x8003, 0x8003, 0x8003, 0xa0e0, 0x5380, 0x6004, 0xa084, 0x000a,
+       0x00c0, 0x3886, 0x6108, 0xa194, 0xff00, 0x0040, 0x3886, 0xa18c,
+       0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x3875, 0x2001, 0x0032,
+       0xa106, 0x0040, 0x3879, 0x0078, 0x387d, 0x2009, 0x0020, 0x0078,
+       0x387f, 0x2009, 0x003f, 0x0078, 0x387f, 0x2011, 0x0000, 0x2100,
+       0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c,
+       0x781b, 0x0065, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b, 0x0065,
+       0x0078, 0x2459, 0x781b, 0x0058, 0x0078, 0x2459, 0x782b, 0x3008,
+       0x781b, 0x0056, 0x0078, 0x2459, 0x2009, 0x5120, 0x210c, 0xa186,
+       0x0000, 0x0040, 0x38b0, 0xa186, 0x0001, 0x0040, 0x38b3, 0x2009,
+       0x5138, 0x200b, 0x000b, 0x706f, 0x0001, 0x781b, 0x0048, 0x007c,
+       0x781b, 0x00c7, 0x007c, 0x2009, 0x5138, 0x200b, 0x000a, 0x007c,
+       0x2009, 0x5120, 0x210c, 0xa186, 0x0000, 0x0040, 0x38d3, 0xa186,
+       0x0001, 0x0040, 0x38cd, 0x2009, 0x5138, 0x200b, 0x000b, 0x706f,
+       0x0001, 0x781b, 0x0048, 0x0078, 0x2459, 0x2009, 0x5138, 0x200b,
+       0x000a, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b, 0x00c7, 0x0078,
+       0x2459, 0x781b, 0x00cd, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b,
+       0x00cd, 0x0078, 0x2459, 0x781b, 0x008e, 0x0078, 0x2459, 0x782b,
+       0x3008, 0x781b, 0x008e, 0x0078, 0x2459, 0x6818, 0xa084, 0x8000,
+       0x0040, 0x38f4, 0x681b, 0x001d, 0x706f, 0x0001, 0x781b, 0x0048,
+       0x0078, 0x2459, 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3910,
+       0x7808, 0xa084, 0xfffc, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005,
+       0x78ec, 0xa084, 0x0021, 0x0040, 0x3910, 0x7044, 0x780a, 0xa005,
+       0x007f, 0x007c, 0x7044, 0xa085, 0x0002, 0x7046, 0x780a, 0x007c,
+       0x007e, 0x7830, 0xa084, 0x0040, 0x00c0, 0x3919, 0x0098, 0x3924,
+       0x007f, 0x789a, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a,
+       0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
+       0x3933, 0x0098, 0x3931, 0x007f, 0x789a, 0x78ac, 0x007e, 0x7044,
+       0x780a, 0x007f, 0x007c, 0x78ec, 0xa084, 0x0002, 0x00c0, 0x4760,
+       0xa784, 0x007d, 0x00c0, 0x3947, 0x2700, 0x1078, 0x23eb, 0xa784,
+       0x0001, 0x00c0, 0x2f6d, 0xa784, 0x0070, 0x0040, 0x3957, 0x0c7e,
+       0x2d60, 0x2f68, 0x1078, 0x2396, 0x2d78, 0x2c68, 0x0c7f, 0xa784,
+       0x0008, 0x0040, 0x3964, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003,
+       0x0040, 0x2482, 0x0078, 0x3888, 0xa784, 0x0004, 0x0040, 0x3997,
+       0x78b8, 0xa084, 0x4001, 0x0040, 0x3997, 0x784b, 0x0008, 0x78ec,
+       0xa084, 0x0003, 0x0040, 0x2482, 0x78e4, 0xa084, 0x0007, 0xa086,
+       0x0001, 0x00c0, 0x3997, 0x78c0, 0xa085, 0x4800, 0x2030, 0x7e5a,
+       0x781b, 0x00cd, 0x0078, 0x2459, 0x784b, 0x0008, 0x6818, 0xa084,
+       0x8000, 0x0040, 0x3993, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040,
+       0x3993, 0x681b, 0x0007, 0x1078, 0x389c, 0x0078, 0x2459, 0x681b,
+       0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833,
+       0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2965,
+       0x0018, 0x2459, 0x0078, 0x36a5, 0x6b14, 0x8307, 0xa084, 0x000f,
+       0x8003, 0x8003, 0x8003, 0xa080, 0x5380, 0x2060, 0x2048, 0x7056,
+       0x6000, 0x705a, 0x6004, 0x705e, 0x2a60, 0x007c, 0x0079, 0x39c0,
+       0x39c8, 0x39c9, 0x39c8, 0x39cb, 0x39c8, 0x39c8, 0x39c8, 0x39d0,
+       0x007c, 0x1078, 0x33ee, 0x1078, 0x4776, 0x7038, 0x600a, 0x007c,
+       0x70a0, 0xa005, 0x0040, 0x39dd, 0x2068, 0x1078, 0x1b62, 0x1078,
+       0x46f8, 0x1078, 0x46ff, 0x70a3, 0x0000, 0x007c, 0x0e7e, 0x2091,
+       0x8000, 0x2071, 0x5140, 0x7000, 0xa086, 0x0007, 0x00c0, 0x39f4,
+       0x6110, 0x70bc, 0xa106, 0x00c0, 0x39f4, 0x0e7f, 0x1078, 0x1b6f,
+       0x1078, 0x39fa, 0xa006, 0x007c, 0x2091, 0x8001, 0x0e7f, 0xa085,
+       0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x5140, 0x0078, 0x21fa,
+       0x785b, 0x0000, 0x70af, 0x000e, 0x2009, 0x0100, 0x017e, 0x70a0,
+       0xa06d, 0x0040, 0x3a0f, 0x70a3, 0x0000, 0x0078, 0x3a15, 0x70b3,
+       0x0000, 0x1078, 0x1b8b, 0x0040, 0x3a1b, 0x70ac, 0x6826, 0x1078,
+       0x3af8, 0x0078, 0x3a0f, 0x017f, 0x157e, 0x0c7e, 0x0d7e, 0x20a9,
+       0x0008, 0x2061, 0x7510, 0x6000, 0xa105, 0x6002, 0x601c, 0xa06d,
+       0x0040, 0x3a33, 0x6800, 0x601e, 0x1078, 0x195a, 0x6008, 0x8000,
+       0x600a, 0x0078, 0x3a26, 0x6018, 0xa06d, 0x0040, 0x3a3d, 0x6800,
+       0x601a, 0x1078, 0x195a, 0x0078, 0x3a33, 0xace0, 0x0008, 0x0070,
+       0x3a43, 0x0078, 0x3a23, 0x709c, 0xa084, 0x8000, 0x0040, 0x3a4a,
+       0x1078, 0x3b72, 0x0d7f, 0x0c7f, 0x157f, 0x007c, 0x127e, 0x2091,
+       0x2300, 0x6804, 0xa084, 0x000f, 0x0079, 0x3a56, 0x3a66, 0x3a66,
+       0x3a66, 0x3a66, 0x3a66, 0x3a66, 0x3a68, 0x3a6e, 0x3a66, 0x3a66,
+       0x3a66, 0x3a66, 0x3a66, 0x3a70, 0x3a66, 0x3a68, 0x1078, 0x23eb,
+       0x1078, 0x44d0, 0x1078, 0x195a, 0x0078, 0x3a74, 0x6827, 0x000b,
+       0x1078, 0x44d0, 0x1078, 0x3af8, 0x127f, 0x007c, 0x127e, 0x2091,
+       0x2300, 0x0098, 0x3a92, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3a92,
+       0x0d7e, 0x1078, 0x4708, 0x2d00, 0x682e, 0x2009, 0x0004, 0x2001,
+       0x0000, 0x6827, 0x0084, 0x1078, 0x46c1, 0x1078, 0x3af8, 0x0d7f,
+       0x0078, 0x3ac6, 0x7948, 0xa185, 0x4000, 0x784a, 0x0098, 0x3a9b,
+       0x794a, 0x0078, 0x3a80, 0x7828, 0xa086, 0x1834, 0x00c0, 0x3aa4,
+       0xa185, 0x0004, 0x0078, 0x3aab, 0x7828, 0xa086, 0x1814, 0x00c0,
+       0x3a98, 0xa185, 0x000c, 0x784a, 0x789b, 0x000e, 0x78ab, 0x0002,
+       0x7858, 0xa084, 0x00ff, 0xa085, 0x0400, 0x785a, 0x70b4, 0xa080,
+       0x0091, 0x781a, 0x6827, 0x0284, 0x682c, 0x6836, 0x6830, 0x683a,
+       0x2009, 0x0004, 0x2001, 0x0000, 0x1078, 0x46c1, 0x127f, 0x007c,
+       0x0d7e, 0x6b14, 0x1078, 0x1bfd, 0x0040, 0x3ad5, 0x2068, 0x6827,
+       0x0002, 0x1078, 0x3af8, 0x0078, 0x3aca, 0x0d7f, 0x007c, 0x0d7e,
+       0x6b14, 0x6c28, 0xa4a4, 0x00ff, 0x1078, 0x1b9b, 0x0040, 0x3ae5,
+       0x2068, 0x6827, 0x0002, 0x1078, 0x3af8, 0x0d7f, 0x007c, 0x0d7e,
+       0x6b14, 0xa39c, 0x00ff, 0x1078, 0x1bce, 0x0040, 0x3af6, 0x2068,
+       0x6827, 0x0002, 0x1078, 0x3af8, 0x0078, 0x3aeb, 0x0d7f, 0x007c,
+       0x0c7e, 0x6914, 0x1078, 0x3b69, 0x6904, 0xa18c, 0x00ff, 0xa186,
+       0x0006, 0x0040, 0x3b13, 0xa186, 0x000d, 0x0040, 0x3b32, 0xa186,
+       0x0017, 0x00c0, 0x3b0f, 0x1078, 0x195a, 0x0078, 0x3b11, 0x1078,
+       0x1c72, 0x0c7f, 0x007c, 0x6004, 0x8001, 0x0048, 0x3b30, 0x6006,
+       0x2009, 0x0000, 0xa684, 0x0001, 0x00c0, 0x3b20, 0xa18d, 0x8000,
+       0xa684, 0x0004, 0x0040, 0x3b26, 0xa18d, 0x0002, 0x691e, 0x6823,
+       0x0000, 0x7104, 0x810f, 0x6818, 0xa105, 0x681a, 0x0078, 0x3b0f,
+       0x1078, 0x23eb, 0x6018, 0xa005, 0x00c0, 0x3b41, 0x6008, 0x8001,
+       0x0048, 0x3b41, 0x600a, 0x601c, 0x6802, 0x2d00, 0x601e, 0x0078,
+       0x3b57, 0xac88, 0x0006, 0x2104, 0xa005, 0x0040, 0x3b4a, 0x2008,
+       0x0078, 0x3b43, 0x6802, 0x2d0a, 0x6008, 0x8001, 0x0048, 0x3b11,
+       0x600a, 0x6018, 0x2068, 0x6800, 0x601a, 0x0078, 0x3b3b, 0x157e,
+       0x137e, 0x147e, 0x0c7e, 0x0d7e, 0x1078, 0x1937, 0x2da0, 0x137f,
+       0x20a9, 0x0031, 0x53a3, 0x0c7f, 0x147f, 0x137f, 0x157f, 0x0078,
+       0x3b0f, 0xa184, 0x001f, 0x8003, 0x8003, 0x8003, 0xa080, 0x7510,
+       0x2060, 0x007c, 0x2019, 0x5151, 0x2304, 0xa085, 0x0001, 0x201a,
+       0x2019, 0x0102, 0x2304, 0xa085, 0x0001, 0x201a, 0x007c, 0x2019,
+       0x5151, 0x2304, 0xa084, 0xfffe, 0x201a, 0x2019, 0x0102, 0x2304,
+       0xa084, 0xfffe, 0x201a, 0x007c, 0x7990, 0xa18c, 0xfff8, 0x7992,
+       0x70b4, 0xa080, 0x00dd, 0x781a, 0x0078, 0x2459, 0x70a3, 0x0000,
+       0x7003, 0x0000, 0x7043, 0x0001, 0x7037, 0x0000, 0x0018, 0x2410,
+       0x1078, 0x1b8b, 0x0040, 0x3bc7, 0x2009, 0x510f, 0x200b, 0x0000,
+       0x68bc, 0x2060, 0x6100, 0xa184, 0x0300, 0x0040, 0x3bbb, 0x6827,
+       0x000e, 0xa084, 0x0200, 0x0040, 0x3bb7, 0x6827, 0x0017, 0x1078,
+       0x3af8, 0x0078, 0x3b96, 0x7000, 0xa086, 0x0007, 0x00c0, 0x3c29,
+       0x2d00, 0x70a2, 0xad80, 0x000f, 0x7036, 0x0078, 0x3bce, 0x7040,
+       0xa086, 0x0001, 0x0040, 0x2492, 0x0078, 0x2459, 0x2031, 0x0000,
+       0x691c, 0xa184, 0x0002, 0x0040, 0x3bd7, 0xa6b5, 0x0004, 0xa184,
+       0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3cc2, 0x2004, 0xa635,
+       0x6820, 0xa084, 0x0400, 0x0040, 0x3bef, 0x789b, 0x0018, 0x78ab,
+       0x0003, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5, 0x1000, 0x6820,
+       0xa084, 0x8000, 0x00c0, 0x3bfd, 0x681c, 0xa084, 0x8000, 0x00c0,
+       0x3c04, 0xa6b5, 0x0800, 0x0078, 0x3c04, 0xa6b5, 0x0400, 0x789b,
+       0x000e, 0x6824, 0x8007, 0x78aa, 0x6820, 0xa084, 0x0100, 0x0040,
+       0x3c0b, 0xa6b5, 0x4000, 0xa684, 0x0200, 0x0040, 0x3c25, 0x682c,
+       0x78d2, 0x6830, 0x78d6, 0xa684, 0x0100, 0x0040, 0x3c23, 0x682c,
+       0xa084, 0x0001, 0x0040, 0x3c23, 0x7888, 0xa084, 0x0040, 0x0040,
+       0x3c23, 0xa6b5, 0x8000, 0x1078, 0x46f0, 0x7e5a, 0x6eb6, 0x0078,
+       0x4727, 0x1078, 0x38fa, 0x00c0, 0x3cbc, 0x702c, 0x8004, 0x0048,
+       0x3c37, 0x2019, 0x4e3b, 0x1078, 0x2276, 0x702f, 0x0001, 0x2041,
+       0x0001, 0x2031, 0x1000, 0x789b, 0x0018, 0x6814, 0xa084, 0x001f,
+       0xa085, 0x0080, 0x78aa, 0x691c, 0xa184, 0x0002, 0x0040, 0x3c50,
+       0xa6b5, 0x0004, 0x78ab, 0x0020, 0x6828, 0x78aa, 0xa8c0, 0x0002,
+       0x681c, 0xd0f4, 0x0040, 0x3c59, 0x2c50, 0x1078, 0x39ac, 0x1078,
+       0x45ff, 0x6820, 0xa084, 0x8000, 0x0040, 0x3c67, 0xa6b5, 0x0400,
+       0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0x0078, 0x3c6e, 0x681c,
+       0xa084, 0x8000, 0x00c0, 0x3c6e, 0xa6b5, 0x0800, 0x6820, 0xa084,
+       0x0100, 0x0040, 0x3c75, 0xa6b5, 0x4000, 0x681c, 0xa084, 0x00c0,
+       0x8003, 0x8003, 0x8007, 0xa080, 0x3cc2, 0x2004, 0xa635, 0xa684,
+       0x0100, 0x0040, 0x3c8f, 0x682c, 0xa084, 0x0001, 0x0040, 0x3c8f,
+       0x7888, 0xa084, 0x0040, 0x0040, 0x3c8f, 0xa6b5, 0x8000, 0x789b,
+       0x007e, 0x7eae, 0x6eb6, 0x6814, 0x8007, 0x78aa, 0x7882, 0x2810,
+       0x7aaa, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3cbc, 0x0018, 0x3cbc,
+       0x70b4, 0xa080, 0x00e2, 0x781a, 0x1078, 0x3912, 0xa684, 0x0200,
+       0x0040, 0x3cb0, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x46f0,
+       0x2d00, 0x70a2, 0x704a, 0x6810, 0x70be, 0x7003, 0x0007, 0xad80,
+       0x000f, 0x7036, 0x0078, 0x2459, 0x1078, 0x1b62, 0x1078, 0x3912,
+       0x0078, 0x2459, 0x0000, 0x0300, 0x0200, 0x0000, 0x1078, 0x23eb,
+       0x2300, 0x0079, 0x3ccb, 0x3cce, 0x3cce, 0x3cd0, 0x1078, 0x23eb,
+       0x1078, 0x46ff, 0x6924, 0xa184, 0x00ff, 0xa086, 0x000a, 0x0040,
+       0x3ce2, 0xa184, 0xff00, 0xa085, 0x000a, 0x6826, 0x1078, 0x1b62,
+       0x0078, 0x3b96, 0x2001, 0x000a, 0x1078, 0x4691, 0x0078, 0x3b96,
+       0xa282, 0x0005, 0x0050, 0x3cee, 0x1078, 0x23eb, 0x7000, 0xa084,
+       0x0007, 0x10c0, 0x39be, 0x1078, 0x1937, 0x00c0, 0x3d0d, 0xa684,
+       0x0004, 0x0040, 0x3cff, 0x2001, 0x2800, 0x0078, 0x3d01, 0x2001,
+       0x0800, 0x71b4, 0xa188, 0x0091, 0x789b, 0x000e, 0x78aa, 0x2031,
+       0x0400, 0x7e5a, 0x791a, 0x0078, 0x2459, 0x6807, 0x0106, 0x680b,
+       0x0000, 0x689f, 0x0000, 0x6827, 0x0000, 0xa386, 0x0002, 0x00c0,
+       0x3d2e, 0xa286, 0x0002, 0x00c0, 0x3d2e, 0x78a0, 0xa005, 0x00c0,
+       0x3d2e, 0xa484, 0x8000, 0x00c0, 0x3d2e, 0x78e4, 0xa084, 0x0008,
+       0x0040, 0x3d2e, 0xa6b5, 0x0008, 0x2019, 0x0000, 0x1078, 0x411e,
+       0x2d00, 0x70a2, 0x704a, 0x7003, 0x0007, 0x7037, 0x0000, 0x6824,
+       0xa084, 0x0080, 0x0040, 0x3d40, 0x1078, 0x41d0, 0x0078, 0x2459,
+       0x2300, 0x0079, 0x3d43, 0x3d46, 0x3dc7, 0x3de6, 0x2200, 0x0079,
+       0x3d49, 0x3d4e, 0x3d5e, 0x3d84, 0x3d90, 0x3db3, 0x2029, 0x0001,
+       0xa026, 0x2011, 0x0000, 0x1078, 0x42f1, 0x0079, 0x3d57, 0x3d5c,
+       0x2459, 0x3b96, 0x3d5c, 0x3d5c, 0x1078, 0x23eb, 0x7990, 0xa18c,
+       0x0007, 0x00c0, 0x3d65, 0x2009, 0x0008, 0x2011, 0x0001, 0xa684,
+       0x0004, 0x0040, 0x3d6d, 0x2011, 0x0003, 0x2220, 0xa12a, 0x2011,
+       0x0001, 0x1078, 0x42f1, 0x0079, 0x3d75, 0x3d7a, 0x2459, 0x3b96,
+       0x3d82, 0x3d7c, 0x0078, 0x472d, 0x70ab, 0x3d80, 0x0078, 0x2459,
+       0x0078, 0x3d7a, 0x1078, 0x23eb, 0xa684, 0x0010, 0x0040, 0x3d8e,
+       0x1078, 0x419f, 0x0040, 0x3d8e, 0x0078, 0x2459, 0x0078, 0x420c,
+       0x6000, 0xa084, 0x0002, 0x0040, 0x3dad, 0x70b4, 0xa080, 0x00d2,
+       0x781a, 0x0d7e, 0x1078, 0x4708, 0x2d00, 0x682e, 0x6827, 0x0000,
+       0x1078, 0x3af8, 0x0d7f, 0x1078, 0x195a, 0x7003, 0x0000, 0x7037,
+       0x0000, 0x704b, 0x0000, 0x0078, 0x3b96, 0xa684, 0x0004, 0x00c0,
+       0x3db3, 0x0078, 0x472d, 0x6000, 0xa084, 0x0004, 0x00c0, 0x3dc5,
+       0x6000, 0xa084, 0x0001, 0x0040, 0x3dc5, 0x70ab, 0x3dc5, 0x2001,
+       0x0007, 0x1078, 0x4689, 0x0078, 0x4733, 0x0078, 0x472d, 0x2200,
+       0x0079, 0x3dca, 0x3dcf, 0x3dcf, 0x3dcf, 0x3dd1, 0x3dcf, 0x1078,
+       0x23eb, 0x70a7, 0x3dd5, 0x0078, 0x4739, 0x2011, 0x0018, 0x1078,
+       0x42eb, 0x0079, 0x3ddb, 0x3de0, 0x2459, 0x3b96, 0x3de2, 0x3de4,
+       0x1078, 0x23eb, 0x1078, 0x23eb, 0x1078, 0x23eb, 0x2200, 0x0079,
+       0x3de9, 0x3dee, 0x3df0, 0x3df0, 0x3dee, 0x3dee, 0x1078, 0x23eb,
+       0x78e4, 0xa084, 0x0008, 0x0040, 0x3e05, 0x70a7, 0x3df9, 0x0078,
+       0x4739, 0x2011, 0x0004, 0x1078, 0x42eb, 0x0079, 0x3dff, 0x3e05,
+       0x2459, 0x3b96, 0x3e05, 0x3e0f, 0x3e13, 0x70ab, 0x3e0d, 0x2001,
+       0x0003, 0x1078, 0x4689, 0x0078, 0x4733, 0x0078, 0x472d, 0x70ab,
+       0x3e05, 0x0078, 0x2459, 0x70ab, 0x3e17, 0x0078, 0x2459, 0x0078,
+       0x3e0d, 0xa282, 0x0003, 0x0050, 0x3e1f, 0x1078, 0x23eb, 0xa386,
+       0x0002, 0x00c0, 0x3e38, 0xa286, 0x0002, 0x00c0, 0x3e3e, 0x78a0,
+       0xa005, 0x00c0, 0x3e3e, 0xa484, 0x8000, 0x00c0, 0x3e3e, 0x78e4,
+       0xa084, 0x0008, 0x0040, 0x3e38, 0xa6b5, 0x0008, 0x2019, 0x0000,
+       0xa684, 0x0008, 0x0040, 0x3e3e, 0x1078, 0x417c, 0x6810, 0x70be,
+       0x7003, 0x0007, 0x2300, 0x0079, 0x3e45, 0x3e48, 0x3e75, 0x3e7d,
+       0x2200, 0x0079, 0x3e4b, 0x3e50, 0x3e4e, 0x3e69, 0x1078, 0x23eb,
+       0x7990, 0xa1ac, 0x0007, 0xa026, 0x2011, 0x0001, 0x1078, 0x42f1,
+       0x0079, 0x3e5a, 0x3e5f, 0x2459, 0x3b96, 0x3e67, 0x3e61, 0x0078,
+       0x472d, 0x70ab, 0x3e65, 0x0078, 0x2459, 0x0078, 0x3e5f, 0x1078,
+       0x23eb, 0xa684, 0x0010, 0x0040, 0x3e73, 0x1078, 0x419f, 0x0040,
+       0x3e73, 0x0078, 0x2459, 0x0078, 0x420c, 0x2200, 0x0079, 0x3e78,
+       0x3e7b, 0x3e7b, 0x3e7b, 0x1078, 0x23eb, 0x2200, 0x0079, 0x3e80,
+       0x3e83, 0x3e85, 0x3e85, 0x1078, 0x23eb, 0x78e4, 0xa084, 0x0008,
+       0x0040, 0x3e9a, 0x70a7, 0x3e8e, 0x0078, 0x4739, 0x2011, 0x0004,
+       0x1078, 0x42eb, 0x0079, 0x3e94, 0x3e9a, 0x2459, 0x3b96, 0x3e9a,
+       0x3ea4, 0x3ea8, 0x70ab, 0x3ea2, 0x2001, 0x0003, 0x1078, 0x4689,
+       0x0078, 0x4733, 0x0078, 0x472d, 0x70ab, 0x3e9a, 0x0078, 0x2459,
+       0x70ab, 0x3eac, 0x0078, 0x2459, 0x0078, 0x3ea2, 0x2300, 0x0079,
+       0x3eb1, 0x3eb6, 0x3eb8, 0x3eb4, 0x1078, 0x23eb, 0x70a4, 0x007a,
+       0x70a4, 0x007a, 0xa282, 0x0002, 0x0050, 0x3ec0, 0x1078, 0x23eb,
+       0xa684, 0x0200, 0x0040, 0x3eca, 0x1078, 0x46f8, 0x1078, 0x42d3,
+       0x1078, 0x46ff, 0x2300, 0x0079, 0x3ecd, 0x3ed0, 0x3ef4, 0x3f5a,
+       0xa286, 0x0001, 0x0040, 0x3ed6, 0x1078, 0x23eb, 0xa684, 0x0200,
+       0x0040, 0x3ede, 0x1078, 0x46f8, 0x1078, 0x46ff, 0x2001, 0x0001,
+       0x1078, 0x4691, 0x78b8, 0xa084, 0xc001, 0x0040, 0x3ef0, 0x7848,
+       0xa085, 0x0008, 0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3eeb,
+       0x7003, 0x0000, 0x0078, 0x3b96, 0x2200, 0x0079, 0x3ef7, 0x3ef9,
+       0x3f2a, 0x70a7, 0x3efd, 0x0078, 0x4739, 0x2011, 0x000d, 0x1078,
+       0x42eb, 0x0079, 0x3f03, 0x3f0a, 0x2459, 0x3b96, 0x3f12, 0x3f1a,
+       0x3f20, 0x3f22, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+       0x0078, 0x4727, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+       0x0078, 0x4727, 0x70ab, 0x3f1e, 0x0078, 0x2459, 0x0078, 0x3f0a,
+       0x1078, 0x23eb, 0x70ab, 0x3f26, 0x0078, 0x2459, 0x1078, 0x473f,
+       0x0078, 0x2459, 0x70a7, 0x3f2e, 0x0078, 0x4739, 0x2011, 0x0012,
+       0x1078, 0x42eb, 0x0079, 0x3f34, 0x3f3a, 0x2459, 0x3b96, 0x3f46,
+       0x3f4e, 0x3f54, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+       0x70b4, 0xa080, 0x00a6, 0x781a, 0x0078, 0x2459, 0xa6b4, 0x00ff,
+       0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x4727, 0x70ab, 0x3f52,
+       0x0078, 0x2459, 0x0078, 0x3f3a, 0x70ab, 0x3f58, 0x0078, 0x2459,
+       0x0078, 0x3f46, 0xa286, 0x0001, 0x0040, 0x3f60, 0x1078, 0x23eb,
+       0x70a7, 0x3f64, 0x0078, 0x4739, 0x2011, 0x0015, 0x1078, 0x42eb,
+       0x0079, 0x3f6a, 0x3f6f, 0x2459, 0x3b96, 0x3f7d, 0x3f89, 0xa6b4,
+       0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x783b, 0x1301, 0x70b4,
+       0xa080, 0x00b4, 0x781a, 0x0078, 0x2459, 0xa6b4, 0x00ff, 0xa6b5,
+       0x0400, 0x6eb6, 0x7e5a, 0x70b4, 0xa080, 0x00a6, 0x781a, 0x0078,
+       0x2459, 0x70ab, 0x3f8d, 0x0078, 0x2459, 0x0078, 0x3f6f, 0xa282,
+       0x0003, 0x0050, 0x3f95, 0x1078, 0x23eb, 0x2300, 0x0079, 0x3f98,
+       0x3f9b, 0x3fd2, 0x402d, 0xa286, 0x0001, 0x0040, 0x3fa1, 0x1078,
+       0x23eb, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3fae,
+       0x1078, 0x3af8, 0x7003, 0x0000, 0x0078, 0x3b96, 0x683b, 0x0000,
+       0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x3fbc, 0x1078, 0x46f8,
+       0x1078, 0x42d3, 0x1078, 0x46ff, 0x2001, 0x0001, 0x1078, 0x4691,
+       0x78b8, 0xa084, 0xc001, 0x0040, 0x3fce, 0x7848, 0xa085, 0x0008,
+       0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3fc9, 0x7003, 0x0000,
+       0x0078, 0x3b96, 0x2200, 0x0079, 0x3fd5, 0x3fd7, 0x4008, 0x70a7,
+       0x3fdb, 0x0078, 0x4739, 0x2011, 0x000d, 0x1078, 0x42eb, 0x0079,
+       0x3fe1, 0x3fe8, 0x2459, 0x3b96, 0x3ff0, 0x3ff8, 0x3ffe, 0x4000,
+       0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727,
+       0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727,
+       0x70ab, 0x3ffc, 0x0078, 0x2459, 0x0078, 0x3fe8, 0x1078, 0x23eb,
+       0x70ab, 0x4004, 0x0078, 0x2459, 0x1078, 0x473f, 0x0078, 0x2459,
+       0x70a7, 0x400c, 0x0078, 0x4739, 0x2011, 0x0005, 0x1078, 0x42eb,
+       0x0079, 0x4012, 0x4017, 0x2459, 0x3b96, 0x401f, 0x4027, 0xa6b4,
+       0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727, 0xa6b4,
+       0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727, 0x70ab,
+       0x402b, 0x0078, 0x2459, 0x0078, 0x4017, 0xa286, 0x0001, 0x0040,
+       0x4033, 0x1078, 0x23eb, 0x70a7, 0x4037, 0x0078, 0x4739, 0x2011,
+       0x0006, 0x1078, 0x42eb, 0x0079, 0x403d, 0x4042, 0x2459, 0x3b96,
+       0x4048, 0x4052, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727,
+       0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0xa6b5, 0x4000, 0x7e5a,
+       0x0078, 0x4727, 0x70ab, 0x4056, 0x0078, 0x2459, 0x0078, 0x4042,
+       0x2300, 0x0079, 0x405b, 0x4060, 0x405e, 0x405e, 0x1078, 0x23eb,
+       0x1078, 0x23eb, 0x2300, 0x71a8, 0xa005, 0x017a, 0x6810, 0x70be,
+       0xa282, 0x0003, 0x0050, 0x406e, 0x1078, 0x23eb, 0x2300, 0x0079,
+       0x4071, 0x4074, 0x4082, 0x40a4, 0xa684, 0x0200, 0x0040, 0x407c,
+       0x1078, 0x46f8, 0x1078, 0x46ff, 0x2001, 0x0001, 0x1078, 0x4691,
+       0x0078, 0x2459, 0xa296, 0x0002, 0x0040, 0x408b, 0x82ff, 0x0040,
+       0x408b, 0x1078, 0x23eb, 0x70a7, 0x408f, 0x0078, 0x4739, 0x2011,
+       0x0018, 0x1078, 0x42eb, 0x0079, 0x4095, 0x409a, 0x2459, 0x3b96,
+       0x409c, 0x409e, 0x0078, 0x4727, 0x0078, 0x4727, 0x70ab, 0x40a2,
+       0x0078, 0x2459, 0x0078, 0x409a, 0x2200, 0x0079, 0x40a7, 0x40a9,
+       0x40c2, 0x70a7, 0x40ad, 0x0078, 0x4739, 0x2011, 0x0017, 0x1078,
+       0x42eb, 0x0079, 0x40b3, 0x40b8, 0x2459, 0x3b96, 0x40ba, 0x40bc,
+       0x0078, 0x4727, 0x0078, 0x4727, 0x70ab, 0x40c0, 0x0078, 0x2459,
+       0x0078, 0x40b8, 0xa484, 0x8000, 0x00c0, 0x410c, 0xa684, 0x0100,
+       0x0040, 0x40d6, 0x1078, 0x46f8, 0x1078, 0x42d3, 0x1078, 0x46ff,
+       0x7848, 0xa085, 0x000c, 0x784a, 0x0078, 0x40da, 0x78d8, 0x78d2,
+       0x78dc, 0x78d6, 0xa6b4, 0xefff, 0x7e5a, 0x70a7, 0x40e1, 0x0078,
+       0x4739, 0x2011, 0x000d, 0x1078, 0x42eb, 0x0079, 0x40e7, 0x40ee,
+       0x2459, 0x3b96, 0x40ee, 0x40fc, 0x4102, 0x4104, 0xa684, 0x0100,
+       0x0040, 0x40fa, 0x1078, 0x46b6, 0x682c, 0x78d2, 0x6830, 0x78d6,
+       0x1078, 0x46f0, 0x0078, 0x4727, 0x70ab, 0x4100, 0x0078, 0x2459,
+       0x0078, 0x40ee, 0x1078, 0x23eb, 0x70ab, 0x4108, 0x0078, 0x2459,
+       0x1078, 0x473f, 0x0078, 0x2459, 0x1078, 0x46ff, 0x70ab, 0x4116,
+       0x2001, 0x0003, 0x1078, 0x4689, 0x0078, 0x4733, 0x1078, 0x46f0,
+       0x682c, 0x78d2, 0x6830, 0x78d6, 0x0078, 0x4727, 0x70b8, 0x6812,
+       0x70be, 0x8000, 0x70ba, 0x681b, 0x0000, 0xa684, 0x0008, 0x0040,
+       0x4141, 0x157e, 0x137e, 0x147e, 0x7890, 0x8004, 0x8004, 0x8004,
+       0x8004, 0xa084, 0x000f, 0x681a, 0x80ac, 0x789b, 0x0000, 0xaf80,
+       0x002b, 0x2098, 0xad80, 0x000b, 0x20a0, 0x53a5, 0x147f, 0x137f,
+       0x157f, 0xa6c4, 0x0f00, 0xa684, 0x0002, 0x00c0, 0x4150, 0x692c,
+       0x810d, 0x810d, 0x810d, 0xa184, 0x0007, 0x2008, 0x0078, 0x415f,
+       0x789b, 0x0010, 0x79ac, 0xa184, 0x0020, 0x0040, 0x415f, 0x017e,
+       0x2009, 0x0005, 0x2001, 0x3d00, 0x1078, 0x46c1, 0x017f, 0xa184,
+       0x001f, 0xa805, 0x6816, 0x1078, 0x3b69, 0x68be, 0xa684, 0x0004,
+       0x0040, 0x4170, 0xa18c, 0xff00, 0x78a8, 0xa084, 0x00ff, 0xa105,
+       0x682a, 0xa6b4, 0x00ff, 0x6000, 0xa084, 0x0008, 0x0040, 0x417a,
+       0xa6b5, 0x4000, 0x6eb6, 0x007c, 0x157e, 0x137e, 0x147e, 0x6918,
+       0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f, 0x007e,
+       0xa100, 0x681a, 0x007f, 0x8000, 0x8004, 0x0040, 0x419b, 0x20a8,
+       0x8104, 0xa080, 0x000b, 0xad00, 0x20a0, 0x789b, 0x0000, 0xaf80,
+       0x002b, 0x2098, 0x53a5, 0x147f, 0x137f, 0x157f, 0x007c, 0x682c,
+       0xa084, 0x0020, 0x00c0, 0x41a7, 0x620c, 0x0078, 0x41a8, 0x6210,
+       0x6b18, 0x2300, 0xa202, 0x0040, 0x41c8, 0x2018, 0xa382, 0x000e,
+       0x0048, 0x41b8, 0x0040, 0x41b8, 0x2019, 0x000e, 0x0078, 0x41bc,
+       0x7858, 0xa084, 0xffef, 0x785a, 0x783b, 0x1b01, 0x7893, 0x0000,
+       0x7ba2, 0x70b4, 0xa080, 0x008e, 0x781a, 0xa085, 0x0001, 0x007c,
+       0x7858, 0xa084, 0xffef, 0x785a, 0x7893, 0x0000, 0xa006, 0x007c,
+       0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x41dd, 0xa196,
+       0x000f, 0x0040, 0x41dd, 0x6807, 0x0117, 0x6914, 0x1078, 0x3b69,
+       0x6100, 0x8104, 0x00c8, 0x41f8, 0x601c, 0xa005, 0x0040, 0x41ec,
+       0x2001, 0x0800, 0x0078, 0x41fa, 0x0d7e, 0x6824, 0x007e, 0x1078,
+       0x4708, 0x007f, 0x6826, 0x2d00, 0x682e, 0x1078, 0x3af8, 0x0d7f,
+       0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820,
+       0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, 0x71b4,
+       0xa188, 0x0091, 0x791a, 0x007c, 0xa6c4, 0x0f00, 0xa684, 0x0002,
+       0x00c0, 0x4220, 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, 0x0007,
+       0x2008, 0xa805, 0x6816, 0x1078, 0x3b69, 0x68be, 0x0078, 0x4223,
+       0x6914, 0x1078, 0x3b69, 0x6100, 0x8104, 0x00c8, 0x4280, 0xa184,
+       0x0300, 0x0040, 0x422f, 0x6807, 0x0117, 0x0078, 0x424d, 0x6004,
+       0xa005, 0x00c0, 0x4256, 0x6807, 0x0117, 0x601c, 0xa005, 0x00c0,
+       0x4243, 0x0d7e, 0x1078, 0x4708, 0x6827, 0x0034, 0x2d00, 0x682e,
+       0x1078, 0x3af8, 0x0d7f, 0xa684, 0x0004, 0x0040, 0x424d, 0x2031,
+       0x0400, 0x2001, 0x2800, 0x0078, 0x4251, 0x2031, 0x0400, 0x2001,
+       0x0800, 0x71b4, 0xa188, 0x0091, 0x0078, 0x42ae, 0x6018, 0xa005,
+       0x00c0, 0x4243, 0x601c, 0xa005, 0x00c0, 0x4243, 0x689f, 0x0000,
+       0x6827, 0x003d, 0xa684, 0x0001, 0x0040, 0x42bc, 0xd694, 0x00c0,
+       0x4279, 0x6100, 0xd1d4, 0x0040, 0x4279, 0x692c, 0x81ff, 0x0040,
+       0x42bc, 0xa186, 0x0003, 0x0040, 0x42bc, 0xa186, 0x0012, 0x0040,
+       0x42bc, 0xa6b5, 0x0800, 0x71b4, 0xa188, 0x00af, 0x0078, 0x42b7,
+       0x6807, 0x0117, 0x2031, 0x0400, 0x692c, 0xa18c, 0x00ff, 0xa186,
+       0x0012, 0x00c0, 0x4291, 0x2001, 0x42c9, 0x2009, 0x0001, 0x0078,
+       0x42a2, 0xa186, 0x0003, 0x00c0, 0x429b, 0x2001, 0x42ca, 0x2009,
+       0x0012, 0x0078, 0x42a2, 0x2001, 0x0200, 0x71b4, 0xa188, 0x0091,
+       0x0078, 0x42ae, 0x1078, 0x46db, 0x78a3, 0x0000, 0x681c, 0xa085,
+       0x0040, 0x681e, 0x71b4, 0xa188, 0x00df, 0xa006, 0x6826, 0x8007,
+       0x789b, 0x000e, 0x78aa, 0x6820, 0xa085, 0x8000, 0x6822, 0x6eb6,
+       0x7e5a, 0x791a, 0x0078, 0x2459, 0x6eb6, 0x1078, 0x3af8, 0x6810,
+       0x70be, 0x7003, 0x0007, 0x70a3, 0x0000, 0x704b, 0x0000, 0x0078,
+       0x2459, 0x0023, 0x0070, 0x0005, 0x0000, 0x0a00, 0x0000, 0x0000,
+       0x0025, 0x0000, 0x0000, 0x683b, 0x0000, 0x6837, 0x0000, 0xa684,
+       0x0200, 0x0040, 0x42ea, 0x78b8, 0xa08c, 0x001f, 0xa084, 0x8000,
+       0x0040, 0x42e3, 0x8108, 0x78d8, 0xa100, 0x6836, 0x78dc, 0xa081,
+       0x0000, 0x683a, 0x007c, 0x7990, 0x810f, 0xa5ac, 0x0007, 0x2021,
+       0x0000, 0xa480, 0x0010, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa184,
+       0x0080, 0x00c0, 0x4319, 0xa182, 0x0020, 0x00c8, 0x4337, 0xa182,
+       0x0012, 0x00c8, 0x467b, 0x2100, 0x1079, 0x4307, 0x007c, 0x467b,
+       0x44e8, 0x467b, 0x467b, 0x4344, 0x4347, 0x4381, 0x43b7, 0x43eb,
+       0x43ee, 0x467b, 0x467b, 0x43a2, 0x4412, 0x444c, 0x467b, 0x467b,
+       0x4473, 0xa184, 0x0020, 0x00c0, 0x44a7, 0xa18c, 0x001f, 0x6814,
+       0xa084, 0x001f, 0xa106, 0x0040, 0x4334, 0x70b4, 0xa080, 0x00d2,
+       0x781a, 0x2001, 0x0014, 0x1078, 0x4691, 0x1078, 0x46ff, 0x7003,
+       0x0000, 0x2001, 0x0002, 0x007c, 0x2001, 0x0000, 0x007c, 0xa182,
+       0x0024, 0x00c8, 0x467b, 0xa184, 0x0003, 0x1079, 0x4307, 0x007c,
+       0x467b, 0x467b, 0x467b, 0x467b, 0x1078, 0x467b, 0x007c, 0x2200,
+       0x0079, 0x434a, 0x4476, 0x4476, 0x436e, 0x436e, 0x436e, 0x436e,
+       0x436e, 0x436e, 0x436e, 0x436e, 0x436c, 0x436e, 0x4363, 0x436e,
+       0x436e, 0x436e, 0x436e, 0x436e, 0x4376, 0x4379, 0x4476, 0x4379,
+       0x436e, 0x436e, 0x436e, 0x0c7e, 0x077e, 0x6f14, 0x1078, 0x36e2,
+       0x077f, 0x0c7f, 0x0078, 0x436e, 0x1078, 0x458b, 0x6827, 0x02b3,
+       0x2009, 0x000b, 0x2001, 0x4800, 0x0078, 0x44aa, 0x1078, 0x4670,
+       0x007c, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4800, 0x0078,
+       0x4492, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
+       0x438b, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x4708, 0x6827,
+       0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ac8, 0x1078,
+       0x44d0, 0x2b68, 0x1078, 0x3af8, 0x0d7f, 0x1078, 0x3af8, 0x2001,
+       0x0002, 0x007c, 0x1078, 0x44d0, 0x2001, 0x0017, 0x1078, 0x4691,
+       0x70a3, 0x0000, 0x2009, 0x5138, 0x200b, 0x0006, 0x70af, 0x0017,
+       0x2009, 0x0200, 0x1078, 0x3a06, 0x2001, 0x0001, 0x007c, 0x2200,
+       0x0079, 0x43ba, 0x4476, 0x44a7, 0x44a7, 0x44a7, 0x43db, 0x44b7,
+       0x43e3, 0x44b7, 0x44b7, 0x44ba, 0x44ba, 0x44bf, 0x44bf, 0x43d3,
+       0x43d3, 0x44a7, 0x44a7, 0x44b7, 0x44a7, 0x43e3, 0x4476, 0x43e3,
+       0x43e3, 0x43e3, 0x43e3, 0x6827, 0x0084, 0x2009, 0x000b, 0x2001,
+       0x4300, 0x0078, 0x44c9, 0x6827, 0x000d, 0x2009, 0x000b, 0x2001,
+       0x4300, 0x0078, 0x44aa, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001,
+       0x4300, 0x0078, 0x4492, 0x2001, 0x0000, 0x007c, 0x2200, 0x0079,
+       0x43f1, 0x4476, 0x440a, 0x440a, 0x440a, 0x440a, 0x44b7, 0x44b7,
+       0x44b7, 0x44b7, 0x44b7, 0x44b7, 0x44b7, 0x44b7, 0x440a, 0x440a,
+       0x440a, 0x440a, 0x44b7, 0x440a, 0x440a, 0x44b7, 0x44b7, 0x44b7,
+       0x44b7, 0x4476, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300,
+       0x0078, 0x4492, 0xa684, 0x0004, 0x00c0, 0x4426, 0x6804, 0xa084,
+       0x00ff, 0xa086, 0x0006, 0x00c0, 0x467b, 0x1078, 0x44d0, 0x6807,
+       0x0117, 0x1078, 0x3af8, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084,
+       0x0004, 0x0040, 0x467b, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086,
+       0x0006, 0x00c0, 0x4435, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078,
+       0x4708, 0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078,
+       0x3ad7, 0x1078, 0x44d0, 0x2b68, 0x1078, 0x3af8, 0x0d7f, 0x1078,
+       0x3af8, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040,
+       0x467b, 0x2d58, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0006, 0x00c0,
+       0x445b, 0x6807, 0x0117, 0x6827, 0x0002, 0x2d58, 0x1078, 0x4708,
+       0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ae7,
+       0x1078, 0x44d0, 0x2b68, 0x1078, 0x3af8, 0x0d7f, 0x1078, 0x3af8,
+       0x2001, 0x0002, 0x007c, 0x1078, 0x467b, 0x007c, 0x70b4, 0xa080,
+       0x00d2, 0x781a, 0x2001, 0x0001, 0x1078, 0x4691, 0x1078, 0x46ff,
+       0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078, 0x46c1, 0x1078,
+       0x46f8, 0x1078, 0x42d3, 0x1078, 0x41d0, 0x1078, 0x46ff, 0x2001,
+       0x0001, 0x007c, 0x1078, 0x46c1, 0x1078, 0x46f8, 0x1078, 0x42d3,
+       0x70b4, 0xa080, 0x00d2, 0x781a, 0x2001, 0x0013, 0x1078, 0x4691,
+       0x1078, 0x46ff, 0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078,
+       0x467b, 0x007c, 0x1078, 0x46c1, 0x1078, 0x46f8, 0x1078, 0x42d3,
+       0x1078, 0x41d0, 0x1078, 0x46ff, 0x2001, 0x0001, 0x007c, 0x2001,
+       0x0003, 0x007c, 0x1078, 0x458b, 0x2001, 0x0000, 0x007c, 0x0c7e,
+       0x077e, 0x6f14, 0x1078, 0x36e2, 0x077f, 0x0c7f, 0x2001, 0x0000,
+       0x007c, 0x1078, 0x46c1, 0x1078, 0x467b, 0x2001, 0x0006, 0x007c,
+       0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x44db, 0xa186,
+       0x000f, 0x00c0, 0x44df, 0x1078, 0x46f8, 0x1078, 0x42d3, 0x70b4,
+       0xa080, 0x00d2, 0x781a, 0x1078, 0x46ff, 0x7003, 0x0000, 0x007c,
+       0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004,
+       0x00c8, 0x467b, 0x1079, 0x44f5, 0x007c, 0x467b, 0x44f9, 0x467b,
+       0x4592, 0xa282, 0x0003, 0x0040, 0x4500, 0x1078, 0x467b, 0x007c,
+       0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0x69b8, 0xa184,
+       0x0100, 0x0040, 0x453f, 0xa18c, 0xfeff, 0x69ba, 0x78a0, 0xa005,
+       0x00c0, 0x453f, 0xa4a4, 0x00ff, 0x0040, 0x4533, 0xa482, 0x000c,
+       0x0040, 0x451c, 0x00c8, 0x4526, 0x852b, 0x852b, 0x1078, 0x3760,
+       0x0040, 0x4526, 0x1078, 0x355b, 0x0078, 0x4535, 0x1078, 0x465d,
+       0x1078, 0x3586, 0x69b8, 0xa18d, 0x0100, 0x69ba, 0xa6b5, 0x1000,
+       0x7e5a, 0x0078, 0x4538, 0x1078, 0x3586, 0xa6b4, 0xefff, 0x7e5a,
+       0x70b4, 0xa080, 0x0091, 0x781a, 0x2001, 0x0001, 0x007c, 0x0c7e,
+       0x1078, 0x457f, 0x6200, 0xd2e4, 0x0040, 0x4570, 0x6208, 0x8217,
+       0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x4552, 0x0040, 0x4552,
+       0x2011, 0x000c, 0x2400, 0xa202, 0x00c8, 0x4557, 0x2220, 0x6208,
+       0xa294, 0x00ff, 0x701c, 0xa202, 0x00c8, 0x455f, 0x721c, 0x2200,
+       0xa502, 0x00c8, 0x4564, 0x2228, 0x1078, 0x4661, 0x852b, 0x852b,
+       0x1078, 0x3760, 0x0040, 0x4570, 0x1078, 0x3562, 0x0078, 0x4574,
+       0x1078, 0x465d, 0x1078, 0x358d, 0xa6b5, 0x1000, 0x7e5a, 0x70b4,
+       0xa080, 0x00be, 0x781a, 0x2001, 0x0004, 0x0c7f, 0x007c, 0x007e,
+       0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0,
+       0x5380, 0x007f, 0x007c, 0x0c7e, 0x1078, 0x457f, 0x1078, 0x358d,
+       0x0c7f, 0x007c, 0xa282, 0x0002, 0x00c0, 0x467b, 0x7aa8, 0xa294,
+       0x00ff, 0x69b8, 0xa184, 0x0200, 0x0040, 0x45c9, 0xa18c, 0xfdff,
+       0x69ba, 0x78a0, 0xa005, 0x00c0, 0x45c9, 0xa282, 0x0002, 0x00c8,
+       0x369d, 0x1078, 0x4627, 0x1078, 0x362b, 0x1078, 0x3586, 0xa684,
+       0x0100, 0x0040, 0x45bf, 0x682c, 0xa084, 0x0001, 0x0040, 0x45bf,
+       0xc6fc, 0x7888, 0xa084, 0x0040, 0x0040, 0x45bf, 0xc6fd, 0xa6b5,
+       0x1000, 0x7e5a, 0x70b4, 0xa080, 0x0091, 0x781a, 0x2001, 0x0001,
+       0x007c, 0x0c7e, 0x1078, 0x457f, 0xa284, 0xfffe, 0x0040, 0x45d4,
+       0x2011, 0x0001, 0x0078, 0x45d8, 0xa284, 0x0001, 0x0040, 0x45de,
+       0x6100, 0xd1ec, 0x00c0, 0x45de, 0x2011, 0x0000, 0x1078, 0x4619,
+       0x1078, 0x3632, 0x1078, 0x358d, 0xa684, 0x0100, 0x0040, 0x45f4,
+       0x682c, 0xa084, 0x0001, 0x0040, 0x45f4, 0xc6fc, 0x7888, 0xa084,
+       0x0040, 0x0040, 0x45f4, 0xc6fd, 0xa6b5, 0x1000, 0x7e5a, 0x70b4,
+       0xa080, 0x00be, 0x781a, 0x2001, 0x0004, 0x0c7f, 0x007c, 0x0c7e,
+       0x2960, 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x460a,
+       0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003,
+       0x7aaa, 0xa8c0, 0x0004, 0x68b8, 0xa085, 0x0200, 0x68ba, 0x0c7f,
+       0x007c, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab,
+       0x0003, 0x7aaa, 0x789b, 0x0081, 0x78ab, 0x0004, 0x007c, 0x0c7e,
+       0x7054, 0x2060, 0x6000, 0xa084, 0x1000, 0x00c0, 0x4635, 0x2029,
+       0x0032, 0x2021, 0x0000, 0x0078, 0x4655, 0x6508, 0xa5ac, 0x00ff,
+       0x7018, 0xa086, 0x0028, 0x00c0, 0x4645, 0xa582, 0x0019, 0x00c8,
+       0x464b, 0x2029, 0x0019, 0x0078, 0x464b, 0xa582, 0x000c, 0x00c8,
+       0x464b, 0x2029, 0x000c, 0x6408, 0x8427, 0xa4a4, 0x00ff, 0xa482,
+       0x000c, 0x0048, 0x4655, 0x2021, 0x000c, 0x1078, 0x4661, 0x68b8,
+       0xa085, 0x0100, 0x68ba, 0x0c7f, 0x007c, 0x2021, 0x0000, 0x2029,
+       0x0032, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+       0x0001, 0x7daa, 0x7caa, 0x789b, 0x0081, 0x78ab, 0x0005, 0x007c,
+       0x2001, 0x0003, 0x1078, 0x4689, 0x70b4, 0xa080, 0x00be, 0x781a,
+       0x2001, 0x0005, 0x007c, 0x2001, 0x0007, 0x1078, 0x4689, 0xa6b5,
+       0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00be, 0x781a, 0x2001, 0x0004,
+       0x007c, 0x789b, 0x0018, 0x78aa, 0x789b, 0x0081, 0x78ab, 0x0001,
+       0x007c, 0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x469f,
+       0xa196, 0x000f, 0x0040, 0x469f, 0x1078, 0x195a, 0x007c, 0x6924,
+       0xa194, 0x003f, 0x00c0, 0x46a8, 0xa18c, 0xffc0, 0xa105, 0x6826,
+       0x1078, 0x3af8, 0x691c, 0xa184, 0x0100, 0x0040, 0x46b5, 0x6914,
+       0x1078, 0x3b69, 0x6204, 0x8210, 0x6206, 0x007c, 0x692c, 0x6834,
+       0x682e, 0xa112, 0x6930, 0x6838, 0x6832, 0xa11b, 0xa200, 0xa301,
+       0x007c, 0x0c7e, 0xade0, 0x0018, 0x6003, 0x0070, 0x6106, 0x600b,
+       0x0000, 0x600f, 0x0a00, 0x6013, 0x0000, 0x6017, 0x0000, 0x8007,
+       0x601a, 0x601f, 0x0000, 0x6023, 0x0000, 0x0c7f, 0x6824, 0xa085,
+       0x0080, 0x6826, 0x007c, 0x157e, 0x137e, 0x147e, 0x2098, 0xaf80,
+       0x002d, 0x20a0, 0x81ac, 0x0040, 0x46e6, 0x53a6, 0xa184, 0x0001,
+       0x0040, 0x46ec, 0x3304, 0x78be, 0x147f, 0x137f, 0x157f, 0x007c,
+       0x70b0, 0xa005, 0x10c0, 0x23eb, 0x70b3, 0x8000, 0x0078, 0x4a3a,
+       0x71b0, 0x81ff, 0x0040, 0x46fe, 0x1078, 0x4b30, 0x007c, 0x71b0,
+       0x81ff, 0x0040, 0x4707, 0x70b3, 0x0000, 0x1078, 0x4776, 0x007c,
+       0x0c7e, 0x0d7e, 0x1078, 0x1937, 0x0c7f, 0x157e, 0x137e, 0x147e,
+       0x2da0, 0x2c98, 0x20a9, 0x0031, 0x53a3, 0x147f, 0x137f, 0x157f,
+       0x6807, 0x010d, 0x680b, 0x0000, 0x7004, 0x8007, 0x681a, 0x6823,
+       0x0000, 0x681f, 0x0000, 0x689f, 0x0000, 0x0c7f, 0x007c, 0x70b4,
+       0xa080, 0x0091, 0x781a, 0x0078, 0x2459, 0x70b4, 0xa080, 0x0081,
+       0x781a, 0x0078, 0x2459, 0x70b4, 0xa080, 0x00be, 0x781a, 0x0078,
+       0x2459, 0x70b4, 0xa080, 0x00c8, 0x781a, 0x0078, 0x2459, 0x6904,
+       0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x474c, 0xa196, 0x000f,
+       0x0040, 0x474c, 0x6807, 0x0117, 0x2001, 0x0200, 0x6826, 0x8007,
+       0x789b, 0x000e, 0x78aa, 0x6820, 0xa085, 0x8000, 0x6822, 0x2031,
+       0x0400, 0x6eb6, 0x7e5a, 0x71b4, 0xa188, 0x0091, 0x791a, 0x007c,
+       0x1078, 0x46ff, 0x7848, 0xa085, 0x000c, 0x784a, 0x70b4, 0xa080,
+       0x00d2, 0x781a, 0x2009, 0x000b, 0x2001, 0x4400, 0x1078, 0x46c1,
+       0x2001, 0x0013, 0x1078, 0x4691, 0x0078, 0x3b96, 0x127e, 0x2091,
+       0x2200, 0x2049, 0x4776, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215,
+       0x7008, 0xa084, 0xfff7, 0xa205, 0x0040, 0x4788, 0x0078, 0x478d,
+       0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x7000, 0xa084, 0x0001,
+       0x00c0, 0x47bb, 0x7108, 0x8103, 0x00c8, 0x479a, 0x1078, 0x48bd,
+       0x0078, 0x4792, 0x700c, 0xa08c, 0x00ff, 0x0040, 0x47bb, 0x7004,
+       0x8004, 0x00c8, 0x47b2, 0x7014, 0xa005, 0x00c0, 0x47ae, 0x7010,
+       0xa005, 0x0040, 0x47b2, 0xa102, 0x00c8, 0x4792, 0x7007, 0x0010,
+       0x0078, 0x47bb, 0x8aff, 0x0040, 0x47bb, 0x1078, 0x4b07, 0x00c0,
+       0x47b5, 0x0040, 0x4792, 0x1078, 0x4846, 0x7003, 0x0000, 0x127f,
+       0x2000, 0x007c, 0x017e, 0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007,
+       0x0040, 0x47ce, 0xa18e, 0x000f, 0x00c0, 0x47d1, 0x6040, 0x0078,
+       0x47d2, 0x6428, 0x017f, 0x84ff, 0x0040, 0x47fc, 0x2c70, 0x7004,
+       0xa0bc, 0x000f, 0xa7b8, 0x480c, 0x273c, 0x87fb, 0x00c0, 0x47ea,
+       0x0048, 0x47e4, 0x1078, 0x23eb, 0x609c, 0xa075, 0x0040, 0x47fc,
+       0x0078, 0x47d7, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529,
+       0x8421, 0x0040, 0x47fc, 0x8738, 0x2704, 0xa005, 0x00c0, 0x47eb,
+       0x709c, 0xa075, 0x00c0, 0x47d7, 0x007c, 0x0000, 0x0005, 0x0009,
+       0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009,
+       0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x4801, 0x47fe, 0x0000,
+       0x0000, 0x8000, 0x0000, 0x4801, 0x0000, 0x4809, 0x4806, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x4809, 0x0000, 0x4804, 0x4804, 0x0000,
+       0x0000, 0x8000, 0x0000, 0x4804, 0x0000, 0x480a, 0x480a, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x480a, 0x127e, 0x2091, 0x2200, 0x2079,
+       0x5100, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+       0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+       0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x2049, 0x4846,
+       0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x4899, 0x7007, 0x0012,
+       0x7108, 0x7008, 0xa106, 0x00c0, 0x4850, 0xa184, 0x01e0, 0x0040,
+       0x485b, 0x1078, 0x23eb, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+       0x00c8, 0x4866, 0xa184, 0x4000, 0x00c0, 0x4850, 0xa19c, 0x300c,
+       0xa386, 0x2004, 0x0040, 0x4874, 0xa386, 0x0008, 0x0040, 0x487f,
+       0xa386, 0x200c, 0x00c0, 0x4850, 0x7200, 0x8204, 0x0048, 0x487f,
+       0x730c, 0xa384, 0x00ff, 0x0040, 0x487f, 0x1078, 0x23eb, 0x7007,
+       0x0012, 0x7000, 0xa084, 0x0001, 0x00c0, 0x4899, 0x7008, 0xa084,
+       0x01e0, 0x00c0, 0x4899, 0x7310, 0x7014, 0xa305, 0x0040, 0x4899,
+       0x710c, 0xa184, 0x0300, 0x00c0, 0x4899, 0xa184, 0x00ff, 0x00c0,
+       0x4846, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008,
+       0x00c0, 0x489d, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, 0x48a2,
+       0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e, 0x127e,
+       0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x48bd, 0x157f, 0x127f,
+       0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x7500, 0x730c,
+       0xa384, 0x0300, 0x00c0, 0x48e4, 0xa184, 0x01e0, 0x00c0, 0x4908,
+       0x7108, 0xa184, 0x01e0, 0x00c0, 0x4908, 0x2001, 0x04fd, 0x2004,
+       0xa082, 0x0005, 0x00c8, 0x48d8, 0xa184, 0x4000, 0x00c0, 0x48c8,
+       0xa184, 0x0007, 0x0079, 0x48dc, 0x48e6, 0x48f8, 0x48e4, 0x48f8,
+       0x48e4, 0x4944, 0x48e4, 0x4942, 0x1078, 0x23eb, 0x7004, 0xa084,
+       0x0010, 0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0, 0x48f3, 0x2049,
+       0x0000, 0x0078, 0x48f7, 0x1078, 0x4b07, 0x00c0, 0x48f3, 0x007c,
+       0x7004, 0xa084, 0x0010, 0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0,
+       0x4903, 0x0078, 0x4907, 0x1078, 0x4b07, 0x00c0, 0x4903, 0x007c,
+       0x7007, 0x0012, 0x7108, 0x00e0, 0x490b, 0x2091, 0x6000, 0x00e0,
+       0x490f, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004,
+       0xa084, 0x0008, 0x00c0, 0x4917, 0x7007, 0x0012, 0x7108, 0x8103,
+       0x0048, 0x491c, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x4930,
+       0x7004, 0xa005, 0x00c0, 0x4930, 0x700c, 0xa005, 0x0040, 0x4932,
+       0x0078, 0x4913, 0x2049, 0x0000, 0x1078, 0x3809, 0x6818, 0xa084,
+       0x8000, 0x0040, 0x493d, 0x681b, 0x0002, 0x007c, 0x1078, 0x23eb,
+       0x1078, 0x23eb, 0x1078, 0x49a0, 0x7210, 0x7114, 0x700c, 0xa09c,
+       0x00ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x49a0,
+       0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100,
+       0xa31b, 0x2400, 0xa305, 0x0040, 0x4967, 0x00c8, 0x4967, 0x8412,
+       0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x494e, 0x2b60,
+       0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4973, 0xa7ba,
+       0x4806, 0x0078, 0x4975, 0xa7ba, 0x47fe, 0x007f, 0xa73d, 0x2c00,
+       0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x7007, 0x0012, 0x1078, 0x4846,
+       0x007c, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4994, 0x609c, 0xa005,
+       0x0040, 0x499d, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x480c,
+       0x203c, 0x87fb, 0x1040, 0x23eb, 0x8a51, 0x0040, 0x499c, 0x7008,
+       0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, 0x0000, 0x007c,
+       0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x49b4, 0x6000, 0xa064,
+       0x00c0, 0x49ab, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x481c,
+       0x203c, 0x87fb, 0x1040, 0x23eb, 0x007c, 0x127e, 0x0d7e, 0x2091,
+       0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057,
+       0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084, 0x0008,
+       0x007f, 0x0040, 0x49cf, 0xa0b8, 0x4806, 0x0078, 0x49d1, 0xa0b8,
+       0x47fe, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186,
+       0x0007, 0x0040, 0x49df, 0xa18e, 0x000f, 0x00c0, 0x49e8, 0x681c,
+       0xa084, 0x0040, 0x0040, 0x49ef, 0xa6b5, 0x0001, 0x0078, 0x49ef,
+       0x681c, 0xa084, 0x0040, 0x0040, 0x49ef, 0xa6b5, 0x0001, 0x7007,
+       0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x49f1, 0x2400, 0xa305,
+       0x00c0, 0x49fc, 0x0078, 0x4a22, 0x2c58, 0x2704, 0x6104, 0xac60,
+       0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008,
+       0x0040, 0x4a12, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081,
+       0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300,
+       0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x4981,
+       0x0078, 0x4a24, 0x1078, 0x4b07, 0x00c0, 0x4a22, 0x127f, 0x2000,
+       0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004,
+       0x7004, 0xa084, 0x0004, 0x00c0, 0x4a30, 0x7003, 0x0008, 0x127f,
+       0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049,
+       0x4a3a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4a43,
+       0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007,
+       0x0040, 0x4a56, 0xa18e, 0x000f, 0x00c0, 0x4a61, 0x681c, 0xa084,
+       0x0040, 0x0040, 0x4a5d, 0xa6b5, 0x0001, 0x6840, 0x2050, 0x0078,
+       0x4a6a, 0x681c, 0xa084, 0x0020, 0x00c0, 0x4a68, 0xa6b5, 0x0001,
+       0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x480c,
+       0x273c, 0x87fb, 0x00c0, 0x4a7e, 0x0048, 0x4a78, 0x1078, 0x23eb,
+       0x689c, 0xa065, 0x0040, 0x4a82, 0x0078, 0x4a6b, 0x1078, 0x4b07,
+       0x00c0, 0x4a7e, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e,
+       0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5,
+       0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4a9c,
+       0xa18e, 0x000f, 0x00c0, 0x4aa5, 0x681c, 0xa084, 0x0040, 0x0040,
+       0x4aac, 0xa6b5, 0x0001, 0x0078, 0x4aac, 0x681c, 0xa084, 0x0040,
+       0x0040, 0x4aac, 0xa6b5, 0x0001, 0x2049, 0x4a85, 0x017e, 0x6904,
+       0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4aba, 0xa18e, 0x000f,
+       0x00c0, 0x4abd, 0x6840, 0x0078, 0x4abe, 0x6828, 0x017f, 0xa055,
+       0x0040, 0x4b04, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8,
+       0x480c, 0x273c, 0x87fb, 0x00c0, 0x4ad8, 0x0048, 0x4ad1, 0x1078,
+       0x23eb, 0x709c, 0xa075, 0x2060, 0x0040, 0x4b04, 0x0078, 0x4ac4,
+       0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x4af1,
+       0x8a51, 0x00c0, 0x4ae5, 0x1078, 0x23eb, 0x8738, 0x2704, 0xa005,
+       0x00c0, 0x4ad9, 0x709c, 0xa075, 0x2060, 0x0040, 0x4b04, 0x0078,
+       0x4ac4, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400,
+       0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, 0x4b00, 0x1078, 0x23eb,
+       0x2071, 0x0020, 0x0078, 0x49ef, 0x127f, 0x2000, 0x007c, 0x7008,
+       0xa084, 0x0003, 0xa086, 0x0003, 0x0040, 0x4b2f, 0x2704, 0xac08,
+       0x2104, 0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, 0x7012,
+       0x8108, 0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x4b26,
+       0x8108, 0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, 0x7004,
+       0xa084, 0x0010, 0xa085, 0x0001, 0x7006, 0x1078, 0x4981, 0x007c,
+       0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x4b30, 0x0d7f,
+       0x087f, 0x7108, 0xa184, 0x0003, 0x00c0, 0x4b5a, 0x017e, 0x6904,
+       0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4b4a, 0xa18e, 0x000f,
+       0x00c0, 0x4b4d, 0x6840, 0x0078, 0x4b4e, 0x6828, 0x017f, 0xa005,
+       0x0040, 0x4b68, 0x0078, 0x478d, 0x0020, 0x4b5a, 0x1078, 0x4944,
+       0x0078, 0x4b68, 0x00a0, 0x4b61, 0x7108, 0x1078, 0x48bd, 0x0078,
+       0x4b39, 0x7007, 0x0010, 0x00a0, 0x4b63, 0x7108, 0x1078, 0x48bd,
+       0x7008, 0xa086, 0x0008, 0x00c0, 0x4b39, 0x7000, 0xa005, 0x00c0,
+       0x4b39, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c,
+       0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, 0x2091, 0x2200,
+       0x0d7f, 0x2049, 0x4b78, 0xad80, 0x0011, 0x20a0, 0x2099, 0x0031,
+       0x700c, 0xa084, 0x00ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002,
+       0x7003, 0x0001, 0x0040, 0x4b97, 0x8000, 0x80ac, 0x53a5, 0x7007,
+       0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4b99, 0x0c7f, 0x2049,
+       0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, 0x2000,
+       0x007c, 0x2091, 0x6000, 0x2091, 0x8000, 0x78cc, 0xa005, 0x0040,
+       0x4bc0, 0x7994, 0x70d0, 0xa106, 0x00c0, 0x4bc0, 0x7804, 0xa005,
+       0x0040, 0x4bc0, 0x7807, 0x0000, 0x0068, 0x4bc0, 0x2091, 0x4080,
+       0x7820, 0x8001, 0x7822, 0x00c0, 0x4c1b, 0x7824, 0x7822, 0x2069,
+       0x5140, 0x6800, 0xa084, 0x0007, 0x0040, 0x4bde, 0xa086, 0x0002,
+       0x0040, 0x4bde, 0x6834, 0xa00d, 0x0040, 0x4bde, 0x2104, 0xa005,
+       0x0040, 0x4bde, 0x8001, 0x200a, 0x0040, 0x4cc3, 0x7848, 0xa005,
+       0x0040, 0x4bec, 0x8001, 0x784a, 0x00c0, 0x4bec, 0x2009, 0x0102,
+       0x6844, 0x200a, 0x1078, 0x21d2, 0x6890, 0xa005, 0x0040, 0x4bf8,
+       0x8001, 0x6892, 0x00c0, 0x4bf8, 0x686f, 0x0000, 0x6873, 0x0001,
+       0x2061, 0x5400, 0x20a9, 0x0100, 0x2009, 0x0002, 0x6034, 0xa005,
+       0x0040, 0x4c0e, 0x8001, 0x6036, 0x00c0, 0x4c0e, 0x6010, 0xa005,
+       0x0040, 0x4c0e, 0x017e, 0x1078, 0x21d2, 0x017f, 0xace0, 0x0010,
+       0x0070, 0x4c14, 0x0078, 0x4bfe, 0x8109, 0x0040, 0x4c1b, 0x20a9,
+       0x0100, 0x0078, 0x4bfe, 0x1078, 0x4c28, 0x1078, 0x4c4d, 0x2009,
+       0x5151, 0x2104, 0x2009, 0x0102, 0x200a, 0x2091, 0x8001, 0x007c,
+       0x7834, 0x8001, 0x7836, 0x00c0, 0x4c4c, 0x7838, 0x7836, 0x2091,
+       0x8000, 0x7844, 0xa005, 0x00c0, 0x4c37, 0x2001, 0x0101, 0x8001,
+       0x7846, 0xa080, 0x7400, 0x2040, 0x2004, 0xa065, 0x0040, 0x4c4c,
+       0x6024, 0xa005, 0x0040, 0x4c48, 0x8001, 0x6026, 0x0040, 0x4c7c,
+       0x6000, 0x2c40, 0x0078, 0x4c3d, 0x007c, 0x7828, 0x8001, 0x782a,
+       0x00c0, 0x4c7b, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x4c5a,
+       0x2001, 0x0200, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003,
+       0xa090, 0x5400, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040,
+       0x4c7b, 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x4c73, 0x8001,
+       0x2012, 0x00c0, 0x4c7b, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080,
+       0x201a, 0x1078, 0x21d2, 0x007c, 0x2069, 0x5140, 0x6800, 0xa005,
+       0x0040, 0x4c86, 0x6848, 0xac06, 0x0040, 0x4cc3, 0x601b, 0x0006,
+       0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085,
+       0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6f82, 0x1078, 0x1973,
+       0x6818, 0xa005, 0x0040, 0x4c9e, 0x8001, 0x681a, 0x6808, 0xa084,
+       0xffef, 0x680a, 0x6810, 0x8001, 0x00d0, 0x4ca8, 0x1078, 0x23eb,
+       0x6812, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x1c70,
+       0x2069, 0x5140, 0x7944, 0xa184, 0x0100, 0x2001, 0x0006, 0x686e,
+       0x00c0, 0x4cbe, 0x6986, 0x2001, 0x0004, 0x686e, 0x1078, 0x21cd,
+       0x2091, 0x8001, 0x007c, 0x2069, 0x0100, 0x2009, 0x5140, 0x2104,
+       0xa084, 0x0007, 0x0040, 0x4d1f, 0xa086, 0x0007, 0x00c0, 0x4cd9,
+       0x0d7e, 0x2009, 0x5152, 0x216c, 0x1078, 0x3a4e, 0x0d7f, 0x0078,
+       0x4d1f, 0x2009, 0x5152, 0x2164, 0x1078, 0x2396, 0x601b, 0x0006,
+       0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085,
+       0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, 0xa084,
+       0x0040, 0x0040, 0x4d13, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848,
+       0xa084, 0x0004, 0x0040, 0x4d00, 0x0070, 0x4d00, 0x0078, 0x4cf7,
+       0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040,
+       0x4d0d, 0x0070, 0x4d0d, 0x0078, 0x4d04, 0x20a9, 0x00fa, 0x0070,
+       0x4d13, 0x0078, 0x4d0f, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b,
+       0x0048, 0x2009, 0x515b, 0x200b, 0x0007, 0x784c, 0x784a, 0x2091,
+       0x8001, 0x007c, 0x2079, 0x5100, 0x1078, 0x4d4d, 0x1078, 0x4d31,
+       0x1078, 0x4d3f, 0x7833, 0x0000, 0x7847, 0x0000, 0x784b, 0x0000,
+       0x007c, 0x2019, 0x0003, 0x2011, 0x5146, 0x2204, 0xa086, 0x003c,
+       0x0040, 0x4d3c, 0x2019, 0x0002, 0x7b2a, 0x7b2e, 0x007c, 0x2019,
+       0x0039, 0x2011, 0x5146, 0x2204, 0xa086, 0x003c, 0x0040, 0x4d4a,
+       0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x3971, 0x2011,
+       0x5146, 0x2204, 0xa086, 0x003c, 0x0040, 0x4d58, 0x2019, 0x2626,
+       0x7b22, 0x7b26, 0x783f, 0x0000, 0x7843, 0x000a, 0x007c, 0x0020,
+       0x002b, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0014, 0x0014, 0x9849, 0x0014, 0x0014, 0x0014,
+       0x0014, 0x0014, 0x0014, 0x0014, 0x0080, 0x000f, 0x0000, 0x0201,
+       0x0604, 0x0c08, 0x2120, 0x4022, 0xf880, 0x0018, 0x300b, 0xa201,
+       0x0014, 0xa200, 0x0014, 0xa200, 0x0214, 0x0000, 0x006c, 0x0002,
+       0x0014, 0x98d0, 0x009e, 0x0096, 0xa202, 0x8838, 0x3806, 0x8839,
+       0x20c3, 0x0864, 0x9884, 0x28c1, 0x9cb1, 0xa203, 0x300c, 0x2846,
+       0x8161, 0x846a, 0x8300, 0x1856, 0x883a, 0x9865, 0x28f2, 0x9c90,
+       0x9858, 0x300c, 0x28e1, 0x9c90, 0x2802, 0xa206, 0x64c3, 0x282d,
+       0xa207, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7824, 0x68c1,
+       0x7864, 0x883e, 0x9878, 0x8576, 0x8677, 0x206b, 0x28c1, 0x9cb1,
+       0x2044, 0x2103, 0x20a2, 0x2081, 0x9865, 0xa209, 0x2901, 0x988c,
+       0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xc601,
+       0xa20a, 0x856e, 0x0704, 0x9c90, 0x0014, 0xa204, 0xa300, 0x3009,
+       0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e, 0x87a9, 0x883f,
+       0x08e6, 0x9890, 0xf881, 0x988b, 0xc801, 0x0014, 0xf8c1, 0x0016,
+       0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014, 0x8532, 0xf241,
+       0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014, 0xa208, 0x6043,
+       0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a, 0xf041, 0x3008,
+       0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016,
+       0x8000, 0x2847, 0x1011, 0x98c3, 0x8000, 0xa000, 0x2802, 0x1011,
+       0x98c9, 0x9865, 0x283e, 0x1011, 0x98cd, 0xa20b, 0x0017, 0x300c,
+       0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0x98da, 0x0014, 0x26e0,
+       0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d, 0x3806, 0x0210,
+       0x9cb6, 0x0704, 0x0000, 0x006c, 0x0002, 0x984f, 0x0014, 0x009e,
+       0x00a5, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211, 0x9cd5, 0x8772,
+       0x8837, 0x2101, 0x987a, 0x10d2, 0x78e2, 0x9cd8, 0x9859, 0xd984,
+       0xf0e2, 0xf0a1, 0x98d2, 0x0014, 0x8831, 0xd166, 0x8830, 0x800f,
+       0x9401, 0xb520, 0xc802, 0x8820, 0x987a, 0x2301, 0x987a, 0x10d2,
+       0x78e4, 0x9cd8, 0x8821, 0x8820, 0x9859, 0xf123, 0xf142, 0xf101,
+       0x98cb, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c, 0xd99e, 0x6001,
+       0x0014, 0x6845, 0x0214, 0xa21b, 0x9cd5, 0x2001, 0x98ca, 0x8201,
+       0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0x988d, 0x3027, 0x84a8,
+       0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9cc1, 0x692a, 0x6902,
+       0x1834, 0x989d, 0x1a14, 0x8010, 0x8592, 0x8026, 0x84b9, 0x7021,
+       0x0014, 0xa300, 0x69e1, 0x9caa, 0x694c, 0xa213, 0x9cba, 0x1462,
+       0xa213, 0x8000, 0x16e1, 0x98b4, 0x8023, 0x16e1, 0x8001, 0x10f1,
+       0x0016, 0x6968, 0xa214, 0x9cba, 0x8004, 0x16e1, 0x0101, 0x300a,
+       0x8827, 0x0014, 0x9cba, 0x0014, 0x61c2, 0x8002, 0x14e1, 0x0016,
+       0xa217, 0x9cc1, 0x0014, 0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6,
+       0x882c, 0x0016, 0xa212, 0x9cd5, 0x10d2, 0x70e4, 0x0004, 0x8007,
+       0x9424, 0xcc1a, 0x9cd8, 0x98ca, 0x8827, 0x300a, 0x0013, 0x8000,
+       0x84a4, 0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d, 0x0014, 0x878e,
+       0x0016, 0xa21c, 0x1035, 0x9891, 0xa210, 0xa000, 0x8010, 0x8592,
+       0x853b, 0xd044, 0x8022, 0x3807, 0x84bb, 0x98ef, 0x8021, 0x3807,
+       0x84b9, 0x300c, 0x817e, 0x872b, 0x8772, 0x9891, 0x0000, 0x0020,
+       0x002b, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+       0x0020, 0x0000, 0x0014, 0x0014, 0x9849, 0x0014, 0x0014, 0x98e5,
+       0x98d0, 0x0014, 0x0014, 0x0014, 0x0080, 0x013f, 0x0000, 0x0201,
+       0x0604, 0x0c08, 0x2120, 0x4022, 0xf880, 0x0018, 0x300b, 0xa201,
+       0x0014, 0xa200, 0x0014, 0xa200, 0x0214, 0xa202, 0x8838, 0x3806,
+       0x8839, 0x20c3, 0x0864, 0xa82e, 0x28c1, 0x9cb1, 0xa203, 0x300c,
+       0x2846, 0x8161, 0x846a, 0x8300, 0x1856, 0x883a, 0xa804, 0x28f2,
+       0x9c90, 0xa8f4, 0x300c, 0x28e1, 0x9c90, 0x2802, 0xa206, 0x64c3,
+       0x282d, 0xa207, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7824,
+       0x68c1, 0x7864, 0x883e, 0xa802, 0x8576, 0x8677, 0x206b, 0x28c1,
+       0x9cb1, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8e5, 0xa209, 0x2901,
+       0xa809, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c, 0x1fe2,
+       0xc601, 0xa20a, 0x856e, 0x0704, 0x9c90, 0x0014, 0xa204, 0xa300,
+       0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e, 0x87a9,
+       0x883f, 0x08e6, 0xa8f3, 0xf881, 0xa8ec, 0xc801, 0x0014, 0xf8c1,
+       0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014, 0x8532,
+       0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014, 0xa208,
+       0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a, 0xf041,
+       0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822,
+       0x0016, 0x8000, 0x2847, 0x1011, 0xa8fc, 0x8000, 0xa000, 0x2802,
+       0x1011, 0xa8fd, 0xa898, 0x283e, 0x1011, 0xa8fd, 0xa20b, 0x0017,
+       0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0xa801, 0x0014,
+       0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d, 0x3806,
+       0x0210, 0x9cb6, 0x0704, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211,
+       0x9d6b, 0x8772, 0x8837, 0x2101, 0xa821, 0x10d2, 0x78e2, 0x9d6e,
+       0xa8fc, 0xd984, 0xf0e2, 0xf0a1, 0xa871, 0x0014, 0x8831, 0xd166,
+       0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820, 0xa80f, 0x2301,
+       0xa80d, 0x10d2, 0x78e4, 0x9d6e, 0x8821, 0x8820, 0xa8e6, 0xf123,
+       0xf142, 0xf101, 0xa854, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c,
+       0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b, 0x9d6b, 0x2001,
+       0xa845, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0xa801,
+       0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9d57,
+       0x692a, 0x6902, 0x1834, 0xa805, 0x1a14, 0x8010, 0x8592, 0x8026,
+       0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9d40, 0x694c, 0xa213,
+       0x9d50, 0x1462, 0xa213, 0x8000, 0x16e1, 0xa80a, 0x8023, 0x16e1,
+       0x8001, 0x10f1, 0x0016, 0x6968, 0xa214, 0x9d50, 0x8004, 0x16e1,
+       0x0101, 0x300a, 0x8827, 0x0014, 0x9d50, 0x0014, 0x61c2, 0x8002,
+       0x14e1, 0x0016, 0xa217, 0x9d57, 0x0014, 0xa300, 0x8181, 0x842a,
+       0x84a8, 0x1ce6, 0x882c, 0x0016, 0xa212, 0x9d6b, 0x10d2, 0x70e4,
+       0x0004, 0x8007, 0x9424, 0xcc1a, 0x9d6e, 0xa8f8, 0x8827, 0x300a,
+       0x0013, 0x8000, 0x84a4, 0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d,
+       0x0014, 0x878e, 0x0016, 0xa21c, 0x1035, 0xa8af, 0xa210, 0x3807,
+       0x300c, 0x817e, 0x872b, 0x8772, 0xa8a8, 0x0000, 0xdf21
+};
+static unsigned short   risc_code_length01 = 0x4057;
+
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
new file mode 100644 (file)
index 0000000..b7a5dd7
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Early serial console for 8250/16550 devices
+ *
+ * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on the 8250.c serial driver, Copyright (C) 2001 Russell King,
+ * and on early_printk.c by Andi Kleen.
+ *
+ * This is for use before the serial driver has initialized, in
+ * particular, before the UARTs have been discovered and named.
+ * Instead of specifying the console device as, e.g., "ttyS0",
+ * we locate the device directly by its MMIO or I/O port address.
+ *
+ * The user can specify the device directly, e.g.,
+ *     console=uart,io,0x3f8,9600n8
+ *     console=uart,mmio,0xff5e0000,115200n8
+ * or platform code can call early_uart_console_init() to set
+ * the early UART device.
+ *
+ * After the normal serial driver starts, we try to locate the
+ * matching ttyS device and start a console there.
+ */
+
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial.h>
+#include <asm/io.h>
+#include <asm/serial.h>
+
+struct early_uart_device {
+       struct uart_port port;
+       char options[16];               /* e.g., 115200n8 */
+       unsigned int baud;
+};
+
+static struct early_uart_device early_device __initdata;
+static int early_uart_registered __initdata;
+
+static unsigned int __init serial_in(struct uart_port *port, int offset)
+{
+       if (port->iotype == UPIO_MEM)
+               return readb(port->membase + offset);
+       else
+               return inb(port->iobase + offset);
+}
+
+static void __init serial_out(struct uart_port *port, int offset, int value)
+{
+       if (port->iotype == UPIO_MEM)
+               writeb(value, port->membase + offset);
+       else
+               outb(value, port->iobase + offset);
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void __init wait_for_xmitr(struct uart_port *port)
+{
+       unsigned int status;
+
+       for (;;) {
+               status = serial_in(port, UART_LSR);
+               if ((status & BOTH_EMPTY) == BOTH_EMPTY)
+                       return;
+               cpu_relax();
+       }
+}
+
+static void __init putc(struct uart_port *port, unsigned char c)
+{
+       wait_for_xmitr(port);
+       serial_out(port, UART_TX, c);
+}
+
+static void __init early_uart_write(struct console *console, const char *s, unsigned int count)
+{
+       struct uart_port *port = &early_device.port;
+       unsigned int ier;
+
+       /* Save the IER and disable interrupts */
+       ier = serial_in(port, UART_IER);
+       serial_out(port, UART_IER, 0);
+
+       while (*s && count-- > 0) {
+               putc(port, *s);
+               if (*s == '\n')
+                       putc(port, '\r');
+               s++;
+       }
+
+       /* Wait for transmitter to become empty and restore the IER */
+       wait_for_xmitr(port);
+       serial_out(port, UART_IER, ier);
+}
+
+static unsigned int __init probe_baud(struct uart_port *port)
+{
+       unsigned char lcr, dll, dlm;
+       unsigned int quot;
+
+       lcr = serial_in(port, UART_LCR);
+       serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
+       dll = serial_in(port, UART_DLL);
+       dlm = serial_in(port, UART_DLM);
+       serial_out(port, UART_LCR, lcr);
+
+       quot = (dlm << 8) | dll;
+       return (port->uartclk / 16) / quot;
+}
+
+static void __init init_port(struct early_uart_device *device)
+{
+       struct uart_port *port = &device->port;
+       unsigned int divisor;
+       unsigned char c;
+
+       serial_out(port, UART_LCR, 0x3);        /* 8n1 */
+       serial_out(port, UART_IER, 0);          /* no interrupt */
+       serial_out(port, UART_FCR, 0);          /* no fifo */
+       serial_out(port, UART_MCR, 0x3);        /* DTR + RTS */
+
+       divisor = port->uartclk / (16 * device->baud);
+       c = serial_in(port, UART_LCR);
+       serial_out(port, UART_LCR, c | UART_LCR_DLAB);
+       serial_out(port, UART_DLL, divisor & 0xff);
+       serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
+       serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+}
+
+static int __init parse_options(struct early_uart_device *device, char *options)
+{
+       struct uart_port *port = &device->port;
+       int mapsize = 64;
+       int mmio, length;
+
+       if (!options)
+               return -ENODEV;
+
+       port->uartclk = BASE_BAUD * 16;
+       if (!strncmp(options, "mmio,", 5)) {
+               port->iotype = UPIO_MEM;
+               port->mapbase = simple_strtoul(options + 5, &options, 0);
+               port->membase = ioremap(port->mapbase, mapsize);
+               if (!port->membase) {
+                       printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
+                               __FUNCTION__, port->mapbase);
+                       return -ENOMEM;
+               }
+               mmio = 1;
+       } else if (!strncmp(options, "io,", 3)) {
+               port->iotype = UPIO_PORT;
+               port->iobase = simple_strtoul(options + 3, &options, 0);
+               mmio = 0;
+       } else
+               return -EINVAL;
+
+       if ((options = strchr(options, ','))) {
+               options++;
+               device->baud = simple_strtoul(options, 0, 0);
+               length = min(strcspn(options, " "), sizeof(device->options));
+               strncpy(device->options, options, length);
+       } else {
+               device->baud = probe_baud(port);
+               snprintf(device->options, sizeof(device->options), "%u",
+                       device->baud);
+       }
+
+       printk(KERN_INFO "Early serial console at %s 0x%lx (options '%s')\n",
+               mmio ? "MMIO" : "I/O port",
+               mmio ? port->mapbase : (unsigned long) port->iobase,
+               device->options);
+       return 0;
+}
+
+static int __init early_uart_setup(struct console *console, char *options)
+{
+       struct early_uart_device *device = &early_device;
+       int err;
+
+       if (device->port.membase || device->port.iobase)
+               return 0;
+
+       if ((err = parse_options(device, options)) < 0)
+               return err;
+
+       init_port(device);
+       return 0;
+}
+
+static struct console early_uart_console __initdata = {
+       .name   = "uart",
+       .write  = early_uart_write,
+       .setup  = early_uart_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+};
+
+static int __init early_uart_console_init(void)
+{
+       if (!early_uart_registered) {
+               register_console(&early_uart_console);
+               early_uart_registered = 1;
+       }
+       return 0;
+}
+console_initcall(early_uart_console_init);
+
+int __init early_serial_console_init(char *cmdline)
+{
+       char *options;
+       int err;
+
+       options = strstr(cmdline, "console=uart,");
+       if (!options)
+               return -ENODEV;
+
+       options = strchr(cmdline, ',') + 1;
+       if ((err = early_uart_setup(NULL, options)) < 0)
+               return err;
+       return early_uart_console_init();
+}
+
+static int __init early_uart_console_switch(void)
+{
+       struct early_uart_device *device = &early_device;
+       struct uart_port *port = &device->port;
+       int mmio, line;
+
+       if (!(early_uart_console.flags & CON_ENABLED))
+               return 0;
+
+       /* Try to start the normal driver on a matching line.  */
+       mmio = (port->iotype == UPIO_MEM);
+       line = serial8250_start_console(port, device->options);
+       if (line < 0)
+               printk("No ttyS device at %s 0x%lx for console\n",
+                       mmio ? "MMIO" : "I/O port",
+                       mmio ? port->mapbase :
+                           (unsigned long) port->iobase);
+
+       unregister_console(&early_uart_console);
+       if (mmio)
+               iounmap(port->membase);
+
+       return 0;
+}
+late_initcall(early_uart_console_switch);
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
new file mode 100644 (file)
index 0000000..b8d51eb
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Driver for the 98626/98644/internal serial interface on hp300/hp400
+ * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs)
+ *
+ * Ported from 2.2 and modified to use the normal 8250 driver
+ * by Kars de Jong <jongk@linux-m68k.org>, May 2004.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_core.h>
+#include <linux/delay.h>
+#include <linux/dio.h>
+#include <linux/console.h>
+#include <asm/io.h>
+
+#if !defined(CONFIG_HPDCA) && !defined(CONFIG_HPAPCI)
+#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
+#endif
+
+#ifdef CONFIG_HPAPCI
+struct hp300_port
+{
+       struct hp300_port *next;        /* next port */
+       int line;                       /* line (tty) number */
+};
+
+static struct hp300_port *hp300_ports;
+#endif
+
+#ifdef CONFIG_HPDCA
+
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                                const struct dio_device_id *ent);
+static void __devexit hpdca_remove_one(struct dio_dev *d);
+
+static struct dio_device_id hpdca_dio_tbl[] = {
+       { DIO_ID_DCA0 },
+       { DIO_ID_DCA0REM },
+       { DIO_ID_DCA1 },
+       { DIO_ID_DCA1REM },
+       { 0 }
+};
+
+static struct dio_driver hpdca_driver = {
+       .name      = "hpdca",
+       .id_table  = hpdca_dio_tbl,
+       .probe     = hpdca_init_one,
+       .remove    = __devexit_p(hpdca_remove_one),
+};
+
+#endif
+
+extern int hp300_uart_scode;
+
+/* Offset to UART registers from base of DCA */
+#define UART_OFFSET    17
+
+#define DCA_ID         0x01    /* ID (read), reset (write) */
+#define DCA_IC         0x03    /* Interrupt control        */
+
+/* Interrupt control */
+#define DCA_IC_IE      0x80    /* Master interrupt enable  */
+
+#define HPDCA_BAUD_BASE 153600
+
+/* Base address of the Frodo part */
+#define FRODO_BASE     (0x41c000)
+
+/*
+ * Where we find the 8250-like APCI ports, and how far apart they are.
+ */
+#define FRODO_APCIBASE         0x0
+#define FRODO_APCISPACE                0x20
+#define FRODO_APCI_OFFSET(x)   (FRODO_APCIBASE + ((x) * FRODO_APCISPACE))
+
+#define HPAPCI_BAUD_BASE 500400
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+/*
+ * Parse the bootinfo to find descriptions for headless console and 
+ * debug serial ports and register them with the 8250 driver.
+ * This function should be called before serial_console_init() is called
+ * to make sure the serial console will be available for use. IA-64 kernel
+ * calls this function from setup_arch() after the EFI and ACPI tables have
+ * been parsed.
+ */
+int __init hp300_setup_serial_console(void)
+{
+       int scode;
+       struct uart_port port;
+
+       memset(&port, 0, sizeof(port));
+
+       if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
+               return 0;
+
+       if (DIO_SCINHOLE(hp300_uart_scode))
+               return 0;
+
+       scode = hp300_uart_scode;
+
+       /* Memory mapped I/O */
+       port.iotype = UPIO_MEM;
+       port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+       port.type = PORT_UNKNOWN;
+
+       /* Check for APCI console */
+       if (scode == 256) {
+#ifdef CONFIG_HPAPCI
+               printk(KERN_INFO "Serial console is HP APCI 1\n");
+
+               port.uartclk = HPAPCI_BAUD_BASE * 16;
+               port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
+               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+               port.regshift = 2;
+               add_preferred_console("ttyS", port.line, "9600n8");
+#else
+               printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+               return 0;
+#endif
+       }
+       else {
+#ifdef CONFIG_HPDCA
+               unsigned long pa = dio_scodetophysaddr(scode);
+               if (!pa) {
+                       return 0;
+               }
+
+               printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+
+               port.uartclk = HPDCA_BAUD_BASE * 16;
+               port.mapbase = (pa + UART_OFFSET);
+               port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
+               port.regshift = 1;
+               port.irq = DIO_IPL(pa + DIO_VIRADDRBASE);
+
+               /* Enable board-interrupts */
+               out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+
+               if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) {
+                       add_preferred_console("ttyS", port.line, "9600n8");
+               }
+#else
+               printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+               return 0;
+#endif
+       }
+
+       if (early_serial_setup(&port) < 0) {
+               printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+       }
+
+       return 0;
+}
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+#ifdef CONFIG_HPDCA
+static int __devinit hpdca_init_one(struct dio_dev *d,
+                                const struct dio_device_id *ent)
+{
+       struct serial_struct serial_req;
+       int line;
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+       if (hp300_uart_scode == d->scode) {
+               /* Already got it. */
+               return 0;
+       }
+#endif
+       memset(&serial_req, 0, sizeof(struct serial_struct));
+
+       /* Memory mapped I/O */
+       serial_req.io_type = SERIAL_IO_MEM;
+       serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+       serial_req.irq = d->ipl;
+       serial_req.baud_base = HPDCA_BAUD_BASE;
+       serial_req.iomap_base = (d->resource.start + UART_OFFSET);
+       serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
+       serial_req.iomem_reg_shift = 1;
+       line = register_serial(&serial_req);
+
+       if (line < 0) {
+               printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
+                      " irq %d failed\n", d->scode, serial_req.irq);
+               return -ENOMEM;
+       }
+
+       /* Enable board-interrupts */
+       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
+       dio_set_drvdata(d, (void *)line);
+
+       /* Reset the DCA */
+       out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
+       udelay(100);
+
+       return 0;
+}
+#endif
+
+static int __init hp300_8250_init(void)
+{
+       static int called = 0;
+       int num_ports;
+#ifdef CONFIG_HPAPCI
+       int line;
+       unsigned long base;
+       struct serial_struct serial_req;
+       struct hp300_port *port;
+       int i;
+#endif
+       if (called)
+               return -ENODEV;
+       called = 1;
+
+       if (!MACH_IS_HP300)
+               return -ENODEV;
+
+       num_ports = 0;
+
+#ifdef CONFIG_HPDCA
+       if (dio_module_init(&hpdca_driver) == 0)
+               num_ports++;
+#endif
+#ifdef CONFIG_HPAPCI
+       if (hp300_model < HP_400) {
+               if (!num_ports)
+                       return -ENODEV;
+               return 0;
+       }
+       /* These models have the Frodo chip.
+        * Port 0 is reserved for the Apollo Domain keyboard.
+        * Port 1 is either the console or the DCA.
+        */
+       for (i = 1; i < 4; i++) {
+               /* Port 1 is the console on a 425e, on other machines it's mapped to
+                * DCA.
+                */
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+               if (i == 1) {
+                       continue;
+               }
+#endif
+
+               /* Create new serial device */
+               port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
+               if (!port)
+                       return -ENOMEM;
+
+               memset(&serial_req, 0, sizeof(struct serial_struct));
+
+               base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
+
+               /* Memory mapped I/O */
+               serial_req.io_type = SERIAL_IO_MEM;
+               serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
+               /* XXX - no interrupt support yet */
+               serial_req.irq = 0;
+               serial_req.baud_base = HPAPCI_BAUD_BASE;
+               serial_req.iomap_base = base;
+               serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
+               serial_req.iomem_reg_shift = 2;
+
+               line = register_serial(&serial_req);
+
+               if (line < 0) {
+                       printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
+                              " irq %d failed\n", i, serial_req.irq);
+                       kfree(port);
+                       continue;
+               }
+
+               port->line = line;
+               port->next = hp300_ports;
+               hp300_ports = port;
+
+               num_ports++;
+       }
+#endif
+
+       /* Any boards found? */
+       if (!num_ports)
+               return -ENODEV;
+
+       return 0;
+}
+
+#ifdef CONFIG_HPDCA
+static void __devexit hpdca_remove_one(struct dio_dev *d)
+{
+       int line;
+
+       line = (int) dio_get_drvdata(d);
+       if (d->resource.start) {
+               /* Disable board-interrupts */
+               out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
+       }
+       unregister_serial(line);
+}
+#endif
+
+static void __exit hp300_8250_exit(void)
+{
+#ifdef CONFIG_HPAPCI
+       struct hp300_port *port, *to_free;
+
+       for (port = hp300_ports; port; ) {
+               unregister_serial(port->line);
+               to_free = port;
+               port = port->next;
+               kfree(to_free);
+       }
+
+       hp300_ports = NULL;
+#endif
+#ifdef CONFIG_HPDCA
+       dio_unregister_driver(&hpdca_driver);
+#endif
+}
+
+module_init(hp300_8250_init);
+module_exit(hp300_8250_exit);
+MODULE_DESCRIPTION("HP DCA/APCI serial driver");
+MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
new file mode 100644 (file)
index 0000000..676c423
--- /dev/null
@@ -0,0 +1,5061 @@
+/* $Id: serial.c,v 1.25 2004/09/29 10:33:49 starvik Exp $
+ *
+ * Serial port driver for the ETRAX 100LX chip
+ *
+ *    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Axis Communications AB
+ *
+ *    Many, many authors. Based once upon a time on serial.c for 16x50.
+ *
+ * $Log: serial.c,v $
+ * Revision 1.25  2004/09/29 10:33:49  starvik
+ * Resolved a dealock when printing debug from kernel.
+ *
+ * Revision 1.24  2004/08/27 23:25:59  johana
+ * rs_set_termios() must call change_speed() if c_iflag has changed or
+ * automatic XOFF handling will be enabled and transmitter will stop
+ * if 0x13 is received.
+ *
+ * Revision 1.23  2004/08/24 06:57:13  starvik
+ * More whitespace cleanup
+ *
+ * Revision 1.22  2004/08/24 06:12:20  starvik
+ * Whitespace cleanup
+ *
+ * Revision 1.20  2004/05/24 12:00:20  starvik
+ * Big merge of stuff from Linux 2.4 (e.g. manual mode for the serial port).
+ *
+ * Revision 1.19  2004/05/17 13:12:15  starvik
+ * Kernel console hook
+ * Big merge from Linux 2.4 still pending.
+ *
+ * Revision 1.18  2003/10/28 07:18:30  starvik
+ * Compiles with debug info
+ *
+ * Revision 1.17  2003/07/04 08:27:37  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.16  2003/06/13 10:05:19  johana
+ * Help the user to avoid trouble by:
+ * Forcing mixed mode for status/control lines if not all pins are used.
+ *
+ * Revision 1.15  2003/06/13 09:43:01  johana
+ * Merged in the following changes from os/linux/arch/cris/drivers/serial.c
+ * + some minor changes to reduce diff.
+ *
+ * Revision 1.49  2003/05/30 11:31:54  johana
+ * Merged in change-branch--serial9bit that adds CMSPAR support for sticky
+ * parity (mark/space)
+ *
+ * Revision 1.48  2003/05/30 11:03:57  johana
+ * Implemented rs_send_xchar() by disabling the DMA and writing manually.
+ * Added e100_disable_txdma_channel() and e100_enable_txdma_channel().
+ * Fixed rs_throttle() and rs_unthrottle() to properly call rs_send_xchar
+ * instead of setting info->x_char and check the CRTSCTS flag before
+ * controlling the rts pin.
+ *
+ * Revision 1.14  2003/04/09 08:12:44  pkj
+ * Corrected typo changes made upstream.
+ *
+ * Revision 1.13  2003/04/09 05:20:47  starvik
+ * Merge of Linux 2.5.67
+ *
+ * Revision 1.11  2003/01/22 06:48:37  starvik
+ * Fixed warnings issued by GCC 3.2.1
+ *
+ * Revision 1.9  2002/12/13 09:07:47  starvik
+ * Alert user that RX_TIMEOUT_TICKS==0 doesn't work
+ *
+ * Revision 1.8  2002/12/11 13:13:57  starvik
+ * Added arch/ to v10 specific includes
+ * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
+ *
+ * Revision 1.7  2002/12/06 07:13:57  starvik
+ * Corrected work queue stuff
+ * Removed CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+ *
+ * Revision 1.6  2002/11/21 07:17:46  starvik
+ * Change static inline to extern inline where otherwise outlined with gcc-3.2
+ *
+ * Revision 1.5  2002/11/14 15:59:49  starvik
+ * Linux 2.5 port of the latest serial driver from 2.4. The work queue stuff
+ * probably doesn't work yet.
+ *
+ * Revision 1.42  2002/11/05 09:08:47  johana
+ * Better implementation of rs_stop() and rs_start() that uses the XOFF
+ * register to start/stop transmission.
+ * change_speed() also initilises XOFF register correctly so that
+ * auto_xoff is enabled when IXON flag is set by user.
+ * This gives fast XOFF response times.
+ *
+ * Revision 1.41  2002/11/04 18:40:57  johana
+ * Implemented rs_stop() and rs_start().
+ * Simple tests using hwtestserial indicates that this should be enough
+ * to make it work.
+ *
+ * Revision 1.40  2002/10/14 05:33:18  starvik
+ * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
+ *
+ * Revision 1.39  2002/09/30 21:00:57  johana
+ * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
+ * control pins can be mixed between PA and PB.
+ * If no serial port uses MIXED old solution is used
+ * (saves a few bytes and cycles).
+ * control_pins struct uses masks instead of bit numbers.
+ * Corrected dummy values and polarity in line_info() so
+ * /proc/tty/driver/serial is now correct.
+ * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
+ *
+ * Revision 1.38  2002/08/23 11:01:36  starvik
+ * Check that serial port is enabled in all interrupt handlers to avoid
+ * restarts of DMA channels not assigned to serial ports
+ *
+ * Revision 1.37  2002/08/13 13:02:37  bjornw
+ * Removed some warnings because of unused code
+ *
+ * Revision 1.36  2002/08/08 12:50:01  starvik
+ * Serial interrupt is shared with synchronous serial port driver
+ *
+ * Revision 1.35  2002/06/03 10:40:49  starvik
+ * Increased RS-485 RTS toggle timer to 2 characters
+ *
+ * Revision 1.34  2002/05/28 18:59:36  johana
+ * Whitespace and comment fixing to be more like etrax100ser.c 1.71.
+ *
+ * Revision 1.33  2002/05/28 17:55:43  johana
+ * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time)
+ * timer from tranismit_chars (interrupt context).
+ * The timer toggles RTS in interrupt context when expired giving minimum
+ * latencies.
+ *
+ * Revision 1.32  2002/05/22 13:58:00  johana
+ * Renamed rs_write() to raw_write() and made it inline.
+ * New rs_write() handles RS-485 if configured and enabled
+ * (moved code from e100_write_rs485()).
+ * RS-485 ioctl's uses copy_from_user() instead of verify_area().
+ *
+ * Revision 1.31  2002/04/22 11:20:03  johana
+ * Updated copyright years.
+ *
+ * Revision 1.30  2002/04/22 09:39:12  johana
+ * RS-485 support compiles.
+ *
+ * Revision 1.29  2002/01/14 16:10:01  pkj
+ * Allocate the receive buffers dynamically. The static 4kB buffer was
+ * too small for the peaks. This means that we can get rid of the extra
+ * buffer and the copying to it. It also means we require less memory
+ * under normal operations, but can use more when needed (there is a
+ * cap at 64kB for safety reasons). If there is no memory available
+ * we panic(), and die a horrible death...
+ *
+ * Revision 1.28  2001/12/18 15:04:53  johana
+ * Cleaned up write_rs485() - now it works correctly without padding extra
+ * char.
+ * Added sane default initialisation of rs485.
+ * Added #ifdef around dummy variables.
+ *
+ * Revision 1.27  2001/11/29 17:00:41  pkj
+ * 2kB seems to be too small a buffer when using 921600 bps,
+ * so increase it to 4kB (this was already done for the elinux
+ * version of the serial driver).
+ *
+ * Revision 1.26  2001/11/19 14:20:41  pkj
+ * Minor changes to comments and unused code.
+ *
+ * Revision 1.25  2001/11/12 20:03:43  pkj
+ * Fixed compiler warnings.
+ *
+ * Revision 1.24  2001/11/12 15:10:05  pkj
+ * Total redesign of the receiving part of the serial driver.
+ * Uses eight chained descriptors to write to a 4kB buffer.
+ * This data is then serialised into a 2kB buffer. From there it
+ * is copied into the TTY's flip buffers when they become available.
+ * A lot of copying, and the sizes of the buffers might need to be
+ * tweaked, but all in all it should work better than the previous
+ * version, without the need to modify the TTY code in any way.
+ * Also note that erroneous bytes are now correctly marked in the
+ * flag buffers (instead of always marking the first byte).
+ *
+ * Revision 1.23  2001/10/30 17:53:26  pkj
+ * * Set info->uses_dma to 0 when a port is closed.
+ * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT).
+ * * Call start_flush_timer() in start_receive() if
+ *   CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is defined.
+ *
+ * Revision 1.22  2001/10/30 17:44:03  pkj
+ * Use %lu for received and transmitted counters in line_info().
+ *
+ * Revision 1.21  2001/10/30 17:40:34  pkj
+ * Clean-up. The only change to functionality is that
+ * CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS(=5) is used instead of
+ * MAX_FLUSH_TIME(=8).
+ *
+ * Revision 1.20  2001/10/30 15:24:49  johana
+ * Added char_time stuff from 2.0 driver.
+ *
+ * Revision 1.19  2001/10/30 15:23:03  johana
+ * Merged with 1.13.2 branch + fixed indentation
+ * and changed CONFIG_ETRAX100_XYS to CONFIG_ETRAX_XYZ
+ *
+ * Revision 1.18  2001/09/24 09:27:22  pkj
+ * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud().
+ *
+ * Revision 1.17  2001/08/24 11:32:49  ronny
+ * More fixes for the CONFIG_ETRAX_SERIAL_PORT0 define.
+ *
+ * Revision 1.16  2001/08/24 07:56:22  ronny
+ * Added config ifdefs around ser0 irq requests.
+ *
+ * Revision 1.15  2001/08/16 09:10:31  bjarne
+ * serial.c - corrected the initialization of rs_table, the wrong defines
+ *            where used.
+ *            Corrected a test in timed_flush_handler.
+ *            Changed configured to enabled.
+ * serial.h - Changed configured to enabled.
+ *
+ * Revision 1.14  2001/08/15 07:31:23  bjarne
+ * Introduced two new members to the e100_serial struct.
+ * configured - Will be set to 1 if the port has been configured in .config
+ * uses_dma   - Should be set to 1 if the port uses DMA. Currently it is set
+ *              to 1
+ *              when a port is opened. This is used to limit the DMA interrupt
+ *              routines to only manipulate DMA channels actually used by the
+ *              serial driver.
+ *
+ * Revision 1.13.2.2  2001/10/17 13:57:13  starvik
+ * Receiver was broken by the break fixes
+ *
+ * Revision 1.13.2.1  2001/07/20 13:57:39  ronny
+ * Merge with new stuff from etrax100ser.c. Works but haven't checked stuff
+ * like break handling.
+ *
+ * Revision 1.13  2001/05/09 12:40:31  johana
+ * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
+ *
+ * Revision 1.12  2001/04/19 12:23:07  bjornw
+ * CONFIG_RS485 -> CONFIG_ETRAX_RS485
+ *
+ * Revision 1.11  2001/04/05 14:29:48  markusl
+ * Updated according to review remarks i.e.
+ * -Use correct types in port structure to avoid compiler warnings
+ * -Try to use IO_* macros whenever possible
+ * -Open should never return -EBUSY
+ *
+ * Revision 1.10  2001/03/05 13:14:07  bjornw
+ * Another spelling fix
+ *
+ * Revision 1.9  2001/02/23 13:46:38  bjornw
+ * Spellling check
+ *
+ * Revision 1.8  2001/01/23 14:56:35  markusl
+ * Made use of ser1 optional
+ * Needed by USB
+ *
+ * Revision 1.7  2001/01/19 16:14:48  perf
+ * Added kernel options for serial ports 234.
+ * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ.
+ *
+ * Revision 1.6  2000/11/22 16:36:09  bjornw
+ * Please marketing by using the correct case when spelling Etrax.
+ *
+ * Revision 1.5  2000/11/21 16:43:37  bjornw
+ * Fixed so it compiles under CONFIG_SVINTO_SIM
+ *
+ * Revision 1.4  2000/11/15 17:34:12  bjornw
+ * Added a timeout timer for flushing input channels. The interrupt-based
+ * fast flush system should be easy to merge with this later (works the same
+ * way, only with an irq instead of a system timer_list)
+ *
+ * Revision 1.3  2000/11/13 17:19:57  bjornw
+ * * Incredibly, this almost complete rewrite of serial.c worked (at least
+ *   for output) the first time.
+ *
+ *   Items worth noticing:
+ *
+ *      No Etrax100 port 1 workarounds (does only compile on 2.4 anyway now)
+ *      RS485 is not ported (why can't it be done in userspace as on x86 ?)
+ *      Statistics done through async_icount - if any more stats are needed,
+ *      that's the place to put them or in an arch-dep version of it.
+ *      timeout_interrupt and the other fast timeout stuff not ported yet
+ *      There be dragons in this 3k+ line driver
+ *
+ * Revision 1.2  2000/11/10 16:50:28  bjornw
+ * First shot at a 2.4 port, does not compile totally yet
+ *
+ * Revision 1.1  2000/11/10 16:47:32  bjornw
+ * Added verbatim copy of rev 1.49 etrax100ser.c from elinux
+ *
+ * Revision 1.49  2000/10/30 15:47:14  tobiasa
+ * Changed version number.
+ *
+ * Revision 1.48  2000/10/25 11:02:43  johana
+ * Changed %ul to %lu in printf's
+ *
+ * Revision 1.47  2000/10/18 15:06:53  pkj
+ * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and
+ * CONFIG_ETRAX_SERIAL_PROC_ENTRY together.
+ * Some clean-up of the /proc/serial file.
+ *
+ * Revision 1.46  2000/10/16 12:59:40  johana
+ * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info.
+ *
+ * Revision 1.45  2000/10/13 17:10:59  pkj
+ * Do not flush DMAs while flipping TTY buffers.
+ *
+ * Revision 1.44  2000/10/13 16:34:29  pkj
+ * Added a delay in ser_interrupt() for 2.3ms when an error is detected.
+ * We do not know why this delay is required yet, but without it the
+ * irmaflash program does not work (this was the program that needed
+ * the ser_interrupt() to be needed in the first place). This should not
+ * affect normal use of the serial ports.
+ *
+ * Revision 1.43  2000/10/13 16:30:44  pkj
+ * New version of the fast flush of serial buffers code. This time
+ * it is localized to the serial driver and uses a fast timer to
+ * do the work.
+ *
+ * Revision 1.42  2000/10/13 14:54:26  bennyo
+ * Fix for switching RTS when using rs485
+ *
+ * Revision 1.41  2000/10/12 11:43:44  pkj
+ * Cleaned up a number of comments.
+ *
+ * Revision 1.40  2000/10/10 11:58:39  johana
+ * Made RS485 support generic for all ports.
+ * Toggle rts in interrupt if no delay wanted.
+ * WARNING: No true transmitter empty check??
+ * Set d_wait bit when sending data so interrupt is delayed until
+ * fifo flushed. (Fix tcdrain() problem)
+ *
+ * Revision 1.39  2000/10/04 16:08:02  bjornw
+ * * Use virt_to_phys etc. for DMA addresses
+ * * Removed CONFIG_FLUSH_DMA_FAST hacks
+ * * Indentation fix
+ *
+ * Revision 1.38  2000/10/02 12:27:10  mattias
+ * * added variable used when using fast flush on serial dma.
+ *   (CONFIG_FLUSH_DMA_FAST)
+ *
+ * Revision 1.37  2000/09/27 09:44:24  pkj
+ * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
+ *
+ * Revision 1.36  2000/09/20 13:12:52  johana
+ * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS:
+ *   Number of timer ticks between flush of receive fifo (1 tick = 10ms).
+ *   Try 0-3 for low latency applications. Approx 5 for high load
+ *   applications (e.g. PPP). Maybe this should be more adaptive some day...
+ *
+ * Revision 1.35  2000/09/20 10:36:08  johana
+ * Typo in get_lsr_info()
+ *
+ * Revision 1.34  2000/09/20 10:29:59  johana
+ * Let rs_chars_in_buffer() check fifo content as well.
+ * get_lsr_info() might work now (not tested).
+ * Easier to change the port to debug.
+ *
+ * Revision 1.33  2000/09/13 07:52:11  torbjore
+ * Support RS485
+ *
+ * Revision 1.32  2000/08/31 14:45:37  bjornw
+ * After sending a break we need to reset the transmit DMA channel
+ *
+ * Revision 1.31  2000/06/21 12:13:29  johana
+ * Fixed wait for all chars sent when closing port.
+ * (Used to always take 1 second!)
+ * Added shadows for directions of status/ctrl signals.
+ *
+ * Revision 1.30  2000/05/29 16:27:55  bjornw
+ * Simulator ifdef moved a bit
+ *
+ * Revision 1.29  2000/05/09 09:40:30  mattias
+ * * Added description of dma registers used in timeout_interrupt
+ * * Removed old code
+ *
+ * Revision 1.28  2000/05/08 16:38:58  mattias
+ * * Bugfix for flushing fifo in timeout_interrupt
+ *   Problem occurs when bluetooth stack waits for a small number of bytes
+ *   containing an event acknowledging free buffers in bluetooth HW
+ *   As before, data was stuck in fifo until more data came on uart and
+ *   flushed it up to the stack.
+ *
+ * Revision 1.27  2000/05/02 09:52:28  jonasd
+ * Added fix for peculiar etrax behaviour when eop is forced on an empty
+ * fifo. This is used when flashing the IRMA chip. Disabled by default.
+ *
+ * Revision 1.26  2000/03/29 15:32:02  bjornw
+ * 2.0.34 updates
+ *
+ * Revision 1.25  2000/02/16 16:59:36  bjornw
+ * * Receive DMA directly into the flip-buffer, eliminating an intermediary
+ *   receive buffer and a memcpy. Will avoid some overruns.
+ * * Error message on debug port if an overrun or flip buffer overrun occurs.
+ * * Just use the first byte in the flag flip buffer for errors.
+ * * Check for timeout on the serial ports only each 5/100 s, not 1/100.
+ *
+ * Revision 1.24  2000/02/09 18:02:28  bjornw
+ * * Clear serial errors (overrun, framing, parity) correctly. Before, the
+ *   receiver would get stuck if an error occurred and we did not restart
+ *   the input DMA.
+ * * Cosmetics (indentation, some code made into inlines)
+ * * Some more debug options
+ * * Actually shut down the serial port (DMA irq, DMA reset, receiver stop)
+ *   when the last open is closed. Corresponding fixes in startup().
+ * * rs_close() "tx FIFO wait" code moved into right place, bug & -> && fixed
+ *   and make a special case out of port 1 (R_DMA_CHx_STATUS is broken for that)
+ * * e100_disable_rx/enable_rx just disables/enables the receiver, not RTS
+ *
+ * Revision 1.23  2000/01/24 17:46:19  johana
+ * Wait for flush of DMA/FIFO when closing port.
+ *
+ * Revision 1.22  2000/01/20 18:10:23  johana
+ * Added TIOCMGET ioctl to return modem status.
+ * Implemented modem status/control that works with the extra signals
+ * (DTR, DSR, RI,CD) as well.
+ * 3 different modes supported:
+ * ser0 on PB (Bundy), ser1 on PB (Lisa) and ser2 on PA (Bundy)
+ * Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when
+ * closing the last filehandle, NASTY!.
+ * Added break generation, not tested though!
+ * Use SA_SHIRQ when request_irq() for ser2 and ser3 (shared with) par0 and par1.
+ * You can't use them at the same time (yet..), but you can hopefully switch
+ * between ser2/par0, ser3/par1 with the same kernel config.
+ * Replaced some magic constants with defines
+ *
+ *
+ */
+
+static char *serial_version = "$Revision: 1.25 $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.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/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <linux/delay.h>
+
+#include <asm/arch/svinto.h>
+
+/* non-arch dependent serial structures are in linux/serial.h */
+#include <linux/serial.h>
+/* while we keep our own stuff (struct e100_serial) in a local .h file */
+#include "serial.h"
+#include <asm/fasttimer.h>
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifndef CONFIG_ETRAX_FAST_TIMER
+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"
+#endif
+#endif
+
+#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \
+           (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)
+#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
+#endif
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
+#endif
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS)
+#include "serial_compat.h"
+#endif
+
+#define _INLINE_ inline
+
+struct tty_driver *serial_driver;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL     1
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+//#define SERIAL_DEBUG_INTR
+//#define SERIAL_DEBUG_OPEN
+//#define SERIAL_DEBUG_FLOW
+//#define SERIAL_DEBUG_DATA
+//#define SERIAL_DEBUG_THROTTLE
+//#define SERIAL_DEBUG_IO  /* Debug for Extra control and status pins */
+//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
+
+/* Enable this to use serial interrupts to handle when you
+   expect the first received event on the serial port to
+   be an error, break or similar. Used to be able to flash IRMA
+   from eLinux */
+#define SERIAL_HANDLE_EARLY_ERRORS
+
+/* Defined and used in n_tty.c, but we need it here as well */
+#define TTY_THRESHOLD_THROTTLE 128
+
+/* Due to buffersizes and threshold values, our SERIAL_DESCR_BUF_SIZE
+ * must not be to high or flow control won't work if we leave it to the tty
+ * layer so we have our own throttling in flush_to_flip
+ * TTY_FLIPBUF_SIZE=512,
+ * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128
+ * BUF_SIZE can't be > 128
+ */
+/* Currently 16 descriptors x 128 bytes = 2048 bytes */
+#define SERIAL_DESCR_BUF_SIZE 256
+
+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
+
+/* We don't want to load the system with massive fast timer interrupt
+ * on high baudrates so limit it to 250 us (4kHz) */
+#define MIN_FLUSH_TIME_USEC 250
+
+/* Add an x here to log a lot of timer stuff */
+#define TIMERD(x)
+/* Debug details of interrupt handling */
+#define DINTR1(x)  /* irq on/off, errors */
+#define DINTR2(x)    /* tx and rx */
+/* Debug flip buffer stuff */
+#define DFLIP(x)
+/* Debug flow control and overview of data flow */
+#define DFLOW(x)
+#define DBAUD(x)
+#define DLOG_INT_TRIG(x)
+
+//#define DEBUG_LOG_INCLUDED
+#ifndef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG(line, string, value)
+#else
+struct debug_log_info
+{
+       unsigned long time;
+       unsigned long timer_data;
+//  int line;
+       const char *string;
+       int value;
+};
+#define DEBUG_LOG_SIZE 4096
+
+struct debug_log_info debug_log[DEBUG_LOG_SIZE];
+int debug_log_pos = 0;
+
+#define DEBUG_LOG(_line, _string, _value) do { \
+  if ((_line) == SERIAL_DEBUG_LINE) {\
+    debug_log_func(_line, _string, _value); \
+  }\
+}while(0)
+
+void debug_log_func(int line, const char *string, int value)
+{
+       if (debug_log_pos < DEBUG_LOG_SIZE) {
+               debug_log[debug_log_pos].time = jiffies;
+               debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
+//    debug_log[debug_log_pos].line = line;
+               debug_log[debug_log_pos].string = string;
+               debug_log[debug_log_pos].value = value;
+               debug_log_pos++;
+       }
+       /*printk(string, value);*/
+}
+#endif
+
+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
+/* Default number of timer ticks before flushing rx fifo
+ * When using "little data, low latency applications: use 0
+ * When using "much data applications (PPP)" use ~5
+ */
+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
+#endif
+
+unsigned long timer_data_to_ns(unsigned long timer_data);
+
+static void change_speed(struct e100_serial *info);
+static void rs_throttle(struct tty_struct * tty);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+static int rs_write(struct tty_struct * tty, int from_user,
+                    const unsigned char *buf, int count);
+extern _INLINE_ int rs_raw_write(struct tty_struct * tty, int from_user,
+                            const unsigned char *buf, int count);
+#ifdef CONFIG_ETRAX_RS485
+static int e100_write_rs485(struct tty_struct * tty, int from_user,
+                            const unsigned char *buf, int count);
+#endif
+static int get_lsr_info(struct e100_serial * info, unsigned int *value);
+
+
+#define DEF_BAUD 115200   /* 115.2 kbit/s */
+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define DEF_RX 0x20  /* or SERIAL_CTRL_W >> 8 */
+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
+#define DEF_TX 0x80  /* or SERIAL_CTRL_B */
+
+/* offsets from R_SERIALx_CTRL */
+
+#define REG_DATA 0
+#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
+#define REG_TR_DATA 0
+#define REG_STATUS 1
+#define REG_TR_CTRL 1
+#define REG_REC_CTRL 2
+#define REG_BAUD 3
+#define REG_XOFF 4  /* this is a 32 bit register */
+
+/* The bitfields are the same for all serial ports */
+#define SER_RXD_MASK         IO_MASK(R_SERIAL0_STATUS, rxd)
+#define SER_DATA_AVAIL_MASK  IO_MASK(R_SERIAL0_STATUS, data_avail)
+#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)
+#define SER_PAR_ERR_MASK     IO_MASK(R_SERIAL0_STATUS, par_err)
+#define SER_OVERRUN_MASK     IO_MASK(R_SERIAL0_STATUS, overrun)
+
+#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)
+
+/* Values for info->errorcode */
+#define ERRCODE_SET_BREAK    (TTY_BREAK)
+#define ERRCODE_INSERT        0x100
+#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)
+
+#define FORCE_EOP(info)  *R_SET_EOP = 1U << info->iseteop;
+
+/*
+ * General note regarding the use of IO_* macros in this file:
+ *
+ * We will use the bits defined for DMA channel 6 when using various
+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
+ * the same for all channels (which of course they are).
+ *
+ * We will also use the bits defined for serial port 0 when writing commands
+ * to the different ports, as these bits too are the same for all ports.
+ */
+
+
+/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
+static const unsigned long e100_ser_int_mask = 0
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
+#endif
+;
+unsigned long r_alt_ser_baudrate_shadow = 0;
+
+/* this is the data for the four serial ports in the etrax100 */
+/*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
+
+static struct e100_serial rs_table[] = {
+       { .baud        = DEF_BAUD,
+         .port        = (unsigned char *)R_SERIAL0_CTRL,
+         .irq         = 1U << 12, /* uses DMA 6 and 7 */
+         .oclrintradr = R_DMA_CH6_CLR_INTR,
+         .ofirstadr   = R_DMA_CH6_FIRST,
+         .ocmdadr     = R_DMA_CH6_CMD,
+         .ostatusadr  = R_DMA_CH6_STATUS,
+         .iclrintradr = R_DMA_CH7_CLR_INTR,
+         .ifirstadr   = R_DMA_CH7_FIRST,
+         .icmdadr     = R_DMA_CH7_CMD,
+         .idescradr   = R_DMA_CH7_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 2,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+         .dma_out_enabled = 1,
+#else
+         .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+         .dma_in_enabled = 1,
+#else
+         .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+
+},  /* ttyS0 */
+#ifndef CONFIG_SVINTO_SIM
+       { .baud        = DEF_BAUD,
+         .port        = (unsigned char *)R_SERIAL1_CTRL,
+         .irq         = 1U << 16, /* uses DMA 8 and 9 */
+         .oclrintradr = R_DMA_CH8_CLR_INTR,
+         .ofirstadr   = R_DMA_CH8_FIRST,
+         .ocmdadr     = R_DMA_CH8_CMD,
+         .ostatusadr  = R_DMA_CH8_STATUS,
+         .iclrintradr = R_DMA_CH9_CLR_INTR,
+         .ifirstadr   = R_DMA_CH9_FIRST,
+         .icmdadr     = R_DMA_CH9_CMD,
+         .idescradr   = R_DMA_CH9_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 3,
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+         .dma_out_enabled = 1,
+#else
+         .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+         .dma_in_enabled = 1,
+#else
+         .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+},  /* ttyS1 */
+
+       { .baud        = DEF_BAUD,
+         .port        = (unsigned char *)R_SERIAL2_CTRL,
+         .irq         = 1U << 4,  /* uses DMA 2 and 3 */
+         .oclrintradr = R_DMA_CH2_CLR_INTR,
+         .ofirstadr   = R_DMA_CH2_FIRST,
+         .ocmdadr     = R_DMA_CH2_CMD,
+         .ostatusadr  = R_DMA_CH2_STATUS,
+         .iclrintradr = R_DMA_CH3_CLR_INTR,
+         .ifirstadr   = R_DMA_CH3_FIRST,
+         .icmdadr     = R_DMA_CH3_CMD,
+         .idescradr   = R_DMA_CH3_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 0,
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+         .dma_out_enabled = 1,
+#else
+         .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+         .dma_in_enabled = 1,
+#else
+         .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+ },  /* ttyS2 */
+
+       { .baud        = DEF_BAUD,
+         .port        = (unsigned char *)R_SERIAL3_CTRL,
+         .irq         = 1U << 8,  /* uses DMA 4 and 5 */
+         .oclrintradr = R_DMA_CH4_CLR_INTR,
+         .ofirstadr   = R_DMA_CH4_FIRST,
+         .ocmdadr     = R_DMA_CH4_CMD,
+         .ostatusadr  = R_DMA_CH4_STATUS,
+         .iclrintradr = R_DMA_CH5_CLR_INTR,
+         .ifirstadr   = R_DMA_CH5_FIRST,
+         .icmdadr     = R_DMA_CH5_CMD,
+         .idescradr   = R_DMA_CH5_DESCR,
+         .flags       = STD_FLAGS,
+         .rx_ctrl     = DEF_RX,
+         .tx_ctrl     = DEF_TX,
+         .iseteop     = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+          .enabled  = 1,
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+         .dma_out_enabled = 1,
+#else
+         .dma_out_enabled = 0,
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+         .dma_in_enabled = 1,
+#else
+         .dma_in_enabled = 0
+#endif
+#else
+          .enabled  = 0,
+         .dma_out_enabled = 0,
+         .dma_in_enabled = 0
+#endif
+ }   /* ttyS3 */
+#endif
+};
+
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
+
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static struct fast_timer fast_timers[NR_PORTS];
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
+#define PROCSTAT(x) x
+struct ser_statistics_type {
+       int overrun_cnt;
+       int early_errors_cnt;
+       int ser_ints_ok_cnt;
+       int errors_cnt;
+       unsigned long int processing_flip;
+       unsigned long processing_flip_still_room;
+       unsigned long int timeout_flush_cnt;
+       int rx_dma_ints;
+       int tx_dma_ints;
+       int rx_tot;
+       int tx_tot;
+};
+
+static struct ser_statistics_type ser_stat[NR_PORTS];
+
+#else
+
+#define PROCSTAT(x)
+
+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
+
+/* RS-485 */
+#if defined(CONFIG_ETRAX_RS485)
+#ifdef CONFIG_ETRAX_FAST_TIMER
+static struct fast_timer fast_timers_rs485[NR_PORTS];
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
+#endif
+#endif
+
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (R_PORT_PB_DATA):&dummy_ser[line]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+               (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+/* If not all status pins are used or disabled, use mixed mode */
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+
+#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT)
+
+#if SER0_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT)
+
+#if SER0_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT0 */
+
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+
+#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT)
+
+#if SER1_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
+
+#if SER1_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT1 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+
+#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT)
+
+#if SER2_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT)
+
+#if SER2_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT2 */
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+
+#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT)
+
+#if SER3_PA_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT)
+
+#if SER3_PB_BITSUM != -4
+#  if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#   endif
+# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1
+#   ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#     define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#   endif
+#  endif
+#  if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#  if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1
+#    ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED
+#      define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1
+#    endif
+#  endif
+#endif
+
+#endif /* PORT3 */
+
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+       volatile unsigned char *dtr_port;
+       unsigned char          *dtr_shadow;
+       volatile unsigned char *ri_port;
+       unsigned char          *ri_shadow;
+       volatile unsigned char *dsr_port;
+       unsigned char          *dsr_shadow;
+       volatile unsigned char *cd_port;
+       unsigned char          *cd_shadow;
+
+       unsigned char dtr_mask;
+       unsigned char ri_mask;
+       unsigned char dsr_mask;
+       unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+       /* Ser 0 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+       E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+       E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+       E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+       E100_STRUCT_MASK(0,DTR),
+       E100_STRUCT_MASK(0,RI),
+       E100_STRUCT_MASK(0,DSR),
+       E100_STRUCT_MASK(0,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+       },
+
+       /* Ser 1 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+       E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+       E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+       E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+       E100_STRUCT_MASK(1,DTR),
+       E100_STRUCT_MASK(1,RI),
+       E100_STRUCT_MASK(1,DSR),
+       E100_STRUCT_MASK(1,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+       },
+
+       /* Ser 2 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+       E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+       E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+       E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+       E100_STRUCT_MASK(2,DTR),
+       E100_STRUCT_MASK(2,RI),
+       E100_STRUCT_MASK(2,DSR),
+       E100_STRUCT_MASK(2,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+       },
+
+       /* Ser 3 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+       E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+       E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+       E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+       E100_STRUCT_MASK(3,DTR),
+       E100_STRUCT_MASK(3,RI),
+       E100_STRUCT_MASK(3,DSR),
+       E100_STRUCT_MASK(3,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+       }
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+
+
+struct control_pins
+{
+       volatile unsigned char *port;
+       unsigned char          *shadow;
+
+       unsigned char dtr_mask;
+       unsigned char ri_mask;
+       unsigned char dsr_mask;
+       unsigned char cd_mask;
+};
+
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+       /* Ser 0 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+       E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+       E100_STRUCT_MASK(0,DTR),
+       E100_STRUCT_MASK(0,RI),
+       E100_STRUCT_MASK(0,DSR),
+       E100_STRUCT_MASK(0,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(0)
+#endif
+       },
+
+       /* Ser 1 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+       E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+       E100_STRUCT_MASK(1,DTR),
+       E100_STRUCT_MASK(1,RI),
+       E100_STRUCT_MASK(1,DSR),
+       E100_STRUCT_MASK(1,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(1)
+#endif
+       },
+
+       /* Ser 2 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+       E100_STRUCT_MASK(2,DTR),
+       E100_STRUCT_MASK(2,RI),
+       E100_STRUCT_MASK(2,DSR),
+       E100_STRUCT_MASK(2,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(2)
+#endif
+       },
+
+       /* Ser 3 */
+       {
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+       E100_STRUCT_MASK(3,DTR),
+       E100_STRUCT_MASK(3,RI),
+       E100_STRUCT_MASK(3,DSR),
+       E100_STRUCT_MASK(3,CD)
+#else
+       CONTROL_PINS_PORT_NOT_USED(3)
+#endif
+       }
+};
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+#define E100_RTS_MASK 0x20
+#define E100_CTS_MASK 0x40
+
+/* All serial port signals are active low:
+ * active   = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
+ * inactive = 1 -> 0V   to RS-232 driver -> +12V on RS-232 level
+ *
+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
+ */
+
+/* Output */
+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
+/* Input */
+#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK)
+
+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
+/* Is an output */
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
+
+/* Normally inputs */
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
+
+/* Input */
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
+
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs 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;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+/* Calculate the chartime depending on baudrate, numbor of bits etc. */
+static void update_char_time(struct e100_serial * info)
+{
+       tcflag_t cflags = info->tty->termios->c_cflag;
+       int bits;
+
+       /* calc. number of bits / data byte */
+       /* databits + startbit and 1 stopbit */
+       if ((cflags & CSIZE) == CS7)
+               bits = 9;
+       else
+               bits = 10;
+
+       if (cflags & CSTOPB)     /* 2 stopbits ? */
+               bits++;
+
+       if (cflags & PARENB)     /* parity bit ? */
+               bits++;
+
+       /* calc timeout */
+       info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
+       info->flush_time_usec = 4*info->char_time_usec;
+       if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
+               info->flush_time_usec = MIN_FLUSH_TIME_USEC;
+
+}
+
+/*
+ * This function maps from the Bxxxx defines in asm/termbits.h into real
+ * baud rates.
+ */
+
+static int
+cflag_to_baud(unsigned int cflag)
+{
+       static int baud_table[] = {
+               0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+               4800, 9600, 19200, 38400 };
+
+       static int ext_baud_table[] = {
+               0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000,
+                0, 0, 0, 0, 0, 0, 0, 0 };
+
+       if (cflag & CBAUDEX)
+               return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+       else
+               return baud_table[cflag & CBAUD];
+}
+
+/* and this maps to an etrax100 hardware baud constant */
+
+static unsigned char
+cflag_to_etrax_baud(unsigned int cflag)
+{
+       char retval;
+
+       static char baud_table[] = {
+               -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
+
+       static char ext_baud_table[] = {
+               -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+       if (cflag & CBAUDEX)
+               retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+       else
+               retval = baud_table[cflag & CBAUD];
+
+       if (retval < 0) {
+               printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag);
+               retval = 5; /* choose default 9600 instead */
+       }
+
+       return retval | (retval << 4); /* choose same for both TX and RX */
+}
+
+
+/* Various static support functions */
+
+/* Functions to set or clear DTR/RTS on the requested line */
+/* It is complicated by the fact that RTS is a serial port register, while
+ * DTR might not be implemented in the HW at all, and if it is, it can be on
+ * any general port.
+ */
+
+
+static inline void
+e100_dtr(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       unsigned char mask = e100_modem_pins[info->line].dtr_mask;
+
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
+       printk("ser%i shadow before 0x%02X get: %i\n",
+              info->line, *e100_modem_pins[info->line].dtr_shadow,
+              E100_DTR_GET(info));
+#endif
+       /* DTR is active low */
+       {
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+               *e100_modem_pins[info->line].dtr_shadow &= ~mask;
+               *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
+               restore_flags(flags);
+       }
+
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i shadow after 0x%02X get: %i\n",
+              info->line, *e100_modem_pins[info->line].dtr_shadow,
+              E100_DTR_GET(info));
+#endif
+#endif
+}
+
+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ *                                          0=0V    , 1=3.3V
+ */
+static inline void
+e100_rts(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       unsigned long flags;
+       save_flags(flags);
+       cli();
+       info->rx_ctrl &= ~E100_RTS_MASK;
+       info->rx_ctrl |= (set ? 0 : E100_RTS_MASK);  /* RTS is active low */
+       info->port[REG_REC_CTRL] = info->rx_ctrl;
+       restore_flags(flags);
+#ifdef SERIAL_DEBUG_IO
+       printk("ser%i rts %i\n", info->line, set);
+#endif
+#endif
+}
+
+
+/* If this behaves as a modem, RI and CD is an output */
+static inline void
+e100_ri_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* RI is active low */
+       {
+               unsigned char mask = e100_modem_pins[info->line].ri_mask;
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+               *e100_modem_pins[info->line].ri_shadow &= ~mask;
+               *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
+               restore_flags(flags);
+       }
+#endif
+}
+static inline void
+e100_cd_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* CD is active low */
+       {
+               unsigned char mask = e100_modem_pins[info->line].cd_mask;
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+               *e100_modem_pins[info->line].cd_shadow &= ~mask;
+               *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
+               *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
+               restore_flags(flags);
+       }
+#endif
+}
+
+static inline void
+e100_disable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* disable the receiver */
+       info->port[REG_REC_CTRL] =
+               (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+static inline void
+e100_enable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+       /* enable the receiver */
+       info->port[REG_REC_CTRL] =
+               (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
+#endif
+}
+
+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
+
+static inline void
+e100_disable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("rxdma_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
+}
+
+static inline void
+e100_enable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("rxdma_irq(%d): 1\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
+}
+
+/* the tx DMA uses only dma_descr interrupt */
+
+static _INLINE_ void
+e100_disable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("txdma_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_CLR = info->irq;
+}
+
+static _INLINE_ void
+e100_enable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("txdma_irq(%d): 1\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
+       *R_IRQ_MASK2_SET = info->irq;
+}
+
+static _INLINE_ void
+e100_disable_txdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       /* Disable output DMA channel for the serial port in question
+        * ( set to something other then serialX)
+        */
+       save_flags(flags);
+       cli();
+       DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
+       if (info->line == 0) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
+                   IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
+               }
+       } else if (info->line == 1) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
+                   IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
+               }
+       } else if (info->line == 2) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
+                   IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
+               }
+       } else if (info->line == 3) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
+                   IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
+               }
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       restore_flags(flags);
+}
+
+
+static _INLINE_ void
+e100_enable_txdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
+       /* Enable output DMA channel for the serial port in question */
+       if (info->line == 0) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma6);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0);
+       } else if (info->line == 1) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma8);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1);
+       } else if (info->line == 2) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma2);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2);
+       } else if (info->line == 3) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma4);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       restore_flags(flags);
+}
+
+static _INLINE_ void
+e100_disable_rxdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       /* Disable input DMA channel for the serial port in question
+        * ( set to something other then serialX)
+        */
+       save_flags(flags);
+       cli();
+       if (info->line == 0) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
+                   IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
+               }
+       } else if (info->line == 1) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
+                   IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
+               }
+       } else if (info->line == 2) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
+                   IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
+               }
+       } else if (info->line == 3) {
+               if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
+                   IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
+                       genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+                       genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
+               }
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       restore_flags(flags);
+}
+
+
+static _INLINE_ void
+e100_enable_rxdma_channel(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       /* Enable input DMA channel for the serial port in question */
+       if (info->line == 0) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma7);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
+       } else if (info->line == 1) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma9);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
+       } else if (info->line == 2) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma3);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
+       } else if (info->line == 3) {
+               genconfig_shadow &=  ~IO_MASK(R_GEN_CONFIG, dma5);
+               genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
+       }
+       *R_GEN_CONFIG = genconfig_shadow;
+       restore_flags(flags);
+}
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+/* in order to detect and fix errors on the first byte
+   we have to use the serial interrupts as well. */
+
+static inline void
+e100_disable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
+       *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
+}
+
+static inline void
+e100_enable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_irq(%d): 1\n",info->line);
+       printk("**** %d = %d\n",
+              (8+2*info->line),
+              (1U << (8+2*info->line)));
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
+       *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
+}
+#endif
+
+static inline void
+e100_disable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_tx_irq(%d): 0\n",info->line);
+#endif
+       DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
+       *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
+}
+
+static inline void
+e100_enable_serial_tx_ready_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+       printk("ser_tx_irq(%d): 1\n",info->line);
+       printk("**** %d = %d\n",
+              (8+1+2*info->line),
+              (1U << (8+1+2*info->line)));
+#endif
+       DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
+       *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
+}
+
+static inline void e100_enable_rx_irq(struct e100_serial *info)
+{
+       if (info->uses_dma_in)
+               e100_enable_rxdma_irq(info);
+       else
+               e100_enable_serial_data_irq(info);
+}
+static inline void e100_disable_rx_irq(struct e100_serial *info)
+{
+       if (info->uses_dma_in)
+               e100_disable_rxdma_irq(info);
+       else
+               e100_disable_serial_data_irq(info);
+}
+
+#if defined(CONFIG_ETRAX_RS485)
+/* Enable RS-485 mode on selected port. This is UGLY. */
+static int
+e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+       *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+       REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,
+                      rs485_port_g_bit, 1);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                      CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
+       REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                      CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
+#endif
+
+       info->rs485.rts_on_send = 0x01 & r->rts_on_send;
+       info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
+       if (r->delay_rts_before_send >= 1000)
+               info->rs485.delay_rts_before_send = 1000;
+       else
+               info->rs485.delay_rts_before_send = r->delay_rts_before_send;
+       info->rs485.enabled = r->enabled;
+/*     printk("rts: on send = %i, after = %i, enabled = %i",
+                   info->rs485.rts_on_send,
+                   info->rs485.rts_after_sent,
+                   info->rs485.enabled
+       );
+*/
+       return 0;
+}
+
+static int
+e100_write_rs485(struct tty_struct *tty, int from_user,
+                 const unsigned char *buf, int count)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       int old_enabled = info->rs485.enabled;
+
+       /* rs485 is always implicitly enabled if we're using the ioctl()
+        * but it doesn't have to be set in the rs485_control
+        * (to be backward compatible with old apps)
+        * So we store, set and restore it.
+        */
+       info->rs485.enabled = 1;
+       /* rs_write now deals with RS485 if enabled */
+       count = rs_write(tty, from_user, buf, count);
+       info->rs485.enabled = old_enabled;
+       return count;
+}
+
+#ifdef CONFIG_ETRAX_FAST_TIMER
+/* Timer function to toggle RTS when using FAST_TIMER */
+static void rs485_toggle_rts_timer_function(unsigned long data)
+{
+       struct e100_serial *info = (struct e100_serial *)data;
+
+       fast_timers_rs485[info->line].function = NULL;
+       e100_rts(info, info->rs485.rts_after_sent);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+       e100_enable_rx(info);
+       e100_enable_rx_irq(info);
+#endif
+}
+#endif
+#endif /* CONFIG_ETRAX_RS485 */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void
+rs_stop(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       if (info) {
+               unsigned long flags;
+               unsigned long xoff;
+
+               save_flags(flags); cli();
+               DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
+                               CIRC_CNT(info->xmit.head,
+                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
+
+               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+               if (tty->termios->c_iflag & IXON ) {
+                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+               }
+
+               *((unsigned long *)&info->port[REG_XOFF]) = xoff;
+               restore_flags(flags);
+       }
+}
+
+static void
+rs_start(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       if (info) {
+               unsigned long flags;
+               unsigned long xoff;
+
+               save_flags(flags); cli();
+               DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
+                               CIRC_CNT(info->xmit.head,
+                                        info->xmit.tail,SERIAL_XMIT_SIZE)));
+               xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+               if (tty->termios->c_iflag & IXON ) {
+                       xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+               }
+
+               *((unsigned long *)&info->port[REG_XOFF]) = xoff;
+               if (!info->uses_dma_out &&
+                   info->xmit.head != info->xmit.tail && info->xmit.buf)
+                       e100_enable_serial_tx_ready_irq(info);
+
+               restore_flags(flags);
+       }
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - 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 e100_serial *info,
+                                   int event)
+{
+       if (info->event & (1 << event))
+               return;
+       info->event |= 1 << event;
+       schedule_work(&info->work);
+}
+
+/* The output DMA channel is free - use it to send as many chars as possible
+ * NOTES:
+ *   We don't pay attention to info->x_char, which means if the TTY wants to
+ *   use XON/XOFF it will set info->x_char but we won't send any X char!
+ *
+ *   To implement this, we'd just start a DMA send of 1 byte pointing at a
+ *   buffer containing the X char, and skip updating xmit. We'd also have to
+ *   check if the last sent char was the X char when we enter this function
+ *   the next time, to avoid updating xmit with the sent X value.
+ */
+
+static void
+transmit_chars_dma(struct e100_serial *info)
+{
+       unsigned int c, sentl;
+       struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* This will output too little if tail is not 0 always since
+        * we don't reloop to send the other part. Anyway this SHOULD be a
+        * no-op - transmit_chars_dma would never really be called during sim
+        * since rs_write does not write into the xmit buffer then.
+        */
+       if (info->xmit.tail)
+               printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
+       if (info->xmit.head != info->xmit.tail) {
+               SIMCOUT(info->xmit.buf + info->xmit.tail,
+                       CIRC_CNT(info->xmit.head,
+                                info->xmit.tail,
+                                SERIAL_XMIT_SIZE));
+               info->xmit.head = info->xmit.tail;  /* move back head */
+               info->tr_running = 0;
+       }
+       return;
+#endif
+       /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+       *info->oclrintradr =
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+#ifdef SERIAL_DEBUG_INTR
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("tc\n");
+#endif
+       if (!info->tr_running) {
+               /* weirdo... we shouldn't get here! */
+               printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
+               return;
+       }
+
+       descr = &info->tr_descr;
+
+       /* first get the amount of bytes sent during the last DMA transfer,
+          and update xmit accordingly */
+
+       /* if the stop bit was not set, all data has been sent */
+       if (!(descr->status & d_stop)) {
+               sentl = descr->sw_len;
+       } else
+               /* otherwise we find the amount of data sent here */
+               sentl = descr->hw_len;
+
+       DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
+
+       /* update stats */
+       info->icount.tx += sentl;
+
+       /* update xmit buffer */
+       info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
+
+       /* if there is only a few chars left in the buf, wake up the blocked
+          write if any */
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+       /* find out the largest amount of consecutive bytes we want to send now */
+
+       c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+
+       /* Don't send all in one DMA transfer - divide it so we wake up
+        * application before all is sent
+        */
+
+       if (c >= 4*WAKEUP_CHARS)
+               c = c/2;
+
+       if (c <= 0) {
+               /* our job here is done, don't schedule any new DMA transfer */
+               info->tr_running = 0;
+
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+               if (info->rs485.enabled) {
+                       /* Set a short timer to toggle RTS */
+                       start_one_shot_timer(&fast_timers_rs485[info->line],
+                                            rs485_toggle_rts_timer_function,
+                                            (unsigned long)info,
+                                            info->char_time_usec*2,
+                                            "RS-485");
+               }
+#endif /* RS485 */
+               return;
+       }
+
+       /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
+       /* set up the descriptor correctly for output */
+       DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
+       descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
+       descr->sw_len = c;
+       descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
+       descr->status = 0;
+
+       *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
+       *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+       /* DMA is now running (hopefully) */
+} /* transmit_chars_dma */
+
+static void
+start_transmit(struct e100_serial *info)
+{
+#if 0
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("x\n");
+#endif
+
+       info->tr_descr.sw_len = 0;
+       info->tr_descr.hw_len = 0;
+       info->tr_descr.status = 0;
+       info->tr_running = 1;
+       if (info->uses_dma_out)
+               transmit_chars_dma(info);
+       else
+               e100_enable_serial_tx_ready_irq(info);
+} /* start_transmit */
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static int serial_fast_timer_started = 0;
+static int serial_fast_timer_expired = 0;
+static void flush_timeout_function(unsigned long data);
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
+  unsigned long timer_flags; \
+  save_flags(timer_flags); \
+  cli(); \
+  if (fast_timers[info->line].function == NULL) { \
+    serial_fast_timer_started++; \
+    TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
+    TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \
+    start_one_shot_timer(&fast_timers[info->line], \
+                         flush_timeout_function, \
+                         (unsigned long)info, \
+                         (usec), \
+                         string); \
+  } \
+  else { \
+    TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
+  } \
+  restore_flags(timer_flags); \
+}
+#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
+
+#else
+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
+#define START_FLUSH_FAST_TIMER(info, string)
+#endif
+
+static struct etrax_recv_buffer *
+alloc_recv_buffer(unsigned int size)
+{
+       struct etrax_recv_buffer *buffer;
+
+       if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
+               return NULL;
+
+       buffer->next = NULL;
+       buffer->length = 0;
+       buffer->error = TTY_NORMAL;
+
+       return buffer;
+}
+
+static void
+append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+
+       if (!info->first_recv_buffer)
+               info->first_recv_buffer = buffer;
+       else
+               info->last_recv_buffer->next = buffer;
+
+       info->last_recv_buffer = buffer;
+
+       info->recv_cnt += buffer->length;
+       if (info->recv_cnt > info->max_recv_cnt)
+               info->max_recv_cnt = info->recv_cnt;
+
+       restore_flags(flags);
+}
+
+static int
+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
+{
+       struct etrax_recv_buffer *buffer;
+       if (info->uses_dma_in) {
+               if (!(buffer = alloc_recv_buffer(4)))
+                       return 0;
+
+               buffer->length = 1;
+               buffer->error = flag;
+               buffer->buffer[0] = data;
+
+               append_recv_buffer(info, buffer);
+
+               info->icount.rx++;
+       } else {
+               struct tty_struct *tty = info->tty;
+               *tty->flip.char_buf_ptr = data;
+               *tty->flip.flag_buf_ptr = flag;
+               tty->flip.flag_buf_ptr++;
+               tty->flip.char_buf_ptr++;
+               tty->flip.count++;
+               info->icount.rx++;
+       }
+
+       return 1;
+}
+
+extern _INLINE_ unsigned int
+handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
+{
+       struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
+
+       if (info->recv_cnt + recvl > 65536) {
+               printk(KERN_CRIT
+                      "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl);
+               return 0;
+       }
+
+       buffer->length = recvl;
+
+       if (info->errorcode == ERRCODE_SET_BREAK)
+               buffer->error = TTY_BREAK;
+       info->errorcode = 0;
+
+       append_recv_buffer(info, buffer);
+
+       if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+               panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+
+       descr->buf = virt_to_phys(buffer->buffer);
+
+       return recvl;
+}
+
+static _INLINE_ unsigned int
+handle_all_descr_data(struct e100_serial *info)
+{
+       struct etrax_dma_descr *descr;
+       unsigned int recvl;
+       unsigned int ret = 0;
+
+       while (1)
+       {
+               descr = &info->rec_descr[info->cur_rec_descr];
+
+               if (descr == phys_to_virt(*info->idescradr))
+                       break;
+
+               if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS)
+                       info->cur_rec_descr = 0;
+
+               /* find out how many bytes were read */
+
+               /* if the eop bit was not set, all data has been received */
+               if (!(descr->status & d_eop)) {
+                       recvl = descr->sw_len;
+               } else {
+                       /* otherwise we find the amount of data received here */
+                       recvl = descr->hw_len;
+               }
+
+               /* Reset the status information */
+               descr->status = 0;
+
+               DFLOW(  DEBUG_LOG(info->line, "RX %lu\n", recvl);
+                       if (info->tty->stopped) {
+                               unsigned char *buf = phys_to_virt(descr->buf);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
+                               DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
+                       }
+                       );
+
+               /* update stats */
+               info->icount.rx += recvl;
+
+               ret += handle_descr_data(info, descr, recvl);
+       }
+
+       return ret;
+}
+
+static _INLINE_ void
+receive_chars_dma(struct e100_serial *info)
+{
+       struct tty_struct *tty;
+       unsigned char rstat;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       return;
+#endif
+
+       /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
+       *info->iclrintradr =
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+               IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+
+       tty = info->tty;
+       if (!tty) /* Something wrong... */
+               return;
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       if (info->uses_dma_in)
+               e100_enable_serial_data_irq(info);
+#endif
+
+       if (info->errorcode == ERRCODE_INSERT_BREAK)
+               add_char_and_flag(info, '\0', TTY_BREAK);
+
+       handle_all_descr_data(info);
+
+       /* Read the status register to detect errors */
+       rstat = info->port[REG_STATUS];
+       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
+       }
+
+       if (rstat & SER_ERROR_MASK) {
+               /* If we got an error, we must reset it by reading the
+                * data_in field
+                */
+               unsigned char data = info->port[REG_DATA];
+
+               PROCSTAT(ser_stat[info->line].errors_cnt++);
+               DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
+                         ((rstat & SER_ERROR_MASK) << 8) | data);
+
+               if (rstat & SER_PAR_ERR_MASK)
+                       add_char_and_flag(info, data, TTY_PARITY);
+               else if (rstat & SER_OVERRUN_MASK)
+                       add_char_and_flag(info, data, TTY_OVERRUN);
+               else if (rstat & SER_FRAMING_ERR_MASK)
+                       add_char_and_flag(info, data, TTY_FRAME);
+       }
+
+       START_FLUSH_FAST_TIMER(info, "receive_chars");
+
+       /* Restart the receiving DMA */
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+}
+
+static _INLINE_ int
+start_recv_dma(struct e100_serial *info)
+{
+       struct etrax_dma_descr *descr = info->rec_descr;
+       struct etrax_recv_buffer *buffer;
+        int i;
+
+       /* Set up the receiving descriptors */
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
+               if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+                       panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+
+               descr[i].ctrl = d_int;
+               descr[i].buf = virt_to_phys(buffer->buffer);
+               descr[i].sw_len = SERIAL_DESCR_BUF_SIZE;
+               descr[i].hw_len = 0;
+               descr[i].status = 0;
+               descr[i].next = virt_to_phys(&descr[i+1]);
+       }
+
+       /* Link the last descriptor to the first */
+       descr[i-1].next = virt_to_phys(&descr[0]);
+
+       /* Start with the first descriptor in the list */
+       info->cur_rec_descr = 0;
+
+       /* Start the DMA */
+       *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]);
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+
+       /* Input DMA should be running now */
+       return 1;
+}
+
+static void
+start_receive(struct e100_serial *info)
+{
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       return;
+#endif
+       info->tty->flip.count = 0;
+       if (info->uses_dma_in) {
+               /* reset the input dma channel to be sure it works */
+
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               start_recv_dma(info);
+       }
+}
+
+
+static _INLINE_ void
+status_handle(struct e100_serial *info, unsigned short status)
+{
+}
+
+/* the bits in the MASK2 register are laid out like this:
+   DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
+   where I is the input channel and O is the output channel for the port.
+   info->irq is the bit number for the DMAO_DESCR so to check the others we
+   shift info->irq to the left.
+*/
+
+/* dma output channel interrupt handler
+   this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
+   DMA8(ser1) when they have finished a descriptor with the intr flag set.
+*/
+
+static irqreturn_t
+tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct e100_serial *info;
+       unsigned long ireg;
+       int i;
+       int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       {
+               const char *s = "What? tr_interrupt in simulator??\n";
+               SIMCOUT(s,strlen(s));
+       }
+       return IRQ_HANDLED;
+#endif
+
+       /* find out the line that caused this irq and get it from rs_table */
+
+       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (!info->enabled || !info->uses_dma_out)
+                       continue;
+               /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
+               if (ireg & info->irq) {
+                       handled = 1;
+                       /* we can send a new dma bunch. make it so. */
+                       DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
+                       /* Read jiffies_usec first,
+                        * we want this time to be as late as possible
+                        */
+                       PROCSTAT(ser_stat[info->line].tx_dma_ints++);
+                       info->last_tx_active_usec = GET_JIFFIES_USEC();
+                       info->last_tx_active = jiffies;
+                       transmit_chars_dma(info);
+               }
+
+               /* FIXME: here we should really check for a change in the
+                  status lines and if so call status_handle(info) */
+       }
+       return IRQ_RETVAL(handled);
+} /* tr_interrupt */
+
+/* dma input channel interrupt handler */
+
+static irqreturn_t
+rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct e100_serial *info;
+       unsigned long ireg;
+       int i;
+       int handled = 0;
+
+#ifdef CONFIG_SVINTO_SIM
+       /* No receive in the simulator.  Will probably be when the rest of
+        * the serial interface works, and this piece will just be removed.
+        */
+       {
+               const char *s = "What? rec_interrupt in simulator??\n";
+               SIMCOUT(s,strlen(s));
+       }
+       return IRQ_HANDLED;
+#endif
+
+       /* find out the line that caused this irq and get it from rs_table */
+
+       ireg = *R_IRQ_MASK2_RD;  /* get the active irq bits for the dma channels */
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (!info->enabled || !info->uses_dma_in)
+                       continue;
+               /* check for both dma_eop and dma_descr for the input dma channel */
+               if (ireg & ((info->irq << 2) | (info->irq << 3))) {
+                       handled = 1;
+                       /* we have received something */
+                       receive_chars_dma(info);
+               }
+
+               /* FIXME: here we should really check for a change in the
+                  status lines and if so call status_handle(info) */
+       }
+       return IRQ_RETVAL(handled);
+} /* rec_interrupt */
+
+static _INLINE_ int
+force_eop_if_needed(struct e100_serial *info)
+{
+       /* We check data_avail bit to determine if data has
+        * arrived since last time
+        */
+       unsigned char rstat = info->port[REG_STATUS];
+
+       /* error or datavail? */
+       if (rstat & SER_ERROR_MASK) {
+               /* Some error has occurred. If there has been valid data, an
+                * EOP interrupt will be made automatically. If no data, the
+                * normal ser_interrupt should be enabled and handle it.
+                * So do nothing!
+                */
+               DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n",
+                         rstat | (info->line << 8));
+               return 0;
+       }
+
+       if (rstat & SER_DATA_AVAIL_MASK) {
+               /* Ok data, no error, count it */
+               TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n",
+                         rstat | (info->line << 8)));
+               /* Read data to clear status flags */
+               (void)info->port[REG_DATA];
+
+               info->forced_eop = 0;
+               START_FLUSH_FAST_TIMER(info, "magic");
+               return 0;
+       }
+
+       /* hit the timeout, force an EOP for the input
+        * dma channel if we haven't already
+        */
+       if (!info->forced_eop) {
+               info->forced_eop = 1;
+               PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
+               TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
+               FORCE_EOP(info);
+       }
+
+       return 1;
+}
+
+extern _INLINE_ void
+flush_to_flip_buffer(struct e100_serial *info)
+{
+       struct tty_struct *tty;
+       struct etrax_recv_buffer *buffer;
+       unsigned int length;
+       unsigned long flags;
+       int max_flip_size;
+
+       if (!info->first_recv_buffer)
+               return;
+
+       save_flags(flags);
+       cli();
+
+       if (!(tty = info->tty)) {
+               restore_flags(flags);
+               return;
+       }
+
+       length = tty->flip.count;
+       /* Don't flip more than the ldisc has room for.
+        * The return value from ldisc.receive_room(tty) - might not be up to
+        * date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the
+        * processed and not accounted for yet.
+        * Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way.
+        * Lets buffer data here and let flow control take care of it.
+        * Since we normally flip large chunks, the ldisc don't react
+        * with throttle until too late if we flip to much.
+        */
+       max_flip_size = tty->ldisc.receive_room(tty);
+       if (max_flip_size < 0)
+               max_flip_size = 0;
+       if (max_flip_size <= (TTY_FLIPBUF_SIZE +         /* Maybe not accounted for */
+                             length + info->recv_cnt +  /* We have this queued */
+                             2*SERIAL_DESCR_BUF_SIZE +    /* This could be on the way */
+                             TTY_THRESHOLD_THROTTLE)) { /* Some slack */
+               /* check TTY_THROTTLED first so it indicates our state */
+               if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
+                       DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size));
+                       rs_throttle(tty);
+               }
+#if 0
+               else if (max_flip_size <= (TTY_FLIPBUF_SIZE +         /* Maybe not accounted for */
+                                          length + info->recv_cnt +  /* We have this queued */
+                                          SERIAL_DESCR_BUF_SIZE +    /* This could be on the way */
+                                          TTY_THRESHOLD_THROTTLE)) { /* Some slack */
+                       DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size));
+                       rs_throttle(tty);
+               }
+#endif
+       }
+
+       if (max_flip_size > TTY_FLIPBUF_SIZE)
+               max_flip_size = TTY_FLIPBUF_SIZE;
+
+       while ((buffer = info->first_recv_buffer) && length < max_flip_size) {
+               unsigned int count = buffer->length;
+
+               if (length + count > max_flip_size)
+                       count = max_flip_size - length;
+
+               memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count);
+               memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count);
+               tty->flip.flag_buf_ptr[length] = buffer->error;
+
+               length += count;
+               info->recv_cnt -= count;
+               DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length));
+
+               if (count == buffer->length) {
+                       info->first_recv_buffer = buffer->next;
+                       kfree(buffer);
+               } else {
+                       buffer->length -= count;
+                       memmove(buffer->buffer, buffer->buffer + count, buffer->length);
+                       buffer->error = TTY_NORMAL;
+               }
+       }
+
+       if (!info->first_recv_buffer)
+               info->last_recv_buffer = NULL;
+
+       tty->flip.count = length;
+       DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) {
+               DEBUG_LOG(info->line, "ldisc %lu\n",
+                         tty->ldisc.chars_in_buffer(tty));
+               DEBUG_LOG(info->line, "flip.count %lu\n",
+                         tty->flip.count);
+             }
+             );
+       restore_flags(flags);
+
+       DFLIP(
+         if (1) {
+
+                 if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+                         DEBUG_LOG(info->line, "*** TTY_DONT_FLIP set flip.count %i ***\n", tty->flip.count);
+                         DEBUG_LOG(info->line, "*** recv_cnt %i\n", info->recv_cnt);
+                 } else {
+                 }
+                 DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
+                 DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
+                 DEBUG_LOG(info->line, "room  %lu\n", tty->ldisc.receive_room(tty));
+         }
+
+       );
+
+       /* this includes a check for low-latency */
+       tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void
+check_flush_timeout(struct e100_serial *info)
+{
+       /* Flip what we've got (if we can) */
+       flush_to_flip_buffer(info);
+
+       /* We might need to flip later, but not to fast
+        * since the system is busy processing input... */
+       if (info->first_recv_buffer)
+               START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
+
+       /* Force eop last, since data might have come while we're processing
+        * and if we started the slow timer above, we won't start a fast
+        * below.
+        */
+       force_eop_if_needed(info);
+}
+
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+static void flush_timeout_function(unsigned long data)
+{
+       struct e100_serial *info = (struct e100_serial *)data;
+
+       fast_timers[info->line].function = NULL;
+       serial_fast_timer_expired++;
+       TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line));
+       TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired));
+       check_flush_timeout(info);
+}
+
+#else
+
+/* dma fifo/buffer timeout handler
+   forces an end-of-packet for the dma input channel if no chars
+   have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s.
+*/
+
+static struct timer_list flush_timer;
+
+static void
+timed_flush_handler(unsigned long ptr)
+{
+       struct e100_serial *info;
+       int i;
+
+#ifdef CONFIG_SVINTO_SIM
+       return;
+#endif
+
+       for (i = 0; i < NR_PORTS; i++) {
+               info = rs_table + i;
+               if (info->uses_dma_in)
+                       check_flush_timeout(info);
+       }
+
+       /* restart flush timer */
+       mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+}
+#endif
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+
+/* If there is an error (ie break) when the DMA is running and
+ * there are no bytes in the fifo the DMA is stopped and we get no
+ * eop interrupt. Thus we have to monitor the first bytes on a DMA
+ * transfer, and if it is without error we can turn the serial
+ * interrupts off.
+ */
+
+/*
+BREAK handling on ETRAX 100:
+ETRAX will generate interrupt although there is no stop bit between the
+characters.
+
+Depending on how long the break sequence is, the end of the breaksequence
+will look differently:
+| indicates start/end of a character.
+
+B= Break character (0x00) with framing error.
+E= Error byte with parity error received after B characters.
+F= "Faked" valid byte received immediately after B characters.
+V= Valid byte
+
+1.
+    B          BL         ___________________________ V
+.._|__________|__________|                           |valid data |
+
+Multiple frame errors with data == 0x00 (B),
+the timing matches up "perfectly" so no extra ending char is detected.
+The RXD pin is 1 in the last interrupt, in that case
+we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really
+know if another byte will come and this really is case 2. below
+(e.g F=0xFF or 0xFE)
+If RXD pin is 0 we can expect another character (see 2. below).
+
+
+2.
+
+    B          B          E or F__________________..__ V
+.._|__________|__________|______    |                 |valid data
+                          "valid" or
+                          parity error
+
+Multiple frame errors with data == 0x00 (B),
+but the part of the break trigs is interpreted as a start bit (and possibly
+some 0 bits followed by a number of 1 bits and a stop bit).
+Depending on parity settings etc. this last character can be either
+a fake "valid" char (F) or have a parity error (E).
+
+If the character is valid it will be put in the buffer,
+we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt
+will set the flags so the tty will handle it,
+if it's an error byte it will not be put in the buffer
+and we set info->errorcode = ERRCODE_INSERT_BREAK.
+
+To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp
+of the last faulty char (B) and compares it with the current time:
+If the time elapsed time is less then 2*char_time_usec we will assume
+it's a faked F char and not a Valid char and set
+info->errorcode = ERRCODE_SET_BREAK.
+
+Flaws in the above solution:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We use the timer to distinguish a F character from a V character,
+if a V character is to close after the break we might make the wrong decision.
+
+TODO: The break will be delayed until an F or V character is received.
+
+*/
+
+extern _INLINE_
+struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
+{
+       unsigned long data_read;
+       struct tty_struct *tty = info->tty;
+
+       if (!tty) {
+               printk("!NO TTY!\n");
+               return info;
+       }
+       if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) {
+               /* check TTY_THROTTLED first so it indicates our state */
+               if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
+                       DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count));
+                       rs_throttle(tty);
+               }
+       }
+       if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+               DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count);
+               tty->flip.work.func((void *) tty);
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                       DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count);
+                       return info;            /* if TTY_DONT_FLIP is set */
+               }
+       }
+       /* Read data and status at the same time */
+       data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
+more_data:
+       if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+       }
+       DINTR2(DEBUG_LOG(info->line, "ser_rx   %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
+
+       if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
+                         IO_MASK(R_SERIAL0_READ, par_err) |
+                         IO_MASK(R_SERIAL0_READ, overrun) )) {
+               /* An error */
+               info->last_rx_active_usec = GET_JIFFIES_USEC();
+               info->last_rx_active = jiffies;
+               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
+               DLOG_INT_TRIG(
+               if (!log_int_trig1_pos) {
+                       log_int_trig1_pos = log_int_pos;
+                       log_int(rdpc(), 0, 0);
+               }
+               );
+
+
+               if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
+                    (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
+                       /* Most likely a break, but we get interrupts over and
+                        * over again.
+                        */
+
+                       if (!info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "#BRK start\n", 0);
+                       }
+                       if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
+                               /* The RX pin is high now, so the break
+                                * must be over, but....
+                                * we can't really know if we will get another
+                                * last byte ending the break or not.
+                                * And we don't know if the byte (if any) will
+                                * have an error or look valid.
+                                */
+                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       }
+                       info->break_detected_cnt++;
+               } else {
+                       /* The error does not look like a break, but could be
+                        * the end of one
+                        */
+                       if (info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       } else {
+                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
+                                       info->icount.brk++;
+                                       *tty->flip.char_buf_ptr = 0;
+                                       *tty->flip.flag_buf_ptr = TTY_BREAK;
+                                       tty->flip.flag_buf_ptr++;
+                                       tty->flip.char_buf_ptr++;
+                                       tty->flip.count++;
+                                       info->icount.rx++;
+                               }
+                               *tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
+
+                               if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
+                                       info->icount.parity++;
+                                       *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
+                                       info->icount.overrun++;
+                                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                               } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
+                                       info->icount.frame++;
+                                       *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               }
+                               info->errorcode = 0;
+                       }
+                       info->break_detected_cnt = 0;
+               }
+       } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+               /* No error */
+               DLOG_INT_TRIG(
+               if (!log_int_trig1_pos) {
+                       if (log_int_pos >= log_int_size) {
+                               log_int_pos = 0;
+                       }
+                       log_int_trig0_pos = log_int_pos;
+                       log_int(rdpc(), 0, 0);
+               }
+               );
+               *tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
+               *tty->flip.flag_buf_ptr = 0;
+       } else {
+               DEBUG_LOG(info->line, "ser_rx int but no data_avail  %08lX\n", data_read);
+       }
+
+
+       tty->flip.flag_buf_ptr++;
+       tty->flip.char_buf_ptr++;
+       tty->flip.count++;
+       info->icount.rx++;
+       data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
+       if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
+               DEBUG_LOG(info->line, "ser_rx   %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
+               goto more_data;
+       }
+
+       tty_flip_buffer_push(info->tty);
+       return info;
+}
+
+extern _INLINE_
+struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
+{
+       unsigned char rstat;
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("Interrupt from serport %d\n", i);
+#endif
+/*     DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
+       if (!info->uses_dma_in) {
+               return handle_ser_rx_interrupt_no_dma(info);
+       }
+       /* DMA is used */
+       rstat = info->port[REG_STATUS];
+       if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
+               DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
+       }
+
+       if (rstat & SER_ERROR_MASK) {
+               unsigned char data;
+
+               info->last_rx_active_usec = GET_JIFFIES_USEC();
+               info->last_rx_active = jiffies;
+               /* If we got an error, we must reset it by reading the
+                * data_in field
+                */
+               data = info->port[REG_DATA];
+               DINTR1(DEBUG_LOG(info->line, "ser_rx!  %c\n", data));
+               DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
+               if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
+                       /* Most likely a break, but we get interrupts over and
+                        * over again.
+                        */
+
+                       if (!info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "#BRK start\n", 0);
+                       }
+                       if (rstat & SER_RXD_MASK) {
+                               /* The RX pin is high now, so the break
+                                * must be over, but....
+                                * we can't really know if we will get another
+                                * last byte ending the break or not.
+                                * And we don't know if the byte (if any) will
+                                * have an error or look valid.
+                                */
+                               DEBUG_LOG(info->line, "# BL BRK\n", 0);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       }
+                       info->break_detected_cnt++;
+               } else {
+                       /* The error does not look like a break, but could be
+                        * the end of one
+                        */
+                       if (info->break_detected_cnt) {
+                               DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
+                               info->errorcode = ERRCODE_INSERT_BREAK;
+                       } else {
+                               if (info->errorcode == ERRCODE_INSERT_BREAK) {
+                                       info->icount.brk++;
+                                       add_char_and_flag(info, '\0', TTY_BREAK);
+                               }
+
+                               if (rstat & SER_PAR_ERR_MASK) {
+                                       info->icount.parity++;
+                                       add_char_and_flag(info, data, TTY_PARITY);
+                               } else if (rstat & SER_OVERRUN_MASK) {
+                                       info->icount.overrun++;
+                                       add_char_and_flag(info, data, TTY_OVERRUN);
+                               } else if (rstat & SER_FRAMING_ERR_MASK) {
+                                       info->icount.frame++;
+                                       add_char_and_flag(info, data, TTY_FRAME);
+                               }
+
+                               info->errorcode = 0;
+                       }
+                       info->break_detected_cnt = 0;
+                       DEBUG_LOG(info->line, "#iERR s d %04X\n",
+                                 ((rstat & SER_ERROR_MASK) << 8) | data);
+               }
+               PROCSTAT(ser_stat[info->line].early_errors_cnt++);
+       } else { /* It was a valid byte, now let the DMA do the rest */
+               unsigned long curr_time_u = GET_JIFFIES_USEC();
+               unsigned long curr_time = jiffies;
+
+               if (info->break_detected_cnt) {
+                       /* Detect if this character is a new valid char or the
+                        * last char in a break sequence: If LSBits are 0 and
+                        * MSBits are high AND the time is close to the
+                        * previous interrupt we should discard it.
+                        */
+                       long elapsed_usec =
+                         (curr_time - info->last_rx_active) * (1000000/HZ) +
+                         curr_time_u - info->last_rx_active_usec;
+                       if (elapsed_usec < 2*info->char_time_usec) {
+                               DEBUG_LOG(info->line, "FBRK %i\n", info->line);
+                               /* Report as BREAK (error) and let
+                                * receive_chars_dma() handle it
+                                */
+                               info->errorcode = ERRCODE_SET_BREAK;
+                       } else {
+                               DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line);
+                       }
+                       DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt);
+               }
+
+#ifdef SERIAL_DEBUG_INTR
+               printk("** OK, disabling ser_interrupts\n");
+#endif
+               e100_disable_serial_data_irq(info);
+               DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
+               info->break_detected_cnt = 0;
+
+               PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
+       }
+       /* Restarting the DMA never hurts */
+       *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
+       START_FLUSH_FAST_TIMER(info, "ser_int");
+       return info;
+} /* handle_ser_rx_interrupt */
+
+extern _INLINE_ void handle_ser_tx_interrupt(struct e100_serial *info)
+{
+       unsigned long flags;
+
+       if (info->x_char) {
+               unsigned char rstat;
+               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
+               save_flags(flags); cli();
+               rstat = info->port[REG_STATUS];
+               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+
+               info->port[REG_TR_DATA] = info->x_char;
+               info->icount.tx++;
+               info->x_char = 0;
+               /* We must enable since it is disabled in ser_interrupt */
+               e100_enable_serial_tx_ready_irq(info);
+               restore_flags(flags);
+               return;
+       }
+       if (info->uses_dma_out) {
+               unsigned char rstat;
+               int i;
+               /* We only use normal tx interrupt when sending x_char */
+               DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
+               save_flags(flags); cli();
+               rstat = info->port[REG_STATUS];
+               DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
+               e100_disable_serial_tx_ready_irq(info);
+               if (info->tty->stopped)
+                       rs_stop(info->tty);
+               /* Enable the DMA channel and tell it to continue */
+               e100_enable_txdma_channel(info);
+               /* Wait 12 cycles before doing the DMA command */
+               for(i = 6;  i > 0; i--)
+                       nop();
+
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
+               restore_flags(flags);
+               return;
+       }
+       /* Normal char-by-char interrupt */
+       if (info->xmit.head == info->xmit.tail
+           || info->tty->stopped
+           || info->tty->hw_stopped) {
+               DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", info->tty->stopped));
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+               return;
+       }
+       DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
+       /* Send a byte, rs485 timing is critical so turn of ints */
+       save_flags(flags); cli();
+       info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
+       info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+       info->icount.tx++;
+       if (info->xmit.head == info->xmit.tail) {
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
+               if (info->rs485.enabled) {
+                       /* Set a short timer to toggle RTS */
+                       start_one_shot_timer(&fast_timers_rs485[info->line],
+                                            rs485_toggle_rts_timer_function,
+                                            (unsigned long)info,
+                                            info->char_time_usec*2,
+                                            "RS-485");
+               }
+#endif /* RS485 */
+               info->last_tx_active_usec = GET_JIFFIES_USEC();
+               info->last_tx_active = jiffies;
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+               DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
+       } else {
+               /* We must enable since it is disabled in ser_interrupt */
+               e100_enable_serial_tx_ready_irq(info);
+       }
+       restore_flags(flags);
+
+       if (CIRC_CNT(info->xmit.head,
+                    info->xmit.tail,
+                    SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+} /* handle_ser_tx_interrupt */
+
+/* result of time measurements:
+ * RX duration 54-60 us when doing something, otherwise 6-9 us
+ * ser_int duration: just sending: 8-15 us normally, up to 73 us
+ */
+static irqreturn_t
+ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       static volatile int tx_started = 0;
+       struct e100_serial *info;
+       int i;
+       unsigned long flags;
+       unsigned long irq_mask1_rd;
+       unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
+       int handled = 0;
+       static volatile unsigned long reentered_ready_mask = 0;
+
+       save_flags(flags); cli();
+       irq_mask1_rd = *R_IRQ_MASK1_RD;
+       /* First handle all rx interrupts with ints disabled */
+       info = rs_table;
+       irq_mask1_rd &= e100_ser_int_mask;
+       for (i = 0; i < NR_PORTS; i++) {
+               /* Which line caused the data irq? */
+               if (irq_mask1_rd & data_mask) {
+                       handled = 1;
+                       handle_ser_rx_interrupt(info);
+               }
+               info += 1;
+               data_mask <<= 2;
+       }
+       /* Handle tx interrupts with interrupts enabled so we
+        * can take care of new data interrupts while transmitting
+        * We protect the tx part with the tx_started flag.
+        * We disable the tr_ready interrupts we are about to handle and
+        * unblock the serial interrupt so new serial interrupts may come.
+        *
+        * If we get a new interrupt:
+        *  - it migth be due to synchronous serial ports.
+        *  - serial irq will be blocked by general irq handler.
+        *  - async data will be handled above (sync will be ignored).
+        *  - tx_started flag will prevent us from trying to send again and
+        *    we will exit fast - no need to unblock serial irq.
+        *  - Next (sync) serial interrupt handler will be runned with
+        *    disabled interrupt due to restore_flags() at end of function,
+        *    so sync handler will not be preempted or reentered.
+        */
+       if (!tx_started) {
+               unsigned long ready_mask;
+               unsigned long
+               tx_started = 1;
+               /* Only the tr_ready interrupts left */
+               irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+                                IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+               while (irq_mask1_rd) {
+                       /* Disable those we are about to handle */
+                       *R_IRQ_MASK1_CLR = irq_mask1_rd;
+                       /* Unblock the serial interrupt */
+                       *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+                       sti();
+                       ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
+                       info = rs_table;
+                       for (i = 0; i < NR_PORTS; i++) {
+                               /* Which line caused the ready irq? */
+                               if (irq_mask1_rd & ready_mask) {
+                                       handled = 1;
+                                       handle_ser_tx_interrupt(info);
+                               }
+                               info += 1;
+                               ready_mask <<= 2;
+                       }
+                       /* handle_ser_tx_interrupt enables tr_ready interrupts */
+                       cli();
+                       /* Handle reentered TX interrupt */
+                       irq_mask1_rd = reentered_ready_mask;
+               }
+               cli();
+               tx_started = 0;
+       } else {
+               unsigned long ready_mask;
+               ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
+                                            IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
+               if (ready_mask) {
+                       reentered_ready_mask |= ready_mask;
+                       /* Disable those we are about to handle */
+                       *R_IRQ_MASK1_CLR = ready_mask;
+                       DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
+               }
+       }
+
+       restore_flags(flags);
+       return IRQ_RETVAL(handled);
+} /* ser_interrupt */
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void
+do_softint(void *private_)
+{
+       struct e100_serial      *info = (struct e100_serial *) private_;
+       struct tty_struct       *tty;
+
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+               wake_up_interruptible(&tty->write_wait);
+       }
+}
+
+static int
+startup(struct e100_serial * info)
+{
+       unsigned long flags;
+       unsigned long xmit_page;
+       int i;
+
+       xmit_page = get_zeroed_page(GFP_KERNEL);
+       if (!xmit_page)
+               return -ENOMEM;
+
+       save_flags(flags);
+       cli();
+
+       /* if it was already initialized, skip this */
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               restore_flags(flags);
+               free_page(xmit_page);
+               return 0;
+       }
+
+       if (info->xmit.buf)
+               free_page(xmit_page);
+       else
+               info->xmit.buf = (unsigned char *) xmit_page;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+       /* Bits and pieces collected from below.  Better to have them
+          in one ifdef:ed clause than to mix in a lot of ifdefs,
+          right? */
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->xmit.head = info->xmit.tail = 0;
+       info->first_recv_buffer = info->last_recv_buffer = NULL;
+       info->recv_cnt = info->max_recv_cnt = 0;
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               info->rec_descr[i].buf = NULL;
+
+       /* No real action in the simulator, but may set info important
+          to ioctl. */
+       change_speed(info);
+#else
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+
+       /*
+        * Reset the DMA channels and make sure their interrupts are cleared
+        */
+
+       if (info->dma_in_enabled) {
+               info->uses_dma_in = 1;
+               e100_enable_rxdma_channel(info);
+
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+               /* Wait until reset cycle is complete */
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               /* Make sure the irqs are cleared */
+               *info->iclrintradr =
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+       } else {
+               e100_disable_rxdma_channel(info);
+       }
+
+       if (info->dma_out_enabled) {
+               info->uses_dma_out = 1;
+               e100_enable_txdma_channel(info);
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+               /* Make sure the irqs are cleared */
+               *info->oclrintradr =
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+                       IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+       } else {
+               e100_disable_txdma_channel(info);
+       }
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->xmit.head = info->xmit.tail = 0;
+       info->first_recv_buffer = info->last_recv_buffer = NULL;
+       info->recv_cnt = info->max_recv_cnt = 0;
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               info->rec_descr[i].buf = 0;
+
+       /*
+        * and set the speed and other flags of the serial port
+        * this will start the rx/tx as well
+        */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       e100_enable_serial_data_irq(info);
+#endif
+       change_speed(info);
+
+       /* dummy read to reset any serial errors */
+
+       (void)info->port[REG_DATA];
+
+       /* enable the interrupts */
+       if (info->uses_dma_out)
+               e100_enable_txdma_irq(info);
+
+       e100_enable_rx_irq(info);
+
+       info->tr_running = 0; /* to be sure we don't lock up the transmitter */
+
+       /* setup the dma input descriptor and start dma */
+
+       start_receive(info);
+
+       /* for safety, make sure the descriptors last result is 0 bytes written */
+
+       info->tr_descr.sw_len = 0;
+       info->tr_descr.hw_len = 0;
+       info->tr_descr.status = 0;
+
+       /* enable RTS/DTR last */
+
+       e100_rts(info, 1);
+       e100_dtr(info, 1);
+
+#endif /* CONFIG_SVINTO_SIM */
+
+       info->flags |= ASYNC_INITIALIZED;
+
+       restore_flags(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 e100_serial * info)
+{
+       unsigned long flags;
+       struct etrax_dma_descr *descr = info->rec_descr;
+       struct etrax_recv_buffer *buffer;
+       int i;
+
+#ifndef CONFIG_SVINTO_SIM
+       /* shut down the transmitter and receiver */
+       DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
+       e100_disable_rx(info);
+       info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
+
+       /* disable interrupts, reset dma channels */
+       if (info->uses_dma_in) {
+               e100_disable_rxdma_irq(info);
+               *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               info->uses_dma_in = 0;
+       } else {
+               e100_disable_serial_data_irq(info);
+       }
+
+       if (info->uses_dma_out) {
+               e100_disable_txdma_irq(info);
+               info->tr_running = 0;
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+               info->uses_dma_out = 0;
+       } else {
+               e100_disable_serial_tx_ready_irq(info);
+               info->tr_running = 0;
+       }
+
+#endif /* CONFIG_SVINTO_SIM */
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial port %d (irq %d)....\n", info->line,
+              info->irq);
+#endif
+
+       save_flags(flags);
+       cli(); /* Disable interrupts */
+
+       if (info->xmit.buf) {
+               free_page((unsigned long)info->xmit.buf);
+               info->xmit.buf = NULL;
+       }
+
+       for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
+               if (descr[i].buf) {
+                       buffer = phys_to_virt(descr[i].buf) - sizeof *buffer;
+                       kfree(buffer);
+                       descr[i].buf = 0;
+               }
+
+       if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+               /* hang up DTR and RTS if HUPCL is enabled */
+               e100_dtr(info, 0);
+               e100_rts(info, 0); /* could check CRTSCTS before doing this */
+       }
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       info->flags &= ~ASYNC_INITIALIZED;
+       restore_flags(flags);
+}
+
+
+/* change baud rate and other assorted parameters */
+
+static void
+change_speed(struct e100_serial *info)
+{
+       unsigned int cflag;
+       unsigned long xoff;
+       unsigned long flags;
+       /* first some safety checks */
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       if (!info->port)
+               return;
+
+       cflag = info->tty->termios->c_cflag;
+
+       /* possibly, the tx/rx should be disabled first to do this safely */
+
+       /* change baud-rate and write it to the hardware */
+       if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+               /* Special baudrate */
+               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+               unsigned long alt_source =
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+               /* R_ALT_SER_BAUDRATE selects the source */
+               DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
+                      (unsigned long)info->baud_base, info->custom_divisor));
+               if (info->baud_base == SERIAL_PRESCALE_BASE) {
+                       /* 0, 2-65535 (0=65536) */
+                       u16 divisor = info->custom_divisor;
+                       /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
+                       /* baudrate is 3.125MHz/custom_divisor */
+                       alt_source =
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
+                               IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
+                       alt_source = 0x11;
+                       DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
+                       *R_SERIAL_PRESCALE = divisor;
+                       info->baud = SERIAL_PRESCALE_BASE/divisor;
+               }
+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
+               else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
+                         info->custom_divisor == 1) ||
+                        (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
+                         info->custom_divisor == 8)) {
+                               /* ext_clk selected */
+                               alt_source =
+                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
+                                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
+                               DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
+                               info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
+                       }
+               }
+#endif
+               else
+               {
+                       /* Bad baudbase, we don't support using timer0
+                        * for baudrate.
+                        */
+                       printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
+                              (unsigned long)info->baud_base, info->custom_divisor);
+               }
+               r_alt_ser_baudrate_shadow &= ~mask;
+               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+       } else {
+               /* Normal baudrate */
+               /* Make sure we use normal baudrate */
+               u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
+               unsigned long alt_source =
+                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
+                       IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
+               r_alt_ser_baudrate_shadow &= ~mask;
+               r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
+#ifndef CONFIG_SVINTO_SIM
+               *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
+#endif /* CONFIG_SVINTO_SIM */
+
+               info->baud = cflag_to_baud(cflag);
+#ifndef CONFIG_SVINTO_SIM
+               info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
+#endif /* CONFIG_SVINTO_SIM */
+       }
+
+#ifndef CONFIG_SVINTO_SIM
+       /* start with default settings and then fill in changes */
+       save_flags(flags);
+       cli();
+       /* 8 bit, no/even parity */
+       info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
+                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
+                          IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
+
+       /* 8 bit, no/even parity, 1 stop bit, no cts */
+       info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
+                          IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
+
+       if ((cflag & CSIZE) == CS7) {
+               /* set 7 bit mode */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
+       }
+
+       if (cflag & CSTOPB) {
+               /* set 2 stop bit mode */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
+       }
+
+       if (cflag & PARENB) {
+               /* enable parity */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
+       }
+
+       if (cflag & CMSPAR) {
+               /* enable stick parity, PARODD mean Mark which matches ETRAX */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
+       }
+       if (cflag & PARODD) {
+               /* set odd parity (or Mark if CMSPAR) */
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
+               info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
+       }
+
+       if (cflag & CRTSCTS) {
+               /* enable automatic CTS handling */
+               DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
+               info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
+       }
+
+       /* make sure the tx and rx are enabled */
+
+       info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
+       info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+
+       /* actually write the control regs to the hardware */
+
+       info->port[REG_TR_CTRL] = info->tx_ctrl;
+       info->port[REG_REC_CTRL] = info->rx_ctrl;
+       xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+       xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+       if (info->tty->termios->c_iflag & IXON ) {
+               DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->tty)));
+               xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+       }
+
+       *((unsigned long *)&info->port[REG_XOFF]) = xoff;
+       restore_flags(flags);
+#endif /* !CONFIG_SVINTO_SIM */
+
+       update_char_time(info);
+
+} /* change_speed */
+
+/* start transmitting chars NOW */
+
+static void
+rs_flush_chars(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (info->tr_running ||
+           info->xmit.head == info->xmit.tail ||
+           tty->stopped ||
+           tty->hw_stopped ||
+           !info->xmit.buf)
+               return;
+
+#ifdef SERIAL_DEBUG_FLOW
+       printk("rs_flush_chars\n");
+#endif
+
+       /* this protection might not exactly be necessary here */
+
+       save_flags(flags);
+       cli();
+       start_transmit(info);
+       restore_flags(flags);
+}
+
+extern _INLINE_ int
+rs_raw_write(struct tty_struct * tty, int from_user,
+         const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       /* first some sanity checks */
+
+       if (!tty || !info->xmit.buf || !tmp_buf)
+               return 0;
+
+#ifdef SERIAL_DEBUG_DATA
+       if (info->line == SERIAL_DEBUG_LINE)
+               printk("rs_raw_write (%d), status %d\n",
+                      count, info->port[REG_STATUS]);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+       /* Really simple.  The output is here and now. */
+       SIMCOUT(buf, count);
+       return count;
+#endif
+       save_flags(flags);
+       DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
+       DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
+
+
+       /* the cli/restore_flags pairs below are needed because the
+        * DMA interrupt handler moves the info->xmit values. the memcpy
+        * needs to be in the critical region unfortunately, because we
+        * need to read xmit values, memcpy, write xmit values in one
+        * atomic operation... this could perhaps be avoided by more clever
+        * design.
+        */
+       if (from_user) {
+               down(&tmp_buf_sem);
+               while (1) {
+                       int c1;
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+                       if (count < c)
+                               c = count;
+                       if (c <= 0)
+                               break;
+
+                       c -= copy_from_user(tmp_buf, buf, c);
+                       if (!c) {
+                               if (!ret)
+                                       ret = -EFAULT;
+                               break;
+                       }
+                       cli();
+                       c1 = CIRC_SPACE_TO_END(info->xmit.head,
+                                              info->xmit.tail,
+                                              SERIAL_XMIT_SIZE);
+                       if (c1 < c)
+                               c = c1;
+                       memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+                       info->xmit.head = ((info->xmit.head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       restore_flags(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               up(&tmp_buf_sem);
+       } else {
+               cli();
+               while (count) {
+                       c = CIRC_SPACE_TO_END(info->xmit.head,
+                                             info->xmit.tail,
+                                             SERIAL_XMIT_SIZE);
+
+                       if (count < c)
+                               c = count;
+                       if (c <= 0)
+                               break;
+
+                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
+                       info->xmit.head = (info->xmit.head + c) &
+                               (SERIAL_XMIT_SIZE-1);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               restore_flags(flags);
+       }
+
+       /* enable transmitter if not running, unless the tty is stopped
+        * this does not need IRQ protection since if tr_running == 0
+        * the IRQ's are not running anyway for this port.
+        */
+       DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
+
+       if (info->xmit.head != info->xmit.tail &&
+           !tty->stopped &&
+           !tty->hw_stopped &&
+           !info->tr_running) {
+               start_transmit(info);
+       }
+
+       return ret;
+} /* raw_raw_write() */
+
+static int
+rs_write(struct tty_struct * tty, int from_user,
+        const unsigned char *buf, int count)
+{
+#if defined(CONFIG_ETRAX_RS485)
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       if (info->rs485.enabled)
+       {
+               /* If we are in RS-485 mode, we need to toggle RTS and disable
+                * the receiver before initiating a DMA transfer
+                */
+#ifdef CONFIG_ETRAX_FAST_TIMER
+               /* Abort any started timer */
+               fast_timers_rs485[info->line].function = NULL;
+               del_fast_timer(&fast_timers_rs485[info->line]);
+#endif
+               e100_rts(info, info->rs485.rts_on_send);
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+               e100_disable_rx(info);
+               e100_enable_rx_irq(info);
+#endif
+
+               if (info->rs485.delay_rts_before_send > 0) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000);
+               }
+       }
+#endif /* CONFIG_ETRAX_RS485 */
+
+       count = rs_raw_write(tty, from_user, buf, count);
+
+#if defined(CONFIG_ETRAX_RS485)
+       if (info->rs485.enabled)
+       {
+               unsigned int val;
+               /* If we are in RS-485 mode the following has to be done:
+                * wait until DMA is ready
+                * wait on transmit shift register
+                * toggle RTS
+                * enable the receiver
+                */
+
+               /* Sleep until all sent */
+               tty_wait_until_sent(tty, 0);
+#ifdef CONFIG_ETRAX_FAST_TIMER
+               /* Now sleep a little more so that shift register is empty */
+               schedule_usleep(info->char_time_usec * 2);
+#endif
+               /* wait on transmit shift register */
+               do{
+                       get_lsr_info(info, &val);
+               }while (!(val & TIOCSER_TEMT));
+
+               e100_rts(info, info->rs485.rts_after_sent);
+
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
+               e100_enable_rx(info);
+               e100_enable_rxdma_irq(info);
+#endif
+       }
+#endif /* CONFIG_ETRAX_RS485 */
+
+       return count;
+} /* rs_write */
+
+
+/* how much space is available in the xmit buffer? */
+
+static int
+rs_write_room(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* How many chars are in the xmit buffer?
+ * This does not include any chars in the transmitter FIFO.
+ * Use wait_until_sent for waiting for FIFO drain.
+ */
+
+static int
+rs_chars_in_buffer(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* discard everything in the xmit buffer */
+
+static void
+rs_flush_buffer(struct tty_struct *tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       info->xmit.head = info->xmit.tail = 0;
+       restore_flags(flags);
+
+       wake_up_interruptible(&tty->write_wait);
+
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
+               (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ *
+ * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
+ * but we do it in handle_ser_tx_interrupt().
+ * We disable DMA channel and enable tx ready interrupt and write the
+ * character when possible.
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+       save_flags(flags); cli();
+       if (info->uses_dma_out) {
+               /* Put the DMA on hold and disable the channel */
+               *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
+               while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
+                      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
+               e100_disable_txdma_channel(info);
+       }
+
+       /* Must make sure transmitter is not stopped before we can transmit */
+       if (tty->stopped)
+               rs_start(tty);
+
+       /* Enable manual transmit interrupt and send from there */
+       DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
+       info->x_char = ch;
+       e100_enable_serial_tx_ready_irq(info);
+       restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * 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 e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+
+       printk("throttle %s: %lu....\n", tty_name(tty, buf),
+              (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+       DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
+
+       /* Do RTS before XOFF since XOFF might take some time */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               /* Turn off RTS line */
+               e100_rts(info, 0);
+       }
+       if (I_IXOFF(tty))
+               rs_send_xchar(tty, STOP_CHAR(tty));
+
+}
+
+static void
+rs_unthrottle(struct tty_struct * tty)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+
+       printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
+              (unsigned long)tty->ldisc.chars_in_buffer(tty));
+#endif
+       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
+       DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
+       /* Do RTS before XOFF since XOFF might take some time */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               /* Assert RTS line  */
+               e100_rts(info, 1);
+       }
+
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       rs_send_xchar(tty, START_CHAR(tty));
+       }
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+get_serial_info(struct e100_serial * info,
+               struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+
+       /* this is all probably wrong, there are a lot of fields
+        * here that we don't have in e100_serial and maybe we
+        * should set them to something else than 0.
+        */
+
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = (int)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 e100_serial *info,
+               struct serial_struct *new_info)
+{
+       struct serial_struct new_serial;
+       struct e100_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.type != info->type) ||
+                   (new_serial.close_delay != info->close_delay) ||
+                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
+                    (info->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                              (new_serial.flags & ASYNC_USR_MASK));
+               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 & ~ASYNC_FLAGS) |
+                      (new_serial.flags & ASYNC_FLAGS));
+       info->custom_divisor = new_serial.custom_divisor;
+       info->type = new_serial.type;
+       info->close_delay = new_serial.close_delay;
+       info->closing_wait = new_serial.closing_wait;
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ check_and_exit:
+       if (info->flags & ASYNC_INITIALIZED) {
+               change_speed(info);
+       } else
+               retval = startup(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 e100_serial * info, unsigned int *value)
+{
+       unsigned int result = TIOCSER_TEMT;
+#ifndef CONFIG_SVINTO_SIM
+       unsigned long curr_time = jiffies;
+       unsigned long curr_time_usec = GET_JIFFIES_USEC();
+       unsigned long elapsed_usec =
+               (curr_time - info->last_tx_active) * 1000000/HZ +
+               curr_time_usec - info->last_tx_active_usec;
+
+       if (info->xmit.head != info->xmit.tail ||
+           elapsed_usec < 2*info->char_time_usec) {
+               result = 0;
+       }
+#endif
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+#ifdef SERIAL_DEBUG_IO
+struct state_str
+{
+       int state;
+       const char *str;
+};
+
+const struct state_str control_state_str[] = {
+       {TIOCM_DTR, "DTR" },
+       {TIOCM_RTS, "RTS"},
+       {TIOCM_ST, "ST?" },
+       {TIOCM_SR, "SR?" },
+       {TIOCM_CTS, "CTS" },
+       {TIOCM_CD, "CD" },
+       {TIOCM_RI, "RI" },
+       {TIOCM_DSR, "DSR" },
+       {0, NULL }
+};
+
+char *get_control_state_str(int MLines, char *s)
+{
+       int i = 0;
+
+       s[0]='\0';
+       while (control_state_str[i].str != NULL) {
+               if (MLines & control_state_str[i].state) {
+                       if (s[0] != '\0') {
+                               strcat(s, ", ");
+                       }
+                       strcat(s, control_state_str[i].str);
+               }
+               i++;
+       }
+       return s;
+}
+#endif
+
+static int
+get_modem_info(struct e100_serial * info, unsigned int *value)
+{
+       unsigned int result;
+       /* Polarity isn't verified */
+#if 0 /*def SERIAL_DEBUG_IO  */
+
+       printk("get_modem_info: RTS: %i DTR: %i CD: %i RI: %i DSR: %i CTS: %i\n",
+              E100_RTS_GET(info),
+              E100_DTR_GET(info),
+              E100_CD_GET(info),
+              E100_RI_GET(info),
+              E100_DSR_GET(info),
+              E100_CTS_GET(info));
+#endif
+
+       result =
+               (!E100_RTS_GET(info) ? TIOCM_RTS : 0)
+               | (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
+               | (!E100_RI_GET(info) ? TIOCM_RNG : 0)
+               | (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+               | (!E100_CD_GET(info) ? TIOCM_CAR : 0)
+               | (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
+
+#ifdef SERIAL_DEBUG_IO
+       printk("e100ser: modem state: %i 0x%08X\n", result, result);
+       {
+               char s[100];
+
+               get_control_state_str(result, s);
+               printk("state: %s\n", s);
+       }
+#endif
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+
+static int
+set_modem_info(struct e100_serial * info, unsigned int cmd,
+              unsigned int *value)
+{
+       unsigned int arg;
+
+       if (copy_from_user(&arg, value, sizeof(int)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case TIOCMBIS:
+               if (arg & TIOCM_RTS) {
+                       e100_rts(info, 1);
+               }
+               if (arg & TIOCM_DTR) {
+                       e100_dtr(info, 1);
+               }
+               /* Handle FEMALE behaviour */
+               if (arg & TIOCM_RI) {
+                       e100_ri_out(info, 1);
+               }
+               if (arg & TIOCM_CD) {
+                       e100_cd_out(info, 1);
+               }
+               break;
+       case TIOCMBIC:
+               if (arg & TIOCM_RTS) {
+                       e100_rts(info, 0);
+               }
+               if (arg & TIOCM_DTR) {
+                       e100_dtr(info, 0);
+               }
+               /* Handle FEMALE behaviour */
+               if (arg & TIOCM_RI) {
+                       e100_ri_out(info, 0);
+               }
+               if (arg & TIOCM_CD) {
+                       e100_cd_out(info, 0);
+               }
+               break;
+       case TIOCMSET:
+               e100_rts(info, arg & TIOCM_RTS);
+               e100_dtr(info, arg & TIOCM_DTR);
+               /* Handle FEMALE behaviour */
+               e100_ri_out(info, arg & TIOCM_RI);
+               e100_cd_out(info, arg & TIOCM_CD);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+static void
+rs_break(struct tty_struct *tty, int break_state)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info->port)
+               return;
+
+       save_flags(flags);
+       cli();
+       if (break_state == -1) {
+               /* Go to manual mode and set the txd pin to 0 */
+               info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */
+       } else {
+               info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
+       }
+       info->port[REG_TR_CTRL] = info->tx_ctrl;
+       restore_flags(flags);
+}
+
+static int
+rs_ioctl(struct tty_struct *tty, struct file * file,
+        unsigned int cmd, unsigned long arg)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+           (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                       return -EIO;
+       }
+
+       switch (cmd) {
+               case TIOCMGET:
+                       return get_modem_info(info, (unsigned int *) arg);
+               case TIOCMBIS:
+               case TIOCMBIC:
+               case TIOCMSET:
+                       return set_modem_info(info, cmd, (unsigned int *) arg);
+               case TIOCGSERIAL:
+                       return get_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+
+               case TIOCSERGSTRUCT:
+                       if (copy_to_user((struct e100_serial *) arg,
+                                        info, sizeof(struct e100_serial)))
+                               return -EFAULT;
+                       return 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+               case TIOCSERSETRS485:
+               {
+                       struct rs485_control rs485ctrl;
+                       if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl)))
+                               return -EFAULT;
+
+                       return e100_enable_rs485(tty, &rs485ctrl);
+               }
+
+               case TIOCSERWRRS485:
+               {
+                       struct rs485_write rs485wr;
+                       if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr)))
+                               return -EFAULT;
+
+                       return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size);
+               }
+#endif
+
+               default:
+                       return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static void
+rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+       if (tty->termios->c_cflag == old_termios->c_cflag &&
+           tty->termios->c_iflag == old_termios->c_iflag)
+               return;
+
+       change_speed(info);
+
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               rs_start(tty);
+       }
+
+}
+
+/* In debugport.c - register a console write function that uses the normal
+ * serial driver
+ */
+typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
+
+extern debugport_write_function debug_write_function;
+
+static int rs_debug_write_function(int i, const char *buf, unsigned int len)
+{
+       int cnt;
+       int written = 0;
+        struct tty_struct *tty;
+        static int recurse_cnt = 0;
+
+        tty = rs_table[i].tty;
+        if (tty)  {
+               unsigned long flags;
+               if (recurse_cnt > 5) /* We skip this debug output */
+                       return 1;
+
+               local_irq_save(flags);
+               recurse_cnt++;
+               local_irq_restore(flags);
+                do {
+                        cnt = rs_write(tty, 0, buf + written, len);
+                        if (cnt >= 0) {
+                               written += cnt;
+                                buf += cnt;
+                                len -= cnt;
+                        } else
+                                len = cnt;
+                } while(len > 0);
+               local_irq_save(flags);
+               recurse_cnt--;
+               local_irq_restore(flags);
+                return 1;
+        }
+        return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_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
+ * S 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)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info)
+               return;
+
+       /* interrupts are disabled for this entire function */
+
+       save_flags(flags);
+       cli();
+
+       if (tty_hung_up_p(filp)) {
+               restore_flags(flags);
+               return;
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
+              info->line, info->count);
+#endif
+       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_CRIT
+                      "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_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               restore_flags(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ASYNC_NORMAL_ACTIVE)
+               info->normal_termios = *tty->termios;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the serial receiver and the DMA receive interrupt.
+        */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+       e100_disable_serial_data_irq(info);
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+       e100_disable_rx(info);
+       e100_disable_rx_irq(info);
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important as we have a transmit FIFO!
+                */
+               rs_wait_until_sent(tty, HZ);
+       }
+#endif
+
+       shutdown(info);
+       if (tty->driver->flush_buffer)
+               tty->driver->flush_buffer(tty);
+       if (tty->ldisc.flush_buffer)
+               tty->ldisc.flush_buffer(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = 0;
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(info->close_delay);
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       restore_flags(flags);
+
+       /* port closed */
+
+#if defined(CONFIG_ETRAX_RS485)
+       if (info->rs485.enabled) {
+               info->rs485.enabled = 0;
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+               *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              rs485_port_g_bit, 0);
+#endif
+#if defined(CONFIG_ETRAX_RS485_LTC1387)
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
+               REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
+                              CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
+#endif
+       }
+#endif
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       unsigned long orig_jiffies;
+       struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+       unsigned long curr_time = jiffies;
+       unsigned long curr_time_usec = GET_JIFFIES_USEC();
+       long elapsed_usec =
+               (curr_time - info->last_tx_active) * (1000000/HZ) +
+               curr_time_usec - info->last_tx_active_usec;
+
+       /*
+        * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+        * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+        */
+       orig_jiffies = jiffies;
+       while (info->xmit.head != info->xmit.tail || /* More in send queue */
+              (*info->ostatusadr & 0x007f) ||  /* more in FIFO */
+              (elapsed_usec < 2*info->char_time_usec)) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(1);
+               if (signal_pending(current))
+                       break;
+               if (timeout && time_after(jiffies, orig_jiffies + timeout))
+                       break;
+               curr_time = jiffies;
+               curr_time_usec = GET_JIFFIES_USEC();
+               elapsed_usec =
+                       (curr_time - info->last_tx_active) * (1000000/HZ) +
+                       curr_time_usec - info->last_tx_active_usec;
+       }
+       set_current_state(TASK_RUNNING);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void
+rs_hangup(struct tty_struct *tty)
+{
+       struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+       rs_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~ASYNC_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 e100_serial *info)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long   flags;
+       int             retval;
+       int             do_clocal = 0, extra_count = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               if (info->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * 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 |= ASYNC_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);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttyS%d, count = %d\n",
+              info->line, info->count);
+#endif
+       save_flags(flags);
+       cli();
+       if (!tty_hung_up_p(filp)) {
+               extra_count++;
+               info->count--;
+       }
+       restore_flags(flags);
+       info->blocked_open++;
+       while (1) {
+               save_flags(flags);
+               cli();
+               /* assert RTS and DTR */
+               e100_rts(info, 1);
+               e100_dtr(info, 1);
+               restore_flags(flags);
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CLOSING) && do_clocal)
+                       /* && (do_clocal || DCD_IS_ASSERTED) */
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttyS%d, count = %d\n",
+                      info->line, info->count);
+#endif
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&info->open_wait, &wait);
+       if (extra_count)
+               info->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttyS%d, count = %d\n",
+              info->line, info->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.
+ * It performs the serial-specific initialization for the tty structure.
+ */
+static int
+rs_open(struct tty_struct *tty, struct file * filp)
+{
+       struct e100_serial      *info;
+       int                     retval, line;
+       unsigned long           page;
+
+       /* find which port we want to open */
+
+       line = tty->index;
+
+       if (line < 0 || line >= NR_PORTS)
+               return -ENODEV;
+
+       /* find the corresponding e100_serial struct in the table */
+       info = rs_table + line;
+
+       /* don't allow the opening of ports that are not enabled in the HW config */
+       if (!info->enabled)
+               return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+        printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
+              info->count);
+#endif
+
+       info->count++;
+       tty->driver_data = info;
+       info->tty = tty;
+
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+       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 in the middle of closing, bail out now
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * Start up the serial port
+        */
+
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("rs_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+       if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+               *tty->termios = info->normal_termios;
+               change_speed(info);
+       }
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("rs_open ttyS%d successful...\n", info->line);
+#endif
+       DLOG_INT_TRIG( log_int_pos = 0);
+
+       DFLIP(  if (info->line == SERIAL_DEBUG_LINE) {
+                       info->icount.rx = 0;
+               } );
+
+       return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+extern _INLINE_ int line_info(char *buf, struct e100_serial *info)
+{
+       char    stat_buf[30];
+       int     ret;
+       unsigned long tmp;
+
+       ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
+                     info->line, (unsigned long)info->port, info->irq);
+
+       if (!info->port || (info->type == PORT_UNKNOWN)) {
+               ret += sprintf(buf+ret, "\n");
+               return ret;
+       }
+
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (!E100_RTS_GET(info))
+               strcat(stat_buf, "|RTS");
+       if (!E100_CTS_GET(info))
+               strcat(stat_buf, "|CTS");
+       if (!E100_DTR_GET(info))
+               strcat(stat_buf, "|DTR");
+       if (!E100_DSR_GET(info))
+               strcat(stat_buf, "|DSR");
+       if (!E100_CD_GET(info))
+               strcat(stat_buf, "|CD");
+       if (!E100_RI_GET(info))
+               strcat(stat_buf, "|RI");
+
+       ret += sprintf(buf+ret, " baud:%d", info->baud);
+
+       ret += sprintf(buf+ret, " tx:%lu rx:%lu",
+                      (unsigned long)info->icount.tx,
+                      (unsigned long)info->icount.rx);
+       tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+       if (tmp) {
+               ret += sprintf(buf+ret, " tx_pend:%lu/%lu",
+                              (unsigned long)tmp,
+                              (unsigned long)SERIAL_XMIT_SIZE);
+       }
+
+       ret += sprintf(buf+ret, " rx_pend:%lu/%lu",
+                      (unsigned long)info->recv_cnt,
+                      (unsigned long)info->max_recv_cnt);
+
+#if 1
+       if (info->tty) {
+
+               if (info->tty->stopped)
+                       ret += sprintf(buf+ret, " stopped:%i",
+                                      (int)info->tty->stopped);
+               if (info->tty->hw_stopped)
+                       ret += sprintf(buf+ret, " hw_stopped:%i",
+                                      (int)info->tty->hw_stopped);
+       }
+
+       {
+               unsigned char rstat = info->port[REG_STATUS];
+               if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) )
+                       ret += sprintf(buf+ret, " xoff_detect:1");
+       }
+
+#endif
+
+
+
+
+       if (info->icount.frame)
+               ret += sprintf(buf+ret, " fe:%lu",
+                              (unsigned long)info->icount.frame);
+
+       if (info->icount.parity)
+               ret += sprintf(buf+ret, " pe:%lu",
+                              (unsigned long)info->icount.parity);
+
+       if (info->icount.brk)
+               ret += sprintf(buf+ret, " brk:%lu",
+                              (unsigned long)info->icount.brk);
+
+       if (info->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%lu",
+                              (unsigned long)info->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       return ret;
+}
+
+int rs_read_proc(char *page, char **start, off_t off, int count,
+                int *eof, void *data)
+{
+       int i, len = 0, l;
+       off_t   begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s\n",
+                      serial_version);
+       for (i = 0; i < NR_PORTS && len < 4000; i++) {
+               if (!rs_table[i].enabled)
+                       continue;
+               l = line_info(page + len, &rs_table[i]);
+               len += l;
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+#ifdef DEBUG_LOG_INCLUDED
+       for (i = 0; i < debug_log_pos; i++) {
+               len += sprintf(page + len, "%-4i %lu.%lu ", i, debug_log[i].time, timer_data_to_ns(debug_log[i].timer_data));
+               len += sprintf(page + len, debug_log[i].string, debug_log[i].value);
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+       len += sprintf(page + len, "debug_log %i/%i  %li bytes\n",
+                      i, DEBUG_LOG_SIZE, begin+len);
+       debug_log_pos = 0;
+#endif
+
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (off-begin);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void
+show_serial_version(void)
+{
+       printk(KERN_INFO
+              "ETRAX 100LX serial-driver %s, (c) 2000-2004 Axis Communications AB\r\n",
+              &serial_version[11]); /* "$Revision: x.yy" */
+}
+
+/* rs_init inits the driver at boot (using the module_init chain) */
+
+static struct tty_operations rs_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,
+       .send_xchar = rs_send_xchar,
+       .wait_until_sent = rs_wait_until_sent,
+       .read_proc = rs_read_proc,
+};
+
+static int __init
+rs_init(void)
+{
+       int i;
+       struct e100_serial *info;
+       struct tty_driver *driver = alloc_tty_driver(NR_PORTS);
+
+       if (!driver)
+               return -ENOMEM;
+
+       show_serial_version();
+
+       /* Setup the timed flush handler system */
+
+#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
+       init_timer(&flush_timer);
+       flush_timer.function = timed_flush_handler;
+       mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+#endif
+
+       /* Initialize the tty_driver structure */
+
+       driver->driver_name = "serial";
+       driver->name = "ttyS";
+       driver->major = TTY_MAJOR;
+       driver->minor_start = 64;
+       driver->type = TTY_DRIVER_TYPE_SERIAL;
+       driver->subtype = SERIAL_TYPE_NORMAL;
+       driver->init_termios = tty_std_termios;
+       driver->init_termios.c_cflag =
+               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+       driver->termios = serial_termios;
+       driver->termios_locked = serial_termios_locked;
+
+       tty_set_operations(driver, &rs_ops);
+        serial_driver = driver;
+       if (tty_register_driver(driver))
+               panic("Couldn't register serial driver\n");
+       /* do some initializing for the separate ports */
+
+       for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+               info->uses_dma_in = 0;
+               info->uses_dma_out = 0;
+               info->line = i;
+               info->tty = 0;
+               info->type = PORT_ETRAX;
+               info->tr_running = 0;
+               info->forced_eop = 0;
+               info->baud_base = DEF_BAUD_BASE;
+               info->custom_divisor = 0;
+               info->flags = 0;
+               info->close_delay = 5*HZ/10;
+               info->closing_wait = 30*HZ;
+               info->x_char = 0;
+               info->event = 0;
+               info->count = 0;
+               info->blocked_open = 0;
+               info->normal_termios = driver->init_termios;
+               init_waitqueue_head(&info->open_wait);
+               init_waitqueue_head(&info->close_wait);
+               info->xmit.buf = NULL;
+               info->xmit.tail = info->xmit.head = 0;
+               info->first_recv_buffer = info->last_recv_buffer = NULL;
+               info->recv_cnt = info->max_recv_cnt = 0;
+               info->last_tx_active_usec = 0;
+               info->last_tx_active = 0;
+
+#if defined(CONFIG_ETRAX_RS485)
+               /* Set sane defaults */
+               info->rs485.rts_on_send = 0;
+               info->rs485.rts_after_sent = 1;
+               info->rs485.delay_rts_before_send = 0;
+               info->rs485.enabled = 0;
+#endif
+               INIT_WORK(&info->work, do_softint, info);
+
+               if (info->enabled) {
+                       printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
+                              serial_driver->name, info->line, (unsigned int)info->port);
+               }
+       }
+#ifdef CONFIG_ETRAX_FAST_TIMER
+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+       memset(fast_timers, 0, sizeof(fast_timers));
+#endif
+#ifdef CONFIG_ETRAX_RS485
+       memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485));
+#endif
+       fast_timer_init();
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+       /* Not needed in simulator.  May only complicate stuff. */
+       /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
+
+       if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
+               panic("irq8");
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
+       if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
+               panic("irq22");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
+       if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
+               panic("irq23");
+#endif
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT1
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
+       if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
+               panic("irq24");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
+       if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
+               panic("irq25");
+#endif
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+       /* DMA Shared with par0 (and SCSI0 and ATA) */
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
+       if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma tr", NULL))
+               panic("irq18");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
+       if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma rec", NULL))
+               panic("irq19");
+#endif
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+       /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
+       if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma tr", NULL))
+               panic("irq20");
+#endif
+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
+       if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma rec", NULL))
+               panic("irq21");
+#endif
+#endif
+
+#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
+       if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT,
+                      "fast serial dma timeout", NULL)) {
+               printk(KERN_CRIT "err: timer1 irq\n");
+       }
+#endif
+#endif /* CONFIG_SVINTO_SIM */
+       debug_write_function = rs_debug_write_function;
+       return 0;
+}
+
+/* this makes sure that rs_init is called during kernel boot */
+
+module_init(rs_init);
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+int
+register_serial(struct serial_struct *req)
+{
+       return -1;
+}
+
+void unregister_serial(int line)
+{
+}
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
new file mode 100644 (file)
index 0000000..1800c0e
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * serial.h: Arch-dep definitions for the Etrax100 serial driver.
+ *
+ * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ */
+
+#ifndef _ETRAX_SERIAL_H
+#define _ETRAX_SERIAL_H
+
+#include <linux/config.h>
+#include <linux/circ_buf.h>
+#include <asm/termios.h>
+
+/* 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
+ */
+
+#define SERIAL_RECV_DESCRIPTORS 8
+
+struct etrax_recv_buffer {
+       struct etrax_recv_buffer *next;
+       unsigned short length;
+       unsigned char error;
+       unsigned char pad;
+
+       unsigned char buffer[0];
+};
+
+struct e100_serial {
+       int                     baud;
+       volatile u8             *port; /* R_SERIALx_CTRL */
+       u32                     irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+       /* Output registers */
+       volatile u8             *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+       volatile u32            *ofirstadr;   /* adr to R_DMA_CHx_FIRST */
+       volatile u8             *ocmdadr;     /* adr to R_DMA_CHx_CMD */
+       const volatile u8       *ostatusadr;  /* adr to R_DMA_CHx_STATUS */
+
+       /* Input registers */
+       volatile u8             *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+       volatile u32            *ifirstadr;   /* adr to R_DMA_CHx_FIRST */
+       volatile u8             *icmdadr;     /* adr to R_DMA_CHx_CMD */
+       volatile u32            *idescradr;   /* adr to R_DMA_CHx_DESCR */
+
+       int                     flags;  /* defined in tty.h */
+
+       u8                      rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+       u8                      tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+       u8                      iseteop; /* bit number for R_SET_EOP for the input dma */
+       int                     enabled; /* Set to 1 if the port is enabled in HW config */
+
+       u8              dma_out_enabled:1; /* Set to 1 if DMA should be used */
+       u8              dma_in_enabled:1;  /* Set to 1 if DMA should be used */
+
+       /* end of fields defined in rs_table[] in .c-file */
+       u8              uses_dma_in;  /* Set to 1 if DMA is used */
+       u8              uses_dma_out; /* Set to 1 if DMA is used */
+       u8              forced_eop;   /* a fifo eop has been forced */
+       int                     baud_base;     /* For special baudrates */
+       int                     custom_divisor; /* For special baudrates */
+       struct etrax_dma_descr  tr_descr;
+       struct etrax_dma_descr  rec_descr[SERIAL_RECV_DESCRIPTORS];
+       int                     cur_rec_descr;
+
+       volatile int            tr_running; /* 1 if output is running */
+
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       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                     type;  /* PORT_ETRAX */
+       int                     count;      /* # of fd on device */
+       int                     blocked_open; /* # of blocked opens */
+       struct circ_buf         xmit;
+       struct etrax_recv_buffer *first_recv_buffer;
+       struct etrax_recv_buffer *last_recv_buffer;
+       unsigned int            recv_cnt;
+       unsigned int            max_recv_cnt;
+
+       struct work_struct      work;
+       struct async_icount     icount;   /* error-statistics etc.*/
+       struct termios          normal_termios;
+       struct termios          callout_termios;
+#ifdef DECLARE_WAITQUEUE
+       wait_queue_head_t       open_wait;
+       wait_queue_head_t       close_wait;
+#else
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+#endif
+
+       unsigned long           char_time_usec;       /* The time for 1 char, in usecs */
+       unsigned long           flush_time_usec;      /* How often we should flush */
+       unsigned long           last_tx_active_usec;  /* Last tx usec in the jiffies */
+       unsigned long           last_tx_active;       /* Last tx time in jiffies */
+       unsigned long           last_rx_active_usec;  /* Last rx usec in the jiffies */
+       unsigned long           last_rx_active;       /* Last rx time in jiffies */
+
+       int                     break_detected_cnt;
+       int                     errorcode;
+
+#ifdef CONFIG_ETRAX_RS485
+       struct rs485_control    rs485;  /* RS-485 support */
+#endif
+};
+
+/* this PORT is not in the standard serial.h. it's not actually used for
+ * anything since we only have one type of async serial-port anyway in this
+ * system.
+ */
+
+#define PORT_ETRAX 1
+
+/*
+ * 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__ */
+
+#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
new file mode 100644 (file)
index 0000000..c15c8a0
--- /dev/null
@@ -0,0 +1,1702 @@
+/*
+  * icom.c
+  *
+  * Copyright (C) 2001 IBM Corporation. All rights reserved.
+  *
+  * Serial device driver.
+  *
+  * Based on code from serial.c
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+  *
+  */
+#define SERIAL_DO_RESTART
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/termios.h>
+#include <linux/fs.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/kobject.h>
+#include <linux/firmware.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include "icom.h"
+
+/*#define ICOM_TRACE            enable port trace capabilities */
+
+#define ICOM_DRIVER_NAME "icom"
+#define ICOM_VERSION_STR "1.3.1"
+#define NR_PORTS              128
+#define ICOM_PORT ((struct icom_port *)port)
+#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj)
+
+static const struct pci_device_id icom_pci_table[] = {
+       {
+             .vendor = PCI_VENDOR_ID_IBM,
+             .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
+             .subvendor = PCI_ANY_ID,
+             .subdevice = PCI_ANY_ID,
+             .driver_data = ADAPTER_V1,
+        },
+       {
+             .vendor = PCI_VENDOR_ID_IBM,
+             .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+             .subvendor = PCI_VENDOR_ID_IBM,
+             .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
+             .driver_data = ADAPTER_V2,
+        },
+       {
+             .vendor = PCI_VENDOR_ID_IBM,
+             .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+             .subvendor = PCI_VENDOR_ID_IBM,
+             .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
+             .driver_data = ADAPTER_V2,
+        },
+       {
+             .vendor = PCI_VENDOR_ID_IBM,
+             .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
+             .subvendor = PCI_VENDOR_ID_IBM,
+             .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
+             .driver_data = ADAPTER_V2,
+        },
+       {}
+};
+
+struct lookup_proc_table start_proc[4] = {
+       {0, ICOM_CONTROL_START_A},
+       {0, ICOM_CONTROL_START_B},
+       {0, ICOM_CONTROL_START_C},
+       {0, ICOM_CONTROL_START_D}
+};
+
+
+struct lookup_proc_table stop_proc[4] = {
+       {0, ICOM_CONTROL_STOP_A},
+       {0, ICOM_CONTROL_STOP_B},
+       {0, ICOM_CONTROL_STOP_C},
+       {0, ICOM_CONTROL_STOP_D}
+};
+
+struct lookup_int_table int_mask_tbl[4] = {
+       {0, ICOM_INT_MASK_PRC_A},
+       {0, ICOM_INT_MASK_PRC_B},
+       {0, ICOM_INT_MASK_PRC_C},
+       {0, ICOM_INT_MASK_PRC_D},
+};
+
+
+MODULE_DEVICE_TABLE(pci, icom_pci_table);
+
+static LIST_HEAD(icom_adapter_head);
+
+/* spinlock for adapter initialization and changing adapter operations */
+static spinlock_t icom_lock;
+
+#ifdef ICOM_TRACE
+static inline void trace(struct icom_port *, char *, unsigned long) {};
+#else
+static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
+#endif
+
+static void msleep(unsigned long msecs)
+{
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(MSECS_TO_JIFFIES(msecs));
+}
+
+static void free_port_memory(struct icom_port *icom_port)
+{
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       trace(icom_port, "RET_PORT_MEM", 0);
+       if (icom_port->recv_buf) {
+               pci_free_consistent(dev, 4096, icom_port->recv_buf,
+                                   icom_port->recv_buf_pci);
+               icom_port->recv_buf = 0;
+       }
+       if (icom_port->xmit_buf) {
+               pci_free_consistent(dev, 4096, icom_port->xmit_buf,
+                                   icom_port->xmit_buf_pci);
+               icom_port->xmit_buf = 0;
+       }
+       if (icom_port->statStg) {
+               pci_free_consistent(dev, 4096, icom_port->statStg,
+                                   icom_port->statStg_pci);
+               icom_port->statStg = 0;
+       }
+
+       if (icom_port->xmitRestart) {
+               pci_free_consistent(dev, 4096, icom_port->xmitRestart,
+                                   icom_port->xmitRestart_pci);
+               icom_port->xmitRestart = 0;
+       }
+}
+
+static int __init get_port_memory(struct icom_port *icom_port)
+{
+       int index;
+       unsigned long stgAddr;
+       unsigned long startStgAddr;
+       unsigned long offset;
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       icom_port->xmit_buf =
+           pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
+       if (!icom_port->xmit_buf) {
+               dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
+               return -ENOMEM;
+       }
+
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->xmit_buf);
+
+       icom_port->recv_buf =
+           pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
+       if (!icom_port->recv_buf) {
+               dev_err(&dev->dev, "Can not allocate Receive buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->recv_buf);
+
+       icom_port->statStg =
+           pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
+       if (!icom_port->statStg) {
+               dev_err(&dev->dev, "Can not allocate Status buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+       trace(icom_port, "GET_PORT_MEM",
+             (unsigned long) icom_port->statStg);
+
+       icom_port->xmitRestart =
+           pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
+       if (!icom_port->xmitRestart) {
+               dev_err(&dev->dev,
+                       "Can not allocate xmit Restart buffer\n");
+               free_port_memory(icom_port);
+               return -ENOMEM;
+       }
+
+       memset(icom_port->statStg, 0, 4096);
+
+       /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
+           indicates that frames are to be transmitted
+       */
+
+       stgAddr = (unsigned long) icom_port->statStg;
+       for (index = 0; index < NUM_XBUFFS; index++) {
+               trace(icom_port, "FOD_ADDR", stgAddr);
+               stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
+               if (index < (NUM_XBUFFS - 1)) {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+                       icom_port->statStg->xmit[index].leLengthASD =
+                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
+                       trace(icom_port, "FOD_ADDR", stgAddr);
+                       trace(icom_port, "FOD_XBUFF",
+                             (unsigned long) icom_port->xmit_buf);
+                       icom_port->statStg->xmit[index].leBuffer =
+                           cpu_to_le32(icom_port->xmit_buf_pci);
+               } else if (index == (NUM_XBUFFS - 1)) {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+                       icom_port->statStg->xmit[index].leLengthASD =
+                           (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
+                       trace(icom_port, "FOD_XBUFF",
+                             (unsigned long) icom_port->xmit_buf);
+                       icom_port->statStg->xmit[index].leBuffer =
+                           cpu_to_le32(icom_port->xmit_buf_pci);
+               } else {
+                       memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
+               }
+       }
+       /* FIDs */
+       startStgAddr = stgAddr;
+
+       /* fill in every entry, even if no buffer */
+       for (index = 0; index <  NUM_RBUFFS; index++) {
+               trace(icom_port, "FID_ADDR", stgAddr);
+               stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
+               icom_port->statStg->rcv[index].leLength = 0;
+               icom_port->statStg->rcv[index].WorkingLength =
+                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+               if (index < (NUM_RBUFFS - 1) ) {
+                       offset = stgAddr - (unsigned long) icom_port->statStg;
+                       icom_port->statStg->rcv[index].leNext =
+                             cpu_to_le32(icom_port-> statStg_pci + offset);
+                       trace(icom_port, "FID_RBUFF",
+                             (unsigned long) icom_port->recv_buf);
+                       icom_port->statStg->rcv[index].leBuffer =
+                           cpu_to_le32(icom_port->recv_buf_pci);
+               } else if (index == (NUM_RBUFFS -1) ) {
+                       offset = startStgAddr - (unsigned long) icom_port->statStg;
+                       icom_port->statStg->rcv[index].leNext =
+                           cpu_to_le32(icom_port-> statStg_pci + offset);
+                       trace(icom_port, "FID_RBUFF",
+                             (unsigned long) icom_port->recv_buf + 2048);
+                       icom_port->statStg->rcv[index].leBuffer =
+                           cpu_to_le32(icom_port->recv_buf_pci + 2048);
+               } else {
+                       icom_port->statStg->rcv[index].leNext = 0;
+                       icom_port->statStg->rcv[index].leBuffer = 0;
+               }
+       }
+
+       return 0;
+}
+
+static void stop_processor(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               stop_proc[port].global_control_reg = &icom_port->global_reg->control;
+       else
+               stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+
+
+       if (port < 4) {
+               temp = readl(stop_proc[port].global_control_reg);
+               temp =
+                       (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
+               writel(temp, stop_proc[port].global_control_reg);
+
+               /* write flush */
+               readl(stop_proc[port].global_control_reg);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+}
+
+static void start_processor(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               start_proc[port].global_control_reg = &icom_port->global_reg->control;
+       else
+               start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
+       if (port < 4) {
+               temp = readl(start_proc[port].global_control_reg);
+               temp =
+                       (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
+               writel(temp, start_proc[port].global_control_reg);
+
+               /* write flush */
+               readl(start_proc[port].global_control_reg);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+}
+
+static void load_code(struct icom_port *icom_port)
+{
+       const struct firmware *fw;
+       char *iram_ptr;
+       int index;
+       int status = 0;
+       char *dram_ptr = (char *) icom_port->dram;
+       dma_addr_t temp_pci;
+       unsigned char *new_page = NULL;
+       unsigned char cable_id = NO_CABLE;
+       struct pci_dev *dev = icom_port->adapter->pci_dev;
+
+       /* Clear out any pending interrupts */
+       writew(0x3FFF, (void *) icom_port->int_reg);
+
+       trace(icom_port, "CLEAR_INTERRUPTS", 0);
+
+       /* Stop processor */
+       stop_processor(icom_port);
+
+       /* Zero out DRAM */
+       memset_io(dram_ptr, 0, 512);
+
+       /* Load Call Setup into Adapter */
+       if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       iram_ptr = (char *) icom_port->dram + ICOM_IRAM_OFFSET;
+       for (index = 0; index < fw->size; index++)
+               writeb(fw->data[index], &iram_ptr[index]);
+
+       release_firmware(fw);
+
+       /* Load Resident DCE portion of Adapter */
+       if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_IRAM_SIZE) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       iram_ptr = (char *) icom_port->dram + ICOM_IRAM_OFFSET;
+       for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
+               writeb(fw->data[index], &iram_ptr[index]);
+
+       release_firmware(fw);
+
+       /* Set Hardware level */
+       if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2)
+               writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
+
+       /* Start the processor in Adapter */
+       start_processor(icom_port);
+
+       writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
+              &(icom_port->dram->HDLCConfigReg));
+       writeb(0x04, &(icom_port->dram->FlagFillIdleTimer));    /* 0.5 seconds */
+       writeb(0x00, &(icom_port->dram->CmdReg));
+       writeb(0x10, &(icom_port->dram->async_config3));
+       writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
+               ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
+
+       /*Set up data in icom DRAM to indicate where personality
+        *code is located and its length.
+        */
+       new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
+
+       if (!new_page) {
+               dev_err(&dev->dev, "Can not allocate DMA buffer\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) {
+               dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n");
+               status = -1;
+               goto load_code_exit;
+       }
+
+       if (fw->size > ICOM_DCE_IRAM_OFFSET) {
+               dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n");
+               release_firmware(fw);
+               status = -1;
+               goto load_code_exit;
+       }
+
+       for (index = 0; index < fw->size; index++)
+               new_page[index] = fw->data[index];
+
+       release_firmware(fw);
+
+       writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
+       writel(temp_pci, &icom_port->dram->mac_load_addr);
+
+       /*Setting the syncReg to 0x80 causes adapter to start downloading
+          the personality code into adapter instruction RAM.
+          Once code is loaded, it will begin executing and, based on
+          information provided above, will start DMAing data from
+          shared memory to adapter DRAM.
+        */
+       /* the wait loop below verifies this write operation has been done
+          and processed
+       */
+       writeb(START_DOWNLOAD, &icom_port->dram->sync);
+
+       /* Wait max 1 Sec for data download and processor to start */
+       for (index = 0; index < 10; index++) {
+               msleep(100);
+               if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
+                       break;
+       }
+
+       if (index == 10)
+               status = -1;
+
+       /*
+        * check Cable ID
+        */
+       cable_id = readb(&icom_port->dram->cable_id);
+
+       if (cable_id & ICOM_CABLE_ID_VALID) {
+               /* Get cable ID into the lower 4 bits (standard form) */
+               cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
+               icom_port->cable_id = cable_id;
+       } else {
+               dev_err(&dev->dev,"Invalid or no cable attached\n");
+               icom_port->cable_id = NO_CABLE;
+       }
+
+      load_code_exit:
+
+       if (status != 0) {
+               /* Clear out any pending interrupts */
+               writew(0x3FFF, (void *) icom_port->int_reg);
+
+               /* Turn off port */
+               writeb(ICOM_DISABLE, &(icom_port->dram->disable));
+
+               /* Stop processor */
+               stop_processor(icom_port);
+
+               dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n");
+       }
+
+      if (new_page != NULL)
+             pci_free_consistent(dev, 4096, new_page, temp_pci);
+}
+
+static int startup(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned char cable_id, raw_cable_id;
+       unsigned long flags;
+       int port;
+
+       trace(icom_port, "STARTUP", 0);
+
+       if (icom_port->dram == 0x00000000) {
+               /* should NEVER be zero */
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                       "Unusable Port, port configuration missing\n");
+               return -ENODEV;
+       }
+
+       /*
+        * check Cable ID
+        */
+       raw_cable_id = readb(&icom_port->dram->cable_id);
+       trace(icom_port, "CABLE_ID", raw_cable_id);
+
+       /* Get cable ID into the lower 4 bits (standard form) */
+       cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
+
+       /* Check for valid Cable ID */
+       if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
+           (cable_id != icom_port->cable_id)) {
+
+               /* reload adapter code, pick up any potential changes in cable id */
+               load_code(icom_port);
+
+               /* still no sign of cable, error out */
+               raw_cable_id = readb(&icom_port->dram->cable_id);
+               cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
+               if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
+                   (icom_port->cable_id == NO_CABLE))
+                       return -EIO;
+       }
+
+       /*
+        * Finally, clear and  enable interrupts
+        */
+       spin_lock_irqsave(&icom_lock, flags);
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
+       else
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
+
+       if (port == 0 || port == 2)
+               writew(0x00FF,(void *) icom_port->int_reg);
+       else
+               writew(0x3F00,(void *) icom_port->int_reg);
+       if (port < 4) {
+               temp = readl(int_mask_tbl[port].global_int_mask);
+               writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+
+               /* write flush */
+               readl(int_mask_tbl[port].global_int_mask);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+
+       spin_unlock_irqrestore(&icom_lock, flags);
+       return 0;
+}
+
+static void shutdown(struct icom_port *icom_port)
+{
+       unsigned long temp;
+       unsigned char cmdReg;
+       unsigned long flags;
+       int port;
+
+       spin_lock_irqsave(&icom_lock, flags);
+       trace(icom_port, "SHUTDOWN", 0);
+
+       /*
+        * disable all interrupts
+        */
+       port = icom_port->port;
+       if (port == 0 || port == 1)
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
+       else
+               int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
+
+       if (port < 4) {
+               temp = readl(int_mask_tbl[port].global_int_mask);
+               writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+
+               /* write flush */
+               readl(int_mask_tbl[port].global_int_mask);
+       } else {
+               dev_err(&icom_port->adapter->pci_dev->dev,
+                        "Invalid port assignment\n");
+       }
+       spin_unlock_irqrestore(&icom_lock, flags);
+
+       /*
+        * disable break condition
+        */
+       cmdReg = readb(&icom_port->dram->CmdReg);
+       if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) {
+               writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
+       }
+}
+
+static int icom_write(struct uart_port *port)
+{
+       unsigned long data_count;
+       unsigned char cmdReg;
+       unsigned long offset;
+       int temp_tail = port->info->xmit.tail;
+
+       trace(ICOM_PORT, "WRITE", 0);
+
+       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
+           SA_FLAGS_READY_TO_XMIT) {
+               trace(ICOM_PORT, "WRITE_FULL", 0);
+               return 0;
+       }
+
+       data_count = 0;
+       while ((port->info->xmit.head != temp_tail) &&
+              (data_count <= XMIT_BUFF_SZ)) {
+
+               ICOM_PORT->xmit_buf[data_count++] =
+                   port->info->xmit.buf[temp_tail];
+
+               temp_tail++;
+               temp_tail &= (UART_XMIT_SIZE - 1);
+       }
+
+       if (data_count) {
+               ICOM_PORT->statStg->xmit[0].flags =
+                   cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
+               ICOM_PORT->statStg->xmit[0].leLength =
+                   cpu_to_le16(data_count);
+               offset =
+                   (unsigned long) &ICOM_PORT->statStg->xmit[0] -
+                   (unsigned long) ICOM_PORT->statStg;
+               *ICOM_PORT->xmitRestart =
+                   cpu_to_le32(ICOM_PORT->statStg_pci + offset);
+               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+               writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
+                      &ICOM_PORT->dram->CmdReg);
+               writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
+               trace(ICOM_PORT, "WRITE_START", data_count);
+               /* write flush */
+               readb(&ICOM_PORT->dram->StartXmitCmd);
+       }
+
+       return data_count;
+}
+
+static inline void check_modem_status(struct icom_port *icom_port)
+{
+       static char old_status = 0;
+       char delta_status;
+       unsigned char status;
+
+       spin_lock(&icom_port->uart_port.lock);
+
+       /*modem input register */
+       status = readb(&icom_port->dram->isr);
+       trace(icom_port, "CHECK_MODEM", status);
+       delta_status = status ^ old_status;
+       if (delta_status) {
+               if (delta_status & ICOM_RI)
+                       icom_port->uart_port.icount.rng++;
+               if (delta_status & ICOM_DSR)
+                       icom_port->uart_port.icount.dsr++;
+               if (delta_status & ICOM_DCD)
+                       uart_handle_dcd_change(&icom_port->uart_port,
+                                              delta_status & ICOM_DCD);
+               if (delta_status & ICOM_CTS)
+                       uart_handle_cts_change(&icom_port->uart_port,
+                                              delta_status & ICOM_CTS);
+
+               wake_up_interruptible(&icom_port->uart_port.info->
+                                     delta_msr_wait);
+               old_status = status;
+       }
+       spin_unlock(&icom_port->uart_port.lock);
+}
+
+static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
+{
+       unsigned short int count;
+       int i;
+
+       if (port_int_reg & (INT_XMIT_COMPLETED)) {
+               trace(icom_port, "XMIT_COMPLETE", 0);
+
+               /* clear buffer in use bit */
+               icom_port->statStg->xmit[0].flags &=
+                       cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
+
+               count = (unsigned short int)
+                       cpu_to_le16(icom_port->statStg->xmit[0].leLength);
+               icom_port->uart_port.icount.tx += count;
+
+               for (i=0; i<count &&
+                       !uart_circ_empty(&icom_port->uart_port.info->xmit); i++) {
+
+                       icom_port->uart_port.info->xmit.tail++;
+                       icom_port->uart_port.info->xmit.tail &=
+                               (UART_XMIT_SIZE - 1);
+               }
+
+               if (!icom_write(&icom_port->uart_port))
+                       /* activate write queue */
+                       uart_write_wakeup(&icom_port->uart_port);
+       } else
+               trace(icom_port, "XMIT_DISABLED", 0);
+}
+
+static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
+{
+       short int count, rcv_buff;
+       struct tty_struct *tty = icom_port->uart_port.info->tty;
+       unsigned short int status;
+       struct uart_icount *icount;
+       unsigned long offset;
+
+       trace(icom_port, "RCV_COMPLETE", 0);
+       rcv_buff = icom_port->next_rcv;
+
+       status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
+       while (status & SA_FL_RCV_DONE) {
+
+               trace(icom_port, "FID_STATUS", status);
+               count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
+
+               trace(icom_port, "RCV_COUNT", count);
+               if (count > (TTY_FLIPBUF_SIZE - tty->flip.count))
+                       count = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+               trace(icom_port, "REAL_COUNT", count);
+
+               offset =
+                       cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
+                       icom_port->recv_buf_pci;
+
+               memcpy(tty->flip.char_buf_ptr,(unsigned char *)
+                      ((unsigned long)icom_port->recv_buf + offset), count);
+
+               if (count > 0) {
+                       tty->flip.count += count - 1;
+                       tty->flip.char_buf_ptr += count - 1;
+
+                       memset(tty->flip.flag_buf_ptr, 0, count);
+                       tty->flip.flag_buf_ptr += count - 1;
+               }
+
+               icount = &icom_port->uart_port.icount;
+               icount->rx += count;
+
+               /* Break detect logic */
+               if ((status & SA_FLAGS_FRAME_ERROR)
+                   && (tty->flip.char_buf_ptr[0] == 0x00)) {
+                       status &= ~SA_FLAGS_FRAME_ERROR;
+                       status |= SA_FLAGS_BREAK_DET;
+                       trace(icom_port, "BREAK_DET", 0);
+               }
+
+               if (status &
+                   (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
+                    SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
+
+                       if (status & SA_FLAGS_BREAK_DET)
+                               icount->brk++;
+                       if (status & SA_FLAGS_PARITY_ERROR)
+                               icount->parity++;
+                       if (status & SA_FLAGS_FRAME_ERROR)
+                               icount->frame++;
+                       if (status & SA_FLAGS_OVERRUN)
+                               icount->overrun++;
+
+                       /*
+                        * Now check to see if character should be
+                        * ignored, and mask off conditions which
+                        * should be ignored.
+                        */
+                       if (status & icom_port->ignore_status_mask) {
+                               trace(icom_port, "IGNORE_CHAR", 0);
+                               goto ignore_char;
+                       }
+
+                       status &= icom_port->read_status_mask;
+
+                       if (status & SA_FLAGS_BREAK_DET) {
+                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                       } else if (status & SA_FLAGS_PARITY_ERROR) {
+                               trace(icom_port, "PARITY_ERROR", 0);
+                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                       } else if (status & SA_FLAGS_FRAME_ERROR)
+                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+
+                       if (status & SA_FLAGS_OVERRUN) {
+                               /*
+                                * Overrun is special, since it's
+                                * reported immediately, and doesn't
+                                * affect the current character
+                                */
+                               if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+                                       tty->flip.count++;
+                                       tty->flip.flag_buf_ptr++;
+                                       tty->flip.char_buf_ptr++;
+                                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                               }
+                       }
+               }
+
+               tty->flip.flag_buf_ptr++;
+               tty->flip.char_buf_ptr++;
+               tty->flip.count++;
+               ignore_char:
+                       icom_port->statStg->rcv[rcv_buff].flags = 0;
+               icom_port->statStg->rcv[rcv_buff].leLength = 0;
+               icom_port->statStg->rcv[rcv_buff].WorkingLength =
+                       (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+
+               rcv_buff++;
+               if (rcv_buff == NUM_RBUFFS)
+                       rcv_buff = 0;
+
+               status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
+       }
+       icom_port->next_rcv = rcv_buff;
+       tty_flip_buffer_push(tty);
+}
+
+static void process_interrupt(u16 port_int_reg,
+                             struct icom_port *icom_port)
+{
+
+       spin_lock(&icom_port->uart_port.lock);
+       trace(icom_port, "INTERRUPT", port_int_reg);
+
+       if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
+               xmit_interrupt(port_int_reg, icom_port);
+
+       if (port_int_reg & INT_RCV_COMPLETED)
+               recv_interrupt(port_int_reg, icom_port);
+
+       spin_unlock(&icom_port->uart_port.lock);
+}
+
+static irqreturn_t icom_interrupt(int irq, void *dev_id,
+                                 struct pt_regs *regs)
+{
+       unsigned long int_reg;
+       u32 adapter_interrupts;
+       u16 port_int_reg;
+       struct icom_adapter *icom_adapter;
+       struct icom_port *icom_port;
+
+       /* find icom_port for this interrupt */
+       icom_adapter = (struct icom_adapter *) dev_id;
+
+       if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) {
+               int_reg = icom_adapter->base_addr + 0x8024;
+
+               adapter_interrupts = readl((void *) int_reg);
+
+               if (adapter_interrupts & 0x00003FFF) {
+                       /* port 2 interrupt,  NOTE:  for all ADAPTER_V2, port 2 will be active */
+                       icom_port = &icom_adapter->port_info[2];
+                       port_int_reg = (u16) adapter_interrupts;
+                       process_interrupt(port_int_reg, icom_port);
+                       check_modem_status(icom_port);
+               }
+               if (adapter_interrupts & 0x3FFF0000) {
+                       /* port 3 interrupt */
+                       icom_port = &icom_adapter->port_info[3];
+                       if (icom_port->status == ICOM_PORT_ACTIVE) {
+                               port_int_reg =
+                                   (u16) (adapter_interrupts >> 16);
+                               process_interrupt(port_int_reg, icom_port);
+                               check_modem_status(icom_port);
+                       }
+               }
+
+               /* Clear out any pending interrupts */
+               writel(adapter_interrupts, (void *) int_reg);
+
+               int_reg = icom_adapter->base_addr + 0x8004;
+       } else {
+               int_reg = icom_adapter->base_addr + 0x4004;
+       }
+
+       adapter_interrupts = readl((void *) int_reg);
+
+       if (adapter_interrupts & 0x00003FFF) {
+               /* port 0 interrupt, NOTE:  for all adapters, port 0 will be active */
+               icom_port = &icom_adapter->port_info[0];
+               port_int_reg = (u16) adapter_interrupts;
+               process_interrupt(port_int_reg, icom_port);
+               check_modem_status(icom_port);
+       }
+       if (adapter_interrupts & 0x3FFF0000) {
+               /* port 1 interrupt */
+               icom_port = &icom_adapter->port_info[1];
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       port_int_reg = (u16) (adapter_interrupts >> 16);
+                       process_interrupt(port_int_reg, icom_port);
+                       check_modem_status(icom_port);
+               }
+       }
+
+       /* Clear out any pending interrupts */
+       writel(adapter_interrupts, (void *) int_reg);
+
+       /* flush the write */
+       adapter_interrupts = readl((void *) int_reg);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ------------------------------------------------------------------
+ * Begin serial-core API
+ * ------------------------------------------------------------------
+ */
+static unsigned int icom_tx_empty(struct uart_port *port)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
+           SA_FLAGS_READY_TO_XMIT)
+               ret = TIOCSER_TEMT;
+       else
+               ret = 0;
+
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+}
+
+static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       unsigned char local_osr;
+
+       trace(ICOM_PORT, "SET_MODEM", 0);
+       local_osr = readb(&ICOM_PORT->dram->osr);
+
+       if (mctrl & TIOCM_RTS) {
+               trace(ICOM_PORT, "RAISE_RTS", 0);
+               local_osr |= ICOM_RTS;
+       } else {
+               trace(ICOM_PORT, "LOWER_RTS", 0);
+               local_osr &= ~ICOM_RTS;
+       }
+
+       if (mctrl & TIOCM_DTR) {
+               trace(ICOM_PORT, "RAISE_DTR", 0);
+               local_osr |= ICOM_DTR;
+       } else {
+               trace(ICOM_PORT, "LOWER_DTR", 0);
+               local_osr &= ~ICOM_DTR;
+       }
+
+       writeb(local_osr, &ICOM_PORT->dram->osr);
+}
+
+static unsigned int icom_get_mctrl(struct uart_port *port)
+{
+       unsigned char status;
+       unsigned int result;
+
+       trace(ICOM_PORT, "GET_MODEM", 0);
+
+       status = readb(&ICOM_PORT->dram->isr);
+
+       result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
+           | ((status & ICOM_RI) ? TIOCM_RNG : 0)
+           | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
+           | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
+       return result;
+}
+
+static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+       unsigned char cmdReg;
+
+       if (tty_stop) {
+               trace(ICOM_PORT, "STOP", 0);
+               cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+               writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
+       }
+}
+
+static void icom_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "START", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
+               writeb(cmdReg & ~CMD_HOLD_XMIT,
+                      &ICOM_PORT->dram->CmdReg);
+
+       icom_write(port);
+}
+
+static void icom_send_xchar(struct uart_port *port, char ch)
+{
+       unsigned char xdata;
+       int index;
+       unsigned long flags;
+
+       trace(ICOM_PORT, "SEND_XCHAR", ch);
+
+       /* wait .1 sec to send char */
+       for (index = 0; index < 10; index++) {
+               spin_lock_irqsave(&port->lock, flags);
+               xdata = readb(&ICOM_PORT->dram->xchar);
+               if (xdata == 0x00) {
+                       trace(ICOM_PORT, "QUICK_WRITE", 0);
+                       writeb(ch, &ICOM_PORT->dram->xchar);
+
+                       /* flush write operation */
+                       xdata = readb(&ICOM_PORT->dram->xchar);
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       break;
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+               msleep(10);
+       }
+}
+
+static void icom_stop_rx(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
+}
+
+static void icom_enable_ms(struct uart_port *port)
+{
+       /* no-op */
+}
+
+static void icom_break(struct uart_port *port, int break_state)
+{
+       unsigned char cmdReg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       trace(ICOM_PORT, "BREAK", 0);
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       if (break_state == -1) {
+               writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
+       } else {
+               writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int icom_open(struct uart_port *port)
+{
+       int retval;
+
+       kobject_get(&ICOM_PORT->adapter->kobj);
+       retval = startup(ICOM_PORT);
+
+       if (retval) {
+               kobject_put(&ICOM_PORT->adapter->kobj);
+               trace(ICOM_PORT, "STARTUP_ERROR", 0);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void icom_close(struct uart_port *port)
+{
+       unsigned char cmdReg;
+
+       trace(ICOM_PORT, "CLOSE", 0);
+
+       /* stop receiver */
+       cmdReg = readb(&ICOM_PORT->dram->CmdReg);
+       writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
+              &ICOM_PORT->dram->CmdReg);
+
+       shutdown(ICOM_PORT);
+
+       kobject_put(&ICOM_PORT->adapter->kobj);
+}
+
+static void icom_set_termios(struct uart_port *port,
+                            struct termios *termios,
+                            struct termios *old_termios)
+{
+       int baud;
+       unsigned cflag, iflag;
+       int bits;
+       char new_config2;
+       char new_config3 = 0;
+       char tmp_byte;
+       int index;
+       int rcv_buff, xmit_buff;
+       unsigned long offset;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       trace(ICOM_PORT, "CHANGE_SPEED", 0);
+
+       cflag = termios->c_cflag;
+       iflag = termios->c_iflag;
+
+       new_config2 = ICOM_ACFG_DRIVE1;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+       case CS5:               /* 5 bits/char */
+               new_config2 |= ICOM_ACFG_5BPC;
+               bits = 7;
+               break;
+       case CS6:               /* 6 bits/char */
+               new_config2 |= ICOM_ACFG_6BPC;
+               bits = 8;
+               break;
+       case CS7:               /* 7 bits/char */
+               new_config2 |= ICOM_ACFG_7BPC;
+               bits = 9;
+               break;
+       case CS8:               /* 8 bits/char */
+               new_config2 |= ICOM_ACFG_8BPC;
+               bits = 10;
+               break;
+       default:
+               bits = 10;
+               break;
+       }
+       if (cflag & CSTOPB) {
+               /* 2 stop bits */
+               new_config2 |= ICOM_ACFG_2STOP_BIT;
+               bits++;
+       }
+       if (cflag & PARENB) {
+               /* parity bit enabled */
+               new_config2 |= ICOM_ACFG_PARITY_ENAB;
+               trace(ICOM_PORT, "PARENB", 0);
+               bits++;
+       }
+       if (cflag & PARODD) {
+               /* odd parity */
+               new_config2 |= ICOM_ACFG_PARITY_ODD;
+               trace(ICOM_PORT, "PARODD", 0);
+       }
+
+       /* Determine divisor based on baud rate */
+       baud = uart_get_baud_rate(port, termios, old_termios,
+                                 icom_acfg_baud[0],
+                                 icom_acfg_baud[BAUD_TABLE_LIMIT]);
+       if (!baud)
+               baud = 9600;    /* B0 transition handled in rs_set_termios */
+
+       for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
+               if (icom_acfg_baud[index] == baud) {
+                       new_config3 = index;
+                       break;
+               }
+       }
+
+       uart_update_timeout(port, cflag, baud);
+
+       /* CTS flow control flag and modem status interrupts */
+       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
+       if (cflag & CRTSCTS)
+               tmp_byte |= HDLC_HDW_FLOW;
+       else
+               tmp_byte &= ~HDLC_HDW_FLOW;
+       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
+
+       /*
+        * Set up parity check flag
+        */
+       ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
+       if (iflag & INPCK)
+               ICOM_PORT->read_status_mask |=
+                   SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
+
+       if ((iflag & BRKINT) || (iflag & PARMRK))
+               ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
+
+       /*
+        * Characters to ignore
+        */
+       ICOM_PORT->ignore_status_mask = 0;
+       if (iflag & IGNPAR)
+               ICOM_PORT->ignore_status_mask |=
+                   SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
+       if (iflag & IGNBRK) {
+               ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
+               /*
+                * If we're ignore parity and break indicators, ignore
+                * overruns too.  (For real raw support).
+                */
+               if (iflag & IGNPAR)
+                       ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
+       }
+
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
+
+       /* Turn off Receiver to prepare for reset */
+       writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
+
+       for (index = 0; index < 10; index++) {
+               if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
+                       break;
+               }
+       }
+
+       /* clear all current buffers of data */
+       for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
+               ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
+               ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
+               ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
+                   (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
+       }
+
+       for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
+               ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
+       }
+
+       /* activate changes and start xmit and receiver here */
+       /* Enable the receiver */
+       writeb(new_config3, &(ICOM_PORT->dram->async_config3));
+       writeb(new_config2, &(ICOM_PORT->dram->async_config2));
+       tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
+       tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
+       writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
+       writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer));    /* 0.5 seconds */
+       writeb(0xFF, &(ICOM_PORT->dram->ier));  /* enable modem signal interrupts */
+
+       /* reset processor */
+       writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
+
+       for (index = 0; index < 10; index++) {
+               if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
+                       break;
+               }
+       }
+
+       /* Enable Transmitter and Reciever */
+       offset =
+           (unsigned long) &ICOM_PORT->statStg->rcv[0] -
+           (unsigned long) ICOM_PORT->statStg;
+       writel(ICOM_PORT->statStg_pci + offset,
+              &ICOM_PORT->dram->RcvStatusAddr);
+       ICOM_PORT->next_rcv = 0;
+       ICOM_PORT->put_length = 0;
+       *ICOM_PORT->xmitRestart = 0;
+       writel(ICOM_PORT->xmitRestart_pci,
+              &ICOM_PORT->dram->XmitStatusAddr);
+       trace(ICOM_PORT, "XR_ENAB", 0);
+       writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *icom_type(struct uart_port *port)
+{
+       return "icom";
+}
+
+static void icom_release_port(struct uart_port *port)
+{
+}
+
+static int icom_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static void icom_config_port(struct uart_port *port, int flags)
+{
+       port->type = PORT_ICOM;
+}
+
+static struct uart_ops icom_ops = {
+       .tx_empty = icom_tx_empty,
+       .set_mctrl = icom_set_mctrl,
+       .get_mctrl = icom_get_mctrl,
+       .stop_tx = icom_stop_tx,
+       .start_tx = icom_start_tx,
+       .send_xchar = icom_send_xchar,
+       .stop_rx = icom_stop_rx,
+       .enable_ms = icom_enable_ms,
+       .break_ctl = icom_break,
+       .startup = icom_open,
+       .shutdown = icom_close,
+       .set_termios = icom_set_termios,
+       .type = icom_type,
+       .release_port = icom_release_port,
+       .request_port = icom_request_port,
+       .config_port = icom_config_port,
+};
+
+#define ICOM_CONSOLE NULL
+
+static struct uart_driver icom_uart_driver = {
+       .owner = THIS_MODULE,
+       .driver_name = ICOM_DRIVER_NAME,
+       .dev_name = "ttyA",
+       .major = ICOM_MAJOR,
+       .minor = ICOM_MINOR_START,
+       .nr = NR_PORTS,
+       .cons = ICOM_CONSOLE,
+};
+
+static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
+{
+       u32 subsystem_id = icom_adapter->subsystem_id;
+       int retval = 0;
+       int i;
+       struct icom_port *icom_port;
+
+       if (icom_adapter->version == ADAPTER_V1) {
+               icom_adapter->numb_ports = 2;
+
+               for (i = 0; i < 2; i++) {
+                       icom_port = &icom_adapter->port_info[i];
+                       icom_port->port = i;
+                       icom_port->status = ICOM_PORT_ACTIVE;
+                       icom_port->imbed_modem = ICOM_UNKNOWN;
+               }
+       } else {
+               if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
+                       icom_adapter->numb_ports = 4;
+
+                       for (i = 0; i < 4; i++) {
+                               icom_port = &icom_adapter->port_info[i];
+
+                               icom_port->port = i;
+                               icom_port->status = ICOM_PORT_ACTIVE;
+                               icom_port->imbed_modem = ICOM_IMBED_MODEM;
+                       }
+               } else {
+                       icom_adapter->numb_ports = 4;
+
+                       icom_adapter->port_info[0].port = 0;
+                       icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
+
+                       if (subsystem_id ==
+                           PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
+                               icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
+                       } else {
+                               icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
+                       }
+
+                       icom_adapter->port_info[1].status = ICOM_PORT_OFF;
+
+                       icom_adapter->port_info[2].port = 2;
+                       icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
+                       icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
+                       icom_adapter->port_info[3].status = ICOM_PORT_OFF;
+               }
+       }
+
+       return retval;
+}
+
+static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
+{
+       if (icom_adapter->version == ADAPTER_V1) {
+               icom_port->global_reg = (struct icom_regs *) ((char *)
+                       icom_adapter->base_addr + 0x4000);
+               icom_port->int_reg = (unsigned long) icom_adapter->base_addr +
+                   0x4004 + 2 - 2 * port_num;
+       } else {
+               icom_port->global_reg = (struct icom_regs *) ((char *)
+                       icom_adapter->base_addr + 0x8000);
+               if (icom_port->port < 2)
+                       icom_port->int_reg = (unsigned long) icom_adapter->base_addr +
+                           0x8004 + 2 - 2 * icom_port->port;
+               else
+                       icom_port->int_reg = (unsigned long) icom_adapter->base_addr +
+                           0x8024 + 2 - 2 * (icom_port->port - 2);
+       }
+}
+static int __init icom_load_ports(struct icom_adapter *icom_adapter)
+{
+       struct icom_port *icom_port;
+       int port_num;
+       int retval;
+
+       for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
+
+               icom_port = &icom_adapter->port_info[port_num];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       icom_port_active(icom_port, icom_adapter, port_num);
+                       icom_port->dram = (struct func_dram *) ((char *)
+                                       icom_adapter->base_addr +
+                                       0x2000 * icom_port->port);
+
+                       icom_port->adapter = icom_adapter;
+
+                       /* get port memory */
+                       if ((retval = get_port_memory(icom_port)) != 0) {
+                               dev_err(&icom_port->adapter->pci_dev->dev,
+                                       "Memory allocation for port FAILED\n");
+                       }
+               }
+       }
+       return 0;
+}
+
+static int __devinit icom_alloc_adapter(struct icom_adapter
+                                       **icom_adapter_ref)
+{
+       int adapter_count = 0;
+       struct icom_adapter *icom_adapter;
+       struct icom_adapter *cur_adapter_entry;
+       struct list_head *tmp;
+
+       icom_adapter = (struct icom_adapter *)
+           kmalloc(sizeof(struct icom_adapter), GFP_KERNEL);
+
+       if (!icom_adapter) {
+               return -ENOMEM;
+       }
+
+       memset(icom_adapter, 0, sizeof(struct icom_adapter));
+
+       list_for_each(tmp, &icom_adapter_head) {
+               cur_adapter_entry =
+                   list_entry(tmp, struct icom_adapter,
+                              icom_adapter_entry);
+               if (cur_adapter_entry->index != adapter_count) {
+                       break;
+               }
+               adapter_count++;
+       }
+
+       icom_adapter->index = adapter_count;
+       list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
+
+       *icom_adapter_ref = icom_adapter;
+       return 0;
+}
+
+static void icom_free_adapter(struct icom_adapter *icom_adapter)
+{
+       list_del(&icom_adapter->icom_adapter_entry);
+       kfree(icom_adapter);
+}
+
+static void icom_remove_adapter(struct icom_adapter *icom_adapter)
+{
+       struct icom_port *icom_port;
+       int index;
+
+       for (index = 0; index < icom_adapter->numb_ports; index++) {
+               icom_port = &icom_adapter->port_info[index];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       dev_info(&icom_adapter->pci_dev->dev,
+                                "Device removed\n");
+
+                       uart_remove_one_port(&icom_uart_driver,
+                                            &icom_port->uart_port);
+
+                       /* be sure that DTR and RTS are dropped */
+                       writeb(0x00, &icom_port->dram->osr);
+
+                       /* Wait 0.1 Sec for simple Init to complete */
+                       msleep(100);
+
+                       /* Stop proccessor */
+                       stop_processor(icom_port);
+
+                       free_port_memory(icom_port);
+               }
+       }
+
+       free_irq(icom_adapter->irq_number, (void *) icom_adapter);
+       iounmap((void *) icom_adapter->base_addr);
+       icom_free_adapter(icom_adapter);
+       pci_release_regions(icom_adapter->pci_dev);
+}
+
+static void icom_kobj_release(struct kobject *kobj)
+{
+       struct icom_adapter *icom_adapter;
+
+       icom_adapter = to_icom_adapter(kobj);
+       icom_remove_adapter(icom_adapter);
+}
+
+static struct kobj_type icom_kobj_type = {
+       .release = icom_kobj_release,
+};
+
+static int __devinit icom_probe(struct pci_dev *dev,
+                               const struct pci_device_id *ent)
+{
+       int index;
+        unsigned int command_reg;
+        int retval;
+        struct icom_adapter *icom_adapter;
+        struct icom_port *icom_port;
+
+        retval = pci_enable_device(dev);
+        if (retval) {
+               dev_err(&dev->dev, "Device enable FAILED\n");
+                return retval;
+       }
+
+       if ( (retval = pci_request_regions(dev, "icom"))) {
+                dev_err(&dev->dev, "pci_request_region FAILED\n");
+                pci_disable_device(dev);
+                return retval;
+        }
+
+        pci_set_master(dev);
+
+        if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
+               dev_err(&dev->dev, "PCI Config read FAILED\n");
+                return retval;
+        }
+
+       pci_write_config_dword(dev, PCI_COMMAND,
+               command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
+               | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+
+        if (ent->driver_data == ADAPTER_V1) {
+               pci_write_config_dword(dev, 0x44, 0x8300830A);
+        } else {
+               pci_write_config_dword(dev, 0x44, 0x42004200);
+               pci_write_config_dword(dev, 0x48, 0x42004200);
+         }
+
+
+       retval = icom_alloc_adapter(&icom_adapter);
+       if (retval) {
+                dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
+                retval = -EIO;
+                goto probe_exit0;
+       }
+
+        icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
+        icom_adapter->irq_number = dev->irq;
+        icom_adapter->pci_dev = dev;
+        icom_adapter->version = ent->driver_data;
+        icom_adapter->subsystem_id = ent->subdevice;
+
+
+       retval = icom_init_ports(icom_adapter);
+       if (retval) {
+               dev_err(&dev->dev, "Port configuration failed\n");
+               goto probe_exit1;
+       }
+
+        icom_adapter->base_addr =
+            (unsigned long) ioremap(icom_adapter->base_addr_pci,
+                                               pci_resource_len(dev, 0));
+
+       if (!icom_adapter->base_addr)
+               goto probe_exit1;
+
+        /* save off irq and request irq line */
+        if ( (retval = request_irq(dev->irq, icom_interrupt,
+                                  SA_INTERRUPT | SA_SHIRQ, ICOM_DRIVER_NAME,
+                                  (void *) icom_adapter))) {
+                 goto probe_exit2;
+        }
+
+       retval = icom_load_ports(icom_adapter);
+
+        for (index = 0; index < icom_adapter->numb_ports; index++) {
+               icom_port = &icom_adapter->port_info[index];
+
+               if (icom_port->status == ICOM_PORT_ACTIVE) {
+                       icom_port->uart_port.irq = icom_port->adapter->irq_number;
+                       icom_port->uart_port.type = PORT_ICOM;
+                       icom_port->uart_port.iotype = UPIO_MEM;
+                       icom_port->uart_port.membase =
+                                              (char *) icom_adapter->base_addr_pci;
+                       icom_port->uart_port.fifosize = 16;
+                       icom_port->uart_port.ops = &icom_ops;
+                       icom_port->uart_port.line =
+                       icom_port->port + icom_adapter->index * 4;
+                       if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
+                               icom_port->status = ICOM_PORT_OFF;
+                               dev_err(&dev->dev, "Device add failed\n");
+                        } else
+                               dev_info(&dev->dev, "Device added\n");
+               }
+       }
+
+       kobject_init(&icom_adapter->kobj);
+       icom_adapter->kobj.ktype = &icom_kobj_type;
+       return 0;
+
+probe_exit2:
+       iounmap((void *) icom_adapter->base_addr);
+probe_exit1:
+       icom_free_adapter(icom_adapter);
+
+probe_exit0:
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+
+        return retval;
+
+
+}
+
+static void __devexit icom_remove(struct pci_dev *dev)
+{
+       struct icom_adapter *icom_adapter;
+       struct list_head *tmp;
+
+       list_for_each(tmp, &icom_adapter_head) {
+               icom_adapter = list_entry(tmp, struct icom_adapter,
+                                         icom_adapter_entry);
+               if (icom_adapter->pci_dev == dev) {
+                       kobject_put(&icom_adapter->kobj);
+                       return;
+               }
+       }
+
+       dev_err(&dev->dev, "Unable to find device to remove\n");
+}
+
+static struct pci_driver icom_pci_driver = {
+       .name = ICOM_DRIVER_NAME,
+       .id_table = icom_pci_table,
+       .probe = icom_probe,
+       .remove = __devexit_p(icom_remove),
+};
+
+static int __init icom_init(void)
+{
+       int ret;
+
+       spin_lock_init(&icom_lock);
+       icom_lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
+       ret = uart_register_driver(&icom_uart_driver);
+       if (ret)
+               return ret;
+
+       ret = pci_register_driver(&icom_pci_driver);
+
+       if (ret < 0)
+               uart_unregister_driver(&icom_uart_driver);
+
+       return ret;
+}
+
+static void __exit icom_exit(void)
+{
+       pci_unregister_driver(&icom_pci_driver);
+       uart_unregister_driver(&icom_uart_driver);
+}
+
+module_init(icom_init);
+module_exit(icom_exit);
+
+#ifdef ICOM_TRACE
+static inline void trace(struct icom_port *icom_port, char *trace_pt,
+                 unsigned long trace_data)
+{
+       dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
+                icom_port->port, trace_pt, trace_data);
+}
+#endif
+
+MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
+MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
+MODULE_SUPPORTED_DEVICE
+    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
new file mode 100644 (file)
index 0000000..479b52d
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * icom.h
+ *
+ * Copyright (C) 2001 Michael Anderson, IBM Corporation
+ *
+ * Serial device driver include 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
+ * (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/serial_core.h>
+
+#define BAUD_TABLE_LIMIT       ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
+static int icom_acfg_baud[] = {
+       300,
+       600,
+       900,
+       1200,
+       1800,
+       2400,
+       3600,
+       4800,
+       7200,
+       9600,
+       14400,
+       19200,
+       28800,
+       38400,
+       57600,
+       76800,
+       115200,
+       153600,
+       230400,
+       307200,
+       460800,
+};
+
+struct icom_regs {
+       u32 control;            /* Adapter Control Register     */
+       u32 interrupt;          /* Adapter Interrupt Register   */
+       u32 int_mask;           /* Adapter Interrupt Mask Reg   */
+       u32 int_pri;            /* Adapter Interrupt Priority r */
+       u32 int_reg_b;          /* Adapter non-masked Interrupt */
+       u32 resvd01;
+       u32 resvd02;
+       u32 resvd03;
+       u32 control_2;          /* Adapter Control Register 2   */
+       u32 interrupt_2;        /* Adapter Interrupt Register 2 */
+       u32 int_mask_2;         /* Adapter Interrupt Mask 2     */
+       u32 int_pri_2;          /* Adapter Interrupt Prior 2    */
+       u32 int_reg_2b;         /* Adapter non-masked 2         */
+};
+
+struct func_dram {
+       u32 reserved[108];      /* 0-1B0   reserved by personality code */
+       u32 RcvStatusAddr;      /* 1B0-1B3 Status Address for Next rcv */
+       u8 RcvStnAddr;          /* 1B4     Receive Station Addr */
+       u8 IdleState;           /* 1B5     Idle State */
+       u8 IdleMonitor;         /* 1B6     Idle Monitor */
+       u8 FlagFillIdleTimer;   /* 1B7     Flag Fill Idle Timer */
+       u32 XmitStatusAddr;     /* 1B8-1BB Transmit Status Address */
+       u8 StartXmitCmd;        /* 1BC     Start Xmit Command */
+       u8 HDLCConfigReg;       /* 1BD     Reserved */
+       u8 CauseCode;           /* 1BE     Cause code for fatal error */
+       u8 xchar;               /* 1BF     High priority send */
+       u32 reserved3;          /* 1C0-1C3 Reserved */
+       u8 PrevCmdReg;          /* 1C4     Reserved */
+       u8 CmdReg;              /* 1C5     Command Register */
+       u8 async_config2;       /* 1C6     Async Config Byte 2 */
+       u8 async_config3;       /* 1C7     Async Config Byte 3 */
+       u8 dce_resvd[20];       /* 1C8-1DB DCE Rsvd           */
+       u8 dce_resvd21;         /* 1DC     DCE Rsvd (21st byte */
+       u8 misc_flags;          /* 1DD     misc flags         */
+#define V2_HARDWARE     0x40
+#define ICOM_HDW_ACTIVE 0x01
+       u8 call_length;         /* 1DE     Phone #/CFI buff ln */
+       u8 call_length2;        /* 1DF     Upper byte (unused) */
+       u32 call_addr;          /* 1E0-1E3 Phn #/CFI buff addr */
+       u16 timer_value;        /* 1E4-1E5 general timer value */
+       u8 timer_command;       /* 1E6     general timer cmd  */
+       u8 dce_command;         /* 1E7     dce command reg    */
+       u8 dce_cmd_status;      /* 1E8     dce command stat   */
+       u8 x21_r1_ioff;         /* 1E9     dce ready counter  */
+       u8 x21_r0_ioff;         /* 1EA     dce not ready ctr  */
+       u8 x21_ralt_ioff;       /* 1EB     dce CNR counter    */
+       u8 x21_r1_ion;          /* 1EC     dce ready I on ctr */
+       u8 rsvd_ier;            /* 1ED     Rsvd for IER (if ne */
+       u8 ier;                 /* 1EE     Interrupt Enable   */
+       u8 isr;                 /* 1EF     Input Signal Reg   */
+       u8 osr;                 /* 1F0     Output Signal Reg  */
+       u8 reset;               /* 1F1     Reset/Reload Reg   */
+       u8 disable;             /* 1F2     Disable Reg        */
+       u8 sync;                /* 1F3     Sync Reg           */
+       u8 error_stat;          /* 1F4     Error Status       */
+       u8 cable_id;            /* 1F5     Cable ID           */
+       u8 cs_length;           /* 1F6     CS Load Length     */
+       u8 mac_length;          /* 1F7     Mac Load Length    */
+       u32 cs_load_addr;       /* 1F8-1FB Call Load PCI Addr */
+       u32 mac_load_addr;      /* 1FC-1FF Mac Load PCI Addr  */
+};
+
+/*
+ * adapter defines and structures
+ */
+#define ICOM_CONTROL_START_A         0x00000008
+#define ICOM_CONTROL_STOP_A          0x00000004
+#define ICOM_CONTROL_START_B         0x00000002
+#define ICOM_CONTROL_STOP_B          0x00000001
+#define ICOM_CONTROL_START_C         0x00000008
+#define ICOM_CONTROL_STOP_C          0x00000004
+#define ICOM_CONTROL_START_D         0x00000002
+#define ICOM_CONTROL_STOP_D          0x00000001
+#define ICOM_IRAM_OFFSET             0x1000
+#define ICOM_IRAM_SIZE               0x0C00
+#define ICOM_DCE_IRAM_OFFSET         0x0A00
+#define ICOM_CABLE_ID_VALID          0x01
+#define ICOM_CABLE_ID_MASK           0xF0
+#define ICOM_DISABLE                 0x80
+#define CMD_XMIT_RCV_ENABLE          0xC0
+#define CMD_XMIT_ENABLE              0x40
+#define CMD_RCV_DISABLE              0x00
+#define CMD_RCV_ENABLE               0x80
+#define CMD_RESTART                  0x01
+#define CMD_HOLD_XMIT                0x02
+#define CMD_SND_BREAK                0x04
+#define RS232_CABLE                  0x06
+#define V24_CABLE                    0x0E
+#define V35_CABLE                    0x0C
+#define V36_CABLE                    0x02
+#define NO_CABLE                     0x00
+#define START_DOWNLOAD               0x80
+#define ICOM_INT_MASK_PRC_A          0x00003FFF
+#define ICOM_INT_MASK_PRC_B          0x3FFF0000
+#define ICOM_INT_MASK_PRC_C          0x00003FFF
+#define ICOM_INT_MASK_PRC_D          0x3FFF0000
+#define INT_RCV_COMPLETED            0x1000
+#define INT_XMIT_COMPLETED           0x2000
+#define INT_IDLE_DETECT              0x0800
+#define INT_RCV_DISABLED             0x0400
+#define INT_XMIT_DISABLED            0x0200
+#define INT_RCV_XMIT_SHUTDOWN        0x0100
+#define INT_FATAL_ERROR              0x0080
+#define INT_CABLE_PULL               0x0020
+#define INT_SIGNAL_CHANGE            0x0010
+#define HDLC_PPP_PURE_ASYNC          0x02
+#define HDLC_FF_FILL                 0x00
+#define HDLC_HDW_FLOW                0x01
+#define START_XMIT                   0x80
+#define ICOM_ACFG_DRIVE1             0x20
+#define ICOM_ACFG_NO_PARITY          0x00
+#define ICOM_ACFG_PARITY_ENAB        0x02
+#define ICOM_ACFG_PARITY_ODD         0x01
+#define ICOM_ACFG_8BPC               0x00
+#define ICOM_ACFG_7BPC               0x04
+#define ICOM_ACFG_6BPC               0x08
+#define ICOM_ACFG_5BPC               0x0C
+#define ICOM_ACFG_1STOP_BIT          0x00
+#define ICOM_ACFG_2STOP_BIT          0x10
+#define ICOM_DTR                     0x80
+#define ICOM_RTS                     0x40
+#define ICOM_RI                      0x08
+#define ICOM_DSR                     0x80
+#define ICOM_DCD                     0x20
+#define ICOM_CTS                     0x40
+
+#define NUM_XBUFFS 1
+#define NUM_RBUFFS 2
+#define RCV_BUFF_SZ 0x0200
+#define XMIT_BUFF_SZ 0x1000
+struct statusArea {
+    /**********************************************/
+       /* Transmit Status Area                       */
+    /**********************************************/
+       struct xmit_status_area{
+               u32 leNext;     /* Next entry in Little Endian on Adapter */
+               u32 leNextASD;
+               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
+               u16 leLengthASD;
+               u16 leOffsetASD;
+               u16 leLength;   /* Length of data in segment */
+               u16 flags;
+#define SA_FLAGS_DONE           0x0080 /* Done with Segment */
+#define SA_FLAGS_CONTINUED      0x8000 /* More Segments */
+#define SA_FLAGS_IDLE           0x4000 /* Mark IDLE after frm */
+#define SA_FLAGS_READY_TO_XMIT  0x0800
+#define SA_FLAGS_STAT_MASK      0x007F
+       } xmit[NUM_XBUFFS];
+
+    /**********************************************/
+       /* Receive Status Area                        */
+    /**********************************************/
+       struct {
+               u32 leNext;     /* Next entry in Little Endian on Adapter */
+               u32 leNextASD;
+               u32 leBuffer;   /* Buffer for entry in LE for Adapter */
+               u16 WorkingLength;      /* size of segment */
+               u16 reserv01;
+               u16 leLength;   /* Length of data in segment */
+               u16 flags;
+#define SA_FL_RCV_DONE           0x0010        /* Data ready */
+#define SA_FLAGS_OVERRUN         0x0040
+#define SA_FLAGS_PARITY_ERROR    0x0080
+#define SA_FLAGS_FRAME_ERROR     0x0001
+#define SA_FLAGS_FRAME_TRUNC     0x0002
+#define SA_FLAGS_BREAK_DET       0x0004        /* set conditionally by device driver, not hardware */
+#define SA_FLAGS_RCV_MASK        0xFFE6
+       } rcv[NUM_RBUFFS];
+};
+
+struct icom_adapter;
+
+
+#define ICOM_MAJOR       243
+#define ICOM_MINOR_START 0
+
+struct icom_port {
+       struct uart_port uart_port;
+       u8 imbed_modem;
+#define ICOM_UNKNOWN           1
+#define ICOM_RVX               2
+#define ICOM_IMBED_MODEM       3
+       unsigned char cable_id;
+       unsigned char read_status_mask;
+       unsigned char ignore_status_mask;
+       unsigned long int_reg;
+       struct icom_regs *global_reg;
+       struct func_dram *dram;
+       int port;
+       struct statusArea *statStg;
+       dma_addr_t statStg_pci;
+       u32 *xmitRestart;
+       dma_addr_t xmitRestart_pci;
+       unsigned char *xmit_buf;
+       dma_addr_t xmit_buf_pci;
+       unsigned char *recv_buf;
+       dma_addr_t recv_buf_pci;
+       int next_rcv;
+       int put_length;
+       int status;
+#define ICOM_PORT_ACTIVE       1       /* Port exists. */
+#define ICOM_PORT_OFF          0       /* Port does not exist. */
+       int load_in_progress;
+       struct icom_adapter *adapter;
+};
+
+struct icom_adapter {
+       unsigned long base_addr;
+       unsigned long base_addr_pci;
+       unsigned char irq_number;
+       struct pci_dev *pci_dev;
+       struct icom_port port_info[4];
+       int index;
+       int version;
+#define ADAPTER_V1     0x0001
+#define ADAPTER_V2     0x0002
+       u32 subsystem_id;
+#define FOUR_PORT_MODEL                                0x0252
+#define V2_TWO_PORTS_RVX                       0x021A
+#define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM     0x0251
+       int numb_ports;
+       struct list_head icom_adapter_entry;
+       struct kobject kobj;
+};
+
+/* prototype */
+extern void iCom_sercons_init(void);
+
+struct lookup_proc_table {
+       u32     *global_control_reg;
+       unsigned long   processor_id;
+};
+
+struct lookup_int_table {
+       u32     *global_int_mask;
+       unsigned long   processor_id;
+};
+
+#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000)
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
new file mode 100644 (file)
index 0000000..fc2a8f0
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+ *  linux/drivers/serial/imx.c
+ *
+ *  Driver for Motorola IMX serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ *  Author: Sascha Hauer <sascha@saschahauer.de>
+ *  Copyright (C) 2004 Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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>
+
+#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+
+/* We've been assigned a range on the "Low-density serial ports" major */
+#define SERIAL_IMX_MAJOR       204
+#define MINOR_START            41
+
+#define NR_PORTS               2
+
+#define IMX_ISR_PASS_LIMIT     256
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x100
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change.  They generally aren't connected to an IRQ
+ * so we have to poll them.  We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT  (250*HZ/1000)
+
+#define DRIVER_NAME "IMX-uart"
+
+struct imx_port {
+       struct uart_port        port;
+       struct timer_list       timer;
+       unsigned int            old_status;
+       int txirq,rxirq;
+};
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void imx_mctrl_check(struct imx_port *sport)
+{
+       unsigned int status, changed;
+
+       status = sport->port.ops->get_mctrl(&sport->port);
+       changed = status ^ sport->old_status;
+
+       if (changed == 0)
+               return;
+
+       sport->old_status = status;
+
+       if (changed & TIOCM_RI)
+               sport->port.icount.rng++;
+       if (changed & TIOCM_DSR)
+               sport->port.icount.dsr++;
+       if (changed & TIOCM_CAR)
+               uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+       if (changed & TIOCM_CTS)
+               uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+       wake_up_interruptible(&sport->port.info->delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void imx_timeout(unsigned long data)
+{
+       struct imx_port *sport = (struct imx_port *)data;
+       unsigned long flags;
+
+       if (sport->port.info) {
+               spin_lock_irqsave(&sport->port.lock, flags);
+               imx_mctrl_check(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
+
+               mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+       }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN;
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_stop_rx(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       UCR2((u32)sport->port.membase) &= ~UCR2_RXEN;
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void imx_enable_ms(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       mod_timer(&sport->timer, jiffies);
+}
+
+static inline void imx_transmit_buffer(struct imx_port *sport)
+{
+       struct circ_buf *xmit = &sport->port.info->xmit;
+
+       do {
+               /* send xmit->buf[xmit->tail]
+                * out the port here */
+               URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail];
+               xmit->tail = (xmit->tail + 1) &
+                        (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL));
+
+       if (uart_circ_empty(xmit))
+               imx_stop_tx(&sport->port, 0);
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void imx_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN;
+
+       if(UTS((u32)sport->port.membase) & UTS_TXEMPTY)
+               imx_transmit_buffer(sport);
+}
+
+static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct imx_port *sport = (struct imx_port *)dev_id;
+       struct circ_buf *xmit = &sport->port.info->xmit;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock,flags);
+       if (sport->port.x_char)
+       {
+               /* Send next char */
+               URTX0((u32)sport->port.membase) = sport->port.x_char;
+               goto out;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+               imx_stop_tx(&sport->port, 0);
+               goto out;
+       }
+
+       imx_transmit_buffer(sport);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
+
+out:
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int rx,flg,ignored = 0;
+       struct tty_struct *tty = sport->port.info->tty;
+       unsigned long flags;
+
+       rx = URXD0((u32)sport->port.membase);
+       spin_lock_irqsave(&sport->port.lock,flags);
+
+       do {
+               flg = TTY_NORMAL;
+               sport->port.icount.rx++;
+
+               if( USR2((u32)sport->port.membase) & USR2_BRCD ) {
+                       USR2((u32)sport->port.membase) |= USR2_BRCD;
+                       if(uart_handle_break(&sport->port))
+                               goto ignore_char;
+               }
+
+               if (uart_handle_sysrq_char
+                           (&sport->port, (unsigned char)rx, regs))
+                       goto ignore_char;
+
+               if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) )
+                       goto handle_error;
+
+       error_return:
+               tty_insert_flip_char(tty, rx, flg);
+
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                       goto out;
+
+       ignore_char:
+               rx = URXD0((u32)sport->port.membase);
+       } while(rx & URXD_CHARRDY);
+
+out:
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+       tty_flip_buffer_push(tty);
+       return IRQ_HANDLED;
+
+handle_error:
+       if (rx & URXD_PRERR)
+               sport->port.icount.parity++;
+       else if (rx & URXD_FRMERR)
+               sport->port.icount.frame++;
+       if (rx & URXD_OVRRUN)
+               sport->port.icount.overrun++;
+
+       if (rx & sport->port.ignore_status_mask) {
+               if (++ignored > 100)
+                       goto out;
+               goto ignore_char;
+       }
+
+       rx &= sport->port.read_status_mask;
+
+       if (rx & URXD_PRERR)
+               flg = TTY_PARITY;
+       else if (rx & URXD_FRMERR)
+               flg = TTY_FRAME;
+       if (rx & URXD_OVRRUN)
+               flg = TTY_OVERRUN;
+
+#ifdef SUPPORT_SYSRQ
+       sport->port.sysrq = 0;
+#endif
+       goto error_return;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int imx_tx_empty(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return USR2((u32)sport->port.membase) & USR2_TXDC ?  TIOCSER_TEMT : 0;
+}
+
+static unsigned int imx_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void imx_break_ctl(struct uart_port *port, int break_state)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       if ( break_state != 0 )
+               UCR1((u32)sport->port.membase) |= UCR1_SNDBRK;
+       else
+               UCR1((u32)sport->port.membase) &= ~UCR1_SNDBRK;
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+#define TXTL 2 /* reset default */
+#define RXTL 1 /* reset default */
+
+static int imx_startup(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       int retval;
+       unsigned int val;
+       unsigned long flags;
+
+       /* set receiver / transmitter trigger level. We assume
+        * that RFDIV has been set by the arch setup or by the bootloader.
+        */
+       val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV)  | TXTL<<10 | RXTL;
+       UFCR((u32)sport->port.membase) = val;
+
+       /* disable the DREN bit (Data Ready interrupt enable) before
+        * requesting IRQs
+        */
+       UCR4((u32)sport->port.membase) &= ~UCR4_DREN;
+
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(sport->rxirq, imx_rxint, 0,
+                            DRIVER_NAME, sport);
+       if (retval) goto error_out2;
+
+       retval = request_irq(sport->txirq, imx_txint, 0,
+                            "imx-uart", sport);
+       if (retval) goto error_out1;
+
+       /*
+        * Finally, clear and enable interrupts
+        */
+
+       UCR1((u32)sport->port.membase) |=
+                        (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_UARTEN);
+
+       UCR2((u32)sport->port.membase) |= (UCR2_RXEN | UCR2_TXEN);
+       /*
+        * Enable modem status interrupts
+        */
+       spin_lock_irqsave(&sport->port.lock,flags);
+       imx_enable_ms(&sport->port);
+       spin_unlock_irqrestore(&sport->port.lock,flags);
+
+       return 0;
+
+error_out1:
+       free_irq(sport->rxirq, sport);
+error_out2:
+       free_irq(sport->txirq, sport);
+       return retval;
+}
+
+static void imx_shutdown(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       /*
+        * Stop our timer.
+        */
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Free the interrupts
+        */
+       free_irq(sport->txirq, sport);
+       free_irq(sport->rxirq, sport);
+
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+
+       UCR1((u32)sport->port.membase) &=
+                        ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_UARTEN);
+}
+
+static void
+imx_set_termios(struct uart_port *port, struct termios *termios,
+                  struct termios *old)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags;
+       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
+       unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+       /*
+        * If we don't support modem control lines, don't allow
+        * these to be set.
+        */
+       if (0) {
+               termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
+               termios->c_cflag |= CLOCAL;
+       }
+
+       /*
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+       }
+
+       if ((termios->c_cflag & CSIZE) == CS8)
+               ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
+       else
+               ucr2 = UCR2_SRST | UCR2_IRTS;
+
+       if (termios->c_cflag & CSTOPB)
+               ucr2 |= UCR2_STPB;
+       if (termios->c_cflag & PARENB) {
+               ucr2 |= UCR2_PREN;
+               if (!(termios->c_cflag & PARODD))
+                       ucr2 |= UCR2_PROE;
+       }
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+
+       sport->port.read_status_mask = 0;
+       if (termios->c_iflag & INPCK)
+               sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               sport->port.read_status_mask |= URXD_BRK;
+
+       /*
+        * Characters to ignore
+        */
+       sport->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               sport->port.ignore_status_mask |= URXD_PRERR;
+       if (termios->c_iflag & IGNBRK) {
+               sport->port.ignore_status_mask |= URXD_BRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       sport->port.ignore_status_mask |= URXD_OVRRUN;
+       }
+
+       del_timer_sync(&sport->timer);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       /*
+        * disable interrupts and drain transmitter
+        */
+       old_ucr1 = UCR1((u32)sport->port.membase);
+       UCR1((u32)sport->port.membase) &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN);
+
+       while ( !(USR2((u32)sport->port.membase) & USR2_TXDC))
+               barrier();
+
+       /* then, disable everything */
+       old_txrxen = UCR2((u32)sport->port.membase) & ( UCR2_TXEN | UCR2_RXEN );
+       UCR2((u32)sport->port.membase) &= ~( UCR2_TXEN | UCR2_RXEN);
+
+       /* set the parity, stop bits and data size */
+       UCR2((u32)sport->port.membase) = ucr2;
+
+       /* set the baud rate. We assume uartclk = 16 MHz
+        *
+        * baud * 16   UBIR - 1
+        * --------- = --------
+        *  uartclk    UBMR - 1
+        */
+       UBIR((u32)sport->port.membase) = (baud / 100) - 1;
+       UBMR((u32)sport->port.membase) = 10000 - 1;
+
+       UCR1((u32)sport->port.membase) = old_ucr1;
+       UCR2((u32)sport->port.membase) |= old_txrxen;
+
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               imx_enable_ms(&sport->port);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *imx_type(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return sport->port.type == PORT_IMX ? "IMX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void imx_release_port(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int imx_request_port(struct uart_port *port)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+                       "imx-uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void imx_config_port(struct uart_port *port, int flags)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+
+       if (flags & UART_CONFIG_TYPE &&
+           imx_request_port(&sport->port) == 0)
+               sport->port.type = PORT_IMX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_IMX and PORT_UNKNOWN
+ */
+static int
+imx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       struct imx_port *sport = (struct imx_port *)port;
+       int ret = 0;
+
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX)
+               ret = -EINVAL;
+       if (sport->port.irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != UPIO_MEM)
+               ret = -EINVAL;
+       if (sport->port.uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)sport->port.mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (sport->port.iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+}
+
+static struct uart_ops imx_pops = {
+       .tx_empty       = imx_tx_empty,
+       .set_mctrl      = imx_set_mctrl,
+       .get_mctrl      = imx_get_mctrl,
+       .stop_tx        = imx_stop_tx,
+       .start_tx       = imx_start_tx,
+       .stop_rx        = imx_stop_rx,
+       .enable_ms      = imx_enable_ms,
+       .break_ctl      = imx_break_ctl,
+       .startup        = imx_startup,
+       .shutdown       = imx_shutdown,
+       .set_termios    = imx_set_termios,
+       .type           = imx_type,
+       .release_port   = imx_release_port,
+       .request_port   = imx_request_port,
+       .config_port    = imx_config_port,
+       .verify_port    = imx_verify_port,
+};
+
+static struct imx_port imx_ports[] = {
+       {
+       .txirq  = UART1_MINT_TX,
+       .rxirq  = UART1_MINT_RX,
+       .port   = {
+               .type           = PORT_IMX,
+               .iotype         = SERIAL_IO_MEM,
+               .membase        = (void *)IMX_UART1_BASE,
+               .mapbase        = IMX_UART1_BASE, /* FIXME */
+               .irq            = UART1_MINT_RX,
+               .uartclk        = 16000000,
+               .fifosize       = 8,
+               .flags          = ASYNC_BOOT_AUTOCONF,
+               .ops            = &imx_pops,
+               .line           = 0,
+       },
+       }, {
+       .txirq  = UART2_MINT_TX,
+       .rxirq  = UART2_MINT_RX,
+       .port   = {
+               .type           = PORT_IMX,
+               .iotype         = SERIAL_IO_MEM,
+               .membase        = (void *)IMX_UART2_BASE,
+               .mapbase        = IMX_UART2_BASE, /* FIXME */
+               .irq            = UART2_MINT_RX,
+               .uartclk        = 16000000,
+               .fifosize       = 8,
+               .flags          = ASYNC_BOOT_AUTOCONF,
+               .ops            = &imx_pops,
+               .line           = 1,
+       },
+       }
+};
+
+/*
+ * Setup the IMX serial ports.
+ * Note also that we support "console=ttySMXx" where "x" is either 0 or 1.
+ * Which serial port this ends up being depends on the machine you're
+ * running this kernel on.  I'm not convinced that this is a good idea,
+ * but that's the way it traditionally works.
+ *
+ */
+static void __init imx_init_ports(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < ARRAY_SIZE(imx_ports); i++) {
+               init_timer(&imx_ports[i].timer);
+               imx_ports[i].timer.function = imx_timeout;
+               imx_ports[i].timer.data     = (unsigned long)&imx_ports[i];
+       }
+
+       imx_gpio_mode(PC9_PF_UART1_CTS);
+       imx_gpio_mode(PC10_PF_UART1_RTS);
+       imx_gpio_mode(PC11_PF_UART1_TXD);
+       imx_gpio_mode(PC12_PF_UART1_RXD);
+       imx_gpio_mode(PB28_PF_UART2_CTS);
+       imx_gpio_mode(PB29_PF_UART2_RTS);
+
+       imx_gpio_mode(PB30_PF_UART2_TXD);
+       imx_gpio_mode(PB31_PF_UART2_RXD);
+
+#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart
+       * is implemented.
+       */
+       imx_gpio_mode(PD7_AF_UART2_DTR);
+       imx_gpio_mode(PD8_AF_UART2_DCD);
+       imx_gpio_mode(PD9_AF_UART2_RI);
+       imx_gpio_mode(PD10_AF_UART2_DSR);
+#endif
+
+
+}
+
+#ifdef CONFIG_SERIAL_IMX_CONSOLE
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+imx_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct imx_port *sport = &imx_ports[co->index];
+       unsigned int old_ucr1, old_ucr2, i;
+
+       /*
+        *      First, save UCR1/2 and then disable interrupts
+        */
+       old_ucr1 = UCR1((u32)sport->port.membase);
+       old_ucr2 = UCR2((u32)sport->port.membase);
+
+       UCR1((u32)sport->port.membase) =
+                          (old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN)
+                          & ~(UCR1_TXMPTYEN | UCR1_RRDYEN);
+       UCR2((u32)sport->port.membase) = old_ucr2 | UCR2_TXEN;
+
+       /*
+        *      Now, do each character
+        */
+       for (i = 0; i < count; i++) {
+
+               while ((UTS((u32)sport->port.membase) & UTS_TXFULL))
+                       barrier();
+
+               URTX0((u32)sport->port.membase) = s[i];
+
+               if (s[i] == '\n') {
+                       while ((UTS((u32)sport->port.membase) & UTS_TXFULL))
+                               barrier();
+                       URTX0((u32)sport->port.membase) = '\r';
+               }
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore UCR1/2
+        */
+       while (!(USR2((u32)sport->port.membase) & USR2_TXDC));
+
+       UCR1((u32)sport->port.membase) = old_ucr1;
+       UCR2((u32)sport->port.membase) = old_ucr2;
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+imx_console_get_options(struct imx_port *sport, int *baud,
+                          int *parity, int *bits)
+{
+       if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
+               /* ok, the port was enabled */
+               unsigned int ucr2, ubir,ubmr, uartclk;
+
+               ucr2 = UCR2((u32)sport->port.membase);
+
+               *parity = 'n';
+               if (ucr2 & UCR2_PREN) {
+                       if (ucr2 & UCR2_PROE)
+                               *parity = 'o';
+                       else
+                               *parity = 'e';
+               }
+
+               if (ucr2 & UCR2_WS)
+                       *bits = 8;
+               else
+                       *bits = 7;
+
+               ubir = UBIR((u32)sport->port.membase) & 0xffff;
+               ubmr = UBMR((u32)sport->port.membase) & 0xffff;
+               uartclk = sport->port.uartclk;
+
+               *baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1);
+       }
+}
+
+static int __init
+imx_console_setup(struct console *co, char *options)
+{
+       struct imx_port *sport;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
+               co->index = 0;
+       sport = &imx_ports[co->index];
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               imx_console_get_options(sport, &baud, &parity, &bits);
+
+       return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+extern struct uart_driver imx_reg;
+static struct console imx_console = {
+       .name           = "ttySMX",
+       .write          = imx_console_write,
+       .device         = uart_console_device,
+       .setup          = imx_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &imx_reg,
+};
+
+static int __init imx_rs_console_init(void)
+{
+       imx_init_ports();
+       register_console(&imx_console);
+       return 0;
+}
+console_initcall(imx_rs_console_init);
+
+#define IMX_CONSOLE    &imx_console
+#else
+#define IMX_CONSOLE    NULL
+#endif
+
+static struct uart_driver imx_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = DRIVER_NAME,
+       .dev_name       = "ttySMX",
+       .devfs_name     = "ttsmx/",
+       .major          = SERIAL_IMX_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ARRAY_SIZE(imx_ports),
+       .cons           = IMX_CONSOLE,
+};
+
+static int serial_imx_suspend(struct device *_dev, u32 state, u32 level)
+{
+        struct imx_port *sport = dev_get_drvdata(_dev);
+
+        if (sport && level == SUSPEND_DISABLE)
+                uart_suspend_port(&imx_reg, &sport->port);
+
+        return 0;
+}
+
+static int serial_imx_resume(struct device *_dev, u32 level)
+{
+        struct imx_port *sport = dev_get_drvdata(_dev);
+
+        if (sport && level == RESUME_ENABLE)
+                uart_resume_port(&imx_reg, &sport->port);
+
+        return 0;
+}
+
+static int serial_imx_probe(struct device *_dev)
+{
+       struct platform_device *dev = to_platform_device(_dev);
+
+       imx_ports[dev->id].port.dev = _dev;
+       uart_add_one_port(&imx_reg, &imx_ports[dev->id].port);
+       dev_set_drvdata(_dev, &imx_ports[dev->id]);
+       return 0;
+}
+
+static int serial_imx_remove(struct device *_dev)
+{
+       struct imx_port *sport = dev_get_drvdata(_dev);
+
+       dev_set_drvdata(_dev, NULL);
+
+       if (sport)
+               uart_remove_one_port(&imx_reg, &sport->port);
+
+       return 0;
+}
+
+static struct device_driver serial_imx_driver = {
+        .name           = "imx-uart",
+        .bus            = &platform_bus_type,
+        .probe          = serial_imx_probe,
+        .remove         = serial_imx_remove,
+
+       .suspend        = serial_imx_suspend,
+       .resume         = serial_imx_resume,
+};
+
+static int __init imx_serial_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Serial: IMX driver\n");
+
+       imx_init_ports();
+
+       ret = uart_register_driver(&imx_reg);
+       if (ret)
+               return ret;
+
+       ret = driver_register(&serial_imx_driver);
+       if (ret != 0)
+               uart_unregister_driver(&imx_reg);
+
+       return 0;
+}
+
+static void __exit imx_serial_exit(void)
+{
+       uart_unregister_driver(&imx_reg);
+}
+
+module_init(imx_serial_init);
+module_exit(imx_serial_exit);
+
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_DESCRIPTION("IMX generic serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
new file mode 100644 (file)
index 0000000..380c295
--- /dev/null
@@ -0,0 +1,1373 @@
+/*
+ *  m32r_sio.c
+ *
+ *  Driver for M32R serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/8250.c.
+ *
+ *  Copyright (C) 2001  Russell King.
+ *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * A note about mapbase / membase
+ *
+ *  mapbase is the physical address of the IO port.  Currently, we don't
+ *  support this very well, and it may well be dropped from this driver
+ *  in future.  As such, mapbase should be NULL.
+ *
+ *  membase is an 'ioremapped' cookie.  This is compatible with the old
+ *  serial.c driver, and is currently the preferred form.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/delay.h>
+
+#include <asm/m32r.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#define PORT_SIO       1
+#define PORT_MAX_SIO   1
+#define BAUD_RATE      115200
+
+#include <linux/serial_core.h>
+#include "m32r_sio.h"
+#include "m32r_sio_reg.h"
+
+/*
+ * Configuration:
+ *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
+ *                is unsafe when used on edge-triggered interrupts.
+ */
+unsigned int share_irqs_sio = M32R_SIO_SHARE_IRQS;
+
+/*
+ * Debugging.
+ */
+#if 0
+#define DEBUG_AUTOCONF(fmt...) printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...) do { } while (0)
+#endif
+
+#if 0
+#define DEBUG_INTR(fmt...)     printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)     do { } while (0)
+#endif
+
+#define PASS_LIMIT     256
+
+/*
+ * We default to IRQ0 for the "no irq" hack.   Some
+ * machine types want others as well - they're free
+ * to redefine this in their header file.
+ */
+#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_M32R_SIO_DETECT_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ 1
+#endif
+#ifdef CONFIG_SERIAL_M32R_SIO_MULTIPORT
+#define CONFIG_SERIAL_MULTIPORT 1
+#endif
+#ifdef CONFIG_SERIAL_M32R_SIO_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS 1
+#endif
+
+/*
+ * HUB6 is always on.  This will be removed once the header
+ * files have been cleaned.
+ */
+#define CONFIG_HUB6 1
+
+#include <asm/serial.h>
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+static struct old_serial_port old_serial_port[] = {
+       { 0, BASE_BAUD, ((unsigned long)PLD_ESIO0CR), PLD_IRQ_SIO0_RCV, STD_COM_FLAGS },
+};
+#else
+static struct old_serial_port old_serial_port[] = {
+       { 0, BASE_BAUD, M32R_SIO_OFFSET, M32R_IRQ_SIO0_R, STD_COM_FLAGS },
+};
+#endif
+
+#define UART_NR        ARRAY_SIZE(old_serial_port)
+
+struct uart_sio_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          rev;
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           lsr_break_flag;
+
+       /*
+        * We provide a per-port pm hook.
+        */
+       void                    (*pm)(struct uart_port *port,
+                                     unsigned int state, unsigned int old);
+};
+
+struct irq_info {
+       spinlock_t              lock;
+       struct list_head        *head;
+};
+
+static struct irq_info irq_lists[NR_IRQS];
+
+/*
+ * Here we define the default xmit fifo size used for each type of UART.
+ */
+static const struct serial_uart_config uart_config[PORT_MAX_SIO+1] = {
+       { "unknown",    1,      0 },
+       { "M32RSIO",    1,      0 }
+};
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+
+#define __sio_in(x) inw((unsigned long)(x))
+#define __sio_out(v,x) outw((v),(unsigned long)(x))
+
+static inline void sio_set_baud_rate(unsigned long baud)
+{
+       unsigned short sbaud;
+       sbaud = (boot_cpu_data.bus_clock / (baud * 4))-1;
+       __sio_out(sbaud, PLD_ESIO0BAUR);
+}
+
+static void sio_reset(void)
+{
+       unsigned short tmp;
+
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0CR);
+       sio_set_baud_rate(BAUD_RATE);
+       __sio_out(0x0300, PLD_ESIO0CR);
+       __sio_out(0x0003, PLD_ESIO0CR);
+}
+
+static void sio_init(void)
+{
+       unsigned short tmp;
+
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0RXB);
+       tmp = __sio_in(PLD_ESIO0CR);
+       __sio_out(0x0300, PLD_ESIO0CR);
+       __sio_out(0x0003, PLD_ESIO0CR);
+}
+
+static void sio_error(int *status)
+{
+       printk("SIO0 error[%04x]\n", *status);
+       do {
+               sio_init();
+       } while ((*status = __sio_in(PLD_ESIO0CR)) != 3);
+}
+
+#else /* not CONFIG_SERIAL_M32R_PLDSIO */
+
+#define __sio_in(x) inl(x)
+#define __sio_out(v,x) outl((v),(x))
+
+static inline void sio_set_baud_rate(unsigned long baud)
+{
+       unsigned long i, j;
+
+       i = boot_cpu_data.bus_clock / (baud * 16);
+       j = (boot_cpu_data.bus_clock - (i * baud * 16)) / baud;
+       i -= 1;
+       j = (j + 1) >> 1;
+
+       __sio_out(i, M32R_SIO0_BAUR_PORTL);
+       __sio_out(j, M32R_SIO0_RBAUR_PORTL);
+}
+
+static void sio_reset(void)
+{
+       __sio_out(0x00000300, M32R_SIO0_CR_PORTL);      /* init status */
+       __sio_out(0x00000800, M32R_SIO0_MOD1_PORTL);    /* 8bit        */
+       __sio_out(0x00000080, M32R_SIO0_MOD0_PORTL);    /* 1stop non   */
+       sio_set_baud_rate(BAUD_RATE);
+       __sio_out(0x00000000, M32R_SIO0_TRCR_PORTL);
+       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);      /* RXCEN */
+}
+
+static void sio_init(void)
+{
+       unsigned int tmp;
+
+       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
+       tmp = __sio_in(M32R_SIO0_RXB_PORTL);
+       tmp = __sio_in(M32R_SIO0_STS_PORTL);
+       __sio_out(0x00000003, M32R_SIO0_CR_PORTL);
+}
+
+static void sio_error(int *status)
+{
+       printk("SIO0 error[%04x]\n", *status);
+       do {
+               sio_init();
+       } while ((*status = __sio_in(M32R_SIO0_CR_PORTL)) != 3);
+}
+
+#endif /* CONFIG_SERIAL_M32R_PLDSIO */
+
+static _INLINE_ unsigned int sio_in(struct uart_sio_port *up, int offset)
+{
+       return __sio_in(up->port.iobase + offset);
+}
+
+static _INLINE_ void sio_out(struct uart_sio_port *up, int offset, int value)
+{
+       __sio_out(value, up->port.iobase + offset);
+}
+
+static _INLINE_ unsigned int serial_in(struct uart_sio_port *up, int offset)
+{
+       if (!offset)
+               return 0;
+
+       return __sio_in(offset);
+}
+
+static _INLINE_ void
+serial_out(struct uart_sio_port *up, int offset, int value)
+{
+       if (!offset)
+               return;
+
+       __sio_out(value, offset);
+}
+
+static void m32r_sio_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (up->ier & UART_IER_THRI) {
+               up->ier &= ~UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+}
+
+static void m32r_sio_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       struct circ_buf *xmit = &up->port.info->xmit;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+       }
+       while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
+#else
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (!(up->ier & UART_IER_THRI)) {
+               up->ier |= UART_IER_THRI;
+               serial_out(up, UART_IER, up->ier);
+       }
+#endif
+}
+
+static void m32r_sio_stop_rx(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       up->ier &= ~UART_IER_RLSI;
+       up->port.read_status_mask &= ~UART_LSR_DR;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static void m32r_sio_enable_ms(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       up->ier |= UART_IER_MSI;
+       serial_out(up, UART_IER, up->ier);
+}
+
+static _INLINE_ void receive_chars(struct uart_sio_port *up, int *status,
+       struct pt_regs *regs)
+{
+       struct tty_struct *tty = up->port.info->tty;
+       unsigned char ch;
+       int max_count = 256;
+
+       do {
+               if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
+                       tty->flip.work.func((void *)tty);
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                               return; // if TTY_DONT_FLIP is set
+               }
+               ch = sio_in(up, SIORXB);
+               *tty->flip.char_buf_ptr = ch;
+               *tty->flip.flag_buf_ptr = TTY_NORMAL;
+               up->port.icount.rx++;
+
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               up->port.icount.brk++;
+                               /*
+                                * We do the SysRQ and SAK checking
+                                * here because otherwise the break
+                                * may get masked by ignore_status_mask
+                                * or read_status_mask.
+                                */
+                               if (uart_handle_break(&up->port))
+                                       goto ignore_char;
+                       } else if (*status & UART_LSR_PE)
+                               up->port.icount.parity++;
+                       else if (*status & UART_LSR_FE)
+                               up->port.icount.frame++;
+                       if (*status & UART_LSR_OE)
+                               up->port.icount.overrun++;
+
+                       /*
+                        * Mask off conditions which should be ingored.
+                        */
+                       *status &= up->port.read_status_mask;
+
+                       if (up->port.line == up->port.cons->index) {
+                               /* Recover the break flag from console xmit */
+                               *status |= up->lsr_break_flag;
+                               up->lsr_break_flag = 0;
+                       }
+
+                       if (*status & UART_LSR_BI) {
+                               DEBUG_INTR("handling break....");
+                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(&up->port, ch, regs))
+                       goto ignore_char;
+               if ((*status & up->port.ignore_status_mask) == 0) {
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
+               }
+               if ((*status & UART_LSR_OE) &&
+                   tty->flip.count < TTY_FLIPBUF_SIZE) {
+                       /*
+                        * Overrun is special, since it's reported
+                        * immediately, and doesn't affect the current
+                        * character.
+                        */
+                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
+               }
+       ignore_char:
+               *status = serial_in(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+       tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct uart_sio_port *up)
+{
+       struct circ_buf *xmit = &up->port.info->xmit;
+       int count;
+
+       if (up->port.x_char) {
+#ifndef CONFIG_SERIAL_M32R_PLDSIO      /* XXX */
+               serial_out(up, UART_TX, up->port.x_char);
+#endif
+               up->port.icount.tx++;
+               up->port.x_char = 0;
+               return;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+               m32r_sio_stop_tx(&up->port, 0);
+               return;
+       }
+
+       count = up->port.fifosize;
+       do {
+               serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               up->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+               while (!serial_in(up, UART_LSR) & UART_LSR_THRE);
+
+       } while (--count > 0);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&up->port);
+
+       DEBUG_INTR("THRE...");
+
+       if (uart_circ_empty(xmit))
+               m32r_sio_stop_tx(&up->port, 0);
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static inline void m32r_sio_handle_port(struct uart_sio_port *up,
+       unsigned int status, struct pt_regs *regs)
+{
+       DEBUG_INTR("status = %x...", status);
+
+       if (status & 0x04)
+               receive_chars(up, &status, regs);
+       // check_modem_status(up);
+       if (status & 0x01)
+               transmit_chars(up);
+}
+
+/*
+ * This is the serial driver's interrupt routine.
+ *
+ * Arjan thinks the old way was overly complex, so it got simplified.
+ * Alan disagrees, saying that need the complexity to handle the weird
+ * nature of ISA shared interrupts.  (This is a special exception.)
+ *
+ * In order to handle ISA shared interrupts properly, we need to check
+ * that all ports have been serviced, and therefore the ISA interrupt
+ * line has been de-asserted.
+ *
+ * This means we need to loop through all ports. checking that they
+ * don't have an interrupt pending.
+ */
+static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id,
+       struct pt_regs *regs)
+{
+       struct irq_info *i = dev_id;
+       struct list_head *l, *end = NULL;
+       int pass_counter = 0;
+
+       DEBUG_INTR("m32r_sio_interrupt(%d)...", irq);
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+//     if (irq == PLD_IRQ_SIO0_SND)
+//             irq = PLD_IRQ_SIO0_RCV;
+#else
+       if (irq == M32R_IRQ_SIO0_S)
+               irq = M32R_IRQ_SIO0_R;
+#endif
+
+       spin_lock(&i->lock);
+
+       l = i->head;
+       do {
+               struct uart_sio_port *up;
+               unsigned int sts;
+
+               up = list_entry(l, struct uart_sio_port, list);
+
+               sts = sio_in(up, SIOSTS);
+               if (sts & 0x5) {
+                       spin_lock(&up->port.lock);
+                       m32r_sio_handle_port(up, sts, regs);
+                       spin_unlock(&up->port.lock);
+
+                       end = NULL;
+               } else if (end == NULL)
+                       end = l;
+
+               l = l->next;
+
+               if (l == i->head && pass_counter++ > PASS_LIMIT) {
+                       if (sts & 0xe0)
+                               sio_error(&sts);
+                       break;
+               }
+       } while (l != end);
+
+       spin_unlock(&i->lock);
+
+       DEBUG_INTR("end.\n");
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * To support ISA shared interrupts, we need to have one interrupt
+ * handler that ensures that the IRQ line has been deasserted
+ * before returning.  Failing to do this will result in the IRQ
+ * line being stuck active, and, since ISA irqs are edge triggered,
+ * no more IRQs will be seen.
+ */
+static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
+{
+       spin_lock_irq(&i->lock);
+
+       if (!list_empty(i->head)) {
+               if (i->head == &up->list)
+                       i->head = i->head->next;
+               list_del(&up->list);
+       } else {
+               BUG_ON(i->head != &up->list);
+               i->head = NULL;
+       }
+
+       spin_unlock_irq(&i->lock);
+}
+
+static int serial_link_irq_chain(struct uart_sio_port *up)
+{
+       struct irq_info *i = irq_lists + up->port.irq;
+       int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
+
+       spin_lock_irq(&i->lock);
+
+       if (i->head) {
+               list_add(&up->list, i->head);
+               spin_unlock_irq(&i->lock);
+
+               ret = 0;
+       } else {
+               INIT_LIST_HEAD(&up->list);
+               i->head = &up->list;
+               spin_unlock_irq(&i->lock);
+
+               ret = request_irq(up->port.irq, m32r_sio_interrupt,
+                                 irq_flags, "SIO0-RX", i);
+               ret |= request_irq(up->port.irq + 1, m32r_sio_interrupt,
+                                 irq_flags, "SIO0-TX", i);
+               if (ret < 0)
+                       serial_do_unlink(i, up);
+       }
+
+       return ret;
+}
+
+static void serial_unlink_irq_chain(struct uart_sio_port *up)
+{
+       struct irq_info *i = irq_lists + up->port.irq;
+
+       BUG_ON(i->head == NULL);
+
+       if (list_empty(i->head)) {
+               free_irq(up->port.irq, i);
+               free_irq(up->port.irq + 1, i);
+       }
+
+       serial_do_unlink(i, up);
+}
+
+/*
+ * This function is used to handle ports that do not have an
+ * interrupt.  This doesn't work very well for 16450's, but gives
+ * barely passable results for a 16550A.  (Although at the expense
+ * of much CPU overhead).
+ */
+static void m32r_sio_timeout(unsigned long data)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)data;
+       unsigned int timeout;
+       unsigned int sts;
+
+       sts = sio_in(up, SIOSTS);
+       if (sts & 0x5) {
+               spin_lock(&up->port.lock);
+               m32r_sio_handle_port(up, sts, NULL);
+               spin_unlock(&up->port.lock);
+       }
+
+       timeout = up->port.timeout;
+       timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+       mod_timer(&up->timer, jiffies + timeout);
+}
+
+static unsigned int m32r_sio_tx_empty(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+       ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+
+       return ret;
+}
+
+static unsigned int m32r_sio_get_mctrl(struct uart_port *port)
+{
+       return 0;
+}
+
+static void m32r_sio_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+
+}
+
+static void m32r_sio_break_ctl(struct uart_port *port, int break_state)
+{
+
+}
+
+static int m32r_sio_startup(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       int retval;
+
+       sio_init();
+
+       /*
+        * If the "interrupt" for this port doesn't correspond with any
+        * hardware interrupt, we use a timer-based system.  The original
+        * driver used to do this with IRQ0.
+        */
+       if (!is_real_interrupt(up->port.irq)) {
+               unsigned int timeout = up->port.timeout;
+
+               timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+
+               up->timer.data = (unsigned long)up;
+               mod_timer(&up->timer, jiffies + timeout);
+       } else {
+               retval = serial_link_irq_chain(up);
+               if (retval)
+                       return retval;
+       }
+
+       /*
+        * Finally, enable interrupts.  Note: Modem status interrupts
+        * are set via set_termios(), which will be occurring imminently
+        * anyway, so we don't enable them here.
+        * - M32R_SIO: 0x0c
+        * - M32R_PLDSIO: 0x04
+        */
+       up->ier = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+       sio_out(up, SIOTRCR, up->ier);
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       sio_reset();
+
+       return 0;
+}
+
+static void m32r_sio_shutdown(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       /*
+        * Disable interrupts from this port
+        */
+       up->ier = 0;
+       sio_out(up, SIOTRCR, 0);
+
+       /*
+        * Disable break condition and FIFOs
+        */
+
+       sio_init();
+
+       if (!is_real_interrupt(up->port.irq))
+               del_timer_sync(&up->timer);
+       else
+               serial_unlink_irq_chain(up);
+}
+
+static unsigned int m32r_sio_get_divisor(struct uart_port *port,
+       unsigned int baud)
+{
+       return uart_get_divisor(port, baud);
+}
+
+static void m32r_sio_set_termios(struct uart_port *port,
+       struct termios *termios, struct termios *old)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned char cval = 0;
+       unsigned long flags;
+       unsigned int baud, quot;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               cval = 0x00;
+               break;
+       case CS6:
+               cval = 0x01;
+               break;
+       case CS7:
+               cval = 0x02;
+               break;
+       default:
+       case CS8:
+               cval = 0x03;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               cval |= 0x04;
+       if (termios->c_cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(termios->c_cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (termios->c_cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
+#else
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+#endif
+       quot = m32r_sio_get_divisor(port, baud);
+
+       /*
+        * Ok, we're now changing the port state.  Do it with
+        * interrupts disabled.
+        */
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       sio_set_baud_rate(baud);
+
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (termios->c_iflag & INPCK)
+               up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               up->port.read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characteres to ignore
+        */
+       up->port.ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (termios->c_iflag & IGNBRK) {
+               up->port.ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       up->port.ignore_status_mask |= UART_LSR_OE;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               up->port.ignore_status_mask |= UART_LSR_DR;
+
+       /*
+        * CTS flow control flag and modem status interrupts
+        */
+       up->ier &= ~UART_IER_MSI;
+       if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+               up->ier |= UART_IER_MSI;
+
+       serial_out(up, UART_IER, up->ier);
+
+       up->lcr = cval;                                 /* Save LCR */
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void m32r_sio_pm(struct uart_port *port, unsigned int state,
+       unsigned int oldstate)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       if (up->pm)
+               up->pm(port, state, oldstate);
+}
+
+/*
+ * Resource handling.  This is complicated by the fact that resources
+ * depend on the port type.  Maybe we should be claiming the standard
+ * 8250 ports, and then trying to get other resources as necessary?
+ */
+static int
+m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
+{
+       unsigned int size = 8 << up->port.regshift;
+#ifndef CONFIG_SERIAL_M32R_PLDSIO
+       unsigned long start;
+#endif
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       case SERIAL_IO_MEM:
+               if (up->port.mapbase) {
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+                       *res = request_mem_region(up->port.mapbase, size, "serial");
+#else
+                       start = up->port.mapbase;
+                       start += UART_RSA_BASE << up->port.regshift;
+                       *res = request_mem_region(start, size, "serial");
+#endif
+                       if (!*res)
+                               ret = -EBUSY;
+               }
+               break;
+
+       case SERIAL_IO_HUB6:
+       case SERIAL_IO_PORT:
+               *res = request_region(up->port.iobase, size, "serial");
+               if (!*res)
+                       ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+static int
+m32r_sio_request_rsa_resource(struct uart_sio_port *up, struct resource **res)
+{
+       unsigned int size = 8 << up->port.regshift;
+       unsigned long start;
+       int ret = 0;
+
+       switch (up->port.iotype) {
+       case SERIAL_IO_MEM:
+               if (up->port.mapbase) {
+                       start = up->port.mapbase;
+                       start += UART_RSA_BASE << up->port.regshift;
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+                       *res = request_mem_region(start, size, "serial-rsa");
+#else
+                       *res = request_mem_region(up->port.mapbase, size, "serial-rsa");
+#endif
+                       if (!*res)
+                               ret = -EBUSY;
+               }
+               break;
+
+       case SERIAL_IO_HUB6:
+       case SERIAL_IO_PORT:
+               start = up->port.iobase;
+               start += UART_RSA_BASE << up->port.regshift;
+               *res = request_region(up->port.iobase, size, "serial-rsa");
+               if (!*res)
+                       ret = -EBUSY;
+               break;
+       }
+
+       return ret;
+}
+
+static void m32r_sio_release_port(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       unsigned long start, offset = 0, size = 0;
+
+       if (up->port.type == PORT_RSA) {
+               offset = UART_RSA_BASE << up->port.regshift;
+               size = 8;
+       }
+
+       size <<= up->port.regshift;
+
+       switch (up->port.iotype) {
+       case SERIAL_IO_MEM:
+               if (up->port.mapbase) {
+                       /*
+                        * Unmap the area.
+                        */
+                       iounmap(up->port.membase);
+                       up->port.membase = NULL;
+
+                       start = up->port.mapbase;
+
+                       if (size)
+                               release_mem_region(start + offset, size);
+                       release_mem_region(start, 8 << up->port.regshift);
+               }
+               break;
+
+       case SERIAL_IO_HUB6:
+       case SERIAL_IO_PORT:
+               start = up->port.iobase;
+
+               if (size)
+                       release_region(start + offset, size);
+               release_region(start + offset, 8 << up->port.regshift);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int m32r_sio_request_port(struct uart_port *port)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+       struct resource *res = NULL, *res_rsa = NULL;
+       int ret = 0;
+
+       if (up->port.type == PORT_RSA){
+               ret = m32r_sio_request_rsa_resource(up, &res_rsa);
+               if (ret < 0)
+                       return ret;
+       }
+       ret = m32r_sio_request_std_resource(up, &res);
+
+       /*
+        * If we have a mapbase, then request that as well.
+        */
+       if (ret == 0 && up->port.flags & UPF_IOREMAP) {
+               int size = res->end - res->start + 1;
+
+               up->port.membase = ioremap(up->port.mapbase, size);
+               if (!up->port.membase)
+                       ret = -ENOMEM;
+       }
+
+       if (ret < 0) {
+               if (res_rsa)
+                       release_resource(res_rsa);
+               if (res)
+                       release_resource(res);
+       }
+       return ret;
+}
+
+static void m32r_sio_config_port(struct uart_port *port, int flags)
+{
+       struct uart_sio_port *up = (struct uart_sio_port *)port;
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       up->port.type = PORT_SIO;
+       up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+
+       spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int
+m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+           ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+           ser->type > PORT_MAX_SIO || ser->type == PORT_CIRRUS ||
+           ser->type == PORT_STARTECH)
+               return -EINVAL;
+       return 0;
+}
+
+static const char *
+m32r_sio_type(struct uart_port *port)
+{
+       int type = port->type;
+
+       if (type >= ARRAY_SIZE(uart_config))
+               type = 0;
+       return uart_config[type].name;
+}
+
+static struct uart_ops m32r_sio_pops = {
+       .tx_empty       = m32r_sio_tx_empty,
+       .set_mctrl      = m32r_sio_set_mctrl,
+       .get_mctrl      = m32r_sio_get_mctrl,
+       .stop_tx        = m32r_sio_stop_tx,
+       .start_tx       = m32r_sio_start_tx,
+       .stop_rx        = m32r_sio_stop_rx,
+       .enable_ms      = m32r_sio_enable_ms,
+       .break_ctl      = m32r_sio_break_ctl,
+       .startup        = m32r_sio_startup,
+       .shutdown       = m32r_sio_shutdown,
+       .set_termios    = m32r_sio_set_termios,
+       .pm             = m32r_sio_pm,
+       .type           = m32r_sio_type,
+       .release_port   = m32r_sio_release_port,
+       .request_port   = m32r_sio_request_port,
+       .config_port    = m32r_sio_config_port,
+       .verify_port    = m32r_sio_verify_port,
+};
+
+static struct uart_sio_port m32r_sio_ports[UART_NR];
+
+static void __init m32r_sio_isa_init_ports(void)
+{
+       struct uart_sio_port *up;
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0, up = m32r_sio_ports; i < ARRAY_SIZE(old_serial_port);
+            i++, up++) {
+               up->port.iobase   = old_serial_port[i].port;
+               up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
+               up->port.uartclk  = old_serial_port[i].baud_base * 16;
+               up->port.flags    = old_serial_port[i].flags;
+               up->port.hub6     = old_serial_port[i].hub6;
+               up->port.membase  = old_serial_port[i].iomem_base;
+               up->port.iotype   = old_serial_port[i].io_type;
+               up->port.regshift = old_serial_port[i].iomem_reg_shift;
+               up->port.ops      = &m32r_sio_pops;
+               if (share_irqs_sio)
+                       up->port.flags |= UPF_SHARE_IRQ;
+       }
+}
+
+static void __init m32r_sio_register_ports(struct uart_driver *drv)
+{
+       int i;
+
+       m32r_sio_isa_init_ports();
+
+       for (i = 0; i < UART_NR; i++) {
+               struct uart_sio_port *up = &m32r_sio_ports[i];
+
+               up->port.line = i;
+               up->port.ops = &m32r_sio_pops;
+               init_timer(&up->timer);
+               up->timer.function = m32r_sio_timeout;
+
+               /*
+                * ALPHA_KLUDGE_MCR needs to be killed.
+                */
+               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
+               up->mcr_force = ALPHA_KLUDGE_MCR;
+
+               uart_add_one_port(drv, &up->port);
+       }
+}
+
+#ifdef CONFIG_SERIAL_M32R_SIO_CONSOLE
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct uart_sio_port *up)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       do {
+               status = sio_in(up, SIOSTS);
+
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       } while ((status & UART_EMPTY) != UART_EMPTY);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout)
+                       udelay(1);
+       }
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void m32r_sio_console_write(struct console *co, const char *s,
+       unsigned int count)
+{
+       struct uart_sio_port *up = &m32r_sio_ports[co->index];
+       unsigned int ier;
+       int i;
+
+       /*
+        *      First save the UER then disable the interrupts
+        */
+       ier = sio_in(up, SIOTRCR);
+       sio_out(up, SIOTRCR, 0);
+
+       /*
+        *      Now, do each character
+        */
+       for (i = 0; i < count; i++, s++) {
+               wait_for_xmitr(up);
+
+               /*
+                *      Send the character out.
+                *      If a LF, also do CR...
+                */
+               sio_out(up, SIOTXB, *s);
+
+               if (*s == 10) {
+                       wait_for_xmitr(up);
+                       sio_out(up, SIOTXB, 13);
+               }
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, SIOTRCR, ier);
+}
+
+static int __init m32r_sio_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= UART_NR)
+               co->index = 0;
+       port = &m32r_sio_ports[co->index].port;
+
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&port->lock);
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+extern struct uart_driver m32r_sio_reg;
+static struct console m32r_sio_console = {
+       .name           = "ttyS",
+       .write          = m32r_sio_console_write,
+       .device         = uart_console_device,
+       .setup          = m32r_sio_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &m32r_sio_reg,
+};
+
+static int __init m32r_sio_console_init(void)
+{
+       sio_reset();
+       sio_init();
+       m32r_sio_isa_init_ports();
+       register_console(&m32r_sio_console);
+       return 0;
+}
+console_initcall(m32r_sio_console_init);
+
+#define M32R_SIO_CONSOLE       &m32r_sio_console
+#else
+#define M32R_SIO_CONSOLE       NULL
+#endif
+
+static struct uart_driver m32r_sio_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "sio",
+       .devfs_name             = "tts/",
+       .dev_name               = "ttyS",
+       .major                  = TTY_MAJOR,
+       .minor                  = 64,
+       .nr                     = UART_NR,
+       .cons                   = M32R_SIO_CONSOLE,
+};
+
+/*
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+
+static int __register_m32r_sio(struct serial_struct *req, int line)
+{
+       struct uart_port port;
+
+       port.iobase   = req->port;
+       port.membase  = req->iomem_base;
+       port.irq      = req->irq;
+       port.uartclk  = req->baud_base * 16;
+       port.fifosize = req->xmit_fifo_size;
+       port.regshift = req->iomem_reg_shift;
+       port.iotype   = req->io_type;
+       port.flags    = req->flags | UPF_BOOT_AUTOCONF;
+       port.mapbase  = req->iomap_base;
+       port.line     = line;
+
+       if (share_irqs_sio)
+               port.flags |= UPF_SHARE_IRQ;
+
+       if (HIGH_BITS_OFFSET)
+               port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
+
+       /*
+        * If a clock rate wasn't specified by the low level
+        * driver, then default to the standard clock rate.
+        */
+       if (port.uartclk == 0)
+               port.uartclk = BASE_BAUD * 16;
+
+       return uart_register_port(&m32r_sio_reg, &port);
+}
+
+/**
+ *     register_serial - configure a 16x50 serial port at runtime
+ *     @req: request structure
+ *
+ *     Configure the serial port specified by the request. If the
+ *     port exists and is in use an error is returned. If the port
+ *     is not currently in the table it is added.
+ *
+ *     The port is then probed and if necessary the IRQ is autodetected
+ *     If this fails an error is returned.
+ *
+ *     On success the port is ready to use and the line number is returned.
+ */
+int register_m32r_sio(struct serial_struct *req)
+{
+       return __register_m32r_sio(req, -1);
+}
+
+int __init early_m32r_sio_setup(struct uart_port *port)
+{
+       m32r_sio_isa_init_ports();
+       m32r_sio_ports[port->line].port = *port;
+       m32r_sio_ports[port->line].port.ops = &m32r_sio_pops;
+
+       return 0;
+}
+
+/**
+ *     unregister_serial - remove a 16x50 serial port at runtime
+ *     @line: serial line number
+ *
+ *     Remove one serial port.  This may be called from interrupt
+ *     context.
+ */
+void unregister_m32r_sio(int line)
+{
+       uart_unregister_port(&m32r_sio_reg, line);
+}
+
+/*
+ * This is for ISAPNP only.
+ */
+void m32r_sio_get_irq_map(unsigned int *map)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++) {
+               if (m32r_sio_ports[i].port.type != PORT_UNKNOWN &&
+                   m32r_sio_ports[i].port.irq < 16)
+                       *map |= 1 << m32r_sio_ports[i].port.irq;
+       }
+}
+
+/**
+ *     m32r_sio_suspend_port - suspend one serial port
+ *     @line: serial line number
+ *
+ *     Suspend one serial port.
+ */
+void m32r_sio_suspend_port(int line)
+{
+       uart_suspend_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
+}
+
+/**
+ *     m32r_sio_resume_port - resume one serial port
+ *     @line: serial line number
+ *
+ *     Resume one serial port.
+ */
+void m32r_sio_resume_port(int line)
+{
+       uart_resume_port(&m32r_sio_reg, &m32r_sio_ports[line].port);
+}
+
+static int __init m32r_sio_init(void)
+{
+       int ret, i;
+
+       printk(KERN_INFO "Serial: M32R SIO driver $Revision: 1.9 $ "
+               "IRQ sharing %sabled\n", share_irqs_sio ? "en" : "dis");
+
+       for (i = 0; i < NR_IRQS; i++)
+               spin_lock_init(&irq_lists[i].lock);
+
+       ret = uart_register_driver(&m32r_sio_reg);
+       if (ret >= 0)
+               m32r_sio_register_ports(&m32r_sio_reg);
+
+       return ret;
+}
+
+static void __exit m32r_sio_exit(void)
+{
+       int i;
+
+       for (i = 0; i < UART_NR; i++)
+               uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
+
+       uart_unregister_driver(&m32r_sio_reg);
+}
+
+module_init(m32r_sio_init);
+module_exit(m32r_sio_exit);
+
+EXPORT_SYMBOL(register_m32r_sio);
+EXPORT_SYMBOL(unregister_m32r_sio);
+EXPORT_SYMBOL(m32r_sio_get_irq_map);
+EXPORT_SYMBOL(m32r_sio_suspend_port);
+EXPORT_SYMBOL(m32r_sio_resume_port);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic M32R SIO serial driver $Revision: 1.9 $");
+
+module_param(share_irqs_sio, bool, 0400);
+MODULE_PARM_DESC(share_irqs_sio, "Share IRQs with other non-M32R SIO devices"
+       " (unsafe)");
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
new file mode 100644 (file)
index 0000000..f957c76
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  m32r_sio.h
+ *
+ *  Driver for M32R serial ports
+ *
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *  Based on drivers/serial/8250.h.
+ *
+ *  Copyright (C) 2001  Russell King.
+ *  Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+
+struct m32r_sio_probe {
+       struct module   *owner;
+       int             (*pci_init_one)(struct pci_dev *dev);
+       void            (*pci_remove_one)(struct pci_dev *dev);
+       void            (*pnp_init)(void);
+};
+
+int m32r_sio_register_probe(struct m32r_sio_probe *probe);
+void m32r_sio_unregister_probe(struct m32r_sio_probe *probe);
+void m32r_sio_get_irq_map(unsigned int *map);
+void m32r_sio_suspend_port(int line);
+void m32r_sio_resume_port(int line);
+
+struct old_serial_port {
+       unsigned int uart;
+       unsigned int baud_base;
+       unsigned int port;
+       unsigned int irq;
+       unsigned int flags;
+       unsigned char hub6;
+       unsigned char io_type;
+       unsigned char *iomem_base;
+       unsigned short iomem_reg_shift;
+};
+
+#define _INLINE_ inline
+
+#define PROBE_RSA      (1 << 0)
+#define PROBE_ANY      (~0)
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+#ifdef CONFIG_SERIAL_SIO_SHARE_IRQ
+#define M32R_SIO_SHARE_IRQS 1
+#else
+#define M32R_SIO_SHARE_IRQS 0
+#endif
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h
new file mode 100644 (file)
index 0000000..d940255
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * m32r_sio_reg.h
+ *
+ * Copyright (C) 1992, 1994 by Theodore Ts'o.
+ * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ *
+ * These are the UART port assignments, expressed as offsets from the base
+ * register.  These assignments should hold for any serial port based on
+ * a 8250, 16450, or 16550(A).
+ */
+
+#ifndef _M32R_SIO_REG_H
+#define _M32R_SIO_REG_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SERIAL_M32R_PLDSIO
+
+#define SIOCR          0x000
+#define SIOMOD0                0x002
+#define SIOMOD1                0x004
+#define SIOSTS         0x006
+#define SIOTRCR                0x008
+#define SIOBAUR                0x00a
+// #define SIORBAUR    0x018
+#define SIOTXB         0x00c
+#define SIORXB         0x00e
+
+#define UART_RX                ((unsigned long) PLD_ESIO0RXB)
+                               /* In:  Receive buffer (DLAB=0) */
+#define UART_TX                ((unsigned long) PLD_ESIO0TXB)
+                               /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels
+                                * XR16C85x only */
+
+#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER       ((unsigned long) PLD_ESIO0INTCR)
+                               /* Out: Interrupt Enable Register */
+#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
+                                * XR16C85x only */
+
+#define UART_IIR       0       /* In:  Interrupt ID Register */
+#define UART_FCR       0       /* Out: FIFO Control Register */
+#define UART_EFR       0       /* I/O: Extended Features Register */
+                               /* (DLAB=1, 16C660 only) */
+
+#define UART_LCR       0       /* Out: Line Control Register */
+#define UART_MCR       0       /* Out: Modem Control Register */
+#define UART_LSR       ((unsigned long) PLD_ESIO0STS)
+                               /* In:  Line Status Register */
+#define UART_MSR       0       /* In:  Modem Status Register */
+#define UART_SCR       0       /* I/O: Scratch Register */
+#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
+                                * FCTR bit 6 selects SCR or EMSR
+                                * XR16c85x only */
+
+#else /* not CONFIG_SERIAL_M32R_PLDSIO */
+
+#define SIOCR          0x000
+#define SIOMOD0                0x004
+#define SIOMOD1                0x008
+#define SIOSTS         0x00c
+#define SIOTRCR                0x010
+#define SIOBAUR                0x014
+#define SIORBAUR       0x018
+#define SIOTXB         0x01c
+#define SIORXB         0x020
+
+#define UART_RX                M32R_SIO0_RXB_PORTL     /* In:  Receive buffer (DLAB=0) */
+#define UART_TX                M32R_SIO0_TXB_PORTL     /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL       0       /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG       0       /* (LCR=BF) FCTR bit 7 selects Rx or Tx
+                                * In: Fifo count
+                                * Out: Fifo custom trigger levels
+                                * XR16C85x only */
+
+#define UART_DLM       0       /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER       M32R_SIO0_TRCR_PORTL    /* Out: Interrupt Enable Register */
+#define UART_FCTR      0       /* (LCR=BF) Feature Control Register
+                                * XR16C85x only */
+
+#define UART_IIR       0       /* In:  Interrupt ID Register */
+#define UART_FCR       0       /* Out: FIFO Control Register */
+#define UART_EFR       0       /* I/O: Extended Features Register */
+                               /* (DLAB=1, 16C660 only) */
+
+#define UART_LCR       0       /* Out: Line Control Register */
+#define UART_MCR       0       /* Out: Modem Control Register */
+#define UART_LSR       M32R_SIO0_STS_PORTL     /* In:  Line Status Register */
+#define UART_MSR       0       /* In:  Modem Status Register */
+#define UART_SCR       0       /* I/O: Scratch Register */
+#define UART_EMSR      0       /* (LCR=BF) Extended Mode Select Register
+                                * FCTR bit 6 selects SCR or EMSR
+                                * XR16c85x only */
+
+#endif /* CONFIG_SERIAL_M32R_PLDSIO */
+
+#define UART_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ * These are the definitions for the FIFO Control Register
+ * (16650 only)
+ */
+#define UART_FCR_ENABLE_FIFO   0x01 /* Enable the FIFO */
+#define UART_FCR_CLEAR_RCVR    0x02 /* Clear the RCVR FIFO */
+#define UART_FCR_CLEAR_XMIT    0x04 /* Clear the XMIT FIFO */
+#define UART_FCR_DMA_SELECT    0x08 /* For DMA applications */
+#define UART_FCR_TRIGGER_MASK  0xC0 /* Mask for the FIFO trigger range */
+#define UART_FCR_TRIGGER_1     0x00 /* Mask for trigger set at 1 */
+#define UART_FCR_TRIGGER_4     0x40 /* Mask for trigger set at 4 */
+#define UART_FCR_TRIGGER_8     0x80 /* Mask for trigger set at 8 */
+#define UART_FCR_TRIGGER_14    0xC0 /* Mask for trigger set at 14 */
+/* 16650 redefinitions */
+#define UART_FCR6_R_TRIGGER_8  0x00 /* Mask for receive trigger set at 1 */
+#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
+#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
+#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
+#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
+#define UART_FCR6_T_TRIGGER_8  0x10 /* Mask for transmit trigger set at 8 */
+#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
+#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
+/* TI 16750 definitions */
+#define UART_FCR7_64BYTE       0x20 /* Go into 64 byte mode */
+
+/*
+ * These are the definitions for the Line Control Register
+ *
+ * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
+ * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
+ */
+#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
+#define UART_LCR_SBC   0x40    /* Set break control */
+#define UART_LCR_SPAR  0x20    /* Stick parity (?) */
+#define UART_LCR_EPAR  0x10    /* Even parity select */
+#define UART_LCR_PARITY        0x08    /* Parity Enable */
+#define UART_LCR_STOP  0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
+#define UART_LCR_WLEN5  0x00   /* Wordlength: 5 bits */
+#define UART_LCR_WLEN6  0x01   /* Wordlength: 6 bits */
+#define UART_LCR_WLEN7  0x02   /* Wordlength: 7 bits */
+#define UART_LCR_WLEN8  0x03   /* Wordlength: 8 bits */
+
+/*
+ * These are the definitions for the Line Status Register
+ */
+#define UART_LSR_TEMT  0x02    /* Transmitter empty */
+#define UART_LSR_THRE  0x01    /* Transmit-hold-register empty */
+#define UART_LSR_BI    0x00    /* Break interrupt indicator */
+#define UART_LSR_FE    0x80    /* Frame error indicator */
+#define UART_LSR_PE    0x40    /* Parity error indicator */
+#define UART_LSR_OE    0x20    /* Overrun error indicator */
+#define UART_LSR_DR    0x04    /* Receiver data ready */
+
+/*
+ * These are the definitions for the Interrupt Identification Register
+ */
+#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
+#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
+
+#define UART_IIR_MSI   0x00    /* Modem status interrupt */
+#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
+#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
+#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
+
+/*
+ * These are the definitions for the Interrupt Enable Register
+ */
+#define UART_IER_MSI   0x00    /* Enable Modem status interrupt */
+#define UART_IER_RLSI  0x08    /* Enable receiver line status interrupt */
+#define UART_IER_THRI  0x03    /* Enable Transmitter holding register int. */
+#define UART_IER_RDI   0x04    /* Enable receiver data interrupt */
+/*
+ * Sleep mode for ST16650 and TI16750.
+ * Note that for 16650, EFR-bit 4 must be selected as well.
+ */
+#define UART_IERX_SLEEP  0x10  /* Enable sleep mode */
+
+/*
+ * These are the definitions for the Modem Control Register
+ */
+#define UART_MCR_LOOP  0x10    /* Enable loopback test mode */
+#define UART_MCR_OUT2  0x08    /* Out2 complement */
+#define UART_MCR_OUT1  0x04    /* Out1 complement */
+#define UART_MCR_RTS   0x02    /* RTS complement */
+#define UART_MCR_DTR   0x01    /* DTR complement */
+
+/*
+ * These are the definitions for the Modem Status Register
+ */
+#define UART_MSR_DCD   0x80    /* Data Carrier Detect */
+#define UART_MSR_RI    0x40    /* Ring Indicator */
+#define UART_MSR_DSR   0x20    /* Data Set Ready */
+#define UART_MSR_CTS   0x10    /* Clear to Send */
+#define UART_MSR_DDCD  0x08    /* Delta DCD */
+#define UART_MSR_TERI  0x04    /* Trailing edge ring indicator */
+#define UART_MSR_DDSR  0x02    /* Delta DSR */
+#define UART_MSR_DCTS  0x01    /* Delta CTS */
+#define UART_MSR_ANY_DELTA 0x0F        /* Any of the delta bits! */
+
+/*
+ * These are the definitions for the Extended Features Register
+ * (StarTech 16C660 only, when DLAB=1)
+ */
+#define UART_EFR_CTS   0x80    /* CTS flow control */
+#define UART_EFR_RTS   0x40    /* RTS flow control */
+#define UART_EFR_SCD   0x20    /* Special character detect */
+#define UART_EFR_ECB   0x10    /* Enhanced control bit */
+/*
+ * the low four bits control software flow control
+ */
+
+/*
+ * These register definitions are for the 16C950
+ */
+#define UART_ASR       0x01    /* Additional Status Register */
+#define UART_RFL       0x03    /* Receiver FIFO level */
+#define UART_TFL       0x04    /* Transmitter FIFO level */
+#define UART_ICR       0x05    /* Index Control Register */
+
+/* The 16950 ICR registers */
+#define UART_ACR       0x00    /* Additional Control Register */
+#define UART_CPR       0x01    /* Clock Prescalar Register */
+#define UART_TCR       0x02    /* Times Clock Register */
+#define UART_CKS       0x03    /* Clock Select Register */
+#define UART_TTL       0x04    /* Transmitter Interrupt Trigger Level */
+#define UART_RTL       0x05    /* Receiver Interrupt Trigger Level */
+#define UART_FCL       0x06    /* Flow Control Level Lower */
+#define UART_FCH       0x07    /* Flow Control Level Higher */
+#define UART_ID1       0x08    /* ID #1 */
+#define UART_ID2       0x09    /* ID #2 */
+#define UART_ID3       0x0A    /* ID #3 */
+#define UART_REV       0x0B    /* Revision */
+#define UART_CSR       0x0C    /* Channel Software Reset */
+#define UART_NMR       0x0D    /* Nine-bit Mode Register */
+#define UART_CTR       0xFF
+
+/*
+ * The 16C950 Additional Control Reigster
+ */
+#define UART_ACR_RXDIS 0x01    /* Receiver disable */
+#define UART_ACR_TXDIS 0x02    /* Receiver disable */
+#define UART_ACR_DSRFC 0x04    /* DSR Flow Control */
+#define UART_ACR_TLENB 0x20    /* 950 trigger levels enable */
+#define UART_ACR_ICRRD 0x40    /* ICR Read enable */
+#define UART_ACR_ASREN 0x80    /* Additional status enable */
+
+/*
+ * These are the definitions for the Feature Control Register
+ * (XR16C85x only, when LCR=bf; doubles with the Interrupt Enable
+ * Register, UART register #1)
+ */
+#define UART_FCTR_RTS_NODELAY  0x00  /* RTS flow control delay */
+#define UART_FCTR_RTS_4DELAY   0x01
+#define UART_FCTR_RTS_6DELAY   0x02
+#define UART_FCTR_RTS_8DELAY   0x03
+#define UART_FCTR_IRDA 0x04  /* IrDa data encode select */
+#define UART_FCTR_TX_INT       0x08  /* Tx interrupt type select */
+#define UART_FCTR_TRGA 0x00  /* Tx/Rx 550 trigger table select */
+#define UART_FCTR_TRGB 0x10  /* Tx/Rx 650 trigger table select */
+#define UART_FCTR_TRGC 0x20  /* Tx/Rx 654 trigger table select */
+#define UART_FCTR_TRGD 0x30  /* Tx/Rx 850 programmable trigger select */
+#define UART_FCTR_SCR_SWAP     0x40  /* Scratch pad register swap */
+#define UART_FCTR_RX   0x00  /* Programmable trigger mode select */
+#define UART_FCTR_TX   0x80  /* Programmable trigger mode select */
+
+/*
+ * These are the definitions for the Enhanced Mode Select Register
+ * (XR16C85x only, when LCR=bf and FCTR bit 6=1; doubles with the
+ * Scratch register, UART register #7)
+ */
+#define UART_EMSR_FIFO_COUNT   0x01  /* Rx/Tx select */
+#define UART_EMSR_ALT_COUNT    0x02  /* Alternating count select */
+
+/*
+ * These are the definitions for the Programmable Trigger
+ * Register (XR16C85x only, when LCR=bf; doubles with the UART RX/TX
+ * register, UART register #0)
+ */
+#define UART_TRG_1     0x01
+#define UART_TRG_4     0x04
+#define UART_TRG_8     0x08
+#define UART_TRG_16    0x10
+#define UART_TRG_32    0x20
+#define UART_TRG_64    0x40
+#define UART_TRG_96    0x60
+#define UART_TRG_120   0x78
+#define UART_TRG_128   0x80
+
+/*
+ * These definitions are for the RSA-DV II/S card, from
+ *
+ * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ */
+
+#define UART_RSA_BASE (-8)
+
+#define UART_RSA_MSR ((UART_RSA_BASE) + 0) /* I/O: Mode Select Register */
+
+#define UART_RSA_MSR_SWAP (1 << 0) /* Swap low/high 8 bytes in I/O port addr */
+#define UART_RSA_MSR_FIFO (1 << 2) /* Enable the external FIFO */
+#define UART_RSA_MSR_FLOW (1 << 3) /* Enable the auto RTS/CTS flow control */
+#define UART_RSA_MSR_ITYP (1 << 4) /* Level (1) / Edge triger (0) */
+
+#define UART_RSA_IER ((UART_RSA_BASE) + 1) /* I/O: Interrupt Enable Register */
+
+#define UART_RSA_IER_Rx_FIFO_H (1 << 0) /* Enable Rx FIFO half full int. */
+#define UART_RSA_IER_Tx_FIFO_H (1 << 1) /* Enable Tx FIFO half full int. */
+#define UART_RSA_IER_Tx_FIFO_E (1 << 2) /* Enable Tx FIFO empty int. */
+#define UART_RSA_IER_Rx_TOUT (1 << 3) /* Enable char receive timeout int */
+#define UART_RSA_IER_TIMER (1 << 4) /* Enable timer interrupt */
+
+#define UART_RSA_SRR ((UART_RSA_BASE) + 2) /* IN: Status Read Register */
+
+#define UART_RSA_SRR_Tx_FIFO_NEMP (1 << 0) /* Tx FIFO is not empty (1) */
+#define UART_RSA_SRR_Tx_FIFO_NHFL (1 << 1) /* Tx FIFO is not half full (1) */
+#define UART_RSA_SRR_Tx_FIFO_NFUL (1 << 2) /* Tx FIFO is not full (1) */
+#define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
+#define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
+#define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
+#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */
+#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */
+
+#define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
+
+#define UART_RSA_TIVSR ((UART_RSA_BASE) + 3) /* I/O: Timer Interval Value Set Register */
+
+#define UART_RSA_TCR ((UART_RSA_BASE) + 4) /* OUT: Timer Control Register */
+
+#define UART_RSA_TCR_SWITCH (1 << 0) /* Timer on */
+
+/*
+ * The RSA DSV/II board has two fixed clock frequencies.  One is the
+ * standard rate, and the other is 8 times faster.
+ */
+#define SERIAL_RSA_BAUD_BASE (921600)
+#define SERIAL_RSA_BAUD_BASE_LO (SERIAL_RSA_BAUD_BASE / 8)
+
+#endif /* _M32R_SIO_REG_H */
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
new file mode 100644 (file)
index 0000000..0d9f537
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# USB ATM driver configuration
+#
+comment "USB ATM/DSL drivers"
+       depends on USB
+
+config USB_ATM
+       tristate "Generic USB ATM/DSL core I/O 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. 
+
+         To compile this driver as a module, choose M here: the
+         module will be called usb_atm.
+
+config USB_SPEEDTOUCH
+       tristate "Alcatel Speedtouch USB support"
+       depends on USB && ATM
+       select USB_ATM
+       help
+         Say Y here if you have an Alcatel 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.
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
new file mode 100644 (file)
index 0000000..8bf4e81
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * drivers/usb/core/otg_whitelist.h
+ *
+ * Copyright (C) 2004 Texas Instruments
+ *
+ * This 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 OTG Whitelist is the OTG "Targeted Peripheral List".  It should
+ * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
+ *
+ * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
+ */ 
+
+static struct usb_device_id whitelist_table [] = {
+
+/* hubs are optional in OTG, but very handy ... */
+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
+
+#ifdef CONFIG_USB_PRINTER              /* ignoring nonstatic linkage! */
+/* FIXME actually, printers are NOT supposed to use device classes;
+ * they're supposed to use interface classes...
+ */
+{ USB_DEVICE_INFO(7, 1, 1) },
+{ USB_DEVICE_INFO(7, 1, 2) },
+{ USB_DEVICE_INFO(7, 1, 3) },
+#endif
+
+#ifdef CONFIG_USB_CDCETHER
+/* Linux-USB CDC Ethernet gadget */
+{ USB_DEVICE(0x0525, 0xa4a1), },
+/* Linux-USB CDC Ethernet + RNDIS gadget */
+{ USB_DEVICE(0x0525, 0xa4a2), },
+#endif
+
+#if    defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE)
+/* gadget zero, for testing */
+{ USB_DEVICE(0x0525, 0xa4a0), },
+#endif
+
+{ }    /* Terminating entry */
+};
+
+static int is_targeted(struct usb_device *dev)
+{
+       struct usb_device_id    *id = whitelist_table;
+
+       /* possible in developer configs only! */
+       if (!dev->bus->otg_port)
+               return 1;
+
+       /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
+       if (dev->descriptor.idVendor == 0x1a0a
+                       && dev->descriptor.idProduct == 0xbadd)
+               return 0;
+
+       /* NOTE: can't use usb_match_id() since interface caches
+        * aren't set up yet. this is cut/paste from that code.
+        */
+       for (id = whitelist_table; id->match_flags; id++) {
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
+                   id->idVendor != dev->descriptor.idVendor)
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
+                   id->idProduct != dev->descriptor.idProduct)
+                       continue;
+
+               /* No need to test id->bcdDevice_lo != 0, since 0 is never
+                  greater than any unsigned number. */
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
+                   (id->bcdDevice_lo > dev->descriptor.bcdDevice))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
+                   (id->bcdDevice_hi < dev->descriptor.bcdDevice))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
+                   (id->bDeviceClass != dev->descriptor.bDeviceClass))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
+                   (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+                       continue;
+
+               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
+                   (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+                       continue;
+
+               return 1;
+       }
+
+       /* add other match criteria here ... */
+
+
+       /* OTG MESSAGE: report errors here, customize to match your product */
+       dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+                       dev->descriptor.idVendor,
+                       dev->descriptor.idProduct);
+#ifdef CONFIG_USB_OTG_WHITELIST
+       return 0;
+#else
+       return 1;
+#endif
+}
+
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
new file mode 100644 (file)
index 0000000..772627e
--- /dev/null
@@ -0,0 +1,2168 @@
+/*
+ * linux/drivers/usb/gadget/lh7a40x_udc.c
+ * Sharp LH7A40x on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID
+ * Copyright (C) 2004 Bo Henriksen, Nordic ID
+ *
+ * This 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 "lh7a40x_udc.h"
+
+//#define DEBUG printk
+//#define DEBUG_EP0 printk
+//#define DEBUG_SETUP printk
+
+#ifndef DEBUG_EP0
+# define DEBUG_EP0(fmt,args...)
+#endif
+#ifndef DEBUG_SETUP
+# define DEBUG_SETUP(fmt,args...)
+#endif
+#ifndef DEBUG
+# define NO_STATES
+# define DEBUG(fmt,args...)
+#endif
+
+#define        DRIVER_DESC                     "LH7A40x USB Device Controller"
+#define        DRIVER_VERSION          __DATE__
+
+#ifndef _BIT                   /* FIXME - what happended to _BIT in 2.6.7bk18? */
+#define _BIT(x) (1<<(x))
+#endif
+
+struct lh7a40x_udc *the_controller;
+
+static const char driver_name[] = "lh7a40x_udc";
+static const char driver_desc[] = DRIVER_DESC;
+static const char ep0name[] = "ep0-control";
+
+/*
+  Local definintions.
+*/
+#define UDC_PROC_FILE
+
+#ifndef NO_STATES
+static char *state_names[] = {
+       "WAIT_FOR_SETUP",
+       "DATA_STATE_XMIT",
+       "DATA_STATE_NEED_ZLP",
+       "WAIT_FOR_OUT_STATUS",
+       "DATA_STATE_RECV"
+};
+#endif
+
+/*
+  Local declarations.
+*/
+static int lh7a40x_ep_enable(struct usb_ep *ep,
+                            const struct usb_endpoint_descriptor *);
+static int lh7a40x_ep_disable(struct usb_ep *ep);
+static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, int);
+static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *);
+static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *,
+                                 int);
+static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t,
+                               unsigned);
+static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, int);
+static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *);
+static int lh7a40x_set_halt(struct usb_ep *ep, int);
+static int lh7a40x_fifo_status(struct usb_ep *ep);
+static int lh7a40x_fifo_status(struct usb_ep *ep);
+static void lh7a40x_fifo_flush(struct usb_ep *ep);
+static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep);
+static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr);
+
+static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req,
+                int status);
+static void pio_irq_enable(int bEndpointAddress);
+static void pio_irq_disable(int bEndpointAddress);
+static void stop_activity(struct lh7a40x_udc *dev,
+                         struct usb_gadget_driver *driver);
+static void flush(struct lh7a40x_ep *ep);
+static void udc_enable(struct lh7a40x_udc *dev);
+static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address);
+
+static struct usb_ep_ops lh7a40x_ep_ops = {
+       .enable = lh7a40x_ep_enable,
+       .disable = lh7a40x_ep_disable,
+
+       .alloc_request = lh7a40x_alloc_request,
+       .free_request = lh7a40x_free_request,
+
+       .alloc_buffer = lh7a40x_alloc_buffer,
+       .free_buffer = lh7a40x_free_buffer,
+
+       .queue = lh7a40x_queue,
+       .dequeue = lh7a40x_dequeue,
+
+       .set_halt = lh7a40x_set_halt,
+       .fifo_status = lh7a40x_fifo_status,
+       .fifo_flush = lh7a40x_fifo_flush,
+};
+
+/* Inline code */
+
+static __inline__ int write_packet(struct lh7a40x_ep *ep,
+                                  struct lh7a40x_request *req, int max)
+{
+       u8 *buf;
+       int length, count;
+       volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+       buf = req->req.buf + req->req.actual;
+       prefetch(buf);
+
+       length = req->req.length - req->req.actual;
+       length = min(length, max);
+       req->req.actual += length;
+
+       DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo);
+
+       count = length;
+       while (count--) {
+               *fifo = *buf++;
+       }
+
+       return length;
+}
+
+static __inline__ void usb_set_index(u32 ep)
+{
+       *(volatile u32 *)io_p2v(USB_INDEX) = ep;
+}
+
+static __inline__ u32 usb_read(u32 port)
+{
+       return *(volatile u32 *)io_p2v(port);
+}
+
+static __inline__ void usb_write(u32 val, u32 port)
+{
+       *(volatile u32 *)io_p2v(port) = val;
+}
+
+static __inline__ void usb_set(u32 val, u32 port)
+{
+       volatile u32 *ioport = (volatile u32 *)io_p2v(port);
+       u32 after = (*ioport) | val;
+       *ioport = after;
+}
+
+static __inline__ void usb_clear(u32 val, u32 port)
+{
+       volatile u32 *ioport = (volatile u32 *)io_p2v(port);
+       u32 after = (*ioport) & ~val;
+       *ioport = after;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define GPIO_PORTC_DR  (0x80000E08)
+#define GPIO_PORTC_DDR         (0x80000E18)
+#define GPIO_PORTC_PDR         (0x80000E70)
+
+/* get port C pin data register */
+#define get_portc_pdr(bit)             ((usb_read(GPIO_PORTC_PDR) & _BIT(bit)) != 0)
+/* get port C data direction register */
+#define get_portc_ddr(bit)             ((usb_read(GPIO_PORTC_DDR) & _BIT(bit)) != 0)
+/* set port C data register */
+#define set_portc_dr(bit, val)         (val ? usb_set(_BIT(bit), GPIO_PORTC_DR) : usb_clear(_BIT(bit), GPIO_PORTC_DR))
+/* set port C data direction register */
+#define set_portc_ddr(bit, val) (val ? usb_set(_BIT(bit), GPIO_PORTC_DDR) : usb_clear(_BIT(bit), GPIO_PORTC_DDR))
+
+/*
+ * LPD7A404 GPIO's:
+ * Port C bit 1 = USB Port 1 Power Enable
+ * Port C bit 2 = USB Port 1 Data Carrier Detect
+ */
+#define is_usb_connected()             get_portc_pdr(2)
+
+#ifdef UDC_PROC_FILE
+
+static const char proc_node_name[] = "driver/udc";
+
+static int
+udc_proc_read(char *page, char **start, off_t off, int count,
+             int *eof, void *_dev)
+{
+       char *buf = page;
+       struct lh7a40x_udc *dev = _dev;
+       char *next = buf;
+       unsigned size = count;
+       unsigned long flags;
+       int t;
+
+       if (off != 0)
+               return 0;
+
+       local_irq_save(flags);
+
+       /* basic device status */
+       t = scnprintf(next, size,
+                     DRIVER_DESC "\n"
+                     "%s version: %s\n"
+                     "Gadget driver: %s\n"
+                     "Host: %s\n\n",
+                     driver_name, DRIVER_VERSION,
+                     dev->driver ? dev->driver->driver.name : "(none)",
+                     is_usb_connected()? "full speed" : "disconnected");
+       size -= t;
+       next += t;
+
+       t = scnprintf(next, size,
+                     "GPIO:\n"
+                     " Port C bit 1: %d, dir %d\n"
+                     " Port C bit 2: %d, dir %d\n\n",
+                     get_portc_pdr(1), get_portc_ddr(1),
+                     get_portc_pdr(2), get_portc_ddr(2)
+           );
+       size -= t;
+       next += t;
+
+       t = scnprintf(next, size,
+                     "DCP pullup: %d\n\n",
+                     (usb_read(USB_PM) & PM_USB_DCP) != 0);
+       size -= t;
+       next += t;
+
+       local_irq_restore(flags);
+       *eof = 1;
+       return count - size;
+}
+
+#define create_proc_files()    create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
+#define remove_proc_files()    remove_proc_entry(proc_node_name, NULL)
+
+#else                          /* !UDC_PROC_FILE */
+
+#define create_proc_files() do {} while (0)
+#define remove_proc_files() do {} while (0)
+
+#endif                         /* UDC_PROC_FILE */
+
+/*
+ *     udc_disable - disable USB device controller
+ */
+static void udc_disable(struct lh7a40x_udc *dev)
+{
+       DEBUG("%s, %p\n", __FUNCTION__, dev);
+
+       udc_set_address(dev, 0);
+
+       /* Disable interrupts */
+       usb_write(0, USB_IN_INT_EN);
+       usb_write(0, USB_OUT_INT_EN);
+       usb_write(0, USB_INT_EN);
+
+       /* Disable the USB */
+       usb_write(0, USB_PM);
+
+#ifdef CONFIG_ARCH_LH7A404
+       /* Disable USB power */
+       set_portc_dr(1, 0);
+#endif
+
+       /* if hardware supports it, disconnect from usb */
+       /* make_usb_disappear(); */
+
+       dev->ep0state = WAIT_FOR_SETUP;
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+       dev->usb_address = 0;
+}
+
+/*
+ *     udc_reinit - initialize software state
+ */
+static void udc_reinit(struct lh7a40x_udc *dev)
+{
+       u32 i;
+
+       DEBUG("%s, %p\n", __FUNCTION__, dev);
+
+       /* device/ep0 records init */
+       INIT_LIST_HEAD(&dev->gadget.ep_list);
+       INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+       dev->ep0state = WAIT_FOR_SETUP;
+
+       /* basic endpoint records init */
+       for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
+               struct lh7a40x_ep *ep = &dev->ep[i];
+
+               if (i != 0)
+                       list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+               ep->desc = 0;
+               ep->stopped = 0;
+               INIT_LIST_HEAD(&ep->queue);
+               ep->pio_irqs = 0;
+       }
+
+       /* the rest was statically initialized, and is read-only */
+}
+
+#define BYTES2MAXP(x)  (x / 8)
+#define MAXP2BYTES(x)  (x * 8)
+
+/* until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static void udc_enable(struct lh7a40x_udc *dev)
+{
+       int ep;
+
+       DEBUG("%s, %p\n", __FUNCTION__, dev);
+
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+#ifdef CONFIG_ARCH_LH7A404
+       /* Set Port C bit 1 & 2 as output */
+       set_portc_ddr(1, 1);
+       set_portc_ddr(2, 1);
+
+       /* Enable USB power */
+       set_portc_dr(1, 0);
+#endif
+
+       /*
+        * C.f Chapter 18.1.3.1 Initializing the USB
+        */
+
+       /* Disable the USB */
+       usb_clear(PM_USB_ENABLE, USB_PM);
+
+       /* Reset APB & I/O sides of the USB */
+       usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET);
+       mdelay(5);
+       usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET);
+
+       /* Set MAXP values for each */
+       for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) {
+               struct lh7a40x_ep *ep_reg = &dev->ep[ep];
+               u32 csr;
+
+               usb_set_index(ep);
+
+               switch (ep_reg->ep_type) {
+               case ep_bulk_in:
+               case ep_interrupt:
+                       usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET,
+                                 ep_reg->csr2);
+                       /* Fall through */
+               case ep_control:
+                       usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)),
+                                 USB_IN_MAXP);
+                       break;
+               case ep_bulk_out:
+                       usb_clear(USB_OUT_CSR2_USB_DMA_EN |
+                                 USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2);
+                       usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)),
+                                 USB_OUT_MAXP);
+                       break;
+               }
+
+               /* Read & Write CSR1, just in case */
+               csr = usb_read(ep_reg->csr1);
+               usb_write(csr, ep_reg->csr1);
+
+               flush(ep_reg);
+       }
+
+       /* Disable interrupts */
+       usb_write(0, USB_IN_INT_EN);
+       usb_write(0, USB_OUT_INT_EN);
+       usb_write(0, USB_INT_EN);
+
+       /* Enable interrupts */
+       usb_set(USB_IN_INT_EP0, USB_IN_INT_EN);
+       usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN);
+       /* Dont enable rest of the interrupts */
+       /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN);
+          usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */
+
+       /* Enable SUSPEND */
+       usb_set(PM_ENABLE_SUSPEND, USB_PM);
+
+       /* Enable the USB */
+       usb_set(PM_USB_ENABLE, USB_PM);
+
+#ifdef CONFIG_ARCH_LH7A404
+       /* NOTE: DOES NOT WORK! */
+       /* Let host detect UDC:
+        * Software must write a 0 to the PMR:DCP_CTRL bit to turn this
+        * transistor on and pull the USBDP pin HIGH.
+        */
+       /* usb_clear(PM_USB_DCP, USB_PM);
+          usb_set(PM_USB_DCP, USB_PM); */
+#endif
+}
+
+/*
+  Register entry point for the peripheral controller driver.
+*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct lh7a40x_udc *dev = the_controller;
+       int retval;
+
+       DEBUG("%s: %s\n", __FUNCTION__, driver->driver.name);
+
+       if (!driver
+           || driver->speed != USB_SPEED_FULL
+           || !driver->bind
+           || !driver->unbind || !driver->disconnect || !driver->setup)
+               return -EINVAL;
+       if (!dev)
+               return -ENODEV;
+       if (dev->driver)
+               return -EBUSY;
+
+       /* first hook up the driver ... */
+       dev->driver = driver;
+       dev->gadget.dev.driver = &driver->driver;
+
+       device_add(&dev->gadget.dev);
+       retval = driver->bind(&dev->gadget);
+       if (retval) {
+               printk("%s: bind to driver %s --> error %d\n", dev->gadget.name,
+                      driver->driver.name, retval);
+               device_del(&dev->gadget.dev);
+
+               dev->driver = 0;
+               dev->gadget.dev.driver = 0;
+               return retval;
+       }
+
+       /* ... then enable host detection and ep0; and we're ready
+        * for set_configuration as well as eventual disconnect.
+        * NOTE:  this shouldn't power up until later.
+        */
+       printk("%s: registered gadget driver '%s'\n", dev->gadget.name,
+              driver->driver.name);
+
+       udc_enable(dev);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/*
+  Unregister entry point for the peripheral controller driver.
+*/
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct lh7a40x_udc *dev = the_controller;
+       unsigned long flags;
+
+       if (!dev)
+               return -ENODEV;
+       if (!driver || driver != dev->driver)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->driver = 0;
+       stop_activity(dev, driver);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       driver->unbind(&dev->gadget);
+       device_del(&dev->gadget.dev);
+
+       udc_disable(dev);
+
+       DEBUG("unregistered gadget driver '%s'\n", driver->driver.name);
+       return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+
+/** Write request to FIFO (max write == maxp size)
+ *  Return:  0 = still running, 1 = completed, negative = errno
+ *  NOTE: INDEX register must be set for EP
+ */
+static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
+{
+       u32 max;
+       u32 csr;
+
+       max = le16_to_cpu(ep->desc->wMaxPacketSize);
+
+       csr = usb_read(ep->csr1);
+       DEBUG("CSR: %x %d\n", csr, csr & USB_IN_CSR1_FIFO_NOT_EMPTY);
+
+       if (!(csr & USB_IN_CSR1_FIFO_NOT_EMPTY)) {
+               unsigned count;
+               int is_last, is_short;
+
+               count = write_packet(ep, req, max);
+               usb_set(USB_IN_CSR1_IN_PKT_RDY, ep->csr1);
+
+               /* last packet is usually short (or a zlp) */
+               if (unlikely(count != max))
+                       is_last = is_short = 1;
+               else {
+                       if (likely(req->req.length != req->req.actual)
+                           || req->req.zero)
+                               is_last = 0;
+                       else
+                               is_last = 1;
+                       /* interrupt/iso maxpacket may not fill the fifo */
+                       is_short = unlikely(max < ep_maxpacket(ep));
+               }
+
+               DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__,
+                     ep->ep.name, count,
+                     is_last ? "/L" : "", is_short ? "/S" : "",
+                     req->req.length - req->req.actual, req);
+
+               /* requests complete when all IN data is in the FIFO */
+               if (is_last) {
+                       done(ep, req, 0);
+                       if (list_empty(&ep->queue)) {
+                               pio_irq_disable(ep_index(ep));
+                       }
+                       return 1;
+               }
+       } else {
+               DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep));
+       }
+
+       return 0;
+}
+
+/** Read to request from FIFO (max read == bytes in fifo)
+ *  Return:  0 = still running, 1 = completed, negative = errno
+ *  NOTE: INDEX register must be set for EP
+ */
+static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
+{
+       u32 csr;
+       u8 *buf;
+       unsigned bufferspace, count, is_short;
+       volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+       /* make sure there's a packet in the FIFO. */
+       csr = usb_read(ep->csr1);
+       if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) {
+               DEBUG("%s: Packet NOT ready!\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       buf = req->req.buf + req->req.actual;
+       prefetchw(buf);
+       bufferspace = req->req.length - req->req.actual;
+
+       /* read all bytes from this packet */
+       count = usb_read(USB_OUT_FIFO_WC1);
+       req->req.actual += min(count, bufferspace);
+
+       is_short = (count < ep->ep.maxpacket);
+       DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n",
+             ep->ep.name, csr, count,
+             is_short ? "/S" : "", req, req->req.actual, req->req.length);
+
+       while (likely(count-- != 0)) {
+               u8 byte = (u8) (*fifo & 0xff);
+
+               if (unlikely(bufferspace == 0)) {
+                       /* this happens when the driver's buffer
+                        * is smaller than what the host sent.
+                        * discard the extra data.
+                        */
+                       if (req->req.status != -EOVERFLOW)
+                               printk("%s overflow %d\n", ep->ep.name, count);
+                       req->req.status = -EOVERFLOW;
+               } else {
+                       *buf++ = byte;
+                       bufferspace--;
+               }
+       }
+
+       usb_clear(USB_OUT_CSR1_OUT_PKT_RDY, ep->csr1);
+
+       /* completion */
+       if (is_short || req->req.actual == req->req.length) {
+               done(ep, req, 0);
+               usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1);
+
+               if (list_empty(&ep->queue))
+                       pio_irq_disable(ep_index(ep));
+               return 1;
+       }
+
+       /* finished that packet.  the next one may be waiting... */
+       return 0;
+}
+
+/*
+ *     done - retire a request; caller blocked irqs
+ *  INDEX register is preserved to keep same
+ */
+static void done(struct lh7a40x_ep *ep, struct lh7a40x_request *req, int status)
+{
+       unsigned int stopped = ep->stopped;
+       u32 index;
+
+       DEBUG("%s, %p\n", __FUNCTION__, ep);
+       list_del_init(&req->queue);
+
+       if (likely(req->req.status == -EINPROGRESS))
+               req->req.status = status;
+       else
+               status = req->req.status;
+
+       if (status && status != -ESHUTDOWN)
+               DEBUG("complete %s req %p stat %d len %u/%u\n",
+                     ep->ep.name, &req->req, status,
+                     req->req.actual, req->req.length);
+
+       /* don't modify queue heads during completion callback */
+       ep->stopped = 1;
+       /* Read current index (completion may modify it) */
+       index = usb_read(USB_INDEX);
+
+       spin_unlock(&ep->dev->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&ep->dev->lock);
+
+       /* Restore index */
+       usb_set_index(index);
+       ep->stopped = stopped;
+}
+
+/** Enable EP interrupt */
+static void pio_irq_enable(int ep)
+{
+       DEBUG("%s: %d\n", __FUNCTION__, ep);
+
+       switch (ep) {
+       case 1:
+               usb_set(USB_IN_INT_EP1, USB_IN_INT_EN);
+               break;
+       case 2:
+               usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN);
+               break;
+       case 3:
+               usb_set(USB_IN_INT_EP3, USB_IN_INT_EN);
+               break;
+       default:
+               DEBUG("Unknown endpoint: %d\n", ep);
+               break;
+       }
+}
+
+/** Disable EP interrupt */
+static void pio_irq_disable(int ep)
+{
+       DEBUG("%s: %d\n", __FUNCTION__, ep);
+
+       switch (ep) {
+       case 1:
+               usb_clear(USB_IN_INT_EP1, USB_IN_INT_EN);
+               break;
+       case 2:
+               usb_clear(USB_OUT_INT_EP2, USB_OUT_INT_EN);
+               break;
+       case 3:
+               usb_clear(USB_IN_INT_EP3, USB_IN_INT_EN);
+               break;
+       default:
+               DEBUG("Unknown endpoint: %d\n", ep);
+               break;
+       }
+}
+
+/*
+ *     nuke - dequeue ALL requests
+ */
+void nuke(struct lh7a40x_ep *ep, int status)
+{
+       struct lh7a40x_request *req;
+
+       DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+       /* Flush FIFO */
+       flush(ep);
+
+       /* called with irqs blocked */
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next, struct lh7a40x_request, queue);
+               done(ep, req, status);
+       }
+
+       /* Disable IRQ if EP is enabled (has decriptor) */
+       if (ep->desc)
+               pio_irq_disable(ep_index(ep));
+}
+
+/*
+void nuke_all(struct lh7a40x_udc *dev)
+{
+       int n;
+       for(n=0; n<UDC_MAX_ENDPOINTS; n++) {
+               struct lh7a40x_ep *ep = &dev->ep[n];
+               usb_set_index(n);
+               nuke(ep, 0);
+       }
+}*/
+
+/*
+static void flush_all(struct lh7a40x_udc *dev)
+{
+       int n;
+    for (n = 0; n < UDC_MAX_ENDPOINTS; n++)
+    {
+               struct lh7a40x_ep *ep = &dev->ep[n];
+               flush(ep);
+    }
+}
+*/
+
+/** Flush EP
+ * NOTE: INDEX register must be set before this call
+ */
+static void flush(struct lh7a40x_ep *ep)
+{
+       DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+       switch (ep->ep_type) {
+       case ep_control:
+               /* check, by implication c.f. 15.1.2.11 */
+               break;
+
+       case ep_bulk_in:
+       case ep_interrupt:
+               /* if(csr & USB_IN_CSR1_IN_PKT_RDY) */
+               usb_set(USB_IN_CSR1_FIFO_FLUSH, ep->csr1);
+               break;
+
+       case ep_bulk_out:
+               /* if(csr & USB_OUT_CSR1_OUT_PKT_RDY) */
+               usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1);
+               break;
+       }
+}
+
+/**
+ * lh7a40x_in_epn - handle IN interrupt
+ */
+static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
+{
+       u32 csr;
+       struct lh7a40x_ep *ep = &dev->ep[ep_idx];
+       struct lh7a40x_request *req;
+
+       usb_set_index(ep_idx);
+
+       csr = usb_read(ep->csr1);
+       DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr);
+
+       if (csr & USB_IN_CSR1_SENT_STALL) {
+               DEBUG("USB_IN_CSR1_SENT_STALL\n");
+               usb_set(USB_IN_CSR1_SENT_STALL /*|USB_IN_CSR1_SEND_STALL */ ,
+                       ep->csr1);
+               return;
+       }
+
+       if (!ep->desc) {
+               DEBUG("%s: NO EP DESC\n", __FUNCTION__);
+               return;
+       }
+
+       if (list_empty(&ep->queue))
+               req = 0;
+       else
+               req = list_entry(ep->queue.next, struct lh7a40x_request, queue);
+
+       DEBUG("req: %p\n", req);
+
+       if (!req)
+               return;
+
+       write_fifo(ep, req);
+}
+
+/* ********************************************************************************************* */
+/* Bulk OUT (recv)
+ */
+
+static void lh7a40x_out_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr)
+{
+       struct lh7a40x_ep *ep = &dev->ep[ep_idx];
+       struct lh7a40x_request *req;
+
+       DEBUG("%s: %d\n", __FUNCTION__, ep_idx);
+
+       usb_set_index(ep_idx);
+
+       if (ep->desc) {
+               u32 csr;
+               csr = usb_read(ep->csr1);
+
+               while ((csr =
+                       usb_read(ep->
+                                csr1)) & (USB_OUT_CSR1_OUT_PKT_RDY |
+                                          USB_OUT_CSR1_SENT_STALL)) {
+                       DEBUG("%s: %x\n", __FUNCTION__, csr);
+
+                       if (csr & USB_OUT_CSR1_SENT_STALL) {
+                               DEBUG("%s: stall sent, flush fifo\n",
+                                     __FUNCTION__);
+                               /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */
+                               flush(ep);
+                       } else if (csr & USB_OUT_CSR1_OUT_PKT_RDY) {
+                               if (list_empty(&ep->queue))
+                                       req = 0;
+                               else
+                                       req =
+                                           list_entry(ep->queue.next,
+                                                      struct lh7a40x_request,
+                                                      queue);
+
+                               if (!req) {
+                                       printk("%s: NULL REQ %d\n",
+                                              __FUNCTION__, ep_idx);
+                                       flush(ep);
+                                       break;
+                               } else {
+                                       read_fifo(ep, req);
+                               }
+                       }
+
+               }
+
+       } else {
+               /* Throw packet away.. */
+               printk("%s: No descriptor?!?\n", __FUNCTION__);
+               flush(ep);
+       }
+}
+
+static void stop_activity(struct lh7a40x_udc *dev,
+                         struct usb_gadget_driver *driver)
+{
+       int i;
+
+       /* don't disconnect drivers more than once */
+       if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+               driver = 0;
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+       /* prevent new request submissions, kill any outstanding requests  */
+       for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
+               struct lh7a40x_ep *ep = &dev->ep[i];
+               ep->stopped = 1;
+
+               usb_set_index(i);
+               nuke(ep, -ESHUTDOWN);
+       }
+
+       /* report disconnect; the driver is already quiesced */
+       if (driver) {
+               spin_unlock(&dev->lock);
+               driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+       }
+
+       /* re-init driver-visible data structures */
+       udc_reinit(dev);
+}
+
+/** Handle USB RESET interrupt
+ */
+static void lh7a40x_reset_intr(struct lh7a40x_udc *dev)
+{
+#if 0                          /* def CONFIG_ARCH_LH7A404 */
+       /* Does not work always... */
+
+       DEBUG("%s: %d\n", __FUNCTION__, dev->usb_address);
+
+       if (!dev->usb_address) {
+               /*usb_set(USB_RESET_IO, USB_RESET);
+                  mdelay(5);
+                  usb_clear(USB_RESET_IO, USB_RESET); */
+               return;
+       }
+       /* Put the USB controller into reset. */
+       usb_set(USB_RESET_IO, USB_RESET);
+
+       /* Set Device ID to 0 */
+       udc_set_address(dev, 0);
+
+       /* Let PLL2 settle down */
+       mdelay(5);
+
+       /* Release the USB controller from reset */
+       usb_clear(USB_RESET_IO, USB_RESET);
+
+       /* Re-enable UDC */
+       udc_enable(dev);
+
+#endif
+       dev->gadget.speed = USB_SPEED_FULL;
+}
+
+/*
+ *     lh7a40x usb client interrupt handler.
+ */
+static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev, struct pt_regs *r)
+{
+       struct lh7a40x_udc *dev = _dev;
+
+       DEBUG("\n\n");
+
+       spin_lock(&dev->lock);
+
+       for (;;) {
+               u32 intr_in = usb_read(USB_IN_INT);
+               u32 intr_out = usb_read(USB_OUT_INT);
+               u32 intr_int = usb_read(USB_INT);
+
+               /* Test also against enable bits.. (lh7a40x errata).. Sigh.. */
+               u32 in_en = usb_read(USB_IN_INT_EN);
+               u32 out_en = usb_read(USB_OUT_INT_EN);
+
+               if (!intr_out && !intr_in && !intr_int)
+                       break;
+
+               DEBUG("%s (on state %s)\n", __FUNCTION__,
+                     state_names[dev->ep0state]);
+               DEBUG("intr_out = %x\n", intr_out);
+               DEBUG("intr_in  = %x\n", intr_in);
+               DEBUG("intr_int = %x\n", intr_int);
+
+               if (intr_in) {
+                       usb_write(intr_in, USB_IN_INT);
+
+                       if ((intr_in & USB_IN_INT_EP1)
+                           && (in_en & USB_IN_INT_EP1)) {
+                               DEBUG("USB_IN_INT_EP1\n");
+                               lh7a40x_in_epn(dev, 1, intr_in);
+                       }
+                       if ((intr_in & USB_IN_INT_EP3)
+                           && (in_en & USB_IN_INT_EP3)) {
+                               DEBUG("USB_IN_INT_EP3\n");
+                               lh7a40x_in_epn(dev, 3, intr_in);
+                       }
+                       if (intr_in & USB_IN_INT_EP0) {
+                               DEBUG("USB_IN_INT_EP0 (control)\n");
+                               lh7a40x_handle_ep0(dev, intr_in);
+                       }
+               }
+
+               if (intr_out) {
+                       usb_write(intr_out, USB_OUT_INT);
+
+                       if ((intr_out & USB_OUT_INT_EP2)
+                           && (out_en & USB_OUT_INT_EP2)) {
+                               DEBUG("USB_OUT_INT_EP2\n");
+                               lh7a40x_out_epn(dev, 2, intr_out);
+                       }
+               }
+
+               if (intr_int) {
+                       usb_write(intr_int, USB_INT);
+
+                       if (intr_int & USB_INT_RESET_INT) {
+                               lh7a40x_reset_intr(dev);
+                       }
+
+                       if (intr_int & USB_INT_RESUME_INT) {
+                               DEBUG("USB resume\n");
+
+                               if (dev->gadget.speed != USB_SPEED_UNKNOWN
+                                   && dev->driver
+                                   && dev->driver->resume
+                                   && is_usb_connected()) {
+                                       dev->driver->resume(&dev->gadget);
+                               }
+                       }
+
+                       if (intr_int & USB_INT_SUSPEND_INT) {
+                               DEBUG("USB suspend%s\n",
+                                     is_usb_connected()? "" : "+disconnect");
+                               if (!is_usb_connected()) {
+                                       stop_activity(dev, dev->driver);
+                               } else if (dev->gadget.speed !=
+                                          USB_SPEED_UNKNOWN && dev->driver
+                                          && dev->driver->suspend) {
+                                       dev->driver->suspend(&dev->gadget);
+                               }
+                       }
+
+               }
+       }
+
+       spin_unlock(&dev->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int lh7a40x_ep_enable(struct usb_ep *_ep,
+                            const struct usb_endpoint_descriptor *desc)
+{
+       struct lh7a40x_ep *ep;
+       struct lh7a40x_udc *dev;
+       unsigned long flags;
+
+       DEBUG("%s, %p\n", __FUNCTION__, _ep);
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (!_ep || !desc || ep->desc || _ep->name == ep0name
+           || desc->bDescriptorType != USB_DT_ENDPOINT
+           || ep->bEndpointAddress != desc->bEndpointAddress
+           || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) {
+               DEBUG("%s, bad ep or descriptor\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       /* xfer types must match, except that interrupt ~= bulk */
+       if (ep->bmAttributes != desc->bmAttributes
+           && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+           && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+               DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
+               return -EINVAL;
+       }
+
+       /* hardware _could_ do smaller, but driver doesn't */
+       if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+            && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep))
+           || !desc->wMaxPacketSize) {
+               DEBUG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
+               return -ERANGE;
+       }
+
+       dev = ep->dev;
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+               DEBUG("%s, bogus device state\n", __FUNCTION__);
+               return -ESHUTDOWN;
+       }
+
+       spin_lock_irqsave(&ep->dev->lock, flags);
+
+       ep->stopped = 0;
+       ep->desc = desc;
+       ep->pio_irqs = 0;
+       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+       /* Reset halt state (does flush) */
+       lh7a40x_set_halt(_ep, 0);
+
+       spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+       DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name);
+       return 0;
+}
+
+/** Disable EP
+ *  NOTE: Sets INDEX register
+ */
+static int lh7a40x_ep_disable(struct usb_ep *_ep)
+{
+       struct lh7a40x_ep *ep;
+       unsigned long flags;
+
+       DEBUG("%s, %p\n", __FUNCTION__, _ep);
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (!_ep || !ep->desc) {
+               DEBUG("%s, %s not enabled\n", __FUNCTION__,
+                     _ep ? ep->ep.name : NULL);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ep->dev->lock, flags);
+
+       usb_set_index(ep_index(ep));
+
+       /* Nuke all pending requests (does flush) */
+       nuke(ep, -ESHUTDOWN);
+
+       /* Disable ep IRQ */
+       pio_irq_disable(ep_index(ep));
+
+       ep->desc = 0;
+       ep->stopped = 1;
+
+       spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+       DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name);
+       return 0;
+}
+
+static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,
+                                                int gfp_flags)
+{
+       struct lh7a40x_request *req;
+
+       DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+       req = kmalloc(sizeof *req, gfp_flags);
+       if (!req)
+               return 0;
+
+       memset(req, 0, sizeof *req);
+       INIT_LIST_HEAD(&req->queue);
+
+       return &req->req;
+}
+
+static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+       struct lh7a40x_request *req;
+
+       DEBUG("%s, %p\n", __FUNCTION__, ep);
+
+       req = container_of(_req, struct lh7a40x_request, req);
+       WARN_ON(!list_empty(&req->queue));
+       kfree(req);
+}
+
+static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,
+                                 dma_addr_t * dma, int gfp_flags)
+{
+       char *retval;
+
+       DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags);
+
+       retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));
+       if (retval)
+               *dma = virt_to_bus(retval);
+       return retval;
+}
+
+static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,
+                               unsigned bytes)
+{
+       DEBUG("%s, %p\n", __FUNCTION__, ep);
+       kfree(buf);
+}
+
+/** Queue one request
+ *  Kickstart transfer if needed
+ *  NOTE: Sets INDEX register
+ */
+static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req,
+                        int gfp_flags)
+{
+       struct lh7a40x_request *req;
+       struct lh7a40x_ep *ep;
+       struct lh7a40x_udc *dev;
+       unsigned long flags;
+
+       DEBUG("\n\n\n%s, %p\n", __FUNCTION__, _ep);
+
+       req = container_of(_req, struct lh7a40x_request, req);
+       if (unlikely
+           (!_req || !_req->complete || !_req->buf
+            || !list_empty(&req->queue))) {
+               DEBUG("%s, bad params\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+               DEBUG("%s, bad ep\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       dev = ep->dev;
+       if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+               DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver);
+               return -ESHUTDOWN;
+       }
+
+       DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length,
+             _req->buf);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+
+       /* kickstart this i/o queue? */
+       DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue),
+             ep->stopped);
+       if (list_empty(&ep->queue) && likely(!ep->stopped)) {
+               u32 csr;
+
+               if (unlikely(ep_index(ep) == 0)) {
+                       /* EP0 */
+                       list_add_tail(&req->queue, &ep->queue);
+                       lh7a40x_ep0_kick(dev, ep);
+                       req = 0;
+               } else if (ep_is_in(ep)) {
+                       /* EP1 & EP3 */
+                       usb_set_index(ep_index(ep));
+                       csr = usb_read(ep->csr1);
+                       pio_irq_enable(ep_index(ep));
+                       if ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) == 0) {
+                               if (write_fifo(ep, req) == 1)
+                                       req = 0;
+                       }
+               } else {
+                       /* EP2 */
+                       usb_set_index(ep_index(ep));
+                       csr = usb_read(ep->csr1);
+                       pio_irq_enable(ep_index(ep));
+                       if (!(csr & USB_OUT_CSR1_FIFO_FULL)) {
+                               if (read_fifo(ep, req) == 1)
+                                       req = 0;
+                       }
+               }
+       }
+
+       /* pio or dma irq handler advances the queue. */
+       if (likely(req != 0))
+               list_add_tail(&req->queue, &ep->queue);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+/* dequeue JUST ONE request */
+static int lh7a40x_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct lh7a40x_ep *ep;
+       struct lh7a40x_request *req;
+       unsigned long flags;
+
+       DEBUG("%s, %p\n", __FUNCTION__, _ep);
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (!_ep || ep->ep.name == ep0name)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ep->dev->lock, flags);
+
+       /* make sure it's actually queued on this endpoint */
+       list_for_each_entry(req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+       if (&req->req != _req) {
+               spin_unlock_irqrestore(&ep->dev->lock, flags);
+               return -EINVAL;
+       }
+
+       done(ep, req, -ECONNRESET);
+
+       spin_unlock_irqrestore(&ep->dev->lock, flags);
+       return 0;
+}
+
+/** Halt specific EP
+ *  Return 0 if success
+ *  NOTE: Sets INDEX register to EP !
+ */
+static int lh7a40x_set_halt(struct usb_ep *_ep, int value)
+{
+       struct lh7a40x_ep *ep;
+       unsigned long flags;
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+               DEBUG("%s, bad ep\n", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       usb_set_index(ep_index(ep));
+
+       DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value);
+
+       spin_lock_irqsave(&ep->dev->lock, flags);
+
+       if (ep_index(ep) == 0) {
+               /* EP0 */
+               usb_set(EP0_SEND_STALL, ep->csr1);
+       } else if (ep_is_in(ep)) {
+               u32 csr = usb_read(ep->csr1);
+               if (value && ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY)
+                             || !list_empty(&ep->queue))) {
+                       /*
+                        * Attempts to halt IN endpoints will fail (returning -EAGAIN)
+                        * if any transfer requests are still queued, or if the controller
+                        * FIFO still holds bytes that the host hasn\92t collected.
+                        */
+                       spin_unlock_irqrestore(&ep->dev->lock, flags);
+                       DEBUG
+                           ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n",
+                            (csr & USB_IN_CSR1_FIFO_NOT_EMPTY),
+                            !list_empty(&ep->queue));
+                       return -EAGAIN;
+               }
+               flush(ep);
+               if (value)
+                       usb_set(USB_IN_CSR1_SEND_STALL, ep->csr1);
+               else {
+                       usb_clear(USB_IN_CSR1_SEND_STALL, ep->csr1);
+                       usb_set(USB_IN_CSR1_CLR_DATA_TOGGLE, ep->csr1);
+               }
+
+       } else {
+
+               flush(ep);
+               if (value)
+                       usb_set(USB_OUT_CSR1_SEND_STALL, ep->csr1);
+               else {
+                       usb_clear(USB_OUT_CSR1_SEND_STALL, ep->csr1);
+                       usb_set(USB_OUT_CSR1_CLR_DATA_REG, ep->csr1);
+               }
+       }
+
+       if (value) {
+               ep->stopped = 1;
+       } else {
+               ep->stopped = 0;
+       }
+
+       spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+       DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS");
+
+       return 0;
+}
+
+/** Return bytes in EP FIFO
+ *  NOTE: Sets INDEX register to EP
+ */
+static int lh7a40x_fifo_status(struct usb_ep *_ep)
+{
+       u32 csr;
+       int count = 0;
+       struct lh7a40x_ep *ep;
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (!_ep) {
+               DEBUG("%s, bad ep\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep));
+
+       /* LPD can't report unclaimed bytes from IN fifos */
+       if (ep_is_in(ep))
+               return -EOPNOTSUPP;
+
+       usb_set_index(ep_index(ep));
+
+       csr = usb_read(ep->csr1);
+       if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN ||
+           csr & USB_OUT_CSR1_OUT_PKT_RDY) {
+               count = usb_read(USB_OUT_FIFO_WC1);
+       }
+
+       return count;
+}
+
+/** Flush EP FIFO
+ *  NOTE: Sets INDEX register to EP
+ */
+static void lh7a40x_fifo_flush(struct usb_ep *_ep)
+{
+       struct lh7a40x_ep *ep;
+
+       ep = container_of(_ep, struct lh7a40x_ep, ep);
+       if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+               DEBUG("%s, bad ep\n", __FUNCTION__);
+               return;
+       }
+
+       usb_set_index(ep_index(ep));
+       flush(ep);
+}
+
+/****************************************************************/
+/* End Point 0 related functions                                */
+/****************************************************************/
+
+/* return:  0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
+{
+       u32 max;
+       unsigned count;
+       int is_last;
+
+       max = ep_maxpacket(ep);
+
+       DEBUG_EP0("%s\n", __FUNCTION__);
+
+       count = write_packet(ep, req, max);
+
+       /* last packet is usually short (or a zlp) */
+       if (unlikely(count != max))
+               is_last = 1;
+       else {
+               if (likely(req->req.length != req->req.actual) || req->req.zero)
+                       is_last = 0;
+               else
+                       is_last = 1;
+       }
+
+       DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,
+                 ep->ep.name, count,
+                 is_last ? "/L" : "", req->req.length - req->req.actual, req);
+
+       /* requests complete when all IN data is in the FIFO */
+       if (is_last) {
+               done(ep, req, 0);
+               return 1;
+       }
+
+       return 0;
+}
+
+static __inline__ int lh7a40x_fifo_read(struct lh7a40x_ep *ep,
+                                       unsigned char *cp, int max)
+{
+       int bytes;
+       int count = usb_read(USB_OUT_FIFO_WC1);
+       volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+       if (count > max)
+               count = max;
+       bytes = count;
+       while (count--)
+               *cp++ = *fifo & 0xFF;
+       return bytes;
+}
+
+static __inline__ void lh7a40x_fifo_write(struct lh7a40x_ep *ep,
+                                         unsigned char *cp, int count)
+{
+       volatile u32 *fifo = (volatile u32 *)ep->fifo;
+       DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count);
+       while (count--)
+               *fifo = *cp++;
+}
+
+static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req)
+{
+       u32 csr;
+       u8 *buf;
+       unsigned bufferspace, count, is_short;
+       volatile u32 *fifo = (volatile u32 *)ep->fifo;
+
+       DEBUG_EP0("%s\n", __FUNCTION__);
+
+       csr = usb_read(USB_EP0_CSR);
+       if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY))
+               return 0;
+
+       buf = req->req.buf + req->req.actual;
+       prefetchw(buf);
+       bufferspace = req->req.length - req->req.actual;
+
+       /* read all bytes from this packet */
+       if (likely(csr & EP0_OUT_PKT_RDY)) {
+               count = usb_read(USB_OUT_FIFO_WC1);
+               req->req.actual += min(count, bufferspace);
+       } else                  /* zlp */
+               count = 0;
+
+       is_short = (count < ep->ep.maxpacket);
+       DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n",
+                 ep->ep.name, csr, count,
+                 is_short ? "/S" : "", req, req->req.actual, req->req.length);
+
+       while (likely(count-- != 0)) {
+               u8 byte = (u8) (*fifo & 0xff);
+
+               if (unlikely(bufferspace == 0)) {
+                       /* this happens when the driver's buffer
+                        * is smaller than what the host sent.
+                        * discard the extra data.
+                        */
+                       if (req->req.status != -EOVERFLOW)
+                               DEBUG_EP0("%s overflow %d\n", ep->ep.name,
+                                         count);
+                       req->req.status = -EOVERFLOW;
+               } else {
+                       *buf++ = byte;
+                       bufferspace--;
+               }
+       }
+
+       /* completion */
+       if (is_short || req->req.actual == req->req.length) {
+               done(ep, req, 0);
+               return 1;
+       }
+
+       /* finished that packet.  the next one may be waiting... */
+       return 0;
+}
+
+/**
+ * udc_set_address - set the USB address for this device
+ * @address:
+ *
+ * Called from control endpoint function after it decodes a set address setup packet.
+ */
+static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address)
+{
+       DEBUG_EP0("%s: %d\n", __FUNCTION__, address);
+       /* c.f. 15.1.2.2 Table 15-4 address will be used after DATA_END is set */
+       dev->usb_address = address;
+       usb_set((address & USB_FA_FUNCTION_ADDR), USB_FA);
+       usb_set(USB_FA_ADDR_UPDATE | (address & USB_FA_FUNCTION_ADDR), USB_FA);
+       /* usb_read(USB_FA); */
+}
+
+/*
+ * DATA_STATE_RECV (OUT_PKT_RDY)
+ *      - if error
+ *              set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits
+ *      - else
+ *              set EP0_CLR_OUT bit
+                               if last set EP0_DATA_END bit
+ */
+static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr)
+{
+       struct lh7a40x_request *req;
+       struct lh7a40x_ep *ep = &dev->ep[0];
+       int ret;
+
+       DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+       if (list_empty(&ep->queue))
+               req = 0;
+       else
+               req = list_entry(ep->queue.next, struct lh7a40x_request, queue);
+
+       if (req) {
+
+               if (req->req.length == 0) {
+                       DEBUG_EP0("ZERO LENGTH OUT!\n");
+                       usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);
+                       dev->ep0state = WAIT_FOR_SETUP;
+                       return;
+               }
+               ret = read_fifo_ep0(ep, req);
+               if (ret) {
+                       /* Done! */
+                       DEBUG_EP0("%s: finished, waiting for status\n",
+                                 __FUNCTION__);
+
+                       usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);
+                       dev->ep0state = WAIT_FOR_SETUP;
+               } else {
+                       /* Not done yet.. */
+                       DEBUG_EP0("%s: not finished\n", __FUNCTION__);
+                       usb_set(EP0_CLR_OUT, USB_EP0_CSR);
+               }
+       } else {
+               DEBUG_EP0("NO REQ??!\n");
+       }
+}
+
+/*
+ * DATA_STATE_XMIT
+ */
+static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr)
+{
+       struct lh7a40x_request *req;
+       struct lh7a40x_ep *ep = &dev->ep[0];
+       int ret, need_zlp = 0;
+
+       DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+       if (list_empty(&ep->queue))
+               req = 0;
+       else
+               req = list_entry(ep->queue.next, struct lh7a40x_request, queue);
+
+       if (!req) {
+               DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);
+               return 0;
+       }
+
+       if (req->req.length == 0) {
+
+               usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);
+               dev->ep0state = WAIT_FOR_SETUP;
+               return 1;
+       }
+
+       if (req->req.length - req->req.actual == EP0_PACKETSIZE) {
+               /* Next write will end with the packet size, */
+               /* so we need Zero-length-packet */
+               need_zlp = 1;
+       }
+
+       ret = write_fifo_ep0(ep, req);
+
+       if (ret == 1 && !need_zlp) {
+               /* Last packet */
+               DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__);
+
+               usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);
+               dev->ep0state = WAIT_FOR_SETUP;
+       } else {
+               DEBUG_EP0("%s: not finished\n", __FUNCTION__);
+               usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR);
+       }
+
+       if (need_zlp) {
+               DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__);
+               usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR);
+               dev->ep0state = DATA_STATE_NEED_ZLP;
+       }
+
+       return 1;
+}
+
+static int lh7a40x_handle_get_status(struct lh7a40x_udc *dev,
+                                    struct usb_ctrlrequest *ctrl)
+{
+       struct lh7a40x_ep *ep0 = &dev->ep[0];
+       struct lh7a40x_ep *qep;
+       int reqtype = (ctrl->bRequestType & USB_RECIP_MASK);
+       u16 val = 0;
+
+       if (reqtype == USB_RECIP_INTERFACE) {
+               /* This is not supported.
+                * And according to the USB spec, this one does nothing..
+                * Just return 0
+                */
+               DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n");
+       } else if (reqtype == USB_RECIP_DEVICE) {
+               DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n");
+               val |= (1 << 0);        /* Self powered */
+               /*val |= (1<<1); *//* Remote wakeup */
+       } else if (reqtype == USB_RECIP_ENDPOINT) {
+               int ep_num = (ctrl->wIndex & ~USB_DIR_IN);
+
+               DEBUG_SETUP
+                   ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n",
+                    ep_num, ctrl->wLength);
+
+               if (ctrl->wLength > 2 || ep_num > 3)
+                       return -EOPNOTSUPP;
+
+               qep = &dev->ep[ep_num];
+               if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0)
+                   && ep_index(qep) != 0) {
+                       return -EOPNOTSUPP;
+               }
+
+               usb_set_index(ep_index(qep));
+
+               /* Return status on next IN token */
+               switch (qep->ep_type) {
+               case ep_control:
+                       val =
+                           (usb_read(qep->csr1) & EP0_SEND_STALL) ==
+                           EP0_SEND_STALL;
+                       break;
+               case ep_bulk_in:
+               case ep_interrupt:
+                       val =
+                           (usb_read(qep->csr1) & USB_IN_CSR1_SEND_STALL) ==
+                           USB_IN_CSR1_SEND_STALL;
+                       break;
+               case ep_bulk_out:
+                       val =
+                           (usb_read(qep->csr1) & USB_OUT_CSR1_SEND_STALL) ==
+                           USB_OUT_CSR1_SEND_STALL;
+                       break;
+               }
+
+               /* Back to EP0 index */
+               usb_set_index(0);
+
+               DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num,
+                           ctrl->wIndex, val);
+       } else {
+               DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype);
+               return -EOPNOTSUPP;
+       }
+
+       /* Clear "out packet ready" */
+       usb_set((EP0_CLR_OUT), USB_EP0_CSR);
+       /* Put status to FIFO */
+       lh7a40x_fifo_write(ep0, (u8 *) & val, sizeof(val));
+       /* Issue "In packet ready" */
+       usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);
+
+       return 0;
+}
+
+/*
+ * WAIT_FOR_SETUP (OUT_PKT_RDY)
+ *      - read data packet from EP0 FIFO
+ *      - decode command
+ *      - if error
+ *              set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits
+ *      - else
+ *              set EP0_CLR_OUT | EP0_DATA_END bits
+ */
+static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr)
+{
+       struct lh7a40x_ep *ep = &dev->ep[0];
+       struct usb_ctrlrequest ctrl;
+       int i, bytes, is_in;
+
+       DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr);
+
+       /* Nuke all previous transfers */
+       nuke(ep, -EPROTO);
+
+       /* read control req from fifo (8 bytes) */
+       bytes = lh7a40x_fifo_read(ep, (unsigned char *)&ctrl, 8);
+
+       DEBUG_SETUP("Read CTRL REQ %d bytes\n", bytes);
+       DEBUG_SETUP("CTRL.bRequestType = %d (is_in %d)\n", ctrl.bRequestType,
+                   ctrl.bRequestType == USB_DIR_IN);
+       DEBUG_SETUP("CTRL.bRequest = %d\n", ctrl.bRequest);
+       DEBUG_SETUP("CTRL.wLength = %d\n", ctrl.wLength);
+       DEBUG_SETUP("CTRL.wValue = %d (%d)\n", ctrl.wValue, ctrl.wValue >> 8);
+       DEBUG_SETUP("CTRL.wIndex = %d\n", ctrl.wIndex);
+
+       /* Set direction of EP0 */
+       if (likely(ctrl.bRequestType & USB_DIR_IN)) {
+               ep->bEndpointAddress |= USB_DIR_IN;
+               is_in = 1;
+       } else {
+               ep->bEndpointAddress &= ~USB_DIR_IN;
+               is_in = 0;
+       }
+
+       dev->req_pending = 1;
+
+       /* Handle some SETUP packets ourselves */
+       switch (ctrl.bRequest) {
+       case USB_REQ_SET_ADDRESS:
+               if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+                       break;
+
+               DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue);
+               udc_set_address(dev, ctrl.wValue);
+               usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);
+               return;
+
+       case USB_REQ_GET_STATUS:{
+                       if (lh7a40x_handle_get_status(dev, &ctrl) == 0)
+                               return;
+
+       case USB_REQ_CLEAR_FEATURE:
+       case USB_REQ_SET_FEATURE:
+                       if (ctrl.bRequestType == USB_RECIP_ENDPOINT) {
+                               struct lh7a40x_ep *qep;
+                               int ep_num = (ctrl.wIndex & 0x0f);
+
+                               /* Support only HALT feature */
+                               if (ctrl.wValue != 0 || ctrl.wLength != 0
+                                   || ep_num > 3 || ep_num < 1)
+                                       break;
+
+                               qep = &dev->ep[ep_num];
+                               if (ctrl.bRequest == USB_REQ_SET_FEATURE) {
+                                       DEBUG_SETUP("SET_FEATURE (%d)\n",
+                                                   ep_num);
+                                       lh7a40x_set_halt(&qep->ep, 1);
+                               } else {
+                                       DEBUG_SETUP("CLR_FEATURE (%d)\n",
+                                                   ep_num);
+                                       lh7a40x_set_halt(&qep->ep, 0);
+                               }
+                               usb_set_index(0);
+
+                               /* Reply with a ZLP on next IN token */
+                               usb_set((EP0_CLR_OUT | EP0_DATA_END),
+                                       USB_EP0_CSR);
+                               return;
+                       }
+                       break;
+               }
+
+       default:
+               break;
+       }
+
+       if (likely(dev->driver)) {
+               /* device-2-host (IN) or no data setup command, process immediately */
+               spin_unlock(&dev->lock);
+               i = dev->driver->setup(&dev->gadget, &ctrl);
+               spin_lock(&dev->lock);
+
+               if (i < 0) {
+                       /* setup processing failed, force stall */
+                       DEBUG_SETUP
+                           ("  --> ERROR: gadget setup FAILED (stalling), setup returned %d\n",
+                            i);
+                       usb_set_index(0);
+                       usb_set((EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL),
+                               USB_EP0_CSR);
+
+                       /* ep->stopped = 1; */
+                       dev->ep0state = WAIT_FOR_SETUP;
+               }
+       }
+}
+
+/*
+ * DATA_STATE_NEED_ZLP
+ */
+static void lh7a40x_ep0_in_zlp(struct lh7a40x_udc *dev, u32 csr)
+{
+       DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+       /* c.f. Table 15-14 */
+       usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);
+       dev->ep0state = WAIT_FOR_SETUP;
+}
+
+/*
+ * handle ep0 interrupt
+ */
+static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr)
+{
+       struct lh7a40x_ep *ep = &dev->ep[0];
+       u32 csr;
+
+       /* Set index 0 */
+       usb_set_index(0);
+       csr = usb_read(USB_EP0_CSR);
+
+       DEBUG_EP0("%s: csr = %x\n", __FUNCTION__, csr);
+
+       /*
+        * For overview of what we should be doing see c.f. Chapter 18.1.2.4
+        * We will follow that outline here modified by our own global state
+        * indication which provides hints as to what we think should be
+        * happening..
+        */
+
+       /*
+        * if SENT_STALL is set
+        *      - clear the SENT_STALL bit
+        */
+       if (csr & EP0_SENT_STALL) {
+               DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __FUNCTION__, csr);
+               usb_clear((EP0_SENT_STALL | EP0_SEND_STALL), USB_EP0_CSR);
+               nuke(ep, -ECONNABORTED);
+               dev->ep0state = WAIT_FOR_SETUP;
+               return;
+       }
+
+       /*
+        * if a transfer is in progress && IN_PKT_RDY and OUT_PKT_RDY are clear
+        *      - fill EP0 FIFO
+        *      - if last packet
+        *      -       set IN_PKT_RDY | DATA_END
+        *      - else
+        *              set IN_PKT_RDY
+        */
+       if (!(csr & (EP0_IN_PKT_RDY | EP0_OUT_PKT_RDY))) {
+               DEBUG_EP0("%s: IN_PKT_RDY and OUT_PKT_RDY are clear\n",
+                         __FUNCTION__);
+
+               switch (dev->ep0state) {
+               case DATA_STATE_XMIT:
+                       DEBUG_EP0("continue with DATA_STATE_XMIT\n");
+                       lh7a40x_ep0_in(dev, csr);
+                       return;
+               case DATA_STATE_NEED_ZLP:
+                       DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n");
+                       lh7a40x_ep0_in_zlp(dev, csr);
+                       return;
+               default:
+                       /* Stall? */
+                       DEBUG_EP0("Odd state!! state = %s\n",
+                                 state_names[dev->ep0state]);
+                       dev->ep0state = WAIT_FOR_SETUP;
+                       /* nuke(ep, 0); */
+                       /* usb_set(EP0_SEND_STALL, ep->csr1); */
+                       break;
+               }
+       }
+
+       /*
+        * if SETUP_END is set
+        *      - abort the last transfer
+        *      - set SERVICED_SETUP_END_BIT
+        */
+       if (csr & EP0_SETUP_END) {
+               DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __FUNCTION__, csr);
+
+               usb_set(EP0_CLR_SETUP_END, USB_EP0_CSR);
+
+               nuke(ep, 0);
+               dev->ep0state = WAIT_FOR_SETUP;
+       }
+
+       /*
+        * if EP0_OUT_PKT_RDY is set
+        *      - read data packet from EP0 FIFO
+        *      - decode command
+        *      - if error
+        *              set SERVICED_OUT_PKT_RDY | DATA_END bits | SEND_STALL
+        *      - else
+        *              set SERVICED_OUT_PKT_RDY | DATA_END bits
+        */
+       if (csr & EP0_OUT_PKT_RDY) {
+
+               DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__,
+                         csr);
+
+               switch (dev->ep0state) {
+               case WAIT_FOR_SETUP:
+                       DEBUG_EP0("WAIT_FOR_SETUP\n");
+                       lh7a40x_ep0_setup(dev, csr);
+                       break;
+
+               case DATA_STATE_RECV:
+                       DEBUG_EP0("DATA_STATE_RECV\n");
+                       lh7a40x_ep0_out(dev, csr);
+                       break;
+
+               default:
+                       /* send stall? */
+                       DEBUG_EP0("strange state!! 2. send stall? state = %d\n",
+                                 dev->ep0state);
+                       break;
+               }
+       }
+}
+
+static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep)
+{
+       u32 csr;
+
+       usb_set_index(0);
+       csr = usb_read(USB_EP0_CSR);
+
+       DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
+
+       /* Clear "out packet ready" */
+       usb_set(EP0_CLR_OUT, USB_EP0_CSR);
+
+       if (ep_is_in(ep)) {
+               dev->ep0state = DATA_STATE_XMIT;
+               lh7a40x_ep0_in(dev, csr);
+       } else {
+               dev->ep0state = DATA_STATE_RECV;
+               lh7a40x_ep0_out(dev, csr);
+       }
+}
+
+/* ---------------------------------------------------------------------------
+ *     device-scoped parts of the api to the usb controller hardware
+ * ---------------------------------------------------------------------------
+ */
+
+static int lh7a40x_udc_get_frame(struct usb_gadget *_gadget)
+{
+       u32 frame1 = usb_read(USB_FRM_NUM1);    /* Least significant 8 bits */
+       u32 frame2 = usb_read(USB_FRM_NUM2);    /* Most significant 3 bits */
+       DEBUG("%s, %p\n", __FUNCTION__, _gadget);
+       return ((frame2 & 0x07) << 8) | (frame1 & 0xff);
+}
+
+static int lh7a40x_udc_wakeup(struct usb_gadget *_gadget)
+{
+       /* host may not have enabled remote wakeup */
+       /*if ((UDCCS0 & UDCCS0_DRWF) == 0)
+          return -EHOSTUNREACH;
+          udc_set_mask_UDCCR(UDCCR_RSM); */
+       return -ENOTSUPP;
+}
+
+static const struct usb_gadget_ops lh7a40x_udc_ops = {
+       .get_frame = lh7a40x_udc_get_frame,
+       .wakeup = lh7a40x_udc_wakeup,
+       /* current versions must always be self-powered */
+};
+
+static void nop_release(struct device *dev)
+{
+       DEBUG("%s %s\n", __FUNCTION__, dev->bus_id);
+}
+
+static struct lh7a40x_udc memory = {
+       .usb_address = 0,
+
+       .gadget = {
+                  .ops = &lh7a40x_udc_ops,
+                  .ep0 = &memory.ep[0].ep,
+                  .name = driver_name,
+                  .dev = {
+                          .bus_id = "gadget",
+                          .release = nop_release,
+                          },
+                  },
+
+       /* control endpoint */
+       .ep[0] = {
+                 .ep = {
+                        .name = ep0name,
+                        .ops = &lh7a40x_ep_ops,
+                        .maxpacket = EP0_PACKETSIZE,
+                        },
+                 .dev = &memory,
+
+                 .bEndpointAddress = 0,
+                 .bmAttributes = 0,
+
+                 .ep_type = ep_control,
+                 .fifo = io_p2v(USB_EP0_FIFO),
+                 .csr1 = USB_EP0_CSR,
+                 .csr2 = USB_EP0_CSR,
+                 },
+
+       /* first group of endpoints */
+       .ep[1] = {
+                 .ep = {
+                        .name = "ep1in-bulk",
+                        .ops = &lh7a40x_ep_ops,
+                        .maxpacket = 64,
+                        },
+                 .dev = &memory,
+
+                 .bEndpointAddress = USB_DIR_IN | 1,
+                 .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+                 .ep_type = ep_bulk_in,
+                 .fifo = io_p2v(USB_EP1_FIFO),
+                 .csr1 = USB_IN_CSR1,
+                 .csr2 = USB_IN_CSR2,
+                 },
+
+       .ep[2] = {
+                 .ep = {
+                        .name = "ep2out-bulk",
+                        .ops = &lh7a40x_ep_ops,
+                        .maxpacket = 64,
+                        },
+                 .dev = &memory,
+
+                 .bEndpointAddress = 2,
+                 .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+                 .ep_type = ep_bulk_out,
+                 .fifo = io_p2v(USB_EP2_FIFO),
+                 .csr1 = USB_OUT_CSR1,
+                 .csr2 = USB_OUT_CSR2,
+                 },
+
+       .ep[3] = {
+                 .ep = {
+                        .name = "ep3in-int",
+                        .ops = &lh7a40x_ep_ops,
+                        .maxpacket = 64,
+                        },
+                 .dev = &memory,
+
+                 .bEndpointAddress = USB_DIR_IN | 3,
+                 .bmAttributes = USB_ENDPOINT_XFER_INT,
+
+                 .ep_type = ep_interrupt,
+                 .fifo = io_p2v(USB_EP3_FIFO),
+                 .csr1 = USB_IN_CSR1,
+                 .csr2 = USB_IN_CSR2,
+                 },
+};
+
+/*
+ *     probe - binds to the platform device
+ */
+static int lh7a40x_udc_probe(struct device *_dev)
+{
+       struct lh7a40x_udc *dev = &memory;
+       int retval;
+
+       DEBUG("%s: %p\n", __FUNCTION__, _dev);
+
+       spin_lock_init(&dev->lock);
+       dev->dev = _dev;
+
+       device_initialize(&dev->gadget.dev);
+       dev->gadget.dev.parent = _dev;
+
+       the_controller = dev;
+       dev_set_drvdata(_dev, dev);
+
+       udc_disable(dev);
+       udc_reinit(dev);
+
+       /* irq setup after old hardware state is cleaned up */
+       retval =
+           request_irq(IRQ_USBINTR, lh7a40x_udc_irq, SA_INTERRUPT, driver_name,
+                       dev);
+       if (retval != 0) {
+               DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name,
+                     IRQ_USBINTR, retval);
+               return -EBUSY;
+       }
+
+       create_proc_files();
+
+       return retval;
+}
+
+static int lh7a40x_udc_remove(struct device *_dev)
+{
+       struct lh7a40x_udc *dev = _dev->driver_data;
+
+       DEBUG("%s: %p\n", __FUNCTION__, dev);
+
+       udc_disable(dev);
+       remove_proc_files();
+       usb_gadget_unregister_driver(dev->driver);
+
+       free_irq(IRQ_USBINTR, dev);
+
+       dev_set_drvdata(_dev, 0);
+
+       the_controller = 0;
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct device_driver udc_driver = {
+       .name = (char *)driver_name,
+       .bus = &platform_bus_type,
+       .probe = lh7a40x_udc_probe,
+       .remove = lh7a40x_udc_remove
+           /* FIXME power management support */
+           /* .suspend = ... disable UDC */
+           /* .resume = ... re-enable UDC */
+};
+
+static int __init udc_init(void)
+{
+       DEBUG("%s: %s version %s\n", __FUNCTION__, driver_name, DRIVER_VERSION);
+       return driver_register(&udc_driver);
+}
+
+static void __exit udc_exit(void)
+{
+       driver_unregister(&udc_driver);
+}
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Mikko Lahteenmaki, Bo Henriksen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
new file mode 100644 (file)
index 0000000..1bb455c
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * linux/drivers/usb/gadget/lh7a40x_udc.h
+ * Sharp LH7A40x on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004 Mikko Lahteenmaki, Nordic ID
+ * Copyright (C) 2004 Bo Henriksen, Nordic ID
+ *
+ * This 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 __LH7A40X_H_
+#define __LH7A40X_H_
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/byteorder.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/hardware.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+/*
+ * Memory map
+ */
+
+#define USB_FA                                 0x80000200      // function address register
+#define USB_PM                                 0x80000204      // power management register
+
+#define USB_IN_INT                             0x80000208      // IN interrupt register bank (EP0-EP3)
+#define USB_OUT_INT                            0x80000210      // OUT interrupt register bank (EP2)
+#define USB_INT                                        0x80000218      // interrupt register bank
+
+#define USB_IN_INT_EN                  0x8000021C      // IN interrupt enable register bank
+#define USB_OUT_INT_EN                 0x80000224      // OUT interrupt enable register bank
+#define USB_INT_EN                             0x8000022C      // USB interrupt enable register bank
+
+#define USB_FRM_NUM1                   0x80000230      // Frame number1 register
+#define USB_FRM_NUM2                   0x80000234      // Frame number2 register
+#define USB_INDEX                              0x80000238      // index register
+
+#define USB_IN_MAXP                            0x80000240      // IN MAXP register
+#define USB_IN_CSR1                            0x80000244      // IN CSR1 register/EP0 CSR register
+#define USB_EP0_CSR                            0x80000244      // IN CSR1 register/EP0 CSR register
+#define USB_IN_CSR2                            0x80000248      // IN CSR2 register
+#define USB_OUT_MAXP                   0x8000024C      // OUT MAXP register
+
+#define USB_OUT_CSR1                   0x80000250      // OUT CSR1 register
+#define USB_OUT_CSR2                   0x80000254      // OUT CSR2 register
+#define USB_OUT_FIFO_WC1               0x80000258      // OUT FIFO write count1 register
+#define USB_OUT_FIFO_WC2               0x8000025C      // OUT FIFO write count2 register
+
+#define USB_RESET                              0x8000044C      // USB reset register
+
+#define        USB_EP0_FIFO                    0x80000280
+#define        USB_EP1_FIFO                    0x80000284
+#define        USB_EP2_FIFO                    0x80000288
+#define        USB_EP3_FIFO                    0x8000028c
+
+/*
+ * USB reset register
+ */
+#define USB_RESET_APB                  (1<<1)  //resets USB APB control side WRITE
+#define USB_RESET_IO                   (1<<0)  //resets USB IO side WRITE
+
+/*
+ * USB function address register
+ */
+#define USB_FA_ADDR_UPDATE             (1<<7)
+#define USB_FA_FUNCTION_ADDR   (0x7F)
+
+/*
+ * Power Management register
+ */
+#define PM_USB_DCP                             (1<<5)
+#define PM_USB_ENABLE                  (1<<4)
+#define PM_USB_RESET                   (1<<3)
+#define PM_UC_RESUME                   (1<<2)
+#define PM_SUSPEND_MODE                        (1<<1)
+#define PM_ENABLE_SUSPEND              (1<<0)
+
+/*
+ * IN interrupt register
+ */
+#define USB_IN_INT_EP3                         (1<<3)
+#define USB_IN_INT_EP1                         (1<<1)
+#define USB_IN_INT_EP0                         (1<<0)
+
+/*
+ * OUT interrupt register
+ */
+#define USB_OUT_INT_EP2                                (1<<2)
+
+/*
+ * USB interrupt register
+ */
+#define USB_INT_RESET_INT                      (1<<2)
+#define USB_INT_RESUME_INT                     (1<<1)
+#define USB_INT_SUSPEND_INT                    (1<<0)
+
+/*
+ * USB interrupt enable register
+ */
+#define USB_INT_EN_USB_RESET_INTER             (1<<2)
+#define USB_INT_EN_RESUME_INTER                        (1<<1)
+#define USB_INT_EN_SUSPEND_INTER               (1<<0)
+
+/*
+ * INCSR1 register
+ */
+#define USB_IN_CSR1_CLR_DATA_TOGGLE            (1<<6)
+#define USB_IN_CSR1_SENT_STALL                 (1<<5)
+#define USB_IN_CSR1_SEND_STALL                 (1<<4)
+#define USB_IN_CSR1_FIFO_FLUSH                 (1<<3)
+#define USB_IN_CSR1_FIFO_NOT_EMPTY             (1<<1)
+#define USB_IN_CSR1_IN_PKT_RDY                 (1<<0)
+
+/*
+ * INCSR2 register
+ */
+#define USB_IN_CSR2_AUTO_SET                   (1<<7)
+#define USB_IN_CSR2_USB_DMA_EN                 (1<<4)
+
+/*
+ * OUT CSR1 register
+ */
+#define USB_OUT_CSR1_CLR_DATA_REG              (1<<7)
+#define USB_OUT_CSR1_SENT_STALL                        (1<<6)
+#define USB_OUT_CSR1_SEND_STALL                        (1<<5)
+#define USB_OUT_CSR1_FIFO_FLUSH                        (1<<4)
+#define USB_OUT_CSR1_FIFO_FULL                 (1<<1)
+#define USB_OUT_CSR1_OUT_PKT_RDY               (1<<0)
+
+/*
+ * OUT CSR2 register
+ */
+#define USB_OUT_CSR2_AUTO_CLR                  (1<<7)
+#define USB_OUT_CSR2_USB_DMA_EN                        (1<<4)
+
+/*
+ * EP0 CSR
+ */
+#define EP0_CLR_SETUP_END              (1<<7)  /* Clear "Setup Ends" Bit (w) */
+#define EP0_CLR_OUT                            (1<<6)  /* Clear "Out packet ready" Bit (w) */
+#define EP0_SEND_STALL                 (1<<5)  /* Send STALL Handshake (rw) */
+#define EP0_SETUP_END                  (1<<4)  /* Setup Ends (r) */
+
+#define EP0_DATA_END                   (1<<3)  /* Data end (rw) */
+#define EP0_SENT_STALL                 (1<<2)  /* Sent Stall Handshake (r) */
+#define EP0_IN_PKT_RDY                 (1<<1)  /* In packet ready (rw) */
+#define EP0_OUT_PKT_RDY                        (1<<0)  /* Out packet ready (r) */
+
+/* general CSR */
+#define OUT_PKT_RDY            (1<<0)
+#define IN_PKT_RDY             (1<<0)
+
+/*
+ * IN/OUT MAXP register
+ */
+#define USB_OUT_MAXP_MAXP                      (0xF)
+#define USB_IN_MAXP_MAXP                       (0xF)
+
+// Max packet size
+//#define EP0_PACKETSIZE        0x10
+#define EP0_PACKETSIZE         0x8
+#define EP0_MAXPACKETSIZE      0x10
+
+#define UDC_MAX_ENDPOINTS       4
+
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_NEED_ZLP     2
+#define WAIT_FOR_OUT_STATUS     3
+#define DATA_STATE_RECV         4
+
+/* ********************************************************************************************* */
+/* IO
+ */
+
+typedef enum ep_type {
+       ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
+} ep_type_t;
+
+struct lh7a40x_ep {
+       struct usb_ep ep;
+       struct lh7a40x_udc *dev;
+
+       const struct usb_endpoint_descriptor *desc;
+       struct list_head queue;
+       unsigned long pio_irqs;
+
+       u8 stopped;
+       u8 bEndpointAddress;
+       u8 bmAttributes;
+
+       ep_type_t ep_type;
+       u32 fifo;
+       u32 csr1;
+       u32 csr2;
+};
+
+struct lh7a40x_request {
+       struct usb_request req;
+       struct list_head queue;
+};
+
+struct lh7a40x_udc {
+       struct usb_gadget gadget;
+       struct usb_gadget_driver *driver;
+       struct device *dev;
+       spinlock_t lock;
+
+       int ep0state;
+       struct lh7a40x_ep ep[UDC_MAX_ENDPOINTS];
+
+       unsigned char usb_address;
+
+       unsigned req_pending:1, req_std:1, req_config:1;
+};
+
+extern struct lh7a40x_udc *the_controller;
+
+#define ep_is_in(EP)           (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN)
+#define ep_index(EP)           ((EP)->bEndpointAddress&0xF)
+#define ep_maxpacket(EP)       ((EP)->ep.maxpacket)
+
+#endif
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
new file mode 100644 (file)
index 0000000..e40089d
--- /dev/null
@@ -0,0 +1,2695 @@
+/*
+ * omap_udc.c -- for OMAP 1610 udc, with OTG support
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#undef DEBUG
+#undef VERBOSE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb_otg.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+
+#include "omap_udc.h"
+
+#undef USB_TRACE
+
+/* OUT-dma seems to be behaving */
+#define        USE_DMA
+
+/* ISO too */
+#define        USE_ISO
+
+
+#define        DRIVER_DESC     "OMAP UDC driver"
+#define        DRIVER_VERSION  "24 August 2004"
+
+#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
+
+
+/*
+ * The OMAP UDC needs _very_ early endpoint setup:  before enabling the
+ * D+ pullup to allow enumeration.  That's too early for the gadget
+ * framework to use from usb_endpoint_enable(), which happens after
+ * enumeration as part of activating an interface.  (But if we add an
+ * optional new "UDC not yet running" state to the gadget driver model,
+ * even just during driver binding, the endpoint autoconfig logic is the
+ * natural spot to manufacture new endpoints.)
+ *
+ * So instead of using endpoint enable calls to control the hardware setup,
+ * this driver defines a "fifo mode" parameter.  It's used during driver
+ * initialization to choose among a set of pre-defined endpoint configs.
+ * See omap_udc_setup() for available modes, or to add others.  That code
+ * lives in an init section, so use this driver as a module if you need
+ * to change the fifo mode after the kernel boots.
+ *
+ * Gadget drivers normally ignore endpoints they don't care about, and
+ * won't include them in configuration descriptors.  That means only
+ * misbehaving hosts would even notice they exist.
+ */
+#ifdef USE_ISO
+static unsigned fifo_mode = 3;
+#else
+static unsigned fifo_mode = 0;
+#endif
+
+/* "modprobe omap_udc fifo_mode=42", or else as a kernel
+ * boot parameter "omap_udc:fifo_mode=42"
+ */
+module_param (fifo_mode, uint, 0);
+MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
+
+
+#ifdef USE_DMA
+static unsigned use_dma = 1;
+
+/* "modprobe omap_udc use_dma=y", or else as a kernel
+ * boot parameter "omap_udc:use_dma=y"
+ */
+module_param (use_dma, bool, 0);
+MODULE_PARM_DESC (use_dma, "enable/disable DMA");
+#else  /* !USE_DMA */
+
+/* save a bit of code */
+#define        use_dma         0
+#endif /* !USE_DMA */
+
+
+static const char driver_name [] = "omap_udc";
+static const char driver_desc [] = DRIVER_DESC;
+
+/*-------------------------------------------------------------------------*/
+
+/* there's a notion of "current endpoint" for modifying endpoint
+ * state, and PIO access to its FIFO.  
+ */
+
+static void use_ep(struct omap_ep *ep, u16 select)
+{
+       u16     num = ep->bEndpointAddress & 0x0f;
+
+       if (ep->bEndpointAddress & USB_DIR_IN)
+               num |= UDC_EP_DIR;
+       UDC_EP_NUM_REG = num | select;
+       /* when select, MUST deselect later !! */
+}
+
+static inline void deselect_ep(void)
+{
+       UDC_EP_NUM_REG &= ~UDC_EP_SEL;
+       /* 6 wait states before TX will happen */
+}
+
+static void dma_channel_claim(struct omap_ep *ep, unsigned preferred);
+
+/*-------------------------------------------------------------------------*/
+
+static int omap_ep_enable(struct usb_ep *_ep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
+       struct omap_udc *udc;
+       unsigned long   flags;
+       u16             maxp;
+
+       /* catch various bogus parameters */
+       if (!_ep || !desc || ep->desc
+                       || desc->bDescriptorType != USB_DT_ENDPOINT
+                       || ep->bEndpointAddress != desc->bEndpointAddress
+                       || ep->maxpacket < le16_to_cpu
+                                               (desc->wMaxPacketSize)) {
+               DBG("%s, bad ep or descriptor\n", __FUNCTION__);
+               return -EINVAL;
+       }
+       maxp = le16_to_cpu (desc->wMaxPacketSize);
+       if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+                               && maxp != ep->maxpacket)
+                       || desc->wMaxPacketSize > ep->maxpacket
+                       || !desc->wMaxPacketSize) {
+               DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
+               return -ERANGE;
+       }
+
+#ifdef USE_ISO
+       if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC
+                               && desc->bInterval != 1)) {
+               /* hardware wants period = 1; USB allows 2^(Interval-1) */
+               DBG("%s, unsupported ISO period %dms\n", _ep->name,
+                               1 << (desc->bInterval - 1));
+               return -EDOM;
+       }
+#else
+       if (desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+               DBG("%s, ISO nyet\n", _ep->name);
+               return -EDOM;
+       }
+#endif
+
+       /* xfer types must match, except that interrupt ~= bulk */
+       if (ep->bmAttributes != desc->bmAttributes
+                       && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+                       && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+               DBG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
+               return -EINVAL;
+       }
+
+       udc = ep->udc;
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+               DBG("%s, bogus device state\n", __FUNCTION__);
+               return -ESHUTDOWN;
+       }
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       ep->desc = desc;
+       ep->irqs = 0;
+       ep->stopped = 0;
+       ep->ep.maxpacket = maxp;
+
+       /* set endpoint to initial state */
+       ep->dma_channel = 0;
+       ep->has_dma = 0;
+       ep->lch = -1;
+       use_ep(ep, UDC_EP_SEL);
+       UDC_CTRL_REG = UDC_RESET_EP;
+       ep->ackwait = 0;
+       deselect_ep();
+
+       if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+               list_add(&ep->iso, &udc->iso);
+
+       /* maybe assign a DMA channel to this endpoint */
+       if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+                       && !(ep->bEndpointAddress & USB_DIR_IN))
+                       /* FIXME ISO can dma, but prefers first channel.
+                        * IN can dma, but lacks debugging.
+                        */
+               dma_channel_claim(ep, 0);
+
+       /* PIO OUT may RX packets */
+       if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC
+                       && !ep->has_dma
+                       && !(ep->bEndpointAddress & USB_DIR_IN))
+               UDC_CTRL_REG = UDC_SET_FIFO_EN;
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       VDBG("%s enabled\n", _ep->name);
+       return 0;
+}
+
+static void nuke(struct omap_ep *, int status);
+
+static int omap_ep_disable(struct usb_ep *_ep)
+{
+       struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
+       unsigned long   flags;
+
+       if (!_ep || !ep->desc) {
+               DBG("%s, %s not enabled\n", __FUNCTION__,
+                       _ep ? ep->ep.name : NULL);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&ep->udc->lock, flags);
+       ep->desc = 0;
+       nuke (ep, -ESHUTDOWN);
+       ep->ep.maxpacket = ep->maxpacket;
+       ep->has_dma = 0;
+       UDC_CTRL_REG = UDC_SET_HALT;
+       list_del_init(&ep->iso);
+
+       spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+       VDBG("%s disabled\n", _ep->name);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+omap_alloc_request(struct usb_ep *ep, int gfp_flags)
+{
+       struct omap_req *req;
+
+       req = kmalloc(sizeof *req, gfp_flags);
+       if (req) {
+               memset (req, 0, sizeof *req);
+               req->req.dma = DMA_ADDR_INVALID;
+               INIT_LIST_HEAD (&req->queue);
+       }
+       return &req->req;
+}
+
+static void
+omap_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+       struct omap_req *req = container_of(_req, struct omap_req, req);
+
+       if (_req)
+               kfree (req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void *
+omap_alloc_buffer(
+       struct usb_ep   *_ep,
+       unsigned        bytes,
+       dma_addr_t      *dma,
+       int             gfp_flags
+)
+{
+       void            *retval;
+       struct omap_ep  *ep;
+
+       ep = container_of(_ep, struct omap_ep, ep);
+       if (use_dma && ep->has_dma) {
+               static int      warned;
+               if (!warned && bytes < PAGE_SIZE) {
+                       dev_warn(ep->udc->gadget.dev.parent,
+                               "using dma_alloc_coherent for "
+                               "small allocations wastes memory\n");
+                       warned++;
+               }
+               return dma_alloc_coherent(ep->udc->gadget.dev.parent,
+                               bytes, dma, gfp_flags);
+       }
+
+       retval = kmalloc(bytes, gfp_flags);
+       if (retval)
+               *dma = virt_to_phys(retval);
+       return retval;
+}
+
+static void omap_free_buffer(
+       struct usb_ep   *_ep,
+       void            *buf,
+       dma_addr_t      dma,
+       unsigned        bytes
+)
+{
+       struct omap_ep  *ep;
+
+       ep = container_of(_ep, struct omap_ep, ep);
+       if (use_dma && _ep && ep->has_dma)
+               dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
+       else
+               kfree (buf);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+done(struct omap_ep *ep, struct omap_req *req, int status)
+{
+       unsigned                stopped = ep->stopped;
+
+       list_del_init(&req->queue);
+
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = status;
+       else
+               status = req->req.status;
+
+       if (use_dma && ep->has_dma) {
+               if (req->mapped) {
+                       dma_unmap_single(ep->udc->gadget.dev.parent,
+                               req->req.dma, req->req.length,
+                               (ep->bEndpointAddress & USB_DIR_IN)
+                                       ? DMA_TO_DEVICE
+                                       : DMA_FROM_DEVICE);
+                       req->req.dma = DMA_ADDR_INVALID;
+                       req->mapped = 0;
+               } else
+                       dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+                               req->req.dma, req->req.length,
+                               (ep->bEndpointAddress & USB_DIR_IN)
+                                       ? DMA_TO_DEVICE
+                                       : DMA_FROM_DEVICE);
+       }
+
+#ifndef        USB_TRACE
+       if (status && status != -ESHUTDOWN)
+#endif
+               VDBG("complete %s req %p stat %d len %u/%u\n",
+                       ep->ep.name, &req->req, status,
+                       req->req.actual, req->req.length);
+
+       /* don't modify queue heads during completion callback */
+       ep->stopped = 1;
+       spin_unlock(&ep->udc->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&ep->udc->lock);
+       ep->stopped = stopped;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define        FIFO_FULL       (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
+#define        FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL)
+
+#define FIFO_EMPTY     (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
+#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
+
+static inline int 
+write_packet(u8 *buf, struct omap_req *req, unsigned max)
+{
+       unsigned        len;
+       u16             *wp;
+
+       len = min(req->req.length - req->req.actual, max);
+       req->req.actual += len;
+
+       max = len;
+       if (likely((((int)buf) & 1) == 0)) {
+               wp = (u16 *)buf;
+               while (max >= 2) {
+                       UDC_DATA_REG = *wp++;
+                       max -= 2;
+               }
+               buf = (u8 *)wp;
+       }
+       while (max--)
+               *(volatile u8 *)&UDC_DATA_REG = *buf++;
+       return len;
+}
+
+// FIXME change r/w fifo calling convention
+
+
+// return:  0 = still running, 1 = completed, negative = errno
+static int write_fifo(struct omap_ep *ep, struct omap_req *req)
+{
+       u8              *buf;
+       unsigned        count;
+       int             is_last;
+       u16             ep_stat;
+
+       buf = req->req.buf + req->req.actual;
+       prefetch(buf);
+
+       /* PIO-IN isn't double buffered except for iso */
+       ep_stat = UDC_STAT_FLG_REG;
+       if (ep_stat & FIFO_UNWRITABLE)
+               return 0;
+
+       count = ep->ep.maxpacket;
+       count = write_packet(buf, req, count);
+       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+       ep->ackwait = 1;
+
+       /* last packet is often short (sometimes a zlp) */
+       if (count != ep->ep.maxpacket)
+               is_last = 1;
+       else if (req->req.length == req->req.actual
+                       && !req->req.zero)
+               is_last = 1;
+       else
+               is_last = 0;
+
+       /* NOTE:  requests complete when all IN data is in a
+        * FIFO (or sometimes later, if a zlp was needed).
+        * Use usb_ep_fifo_status() where needed.
+        */
+       if (is_last)
+               done(ep, req, 0);
+       return is_last;
+}
+
+static inline int 
+read_packet(u8 *buf, struct omap_req *req, unsigned avail)
+{
+       unsigned        len;
+       u16             *wp;
+
+       len = min(req->req.length - req->req.actual, avail);
+       req->req.actual += len;
+       avail = len;
+
+       if (likely((((int)buf) & 1) == 0)) {
+               wp = (u16 *)buf;
+               while (avail >= 2) {
+                       *wp++ = UDC_DATA_REG;
+                       avail -= 2;
+               }
+               buf = (u8 *)wp;
+       }
+       while (avail--)
+               *buf++ = *(volatile u8 *)&UDC_DATA_REG;
+       return len;
+}
+
+// return:  0 = still running, 1 = queue empty, negative = errno
+static int read_fifo(struct omap_ep *ep, struct omap_req *req)
+{
+       u8              *buf;
+       unsigned        count, avail;
+       int             is_last;
+
+       buf = req->req.buf + req->req.actual;
+       prefetchw(buf);
+
+       for (;;) {
+               u16     ep_stat = UDC_STAT_FLG_REG;
+
+               is_last = 0;
+               if (ep_stat & FIFO_UNREADABLE)
+                       break;
+
+               if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL))
+                       avail = ep->ep.maxpacket;
+               else 
+                       avail = UDC_RXFSTAT_REG;
+               count = read_packet(buf, req, avail);
+
+               // FIXME double buffered PIO OUT wasn't behaving...
+
+               /* partial packet reads may not be errors */
+               if (count < ep->ep.maxpacket) {
+                       is_last = 1;
+                       /* overflowed this request?  flush extra data */
+                       if (count != avail) {
+                               req->req.status = -EOVERFLOW;
+                               avail -= count;
+                               while (avail--)
+                                       (void) *(volatile u8 *)&UDC_DATA_REG;
+                       }
+               } else if (req->req.length == req->req.actual)
+                       is_last = 1;
+               else
+                       is_last = 0;
+
+               if (!ep->bEndpointAddress)
+                       break;
+               if (!ep->double_buf) {
+                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                       if (!is_last)
+                               break;
+               }
+
+               if (is_last) {
+                       done(ep, req, 0);
+                       if (list_empty(&ep->queue) || !ep->double_buf)
+                               break;
+                       req = container_of(ep->queue.next,
+                                       struct omap_req, queue);
+                       is_last = 0;
+               }
+       }
+       return is_last;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Each USB transfer request using DMA maps to one or more DMA transfers.
+ * When DMA completion isn't request completion, the UDC continues with
+ * the next DMA transfer for that USB transfer.
+ */
+
+static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
+{
+       u16             txdma_ctrl;
+       unsigned        length = req->req.length - req->req.actual;
+
+       /* measure length in either bytes or packets */
+       if (length <= (UDC_TXN_TSC + 1)) {
+               txdma_ctrl = UDC_TXN_EOT | length;
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
+                               length, 1, OMAP_DMA_SYNC_ELEMENT);
+       } else {
+               length = max(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,
+                               OMAP_DMA_SYNC_ELEMENT);
+               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);
+       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;
+}
+
+static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
+{
+       if (status == 0) {
+               req->req.actual += req->dma_bytes;
+
+               /* return if this request needs to send data or zlp */
+               if (req->req.actual < req->req.length)
+                       return;
+               if (req->req.zero
+                               && req->dma_bytes != 0
+                               && (req->req.actual % ep->maxpacket) == 0)
+                       return;
+       } else {
+               u32     last;
+
+               // FIXME this surely isn't #bytes transferred
+               last = (omap_readw(OMAP_DMA_CSSA_U(ep->lch)) << 16)
+                               | omap_readw(OMAP_DMA_CSSA_L(ep->lch));
+               req->req.actual = last - req->req.dma;
+       }
+
+       /* tx completion */
+       omap_stop_dma(ep->lch);
+       UDC_DMA_IRQ_EN_REG &= ~UDC_TX_DONE_IE(ep->dma_channel);
+       done(ep, req, status);
+}
+
+static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
+{
+       unsigned packets;
+
+       /* NOTE:  we filtered out "short reads" before, so we know
+        * the buffer has only whole numbers of packets.
+        */
+
+       /* set up this DMA transfer, enable the fifo, start */
+       packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
+       packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+       req->dma_bytes = packets * ep->ep.maxpacket;
+       omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
+                       ep->ep.maxpacket, 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);
+
+       UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
+       UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
+       UDC_EP_NUM_REG = (ep->bEndpointAddress & 0xf);
+       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+
+       omap_start_dma(ep->lch);
+}
+
+static void
+finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
+{
+       u16     count;
+
+       /* FIXME must be a better way to see how much dma
+        * happened, even when it never got going...
+        */
+       count = omap_readw(OMAP_DMA_CDAC(ep->lch));
+       count -= 0xffff & (req->req.dma + req->req.actual);
+       count += req->req.actual;
+       if (count <= req->req.length)
+               req->req.actual = count;
+       
+       if (count != req->dma_bytes || status)
+               omap_stop_dma(ep->lch);
+
+       /* if this wasn't short, request may need another transfer */
+       else if (req->req.actual < req->req.length)
+               return;
+
+       /* rx completion */
+       UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel);
+       done(ep, req, status);
+}
+
+static void dma_irq(struct omap_udc *udc, u16 irq_src)
+{
+       u16             dman_stat = UDC_DMAN_STAT_REG;
+       struct omap_ep  *ep;
+       struct omap_req *req;
+
+       /* IN dma: tx to host */
+       if (irq_src & UDC_TXN_DONE) {
+               ep = &udc->ep[16 + UDC_DMA_TX_SRC(dman_stat)];
+               ep->irqs++;
+               /* can see TXN_DONE after dma abort */
+               if (!list_empty(&ep->queue)) {
+                       req = container_of(ep->queue.next,
+                                               struct omap_req, queue);
+                       finish_in_dma(ep, req, 0);
+               }
+               UDC_IRQ_SRC_REG = UDC_TXN_DONE;
+
+               if (!list_empty (&ep->queue)) {
+                       req = container_of(ep->queue.next,
+                                       struct omap_req, queue);
+                       next_in_dma(ep, req);
+               }
+       }
+
+       /* OUT dma: rx from host */
+       if (irq_src & UDC_RXN_EOT) {
+               ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)];
+               ep->irqs++;
+               /* can see RXN_EOT after dma abort */
+               if (!list_empty(&ep->queue)) {
+                       req = container_of(ep->queue.next,
+                                       struct omap_req, queue);
+                       finish_out_dma(ep, req, 0);
+               }
+               UDC_IRQ_SRC_REG = UDC_RXN_EOT;
+
+               if (!list_empty (&ep->queue)) {
+                       req = container_of(ep->queue.next,
+                                       struct omap_req, queue);
+                       next_out_dma(ep, req);
+               }
+       }
+
+       if (irq_src & UDC_RXN_CNT) {
+               ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)];
+               DBG("%s, RX_CNT irq?\n", ep->ep.name);
+               UDC_IRQ_SRC_REG = UDC_RXN_CNT;
+       }
+}
+
+static void dma_error(int lch, u16 ch_status, void *data)
+{
+       struct omap_ep  *ep = data;
+
+       /* if ch_status & OMAP_DMA_DROP_IRQ ... */
+       /* if ch_status & OMAP_DMA_TOUT_IRQ ... */
+       ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status);
+
+       /* complete current transfer ... */
+}
+
+static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
+{
+       u16     reg;
+       int     status, restart, is_in;
+
+       is_in = ep->bEndpointAddress & USB_DIR_IN;
+       if (is_in)
+               reg = UDC_TXDMA_CFG_REG;
+       else
+               reg = UDC_RXDMA_CFG_REG;
+       reg |= 1 << 12;         /* "pulse" activated */
+
+       ep->dma_channel = 0;
+       ep->lch = -1;
+       if (channel == 0 || channel > 3) {
+               if ((reg & 0x0f00) == 0)
+                       channel = 3;
+               else if ((reg & 0x00f0) == 0)
+                       channel = 2;
+               else if ((reg & 0x000f) == 0)   /* preferred for ISO */
+                       channel = 1;
+               else {
+                       status = -EMLINK;
+                       goto just_restart;
+               }
+       }
+       reg |= (0x0f & ep->bEndpointAddress) << (4 * (channel - 1));
+       ep->dma_channel = channel;
+
+       if (is_in) {
+               status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel,
+                       ep->ep.name, dma_error, ep, &ep->lch);
+               if (status == 0) {
+                       UDC_TXDMA_CFG_REG = reg;
+                       omap_set_dma_dest_params(ep->lch,
+                               OMAP_DMA_PORT_TIPB,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+               }
+       } else {
+               status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
+                       ep->ep.name, dma_error, ep, &ep->lch);
+               if (status == 0) {
+                       UDC_RXDMA_CFG_REG = reg;
+                       omap_set_dma_src_params(ep->lch,
+                               OMAP_DMA_PORT_TIPB,
+                               OMAP_DMA_AMODE_CONSTANT,
+                               (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+               }
+       }
+       if (status)
+               ep->dma_channel = 0;
+       else {
+               ep->has_dma = 1;
+               omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
+
+               /* channel type P: hw synch (fifo) */
+               omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
+       }
+
+just_restart:
+       /* restart any queue, even if the claim failed  */
+       restart = !ep->stopped && !list_empty(&ep->queue);
+
+       if (status)
+               DBG("%s no dma channel: %d%s\n", ep->ep.name, status,
+                       restart ? " (restart)" : "");
+       else
+               DBG("%s claimed %cxdma%d lch %d%s\n", ep->ep.name,
+                       is_in ? 't' : 'r',
+                       ep->dma_channel - 1, ep->lch,
+                       restart ? " (restart)" : "");
+
+       if (restart) {
+               struct omap_req *req;
+               req = container_of(ep->queue.next, struct omap_req, queue);
+               if (ep->has_dma)
+                       (is_in ? next_in_dma : next_out_dma)(ep, req);
+               else {
+                       use_ep(ep, UDC_EP_SEL);
+                       (is_in ? write_fifo : read_fifo)(ep, req);
+                       deselect_ep();
+                       /* IN: 6 wait states before it'll tx */
+               }
+       }
+}
+
+static void dma_channel_release(struct omap_ep *ep)
+{
+       int             shift = 4 * (ep->dma_channel - 1);
+       u16             mask = 0x0f << shift;
+       struct omap_req *req;
+       int             active;
+
+       /* abort any active usb transfer request */
+       if (!list_empty(&ep->queue))
+               req = container_of(ep->queue.next, struct omap_req, queue);
+       else
+               req = 0;
+
+       active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
+
+       DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
+                       active ? "active" : "idle",
+                       (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
+                       ep->dma_channel - 1, req);
+
+       /* wait till current packet DMA finishes, and fifo empties */
+       if (ep->bEndpointAddress & USB_DIR_IN) {
+               UDC_TXDMA_CFG_REG &= ~mask;
+
+               if (req) {
+                       if (active)
+                               udelay(50);
+                       finish_in_dma(ep, req, -ECONNRESET);
+                       if (UDC_TXDMA_CFG_REG & mask)
+                               WARN("%s, SPIN abort TX dma\n", ep->ep.name);
+               }
+
+               /* host may empty the fifo (or not...) */
+               while (UDC_TXDMA_CFG_REG & mask)
+                       udelay(10);
+
+       } else {
+               UDC_RXDMA_CFG_REG &= ~mask;
+
+               /* dma empties the fifo */
+               while (active && (UDC_RXDMA_CFG_REG & mask))
+                       udelay(10);
+               omap_stop_dma(ep->lch);
+               if (req)
+                       finish_out_dma(ep, req, -ECONNRESET);
+       }
+       omap_free_dma(ep->lch);
+       ep->dma_channel = 0;
+       ep->lch = -1;
+       /* has_dma still set, till endpoint is fully quiesced */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int
+omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+{
+       struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
+       struct omap_req *req = container_of(_req, struct omap_req, req);
+       struct omap_udc *udc;
+       unsigned long   flags;
+       int             is_iso = 0;
+
+       /* catch various bogus parameters */
+       if (!_req || !req->req.complete || !req->req.buf
+                       || !list_empty(&req->queue)) {
+               DBG("%s, bad params\n", __FUNCTION__);
+               return -EINVAL;
+       }
+       if (!_ep || (!ep->desc && ep->bEndpointAddress)) {
+               DBG("%s, bad ep\n", __FUNCTION__);
+               return -EINVAL;
+       }
+       if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+               if (req->req.length > ep->ep.maxpacket)
+                       return -EMSGSIZE;
+               is_iso = 1;
+       }
+
+       /* this isn't bogus, but OMAP DMA isn't the only hardware to
+        * have a hard time with partial packet reads...  reject it.
+        */
+       if (use_dma
+                       && ep->has_dma
+                       && ep->bEndpointAddress != 0
+                       && (ep->bEndpointAddress & USB_DIR_IN) == 0
+                       && (req->req.length % ep->ep.maxpacket) != 0) {
+               DBG("%s, no partial packet OUT reads\n", __FUNCTION__);
+               return -EMSGSIZE;
+       }
+
+       udc = ep->udc;
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       if (use_dma && ep->has_dma) {
+               if (req->req.dma == DMA_ADDR_INVALID) {
+                       req->req.dma = dma_map_single(
+                               ep->udc->gadget.dev.parent,
+                               req->req.buf,
+                               req->req.length,
+                               (ep->bEndpointAddress & USB_DIR_IN)
+                                       ? DMA_TO_DEVICE
+                                       : DMA_FROM_DEVICE);
+                       req->mapped = 1;
+               } else {
+                       dma_sync_single_for_device(
+                               ep->udc->gadget.dev.parent,
+                               req->req.dma, req->req.length,
+                               (ep->bEndpointAddress & USB_DIR_IN)
+                                       ? DMA_TO_DEVICE
+                                       : DMA_FROM_DEVICE);
+                       req->mapped = 0;
+               }
+       }
+
+       VDBG("%s queue req %p, len %d buf %p\n",
+               ep->ep.name, _req, _req->length, _req->buf);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       req->req.status = -EINPROGRESS;
+       req->req.actual = 0;
+
+       /* maybe kickstart non-iso i/o queues */
+       if (is_iso)
+               UDC_IRQ_EN_REG |= UDC_SOF_IE;
+       else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) {
+               int     is_in;
+
+               if (ep->bEndpointAddress == 0) {
+                       if (!udc->ep0_pending || !list_empty (&ep->queue)) {
+                               spin_unlock_irqrestore(&udc->lock, flags);
+                               return -EL2HLT;
+                       }
+
+                       /* empty DATA stage? */
+                       is_in = udc->ep0_in;
+                       if (!req->req.length) {
+
+                               /* chip became CONFIGURED or ADDRESSED
+                                * earlier; drivers may already have queued
+                                * requests to non-control endpoints
+                                */
+                               if (udc->ep0_set_config) {
+                                       u16     irq_en = UDC_IRQ_EN_REG;
+
+                                       irq_en |= UDC_DS_CHG_IE | UDC_EP0_IE;
+                                       if (!udc->ep0_reset_config)
+                                               irq_en |= UDC_EPN_RX_IE
+                                                       | UDC_EPN_TX_IE;
+                                       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);
+                               UDC_CTRL_REG = UDC_CLR_EP;
+                               UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                               UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR;
+
+                               /* cleanup */
+                               udc->ep0_pending = 0;
+                               done(ep, req, 0);
+                               req = 0;
+
+                       /* non-empty DATA stage */
+                       } else if (is_in) {
+                               UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+                       } else {
+                               if (udc->ep0_setup)
+                                       goto irq_wait;
+                               UDC_EP_NUM_REG = UDC_EP_SEL;
+                       }
+               } else {
+                       is_in = ep->bEndpointAddress & USB_DIR_IN;
+                       if (!ep->has_dma)
+                               use_ep(ep, UDC_EP_SEL);
+                       /* if ISO: SOF IRQs must be enabled/disabled! */
+               }
+
+               if (ep->has_dma)
+                       (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;
+                       deselect_ep();
+                       /* IN: 6 wait states before it'll tx */
+               }
+       }
+
+irq_wait:
+       /* irq handler advances the queue */
+       if (req != 0)
+               list_add_tail(&req->queue, &ep->queue);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
+       struct omap_req *req;
+       unsigned long   flags;
+
+       if (!_ep || !_req)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ep->udc->lock, flags);
+
+       /* make sure it's actually queued on this endpoint */
+       list_for_each_entry (req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+       if (&req->req != _req) {
+               spin_unlock_irqrestore(&ep->udc->lock, flags);
+               return -EINVAL;
+       }
+
+       if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) {
+               int channel = ep->dma_channel;
+
+               /* releasing the dma completion cancels the request,
+                * reclaiming the channel restarts the queue
+                */
+               dma_channel_release(ep);
+               dma_channel_claim(ep, channel);
+       } else 
+               done(ep, req, -ECONNRESET);
+       spin_unlock_irqrestore(&ep->udc->lock, flags);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int omap_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
+       unsigned long   flags;
+       int             status = -EOPNOTSUPP;
+
+       spin_lock_irqsave(&ep->udc->lock, flags);
+
+       /* just use protocol stalls for ep0; real halts are annoying */
+       if (ep->bEndpointAddress == 0) {
+               if (!ep->udc->ep0_pending)
+                       status = -EINVAL;
+               else if (value) {
+                       if (ep->udc->ep0_set_config) {
+                               WARN("error changing config?\n");
+                               UDC_SYSCON2_REG = UDC_CLR_CFG;
+                       }
+                       UDC_SYSCON2_REG = UDC_STALL_CMD;
+                       ep->udc->ep0_pending = 0;
+                       status = 0;
+               } else /* NOP */
+                       status = 0;
+
+       /* otherwise, all active non-ISO endpoints can halt */
+       } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) {
+
+               /* IN endpoints must already be idle */
+               if ((ep->bEndpointAddress & USB_DIR_IN)
+                               && !list_empty(&ep->queue)) { 
+                       status = -EAGAIN;
+                       goto done;
+               }
+
+               if (value) {
+                       int     channel;
+
+                       if (use_dma && ep->dma_channel
+                                       && !list_empty(&ep->queue)) {
+                               channel = ep->dma_channel;
+                               dma_channel_release(ep);
+                       } else
+                               channel = 0;
+
+                       use_ep(ep, UDC_EP_SEL);
+                       if (UDC_STAT_FLG_REG & UDC_NON_ISO_FIFO_EMPTY) {
+                               UDC_CTRL_REG = UDC_SET_HALT;
+                               status = 0;
+                       } else
+                               status = -EAGAIN;
+                       deselect_ep();
+
+                       if (channel)
+                               dma_channel_claim(ep, channel);
+               } else {
+                       use_ep(ep, 0);
+                       UDC_CTRL_REG = UDC_RESET_EP;
+                       ep->ackwait = 0;
+                       if (!(ep->bEndpointAddress & USB_DIR_IN))
+                               UDC_CTRL_REG = UDC_SET_FIFO_EN;
+               }
+       }
+done:
+       VDBG("%s %s halt stat %d\n", ep->ep.name,
+               value ? "set" : "clear", status);
+
+       spin_unlock_irqrestore(&ep->udc->lock, flags);
+       return status;
+}
+
+static struct usb_ep_ops omap_ep_ops = {
+       .enable         = omap_ep_enable,
+       .disable        = omap_ep_disable,
+
+       .alloc_request  = omap_alloc_request,
+       .free_request   = omap_free_request,
+
+       .alloc_buffer   = omap_alloc_buffer,
+       .free_buffer    = omap_free_buffer,
+
+       .queue          = omap_ep_queue,
+       .dequeue        = omap_ep_dequeue,
+
+       .set_halt       = omap_ep_set_halt,
+       // fifo_status ... report bytes in fifo
+       // fifo_flush ... flush fifo
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int omap_get_frame(struct usb_gadget *gadget)
+{
+       u16     sof = UDC_SOF_REG;
+       return (sof & UDC_TS_OK) ? (sof & UDC_TS) : -EL2NSYNC;
+}
+
+static int omap_wakeup(struct usb_gadget *gadget)
+{
+       struct omap_udc *udc;
+       unsigned long   flags;
+       int             retval = -EHOSTUNREACH;
+
+       udc = container_of(gadget, struct omap_udc, gadget);
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (udc->devstat & UDC_SUS) {
+               /* NOTE:  OTG spec erratum says that OTG devices may
+                * issue wakeups without host enable.
+                */
+               if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) {
+                       DBG("remote wakeup...\n");
+                       UDC_SYSCON2_REG = UDC_RMT_WKP;
+                       retval = 0;
+               }
+
+       /* NOTE:  non-OTG systems may use SRP TOO... */
+       } else if (!(udc->devstat & UDC_ATT)) {
+               if (udc->transceiver)
+                       retval = otg_start_srp(udc->transceiver);
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return retval;
+}
+
+static int
+omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+       struct omap_udc *udc;
+       unsigned long   flags;
+       u16             syscon1;
+
+       udc = container_of(gadget, struct omap_udc, gadget);
+       spin_lock_irqsave(&udc->lock, flags);
+       syscon1 = UDC_SYSCON1_REG;
+       if (is_selfpowered)
+               syscon1 |= UDC_SELF_PWR;
+       else
+               syscon1 &= ~UDC_SELF_PWR;
+       UDC_SYSCON1_REG = syscon1;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static int can_pullup(struct omap_udc *udc)
+{
+       return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+static void pullup_enable(struct omap_udc *udc)
+{
+       UDC_SYSCON1_REG |= UDC_PULLUP_EN;
+#ifndef CONFIG_USB_OTG
+       OTG_CTRL_REG |= OTG_BSESSVLD;
+#endif
+       UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
+}
+
+static void pullup_disable(struct omap_udc *udc)
+{
+#ifndef CONFIG_USB_OTG
+       OTG_CTRL_REG &= ~OTG_BSESSVLD;
+#endif
+       UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
+       UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
+}
+
+/*
+ * Called by whatever detects VBUS sessions:  external transceiver
+ * driver, or maybe GPIO0 VBUS IRQ.
+ */
+static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+       struct omap_udc *udc;
+       unsigned long   flags;
+
+       udc = container_of(gadget, struct omap_udc, gadget);
+       spin_lock_irqsave(&udc->lock, flags);
+       VDBG("VBUS %s\n", is_active ? "on" : "off");
+       udc->vbus_active = (is_active != 0);
+       if (can_pullup(udc))
+               pullup_enable(udc);
+       else
+               pullup_disable(udc);
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return 0;
+}
+
+static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       struct omap_udc *udc;
+
+       udc = container_of(gadget, struct omap_udc, gadget);
+       if (udc->transceiver)
+               return otg_set_power(udc->transceiver, mA);
+       return -EOPNOTSUPP;
+}
+
+static int omap_pullup(struct usb_gadget *gadget, int is_on)
+{
+       struct omap_udc *udc;
+       unsigned long   flags;
+
+       udc = container_of(gadget, struct omap_udc, gadget);
+       spin_lock_irqsave(&udc->lock, flags);
+       udc->softconnect = (is_on != 0);
+       if (can_pullup(udc))
+               pullup_enable(udc);
+       else
+               pullup_disable(udc);
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return 0;
+}
+
+static struct usb_gadget_ops omap_gadget_ops = {
+       .get_frame              = omap_get_frame,
+       .wakeup                 = omap_wakeup,
+       .set_selfpowered        = omap_set_selfpowered,
+       .vbus_session           = omap_vbus_session,
+       .vbus_draw              = omap_vbus_draw,
+       .pullup                 = omap_pullup,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* dequeue ALL requests; caller holds udc->lock */
+static void nuke(struct omap_ep *ep, int status)
+{
+       struct omap_req *req;
+
+       ep->stopped = 1;
+
+       if (use_dma && ep->dma_channel)
+               dma_channel_release(ep);
+
+       use_ep(ep, 0);
+       UDC_CTRL_REG = UDC_CLR_EP;
+       if (ep->bEndpointAddress && ep->bmAttributes != USB_ENDPOINT_XFER_ISOC)
+               UDC_CTRL_REG = UDC_SET_HALT;
+
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next, struct omap_req, queue);
+               done(ep, req, status);
+       }
+}
+
+/* caller holds udc->lock */
+static void udc_quiesce(struct omap_udc *udc)
+{
+       struct omap_ep  *ep;
+
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       nuke(&udc->ep[0], -ESHUTDOWN);
+       list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list)
+               nuke(ep, -ESHUTDOWN);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void update_otg(struct omap_udc *udc)
+{
+       u16     devstat;
+
+       if (!udc->gadget.is_otg)
+               return;
+
+       if (OTG_CTRL_REG & OTG_ID)
+               devstat = UDC_DEVSTAT_REG;
+       else
+               devstat = 0;
+
+       udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE);
+       udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT);
+       udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT);
+
+       /* Enable HNP early, avoiding races on suspend irq path.
+        * ASSUMES OTG state machine B_BUS_REQ input is true.
+        */
+       if (udc->gadget.b_hnp_enable)
+               OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ)
+                               & ~OTG_PULLUP;
+}
+
+static void ep0_irq(struct omap_udc *udc, u16 irq_src)
+{
+       struct omap_ep  *ep0 = &udc->ep[0];
+       struct omap_req *req = 0;
+
+       ep0->irqs++;
+
+       /* Clear any pending requests and then scrub any rx/tx state
+        * before starting to handle the SETUP request.
+        */
+       if (irq_src & UDC_SETUP)
+               nuke(ep0, 0);
+
+       /* IN/OUT packets mean we're in the DATA or STATUS stage.  
+        * This driver uses only uses protocol stalls (ep0 never halts),
+        * and if we got this far the gadget driver already had a
+        * chance to stall.  Tries to be forgiving of host oddities.
+        *
+        * NOTE:  the last chance gadget drivers have to stall control
+        * requests is during their request completion callback.
+        */
+       if (!list_empty(&ep0->queue))
+               req = container_of(ep0->queue.next, struct omap_req, queue);
+
+       /* IN == TX to host */
+       if (irq_src & UDC_EP0_TX) {
+               int     stat;
+
+               UDC_IRQ_SRC_REG = UDC_EP0_TX;
+               UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+               stat = UDC_STAT_FLG_REG;
+               if (stat & UDC_ACK) {
+                       if (udc->ep0_in) {
+                               /* write next IN packet from response,
+                                * or set up the status stage.
+                                */
+                               if (req)
+                                       stat = write_fifo(ep0, req);
+                               UDC_EP_NUM_REG = UDC_EP_DIR;
+                               if (!req && udc->ep0_pending) {
+                                       UDC_EP_NUM_REG = UDC_EP_SEL;
+                                       UDC_CTRL_REG = UDC_CLR_EP;
+                                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                                       UDC_EP_NUM_REG = 0;
+                                       udc->ep0_pending = 0;
+                               } /* else:  6 wait states before it'll tx */
+                       } else {
+                               /* ack status stage of OUT transfer */
+                               UDC_EP_NUM_REG = UDC_EP_DIR;
+                               if (req)
+                                       done(ep0, req, 0);
+                       }
+                       req = 0;
+               } else if (stat & UDC_STALL) {
+                       UDC_CTRL_REG = UDC_CLR_HALT;
+                       UDC_EP_NUM_REG = UDC_EP_DIR;
+               } else {
+                       UDC_EP_NUM_REG = UDC_EP_DIR;
+               }
+       }
+
+       /* OUT == RX from host */
+       if (irq_src & UDC_EP0_RX) {
+               int     stat;
+
+               UDC_IRQ_SRC_REG = UDC_EP0_RX;
+               UDC_EP_NUM_REG = UDC_EP_SEL;
+               stat = UDC_STAT_FLG_REG;
+               if (stat & UDC_ACK) {
+                       if (!udc->ep0_in) {
+                               stat = 0;
+                               /* read next OUT packet of request, maybe
+                                * reactiviting the fifo; stall on errors.
+                                */
+                               if (!req || (stat = read_fifo(ep0, req)) < 0) {
+                                       UDC_SYSCON2_REG = UDC_STALL_CMD;
+                                       udc->ep0_pending = 0;
+                                       stat = 0;
+                               } else if (stat == 0)
+                                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                               UDC_EP_NUM_REG = 0;
+                               
+                               /* activate status stage */
+                               if (stat == 1) {
+                                       done(ep0, req, 0);
+                                       /* that may have STALLed ep0... */
+                                       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_EP_DIR;
+                                       udc->ep0_pending = 0;
+                               }
+                       } else {
+                               /* ack status stage of IN transfer */
+                               UDC_EP_NUM_REG = 0;
+                               if (req)
+                                       done(ep0, req, 0);
+                       }
+               } else if (stat & UDC_STALL) {
+                       UDC_CTRL_REG = UDC_CLR_HALT;
+                       UDC_EP_NUM_REG = 0;
+               } else {
+                       UDC_EP_NUM_REG = 0;
+               }
+       }
+
+       /* SETUP starts all control transfers */
+       if (irq_src & UDC_SETUP) {
+               union u {
+                       u16                     word[4];
+                       struct usb_ctrlrequest  r;
+               } u;
+               int                     status = -EINVAL;
+               struct omap_ep          *ep;
+
+               /* read the (latest) SETUP message */
+               do {
+                       UDC_EP_NUM_REG = UDC_SETUP_SEL;
+                       /* two bytes at a time */
+                       u.word[0] = UDC_DATA_REG;
+                       u.word[1] = UDC_DATA_REG;
+                       u.word[2] = UDC_DATA_REG;
+                       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);
+
+               /* Delegate almost all control requests to the gadget driver,
+                * except for a handful of ch9 status/feature requests that
+                * hardware doesn't autodecode _and_ the gadget API hides.
+                */
+               udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0;
+               udc->ep0_set_config = 0;
+               udc->ep0_pending = 1;
+               ep0->stopped = 0;
+               ep0->ackwait = 0;
+               switch (u.r.bRequest) {
+               case USB_REQ_SET_CONFIGURATION:
+                       /* udc needs to know when ep != 0 is valid */
+                       if (u.r.bRequestType != USB_RECIP_DEVICE)
+                               goto delegate;
+                       if (u.r.wLength != 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);
+
+                       /* update udc NOW since gadget driver may start
+                        * queueing requests immediately; clear config
+                        * later if it fails the request.
+                        */
+                       if (udc->ep0_reset_config)
+                               UDC_SYSCON2_REG = UDC_CLR_CFG;
+                       else
+                               UDC_SYSCON2_REG = UDC_DEV_CFG;
+                       update_otg(udc);
+                       goto delegate;
+               case USB_REQ_CLEAR_FEATURE:
+                       /* clear endpoint halt */
+                       if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+                               goto delegate;
+                       if (u.r.wValue != USB_ENDPOINT_HALT
+                                       || u.r.wLength != 0)
+                               goto do_stall;
+                       ep = &udc->ep[u.r.wIndex & 0xf];
+                       if (ep != ep0) {
+                               if (u.r.wIndex & 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;
+                               ep->ackwait = 0;
+                               if (!(ep->bEndpointAddress & USB_DIR_IN))
+                                       UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                       }
+                       VDBG("%s halt cleared by host\n", ep->name);
+                       goto ep0out_status_stage;
+               case USB_REQ_SET_FEATURE:
+                       /* set endpoint halt */
+                       if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+                               goto delegate;
+                       if (u.r.wValue != USB_ENDPOINT_HALT
+                                       || u.r.wLength != 0)
+                               goto do_stall;
+                       ep = &udc->ep[u.r.wIndex & 0xf];
+                       if (u.r.wIndex & USB_DIR_IN)
+                               ep += 16;
+                       if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
+                                       || ep == ep0 || !ep->desc)
+                               goto do_stall;
+                       if (use_dma && ep->has_dma) {
+                               /* this has rude side-effects (aborts) and
+                                * can't really work if DMA-IN is active
+                                */
+                               DBG("%s host set_halt, NYET \n", ep->name);
+                               goto do_stall;
+                       }
+                       use_ep(ep, 0);
+                       /* can't halt if fifo isn't empty... */
+                       UDC_CTRL_REG = UDC_CLR_EP;
+                       UDC_CTRL_REG = UDC_SET_HALT;
+                       VDBG("%s halted by host\n", ep->name);
+ep0out_status_stage:
+                       status = 0;
+                       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_EP_DIR;
+                       udc->ep0_pending = 0;
+                       break;
+               case USB_REQ_GET_STATUS:
+                       /* return interface status.  if we were pedantic,
+                        * we'd detect non-existent interfaces, and stall.
+                        */
+                       if (u.r.bRequestType
+                                       != (USB_DIR_IN|USB_RECIP_INTERFACE))
+                               goto delegate;
+                       /* return two zero bytes */
+                       UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR;
+                       UDC_DATA_REG = 0;
+                       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);
+                       /* next, status stage */
+                       break;
+               default:
+delegate:
+                       /* activate the ep0out fifo right away */
+                       if (!udc->ep0_in && u.r.wLength) {
+                               UDC_EP_NUM_REG = 0;
+                               UDC_CTRL_REG = UDC_SET_FIFO_EN;
+                       }
+
+                       /* gadget drivers see class/vendor specific requests,
+                        * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION},
+                        * and more
+                        */
+                       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);
+
+                       /* The gadget driver may return an error here,
+                        * causing an immediate protocol stall.
+                        *
+                        * Else it must issue a response, either queueing a
+                        * response buffer for the DATA stage, or halting ep0
+                        * (causing a protocol stall, not a real halt).  A
+                        * zero length buffer means no DATA stage.
+                        *
+                        * It's fine to issue that response after the setup()
+                        * call returns, and this IRQ was handled.
+                        */
+                       udc->ep0_setup = 1;
+                       spin_unlock(&udc->lock);
+                       status = udc->driver->setup (&udc->gadget, &u.r);
+                       spin_lock(&udc->lock);
+                       udc->ep0_setup = 0;
+               }
+
+               if (status < 0) {
+do_stall:
+                       VDBG("req %02x.%02x protocol STALL; stat %d\n",
+                                       u.r.bRequestType, u.r.bRequest, status);
+                       if (udc->ep0_set_config) {
+                               if (udc->ep0_reset_config)
+                                       WARN("error resetting config?\n");
+                               else
+                                       UDC_SYSCON2_REG = UDC_CLR_CFG;
+                       }
+                       UDC_SYSCON2_REG = UDC_STALL_CMD;
+                       udc->ep0_pending = 0;
+               }
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT)
+
+static void devstate_irq(struct omap_udc *udc, u16 irq_src)
+{
+       u16     devstat, change;
+
+       devstat = UDC_DEVSTAT_REG;
+       change = devstat ^ udc->devstat;
+       udc->devstat = devstat;
+
+       if (change & (UDC_USB_RESET|UDC_ATT)) {
+               udc_quiesce(udc);
+
+               if (change & UDC_ATT) {
+                       /* driver for any external transceiver will
+                        * have called omap_vbus_session() already
+                        */
+                       if (devstat & UDC_ATT) {
+                               udc->gadget.speed = USB_SPEED_FULL;
+                               VDBG("connect\n");
+                               if (!udc->transceiver)
+                                       pullup_enable(udc);
+                               // if (driver->connect) call it
+                       } else if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+                               udc->gadget.speed = USB_SPEED_UNKNOWN;
+                               if (!udc->transceiver)
+                                       pullup_disable(udc);
+                               DBG("disconnect, gadget %s\n",
+                                       udc->driver->driver.name);
+                               if (udc->driver->disconnect) {
+                                       spin_unlock(&udc->lock);
+                                       udc->driver->disconnect(&udc->gadget);
+                                       spin_lock(&udc->lock);
+                               }
+                       }
+                       change &= ~UDC_ATT;
+               }
+
+               if (change & UDC_USB_RESET) {
+                       if (devstat & UDC_USB_RESET) {
+                               VDBG("RESET=1\n");
+                       } else {
+                               udc->gadget.speed = USB_SPEED_FULL;
+                               INFO("USB reset done, gadget %s\n",
+                                       udc->driver->driver.name);
+                               /* ep0 traffic is legal from now on */
+                               UDC_IRQ_EN_REG = UDC_DS_CHG_IE | UDC_EP0_IE;
+                       }
+                       change &= ~UDC_USB_RESET;
+               }
+       }
+       if (change & UDC_SUS) {
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+                       // FIXME tell isp1301 to suspend/resume (?)
+                       if (devstat & UDC_SUS) {
+                               VDBG("suspend\n");
+                               update_otg(udc);
+                               /* HNP could be under way already */
+                               if (udc->gadget.speed == USB_SPEED_FULL
+                                               && udc->driver->suspend) {
+                                       spin_unlock(&udc->lock);
+                                       udc->driver->suspend(&udc->gadget);
+                                       spin_lock(&udc->lock);
+                               }
+                       } else {
+                               VDBG("resume\n");
+                               if (udc->gadget.speed == USB_SPEED_FULL
+                                               && udc->driver->resume) {
+                                       spin_unlock(&udc->lock);
+                                       udc->driver->resume(&udc->gadget);
+                                       spin_lock(&udc->lock);
+                               }
+                       }
+               }
+               change &= ~UDC_SUS;
+       }
+       if (change & OTG_FLAGS) {
+               update_otg(udc);
+               change &= ~OTG_FLAGS;
+       }
+
+       change &= ~(UDC_CFG|UDC_DEF|UDC_ADD);
+       if (change)
+               VDBG("devstat %03x, ignore change %03x\n",
+                       devstat,  change);
+
+       UDC_IRQ_SRC_REG = UDC_DS_CHG;
+}
+
+static irqreturn_t
+omap_udc_irq(int irq, void *_udc, struct pt_regs *r)
+{
+       struct omap_udc *udc = _udc;
+       u16             irq_src;
+       irqreturn_t     status = IRQ_NONE;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       irq_src = UDC_IRQ_SRC_REG;
+
+       /* Device state change (usb ch9 stuff) */
+       if (irq_src & UDC_DS_CHG) {
+               devstate_irq(_udc, irq_src);
+               status = IRQ_HANDLED;
+               irq_src &= ~UDC_DS_CHG;
+       }
+
+       /* EP0 control transfers */
+       if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) {
+               ep0_irq(_udc, irq_src);
+               status = IRQ_HANDLED;
+               irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX);
+       }
+
+       /* DMA transfer completion */
+       if (use_dma && (irq_src & (UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT))) {
+               dma_irq(_udc, irq_src);
+               status = IRQ_HANDLED;
+               irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT);
+       }
+
+       irq_src &= ~(UDC_SOF|UDC_EPN_TX|UDC_EPN_RX);
+       if (irq_src)
+               DBG("udc_irq, unhandled %03x\n", irq_src);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return status;
+}
+
+static irqreturn_t
+omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
+{
+       u16             epn_stat, irq_src;
+       irqreturn_t     status = IRQ_NONE;
+       struct omap_ep  *ep;
+       int             epnum;
+       struct omap_udc *udc = _dev;
+       struct omap_req *req;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       epn_stat = UDC_EPN_STAT_REG;
+       irq_src = UDC_IRQ_SRC_REG;
+
+       /* handle OUT first, to avoid some wasteful NAKs */
+       if (irq_src & UDC_EPN_RX) {
+               epnum = (epn_stat >> 8) & 0x0f;
+               UDC_IRQ_SRC_REG = UDC_EPN_RX;
+               status = IRQ_HANDLED;
+               ep = &udc->ep[epnum];
+               ep->irqs++;
+
+               if (!list_empty(&ep->queue)) {
+                       UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
+                       if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+                               int stat;
+                               req = container_of(ep->queue.next,
+                                               struct omap_req, queue);
+                               stat = read_fifo(ep, req);
+                               // FIXME double buffered PIO OUT should work
+                       }
+                       UDC_EP_NUM_REG = epnum;
+               }
+       }
+
+       /* then IN transfers */
+       if (irq_src & UDC_EPN_TX) {
+               epnum = epn_stat & 0x0f;
+               UDC_IRQ_SRC_REG = UDC_EPN_TX;
+               status = IRQ_HANDLED;
+               ep = &udc->ep[16 + epnum];
+               ep->irqs++;
+               ep->ackwait = 0;
+
+               if (!list_empty(&ep->queue)) {
+                       UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
+                       if ((UDC_STAT_FLG_REG & UDC_ACK)) {
+                               req = container_of(ep->queue.next,
+                                               struct omap_req, queue);
+                               (void) write_fifo(ep, req);
+                       }
+                       UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
+                       /* 6 wait states before it'll tx */
+               }
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return status;
+}
+
+#ifdef USE_ISO
+static irqreturn_t
+omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
+{
+       struct omap_udc *udc = _dev;
+       struct omap_ep  *ep;
+       int             pending = 0;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       /* handle all non-DMA ISO transfers */
+       list_for_each_entry (ep, &udc->iso, iso) {
+               u16             stat;
+               struct omap_req *req;
+
+               if (ep->has_dma || list_empty(&ep->queue))
+                       continue;
+               req = list_entry(ep->queue.next, struct omap_req, queue);
+
+               use_ep(ep, UDC_EP_SEL);
+               stat = UDC_STAT_FLG_REG;
+
+               /* NOTE: like the other controller drivers, this isn't
+                * currently reporting lost or damaged frames.
+                */
+               if (ep->bEndpointAddress & USB_DIR_IN) {
+                       if (stat & UDC_MISS_IN)
+                               /* done(ep, req, -EPROTO) */;
+                       else
+                               write_fifo(ep, req);
+               } else {
+                       int     status = 0;
+
+                       if (stat & UDC_NO_RXPACKET)
+                               status = -EREMOTEIO;
+                       else if (stat & UDC_ISO_ERR)
+                               status = -EILSEQ;
+                       else if (stat & UDC_DATA_FLUSH)
+                               status = -ENOSR;
+
+                       if (status)
+                               /* done(ep, req, status) */;
+                       else
+                               read_fifo(ep, req);
+               }
+               deselect_ep();
+               /* 6 wait states before next EP */
+
+               ep->irqs++;
+               if (!list_empty(&ep->queue))
+                       pending = 1;
+       }
+       if (!pending)
+               UDC_IRQ_EN_REG &= ~UDC_SOF_IE;
+       UDC_IRQ_SRC_REG = UDC_SOF;
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return IRQ_HANDLED;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static struct omap_udc *udc;
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+       int             status = -ENODEV;
+       struct omap_ep  *ep;
+       unsigned long   flags;
+
+       /* basic sanity tests */
+       if (!udc)
+               return -ENODEV;
+       if (!driver
+                       // FIXME if otg, check:  driver->is_otg
+                       || driver->speed < USB_SPEED_FULL
+                       || !driver->bind
+                       || !driver->unbind
+                       || !driver->setup)
+               return -EINVAL;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (udc->driver) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return -EBUSY;
+       }
+
+       /* reset state */
+       list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+               ep->irqs = 0;
+               if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+                       continue;
+               use_ep(ep, 0);
+               UDC_CTRL_REG = UDC_SET_HALT;
+       }
+       udc->ep0_pending = 0;
+       udc->ep[0].irqs = 0;
+       udc->softconnect = 1;
+
+       /* hook up the driver */
+       driver->driver.bus = 0;
+       udc->driver = driver;
+       udc->gadget.dev.driver = &driver->driver;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       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;
+               goto done;
+       }
+       DBG("bound to driver %s\n", driver->driver.name);
+
+       UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK;
+
+       /* connect to bus through transceiver */
+       if (udc->transceiver) {
+               status = otg_set_peripheral(udc->transceiver, &udc->gadget);
+               if (status < 0) {
+                       ERR("can't bind to transceiver\n");
+                       driver->unbind (&udc->gadget);
+                       udc->gadget.dev.driver = 0;
+                       udc->driver = 0;
+                       goto done;
+               }
+       } else {
+               if (can_pullup(udc))
+                       pullup_enable (udc);
+               else
+                       pullup_disable (udc);
+       }
+
+done:
+       return status;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+       unsigned long   flags;
+       int             status = -ENODEV;
+
+       if (!udc)
+               return -ENODEV;
+       if (!driver || driver != udc->driver)
+               return -EINVAL;
+
+       if (udc->transceiver)
+               (void) otg_set_peripheral(udc->transceiver, 0);
+       else
+               pullup_disable(udc);
+
+       spin_lock_irqsave(&udc->lock, flags);
+       udc_quiesce(udc);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       driver->unbind(&udc->gadget);
+       udc->gadget.dev.driver = 0;
+       udc->driver = 0;
+
+
+       DBG("unregistered driver '%s'\n", driver->driver.name);
+       return status;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_OMAP_PROC
+
+#include <linux/seq_file.h>
+
+static const char proc_filename[] = "driver/udc";
+
+#define FOURBITS "%s%s%s%s"
+#define EIGHTBITS FOURBITS FOURBITS
+
+static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
+{
+       u16             stat_flg;
+       struct omap_req *req;
+       char            buf[20];
+
+       use_ep(ep, 0);
+
+       if (use_dma && ep->has_dma)
+               snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ",
+                       (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
+                       ep->dma_channel - 1, ep->lch);
+       else
+               buf[0] = 0;
+
+       stat_flg = UDC_STAT_FLG_REG;
+       seq_printf(s,
+               "\n%s %sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
+               ep->name, buf, ep->irqs, stat_flg,
+               (stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
+               (stat_flg & UDC_MISS_IN) ? "miss_in " : "",
+               (stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "",
+               (stat_flg & UDC_ISO_ERR) ? "iso_err " : "",
+               (stat_flg & UDC_ISO_FIFO_EMPTY) ? "iso_fifo_empty " : "",
+               (stat_flg & UDC_ISO_FIFO_FULL) ? "iso_fifo_full " : "",
+               (stat_flg & UDC_EP_HALTED) ? "HALT " : "",
+               (stat_flg & UDC_STALL) ? "STALL " : "",
+               (stat_flg & UDC_NAK) ? "NAK " : "",
+               (stat_flg & UDC_ACK) ? "ACK " : "",
+               (stat_flg & UDC_FIFO_EN) ? "fifo_en " : "",
+               (stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "",
+               (stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : "");
+
+       if (list_empty (&ep->queue))
+               seq_printf(s, "\t(queue empty)\n");
+       else
+               list_for_each_entry (req, &ep->queue, queue)
+                       seq_printf(s, "\treq %p len %d/%d buf %p\n",
+                                       &req->req, req->req.actual,
+                                       req->req.length, req->req.buf);
+}
+
+static char *trx_mode(unsigned m)
+{
+       switch (m) {
+       case 3:
+       case 0:         return "6wire";
+       case 1:         return "4wire";
+       case 2:         return "3wire";
+       default:        return "unknown";
+       }
+}
+
+static int proc_udc_show(struct seq_file *s, void *_)
+{
+       u32             tmp;
+       struct omap_ep  *ep;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       seq_printf(s, "%s, version: " DRIVER_VERSION
+#ifdef USE_ISO
+               " (iso)"
+#endif
+               "%s\n",
+               driver_desc,
+               use_dma ?  " (dma)" : "");
+
+       tmp = UDC_REV_REG & 0xff; 
+       seq_printf(s,
+               "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n"
+               "hmc %d, transceiver %08x %s\n",
+               tmp >> 4, tmp & 0xf,
+               OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
+               fifo_mode,
+               udc->driver ? udc->driver->driver.name : "(none)",
+               HMC, USB_TRANSCEIVER_CTRL_REG,
+               udc->transceiver ? udc->transceiver->label : "");
+
+       /* OTG controller registers */
+       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)),
+               trx_mode(USB1_TRX_MODE(tmp)),
+               trx_mode(USB0_TRX_MODE(tmp)),
+               (tmp & OTG_IDLE_EN) ? " !otg" : "",
+               (tmp & HST_IDLE_EN) ? " !host" : "",
+               (tmp & DEV_IDLE_EN) ? " !dev" : "",
+               (tmp & OTG_RESET_DONE) ? " reset_done" : " reset_active");
+       tmp = OTG_SYSCON_2_REG;
+       seq_printf(s, "otg_syscon2 %08x%s" EIGHTBITS
+                       " b_ase_brst=%d hmc=%d\n", tmp,
+               (tmp & OTG_EN) ? " otg_en" : "",
+               (tmp & USBX_SYNCHRO) ? " synchro" : "",
+               // much more SRP stuff
+               (tmp & SRP_DATA) ? " srp_data" : "",
+               (tmp & SRP_VBUS) ? " srp_vbus" : "",
+               (tmp & OTG_PADEN) ? " otg_paden" : "",
+               (tmp & HMC_PADEN) ? " hmc_paden" : "",
+               (tmp & UHOST_EN) ? " uhost_en" : "",
+               (tmp & HMC_TLLSPEED) ? " tllspeed" : "",
+               (tmp & HMC_TLLATTACH) ? " tllattach" : "",
+               B_ASE_BRST(tmp),
+               OTG_HMC(tmp));
+       tmp = OTG_CTRL_REG;
+       seq_printf(s, "otg_ctrl    %06x" EIGHTBITS EIGHTBITS "%s\n", tmp,
+               (tmp & OTG_ASESSVLD) ? " asess" : "",
+               (tmp & OTG_BSESSEND) ? " bsess_end" : "",
+               (tmp & OTG_BSESSVLD) ? " bsess" : "",
+               (tmp & OTG_VBUSVLD) ? " vbus" : "",
+               (tmp & OTG_ID) ? " id" : "",
+               (tmp & OTG_DRIVER_SEL) ? " DEVICE" : " HOST",
+               (tmp & OTG_A_SETB_HNPEN) ? " a_setb_hnpen" : "",
+               (tmp & OTG_A_BUSREQ) ? " a_bus" : "",
+               (tmp & OTG_B_HNPEN) ? " b_hnpen" : "",
+               (tmp & OTG_B_BUSREQ) ? " b_bus" : "",
+               (tmp & OTG_BUSDROP) ? " busdrop" : "",
+               (tmp & OTG_PULLDOWN) ? " down" : "",
+               (tmp & OTG_PULLUP) ? " up" : "",
+               (tmp & OTG_DRV_VBUS) ? " drv" : "",
+               (tmp & OTG_PD_VBUS) ? " pd_vb" : "",
+               (tmp & OTG_PU_VBUS) ? " pu_vb" : "",
+               (tmp & OTG_PU_ID) ? " pu_id" : ""
+               );
+       tmp = OTG_IRQ_EN_REG;
+       seq_printf(s, "otg_irq_en  %04x" "\n", tmp);
+       tmp = OTG_IRQ_SRC_REG;
+       seq_printf(s, "otg_irq_src %04x" "\n", tmp);
+       tmp = OTG_OUTCTRL_REG;
+       seq_printf(s, "otg_outctrl %04x" "\n", tmp);
+       tmp = OTG_TEST_REG;
+       seq_printf(s, "otg_test    %04x" "\n", tmp);
+
+       tmp = UDC_SYSCON1_REG;
+       seq_printf(s, "\nsyscon1     %04x" EIGHTBITS "\n", tmp,
+               (tmp & UDC_CFG_LOCK) ? " cfg_lock" : "",
+               (tmp & UDC_DATA_ENDIAN) ? " data_endian" : "",
+               (tmp & UDC_DMA_ENDIAN) ? " dma_endian" : "",
+               (tmp & UDC_NAK_EN) ? " nak" : "",
+               (tmp & UDC_AUTODECODE_DIS) ? " autodecode_dis" : "",
+               (tmp & UDC_SELF_PWR) ? " self_pwr" : "",
+               (tmp & UDC_SOFF_DIS) ? " soff_dis" : "",
+               (tmp & UDC_PULLUP_EN) ? " PULLUP" : "");
+       // syscon2 is write-only
+
+       /* UDC controller registers */
+       if (!(tmp & UDC_PULLUP_EN)) {
+               seq_printf(s, "(suspended)\n");
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return 0;
+       }
+
+       tmp = UDC_DEVSTAT_REG;
+       seq_printf(s, "devstat     %04x" EIGHTBITS "%s%s\n", tmp,
+               (tmp & UDC_B_HNP_ENABLE) ? " b_hnp" : "",
+               (tmp & UDC_A_HNP_SUPPORT) ? " a_hnp" : "",
+               (tmp & UDC_A_ALT_HNP_SUPPORT) ? " a_alt_hnp" : "",
+               (tmp & UDC_R_WK_OK) ? " r_wk_ok" : "",
+               (tmp & UDC_USB_RESET) ? " usb_reset" : "",
+               (tmp & UDC_SUS) ? " SUS" : "",
+               (tmp & UDC_CFG) ? " CFG" : "",
+               (tmp & UDC_ADD) ? " ADD" : "",
+               (tmp & UDC_DEF) ? " DEF" : "",
+               (tmp & UDC_ATT) ? " ATT" : "");
+       seq_printf(s, "sof         %04x\n", UDC_SOF_REG);
+       tmp = UDC_IRQ_EN_REG;
+       seq_printf(s, "irq_en      %04x" FOURBITS "%s\n", tmp,
+               (tmp & UDC_SOF_IE) ? " sof" : "",
+               (tmp & UDC_EPN_RX_IE) ? " epn_rx" : "",
+               (tmp & UDC_EPN_TX_IE) ? " epn_tx" : "",
+               (tmp & UDC_DS_CHG_IE) ? " ds_chg" : "",
+               (tmp & UDC_EP0_IE) ? " ep0" : "");
+       tmp = UDC_IRQ_SRC_REG;
+       seq_printf(s, "irq_src     %04x" EIGHTBITS "%s%s\n", tmp,
+               (tmp & UDC_TXN_DONE) ? " txn_done" : "",
+               (tmp & UDC_RXN_CNT) ? " rxn_cnt" : "",
+               (tmp & UDC_RXN_EOT) ? " rxn_eot" : "",
+               (tmp & UDC_SOF) ? " sof" : "",
+               (tmp & UDC_EPN_RX) ? " epn_rx" : "",
+               (tmp & UDC_EPN_TX) ? " epn_tx" : "",
+               (tmp & UDC_DS_CHG) ? " ds_chg" : "",
+               (tmp & UDC_SETUP) ? " setup" : "",
+               (tmp & UDC_EP0_RX) ? " ep0out" : "",
+               (tmp & UDC_EP0_TX) ? " ep0in" : "");
+       if (use_dma) {
+               unsigned i;
+
+               tmp = UDC_DMA_IRQ_EN_REG;
+               seq_printf(s, "dma_irq_en  %04x%s" EIGHTBITS "\n", tmp,
+                       (tmp & UDC_TX_DONE_IE(3)) ? " tx2_done" : "",
+                       (tmp & UDC_RX_CNT_IE(3)) ? " rx2_cnt" : "",
+                       (tmp & UDC_RX_EOT_IE(3)) ? " rx2_eot" : "",
+
+                       (tmp & UDC_TX_DONE_IE(2)) ? " tx1_done" : "",
+                       (tmp & UDC_RX_CNT_IE(2)) ? " rx1_cnt" : "",
+                       (tmp & UDC_RX_EOT_IE(2)) ? " rx1_eot" : "",
+
+                       (tmp & UDC_TX_DONE_IE(1)) ? " tx0_done" : "",
+                       (tmp & UDC_RX_CNT_IE(1)) ? " rx0_cnt" : "",
+                       (tmp & UDC_RX_EOT_IE(1)) ? " rx0_eot" : "");
+
+               tmp = UDC_RXDMA_CFG_REG;
+               seq_printf(s, "rxdma_cfg   %04x\n", tmp);
+               if (tmp) {
+                       for (i = 0; i < 3; i++) {
+                               if ((tmp & (0x0f << (i * 4))) == 0)
+                                       continue;
+                               seq_printf(s, "rxdma[%d]    %04x\n", i,
+                                               UDC_RXDMA_REG(i + 1));
+                       }
+               }
+               tmp = UDC_TXDMA_CFG_REG;
+               seq_printf(s, "txdma_cfg   %04x\n", tmp);
+               if (tmp) {
+                       for (i = 0; i < 3; i++) {
+                               if (!(tmp & (0x0f << (i * 4))))
+                                       continue;
+                               seq_printf(s, "txdma[%d]    %04x\n", i,
+                                               UDC_TXDMA_REG(i + 1));
+                       }
+               }
+       }
+
+       tmp = UDC_DEVSTAT_REG;
+       if (tmp & UDC_ATT) {
+               proc_ep_show(s, &udc->ep[0]);
+               if (tmp & UDC_ADD) {
+                       list_for_each_entry (ep, &udc->gadget.ep_list,
+                                       ep.ep_list) {
+                               if (ep->desc)
+                                       proc_ep_show(s, ep);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+       return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_udc_show, 0);
+}
+
+static struct file_operations proc_ops = {
+       .open           = proc_udc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void create_proc_file(void)
+{
+       struct proc_dir_entry *pde;
+
+       pde = create_proc_entry (proc_filename, 0, NULL);
+       if (pde)
+               pde->proc_fops = &proc_ops;
+}
+
+static void remove_proc_file(void)
+{
+       remove_proc_entry(proc_filename, 0);
+}
+
+#else
+
+static inline void create_proc_file(void) {}
+static inline void remove_proc_file(void) {}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* 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.
+ */
+static unsigned __init
+omap_ep_setup(char *name, u8 addr, u8 type,
+               unsigned buf, unsigned maxp, int dbuf)
+{
+       struct omap_ep  *ep;
+       u16             epn_rxtx = 0;
+
+       /* OUT endpoints first, then IN */
+       ep = &udc->ep[addr & 0xf];
+       if (addr & USB_DIR_IN)
+               ep += 16;
+
+       /* in case of ep init table bugs */
+       BUG_ON(ep->name[0]);
+
+       /* chip setup ... bit values are same for IN, OUT */
+       if (type == USB_ENDPOINT_XFER_ISOC) {
+               switch (maxp) {
+               case 8:         epn_rxtx = 0 << 12; break;
+               case 16:        epn_rxtx = 1 << 12; break;
+               case 32:        epn_rxtx = 2 << 12; break;
+               case 64:        epn_rxtx = 3 << 12; break;
+               case 128:       epn_rxtx = 4 << 12; break;
+               case 256:       epn_rxtx = 5 << 12; break;
+               case 512:       epn_rxtx = 6 << 12; break;
+               default:        BUG();
+               }
+               epn_rxtx |= UDC_EPN_RX_ISO;
+               dbuf = 1;
+       } else {
+               /* pio-out could potentially double-buffer,
+                * as can (should!) DMA-IN
+                */
+               if (!use_dma || (addr & USB_DIR_IN))
+                       dbuf = 0;
+
+               switch (maxp) {
+               case 8:         epn_rxtx = 0 << 12; break;
+               case 16:        epn_rxtx = 1 << 12; break;
+               case 32:        epn_rxtx = 2 << 12; break;
+               case 64:        epn_rxtx = 3 << 12; break;
+               default:        BUG();
+               }
+               if (dbuf && addr)
+                       epn_rxtx |= UDC_EPN_RX_DB;
+       }
+       if (addr)
+               epn_rxtx |= UDC_EPN_RX_VALID;
+       BUG_ON(buf & 0x07);
+       epn_rxtx |= buf >> 3;
+
+       DBG("%s addr %02x rxtx %04x maxp %d%s buf %d\n",
+               name, addr, epn_rxtx, maxp, dbuf ? "x2" : "", buf);
+
+       if (addr & USB_DIR_IN)
+               UDC_EP_TX_REG(addr & 0xf) = epn_rxtx;
+       else
+               UDC_EP_RX_REG(addr) = epn_rxtx;
+
+       /* next endpoint's buffer starts after this one's */
+       buf += maxp;
+       if (dbuf)
+               buf += maxp;
+       BUG_ON(buf > 2048);
+
+       /* set up driver data structures */
+       BUG_ON(strlen(name) >= sizeof ep->name);
+       strlcpy(ep->name, name, sizeof ep->name);
+       INIT_LIST_HEAD(&ep->queue);
+       INIT_LIST_HEAD(&ep->iso);
+       ep->bEndpointAddress = addr;
+       ep->bmAttributes = type;
+       ep->double_buf = dbuf;
+       ep->udc = udc; 
+
+       ep->ep.name = ep->name;
+       ep->ep.ops = &omap_ep_ops;
+       ep->ep.maxpacket = ep->maxpacket = maxp;
+       list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list);
+
+       return buf;
+}
+
+static void omap_udc_release(struct device *dev)
+{
+       complete(udc->done);
+       kfree (udc);
+       udc = 0;
+}
+
+static int __init
+omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+{
+       unsigned        tmp, buf;
+
+       /* abolish any previous hardware state */
+       UDC_SYSCON1_REG = 0;
+       UDC_IRQ_EN_REG = 0;
+       UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK;
+       UDC_DMA_IRQ_EN_REG = 0;
+       UDC_RXDMA_CFG_REG = 0;
+       UDC_TXDMA_CFG_REG = 0;
+
+       /* UDC_PULLUP_EN gates the chip clock */
+       // OTG_SYSCON_1_REG |= DEV_IDLE_EN;
+
+       udc = kmalloc (sizeof *udc, SLAB_KERNEL);
+       if (!udc)
+               return -ENOMEM;
+
+       memset(udc, 0, sizeof *udc);
+       spin_lock_init (&udc->lock);
+
+       udc->gadget.ops = &omap_gadget_ops;
+       udc->gadget.ep0 = &udc->ep[0].ep;
+       INIT_LIST_HEAD(&udc->gadget.ep_list);
+       INIT_LIST_HEAD(&udc->iso);
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       udc->gadget.name = driver_name;
+
+       device_initialize(&udc->gadget.dev);
+       strcpy (udc->gadget.dev.bus_id, "gadget");
+       udc->gadget.dev.release = omap_udc_release;
+       udc->gadget.dev.parent = &odev->dev;
+       if (use_dma)
+               udc->gadget.dev.dma_mask = odev->dev.dma_mask;
+
+       udc->transceiver = xceiv;
+
+       /* ep0 is special; put it right after the SETUP buffer */
+       buf = omap_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL,
+                       8 /* after SETUP */, 64 /* maxpacket */, 0);
+       list_del_init(&udc->ep[0].ep.ep_list);
+
+       /* initially disable all non-ep0 endpoints */
+       for (tmp = 1; tmp < 15; tmp++) {
+               UDC_EP_RX_REG(tmp) = 0;
+               UDC_EP_TX_REG(tmp) = 0;
+       }
+
+#define OMAP_BULK_EP(name,addr) \
+       buf = omap_ep_setup(name "-bulk", addr, \
+                       USB_ENDPOINT_XFER_BULK, buf, 64, 1);
+#define OMAP_INT_EP(name,addr, maxp) \
+       buf = omap_ep_setup(name "-int", addr, \
+                       USB_ENDPOINT_XFER_INT, buf, maxp, 0);
+#define OMAP_ISO_EP(name,addr, maxp) \
+       buf = omap_ep_setup(name "-iso", addr, \
+                       USB_ENDPOINT_XFER_ISOC, buf, maxp, 1);
+
+       switch (fifo_mode) {
+       case 0:
+               OMAP_BULK_EP("ep1in",  USB_DIR_IN  | 1);
+               OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+               OMAP_INT_EP("ep3in",   USB_DIR_IN  | 3, 16);
+               break;
+       case 1:
+               OMAP_BULK_EP("ep1in",  USB_DIR_IN  | 1);
+               OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+               OMAP_BULK_EP("ep3in",  USB_DIR_IN  | 3);
+               OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4);
+
+               OMAP_BULK_EP("ep5in",  USB_DIR_IN  | 5);
+               OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
+               OMAP_BULK_EP("ep6in",  USB_DIR_IN  | 6);
+               OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6);
+
+               OMAP_BULK_EP("ep7in",  USB_DIR_IN  | 7);
+               OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
+               OMAP_BULK_EP("ep8in",  USB_DIR_IN  | 8);
+               OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8);
+
+               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
+       case 2:                 /* mixed iso/bulk */
+               OMAP_ISO_EP("ep1in",   USB_DIR_IN  | 1, 256);
+               OMAP_ISO_EP("ep2out",  USB_DIR_OUT | 2, 256);
+               OMAP_ISO_EP("ep3in",   USB_DIR_IN  | 3, 128);
+               OMAP_ISO_EP("ep4out",  USB_DIR_OUT | 4, 128);
+
+               OMAP_INT_EP("ep5in",   USB_DIR_IN  | 5, 16);
+
+               OMAP_BULK_EP("ep6in",  USB_DIR_IN  | 6);
+               OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
+               OMAP_INT_EP("ep8in",   USB_DIR_IN  | 8, 16);
+               break;
+       case 3:                 /* mixed bulk/iso */
+               OMAP_BULK_EP("ep1in",  USB_DIR_IN  | 1);
+               OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+               OMAP_INT_EP("ep3in",   USB_DIR_IN  | 3, 16);
+
+               OMAP_BULK_EP("ep4in",  USB_DIR_IN  | 4);
+               OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
+               OMAP_INT_EP("ep6in",   USB_DIR_IN  | 6, 16);
+
+               OMAP_ISO_EP("ep7in",   USB_DIR_IN  | 7, 256);
+               OMAP_ISO_EP("ep8out",  USB_DIR_OUT | 8, 256);
+               OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
+               break;
+#endif
+
+       /* add more modes as needed */
+
+       default:
+               ERR("unsupported fifo_mode #%d\n", fifo_mode);
+               return -ENODEV;
+       }
+       UDC_SYSCON1_REG = UDC_CFG_LOCK|UDC_SELF_PWR;
+       INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf);
+       return 0;
+}
+
+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 omap_usb_config  *config = dev->platform_data;
+
+       /* NOTE:  "knows" the order of the resources! */
+       if (!request_mem_region(odev->resource[0].start, 
+                       odev->resource[0].end - odev->resource[0].start + 1,
+                       driver_name)) {
+               DBG("request_mem_region failed\n");
+               return -EBUSY;
+       }
+
+       INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n",
+               UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
+               OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
+               config->otg ? "Mini-AB" : "B/Mini-B");
+
+       /* use the mode given to us by board init code */
+       hmc = HMC;
+       switch (hmc) {
+       case 3:
+       case 11:
+       case 19:
+       case 25:
+               xceiv = otg_get_transceiver();
+               if (!xceiv) {
+                       DBG("external transceiver not registered!\n");
+                       goto cleanup0;
+               }
+               type = xceiv->label;
+               break;
+       case 0:                 /* POWERUP DEFAULT == 0 */
+       case 4:
+       case 12:
+       case 20:
+               type = "INTEGRATED";
+               break;
+       case 21:                        /* internal loopback */
+               type = "(loopback)";
+               break;
+       case 14:                        /* transceiverless */
+               type = "(none)";
+               break;
+
+       default:
+               ERR("unrecognized UDC HMC mode %d\n", hmc);
+               return -ENODEV;
+       }
+       INFO("hmc mode %d, transceiver %s\n", hmc, type);
+
+       /* a "gadget" abstracts/virtualizes the controller */
+       status = omap_udc_setup(odev, xceiv);
+       if (status) {
+               goto cleanup0;
+       }
+       xceiv = 0;
+       // "udc" is now valid
+       pullup_disable(udc);
+       udc->gadget.is_otg = (config->otg != 0);
+
+       /* 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);
+       if (status != 0) {
+               ERR( "can't get irq %ld, err %d\n",
+                       odev->resource[1].start, status);
+               goto cleanup1;
+       }
+
+       /* USB "non-iso" IRQ (PIO for all but ep0) */
+       status = request_irq(odev->resource[2].start, omap_udc_pio_irq,
+                       SA_SAMPLE_RANDOM, "omap_udc pio", udc);
+       if (status != 0) {
+               ERR( "can't get irq %ld, err %d\n",
+                       odev->resource[2].start, status);
+               goto cleanup2;
+       }
+#ifdef USE_ISO
+       status = request_irq(odev->resource[3].start, omap_udc_iso_irq,
+                       SA_INTERRUPT, "omap_udc iso", udc);
+       if (status != 0) {
+               ERR("can't get irq %ld, err %d\n",
+                       odev->resource[3].start, status);
+               goto cleanup3;
+       }
+#endif
+
+       create_proc_file();
+       device_add(&udc->gadget.dev);
+       return 0;
+
+#ifdef USE_ISO
+cleanup3:
+       free_irq(odev->resource[2].start, udc);
+#endif
+
+cleanup2:
+       free_irq(odev->resource[1].start, udc);
+
+cleanup1:
+       kfree (udc);
+       udc = 0;
+
+cleanup0:
+       if (xceiv)
+               put_device(xceiv->dev);
+       release_mem_region(odev->resource[0].start,
+                       odev->resource[0].end - odev->resource[0].start + 1);
+       return status;
+}
+
+static int __exit omap_udc_remove(struct device *dev)
+{
+       struct platform_device  *odev = to_platform_device(dev);
+       DECLARE_COMPLETION(done);
+
+       if (!udc)
+               return -ENODEV;
+
+       udc->done = &done;
+
+       pullup_disable(udc);
+       if (udc->transceiver) {
+               put_device(udc->transceiver->dev);
+               udc->transceiver = 0;
+       }
+       UDC_SYSCON1_REG = 0;
+
+       remove_proc_file();
+
+#ifdef USE_ISO
+       free_irq(odev->resource[3].start, udc);
+#endif
+       free_irq(odev->resource[2].start, udc);
+       free_irq(odev->resource[1].start, udc);
+
+       release_mem_region(odev->resource[0].start,
+                       odev->resource[0].end - odev->resource[0].start + 1);
+
+       device_unregister(&udc->gadget.dev);
+       wait_for_completion(&done);
+
+       return 0;
+}
+
+/* suspend/resume/wakeup from sysfs (echo > power/state) */
+
+static int omap_udc_suspend(struct device *dev, u32 state, u32 level)
+{
+       if (level != 0)
+               return 0;
+
+       DBG("suspend, state %d\n", state);
+       omap_pullup(&udc->gadget, 0);
+       udc->gadget.dev.power.power_state = 3;
+       udc->gadget.dev.parent->power.power_state = 3;
+       return 0;
+}
+
+static int omap_udc_resume(struct device *dev, u32 level)
+{
+       if (level != 0)
+               return 0;
+
+       DBG("resume + wakeup/SRP\n");
+       udc->gadget.dev.parent->power.power_state = 0;
+       udc->gadget.dev.power.power_state = 0;
+       omap_pullup(&udc->gadget, 1);
+
+       /* maybe the host would enumerate us if we nudged it */
+       msleep(100);
+       return omap_wakeup(&udc->gadget);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct device_driver udc_driver = {
+       .name           = (char *) driver_name,
+       .bus            = &platform_bus_type,
+       .probe          = omap_udc_probe,
+       .remove         = __exit_p(omap_udc_remove),
+       .suspend        = omap_udc_suspend,
+       .resume         = omap_udc_resume,
+};
+
+static int __init udc_init(void)
+{
+       /* should work on many OMAP systems with at most minor changes,
+        * but the 1510 doesn't have an OTG controller.
+        */
+       if (cpu_is_omap1510()) {
+               DBG("no OMAP1510 support yet\n");
+               return -ENODEV;
+       }
+       INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc,
+               use_dma ?  " (dma)" : "");
+       return driver_register(&udc_driver);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+       driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
new file mode 100644 (file)
index 0000000..bd5420c
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * omap_udc.h -- for omap 3.2 udc, with OTG support
+ *
+ * 2004 (C) Texas Instruments, Inc.
+ * 2004 (C) David Brownell
+ */
+
+/*
+ * USB device/endpoint management registers
+ */
+#define UDC_REG(offset)              __REG16(UDC_BASE + (offset))
+
+#define        UDC_REV_REG                     UDC_REG(0x0)    /* Revision */
+#define        UDC_EP_NUM_REG                  UDC_REG(0x4)    /* Which endpoint */
+#      define  UDC_SETUP_SEL           (1 << 6)
+#      define  UDC_EP_SEL              (1 << 5)
+#      define  UDC_EP_DIR              (1 << 4)
+       /* low 4 bits for endpoint number */
+#define        UDC_DATA_REG                    UDC_REG(0x08)   /* Endpoint FIFO */
+#define        UDC_CTRL_REG                    UDC_REG(0x0C)   /* Endpoint control */
+#      define  UDC_CLR_HALT            (1 << 7)
+#      define  UDC_SET_HALT            (1 << 6)
+#      define  UDC_SET_FIFO_EN         (1 << 2)
+#      define  UDC_CLR_EP              (1 << 1)
+#      define  UDC_RESET_EP            (1 << 0)
+#define        UDC_STAT_FLG_REG                UDC_REG(0x10)   /* Endpoint status */
+#      define  UDC_NO_RXPACKET         (1 << 15)
+#      define  UDC_MISS_IN             (1 << 14)
+#      define  UDC_DATA_FLUSH          (1 << 13)
+#      define  UDC_ISO_ERR             (1 << 12)
+#      define  UDC_ISO_FIFO_EMPTY      (1 << 9)
+#      define  UDC_ISO_FIFO_FULL       (1 << 8)
+#      define  UDC_EP_HALTED           (1 << 6)
+#      define  UDC_STALL               (1 << 5)
+#      define  UDC_NAK                 (1 << 4)
+#      define  UDC_ACK                 (1 << 3)
+#      define  UDC_FIFO_EN             (1 << 2)
+#      define  UDC_NON_ISO_FIFO_EMPTY  (1 << 1)
+#      define  UDC_NON_ISO_FIFO_FULL   (1 << 0)
+#define        UDC_RXFSTAT_REG                 UDC_REG(0x14)   /* OUT bytecount */
+#define        UDC_SYSCON1_REG                 UDC_REG(0x18)   /* System config 1 */
+#      define  UDC_CFG_LOCK            (1 << 8)
+#      define  UDC_DATA_ENDIAN         (1 << 7)
+#      define  UDC_DMA_ENDIAN          (1 << 6)
+#      define  UDC_NAK_EN              (1 << 4)
+#      define  UDC_AUTODECODE_DIS      (1 << 3)
+#      define  UDC_SELF_PWR            (1 << 2)
+#      define  UDC_SOFF_DIS            (1 << 1)
+#      define  UDC_PULLUP_EN           (1 << 0)
+#define        UDC_SYSCON2_REG                 UDC_REG(0x1C)   /* System config 2 */
+#      define  UDC_RMT_WKP             (1 << 6)
+#      define  UDC_STALL_CMD           (1 << 5)
+#      define  UDC_DEV_CFG             (1 << 3)
+#      define  UDC_CLR_CFG             (1 << 2)
+#define        UDC_DEVSTAT_REG                 UDC_REG(0x20)   /* Device status */
+#      define  UDC_B_HNP_ENABLE        (1 << 9)
+#      define  UDC_A_HNP_SUPPORT       (1 << 8)
+#      define  UDC_A_ALT_HNP_SUPPORT   (1 << 7)
+#      define  UDC_R_WK_OK             (1 << 6)
+#      define  UDC_USB_RESET           (1 << 5)
+#      define  UDC_SUS                 (1 << 4)
+#      define  UDC_CFG                 (1 << 3)
+#      define  UDC_ADD                 (1 << 2)
+#      define  UDC_DEF                 (1 << 1)
+#      define  UDC_ATT                 (1 << 0)
+#define        UDC_SOF_REG                     UDC_REG(0x24)   /* Start of frame */
+#      define  UDC_FT_LOCK             (1 << 12)
+#      define  UDC_TS_OK               (1 << 11)
+#      define  UDC_TS                  0x03ff
+#define        UDC_IRQ_EN_REG                  UDC_REG(0x28)   /* Interrupt enable */
+#      define  UDC_SOF_IE              (1 << 7)
+#      define  UDC_EPN_RX_IE           (1 << 5)
+#      define  UDC_EPN_TX_IE           (1 << 4)
+#      define  UDC_DS_CHG_IE           (1 << 3)
+#      define  UDC_EP0_IE              (1 << 0)
+#define        UDC_DMA_IRQ_EN_REG              UDC_REG(0x2C)   /* DMA irq enable */
+       /* rx/tx dma channels numbered 1-3 not 0-2 */
+#      define  UDC_TX_DONE_IE(n)       (1 << (4 * (n) - 2))
+#      define  UDC_RX_CNT_IE(n)        (1 << (4 * (n) - 3))
+#      define  UDC_RX_EOT_IE(n)        (1 << (4 * (n) - 4))
+#define        UDC_IRQ_SRC_REG                 UDC_REG(0x30)   /* Interrupt source */
+#      define  UDC_TXN_DONE            (1 << 10)
+#      define  UDC_RXN_CNT             (1 << 9)
+#      define  UDC_RXN_EOT             (1 << 8)
+#      define  UDC_SOF                 (1 << 7)
+#      define  UDC_EPN_RX              (1 << 5)
+#      define  UDC_EPN_TX              (1 << 4)
+#      define  UDC_DS_CHG              (1 << 3)
+#      define  UDC_SETUP               (1 << 2)
+#      define  UDC_EP0_RX              (1 << 1)
+#      define  UDC_EP0_TX              (1 << 0)
+#      define  UDC_IRQ_SRC_MASK        0x7bf
+#define        UDC_EPN_STAT_REG                UDC_REG(0x34)   /* EP irq status */
+#define        UDC_DMAN_STAT_REG               UDC_REG(0x38)   /* DMA irq status */
+#      define  UDC_DMA_RX_SB           (1 << 12)
+#      define  UDC_DMA_RX_SRC(x)       (((x)>>8) & 0xf)
+#      define  UDC_DMA_TX_SRC(x)       (((x)>>0) & 0xf)
+
+
+/* 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_TXDMA_CFG_REG               UDC_REG(0x44)   /* 3 eps for TX DMA */
+#define        UDC_DATA_DMA_REG                UDC_REG(0x48)   /* rx/tx fifo addr */
+
+/* rx/tx dma control, numbering channels 1-3 not 0-2 */
+#define        UDC_TXDMA_REG(chan)             UDC_REG(0x50 - 4 + 4 * (chan))
+#      define UDC_TXN_EOT              (1 << 15)       /* bytes vs packets */
+#      define UDC_TXN_START            (1 << 14)       /* start transfer */
+#      define UDC_TXN_TSC              0x03ff          /* units in xfer */
+#define        UDC_RXDMA_REG(chan)             UDC_REG(0x60 - 4 + 4 * (chan))
+#      define UDC_RXN_STOP             (1 << 15)       /* enable EOT irq */
+#      define UDC_RXN_TC               0x00ff          /* packets in xfer */
+
+
+/*
+ * Endpoint configuration registers (used before CFG_LOCK is set)
+ * UDC_EP_TX_REG(0) is unused
+ */
+#define        UDC_EP_RX_REG(endpoint)         UDC_REG(0x80 + (endpoint)*4)
+#      define  UDC_EPN_RX_VALID        (1 << 15)
+#      define  UDC_EPN_RX_DB           (1 << 14)
+       /* buffer size in bits 13, 12 */
+#      define  UDC_EPN_RX_ISO          (1 << 11)
+       /* buffer pointer in low 11 bits */
+#define        UDC_EP_TX_REG(endpoint)         UDC_REG(0xc0 + (endpoint)*4)
+       /* same bitfields as in RX_REG */
+
+/*-------------------------------------------------------------------------*/
+
+struct omap_req {
+       struct usb_request              req;
+       struct list_head                queue;
+       unsigned                        dma_bytes;
+       unsigned                        mapped:1;
+};
+
+struct omap_ep {
+       struct usb_ep                   ep;
+       struct list_head                queue;
+       unsigned long                   irqs;
+       struct list_head                iso;
+       const struct usb_endpoint_descriptor    *desc;
+       char                            name[14];
+       u16                             maxpacket;
+       u8                              bEndpointAddress;
+       u8                              bmAttributes;
+       unsigned                        double_buf:1;
+       unsigned                        stopped:1;
+       unsigned                        ackwait:1;
+       unsigned                        has_dma:1;
+       u8                              dma_channel;
+       int                             lch;
+       struct omap_udc                 *udc;
+};
+
+struct omap_udc {
+       struct usb_gadget               gadget;
+       struct usb_gadget_driver        *driver;
+       spinlock_t                      lock;
+       struct omap_ep                  ep[32];
+       u16                             devstat;
+       struct otg_transceiver          *transceiver;
+       struct list_head                iso;
+       unsigned                        softconnect:1;
+       unsigned                        vbus_active:1;
+       unsigned                        ep0_pending:1;
+       unsigned                        ep0_in:1;
+       unsigned                        ep0_set_config:1;
+       unsigned                        ep0_reset_config:1;
+       unsigned                        ep0_setup:1;
+       unsigned                        hmc:6;
+
+       struct completion               *done;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)          printk(KERN_DEBUG "udc: " stuff)
+#else
+#define DBG(stuff...)          do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG               DBG
+#else
+#    define VDBG(stuff...)     do{}while(0)
+#endif
+
+#define ERR(stuff...)          printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...)         printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...)         printk(KERN_INFO "udc: " stuff)
+
+/*-------------------------------------------------------------------------*/
+
+// #define     HMC_1510        ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
+#define        HMC_1610        (OTG_SYSCON_2_REG & 0x3f)
+#define        HMC              HMC_1610
+
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
new file mode 100644 (file)
index 0000000..770c870
--- /dev/null
@@ -0,0 +1,4574 @@
+/*
+ * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
+ *
+ * Copyright (c) 2002, 2003 Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/arch/svinto.h>
+
+#include <linux/usb.h>
+/* Ugly include because we don't live with the other host drivers. */
+#include <../drivers/usb/core/hcd.h>
+#include <../drivers/usb/core/usb.h>
+
+#include "hc_crisv10.h"
+
+#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
+#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
+#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
+
+static const char *usb_hcd_version = "$Revision: 1.2 $";
+
+#undef KERN_DEBUG
+#define KERN_DEBUG ""
+
+
+#undef USB_DEBUG_RH
+#undef USB_DEBUG_EPID
+#undef USB_DEBUG_SB
+#undef USB_DEBUG_DESC
+#undef USB_DEBUG_URB
+#undef USB_DEBUG_TRACE
+#undef USB_DEBUG_BULK
+#undef USB_DEBUG_CTRL
+#undef USB_DEBUG_INTR
+#undef USB_DEBUG_ISOC
+
+#ifdef USB_DEBUG_RH
+#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
+#else
+#define dbg_rh(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_EPID
+#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)
+#else
+#define dbg_epid(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_SB
+#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)
+#else
+#define dbg_sb(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_CTRL
+#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
+#else
+#define dbg_ctrl(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_BULK
+#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
+#else
+#define dbg_bulk(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_INTR
+#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
+#else
+#define dbg_intr(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_ISOC
+#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)
+#else
+#define dbg_isoc(format, arg...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_TRACE
+#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
+#define DBFEXIT  (printk(": Exiting:  %s\n", __FUNCTION__))
+#else
+#define DBFENTER do {} while (0)
+#define DBFEXIT  do {} while (0)
+#endif
+
+#define usb_pipeslow(pipe)     (((pipe) >> 26) & 1)
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+static __u8 root_hub_dev_des[] =
+{
+       0x12,  /*  __u8  bLength; */
+       0x01,  /*  __u8  bDescriptorType; Device */
+       0x00,  /*  __u16 bcdUSB; v1.0 */
+       0x01,
+       0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,  /*  __u8  bDeviceSubClass; */
+       0x00,  /*  __u8  bDeviceProtocol; */
+       0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */
+       0x00,  /*  __u16 idVendor; */
+       0x00,
+       0x00,  /*  __u16 idProduct; */
+       0x00,
+       0x00,  /*  __u16 bcdDevice; */
+       0x00,
+       0x00,  /*  __u8  iManufacturer; */
+       0x02,  /*  __u8  iProduct; */
+       0x01,  /*  __u8  iSerialNumber; */
+       0x01   /*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+       0x09,  /*  __u8  bLength; */
+       0x02,  /*  __u8  bDescriptorType; Configuration */
+       0x19,  /*  __u16 wTotalLength; */
+       0x00,
+       0x01,  /*  __u8  bNumInterfaces; */
+       0x01,  /*  __u8  bConfigurationValue; */
+       0x00,  /*  __u8  iConfiguration; */
+       0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */
+       0x00,  /*  __u8  MaxPower; */
+
+     /* interface */
+       0x09,  /*  __u8  if_bLength; */
+       0x04,  /*  __u8  if_bDescriptorType; Interface */
+       0x00,  /*  __u8  if_bInterfaceNumber; */
+       0x00,  /*  __u8  if_bAlternateSetting; */
+       0x01,  /*  __u8  if_bNumEndpoints; */
+       0x09,  /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,  /*  __u8  if_bInterfaceSubClass; */
+       0x00,  /*  __u8  if_bInterfaceProtocol; */
+       0x00,  /*  __u8  if_iInterface; */
+
+     /* endpoint */
+       0x07,  /*  __u8  ep_bLength; */
+       0x05,  /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,  /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,  /*  __u8  ep_bmAttributes; Interrupt */
+       0x08,  /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+       0x00,
+       0xff   /*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+       0x09,  /*  __u8  bLength; */
+       0x29,  /*  __u8  bDescriptorType; Hub-descriptor */
+       0x02,  /*  __u8  bNbrPorts; */
+       0x00,  /* __u16  wHubCharacteristics; */
+       0x00,
+       0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */
+       0x00,  /*  __u8  bHubContrCurrent; 0 mA */
+       0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+       0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0);
+
+/* We want the start timer to expire before the eot timer, because the former might start
+   traffic, thus making it unnecessary for the latter to time out. */
+#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */
+#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */
+
+#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break
+#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
+{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
+
+#define SLAB_FLAG     (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
+
+/* Most helpful debugging aid */
+#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
+
+/* Alternative assert define which stops after a failed assert. */
+/*
+#define assert(expr)                                      \
+{                                                         \
+        if (!(expr)) {                                    \
+                err("assert failed at line %d",__LINE__); \
+                while (1);                                \
+        }                                                 \
+}
+*/
+
+
+/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?
+   To adjust it dynamically we would have to get an interrupt when we reach the end
+   of the rx descriptor list, or when we get close to the end, and then allocate more
+   descriptors. */
+
+#define NBR_OF_RX_DESC     512
+#define RX_DESC_BUF_SIZE   1024
+#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
+
+/* The number of epids is, among other things, used for pre-allocating
+   ctrl, bulk and isoc EP descriptors (one for each epid).
+   Assumed to be > 1 when initiating the DMA lists. */
+#define NBR_OF_EPIDS       32
+
+/* Support interrupt traffic intervals up to 128 ms. */
+#define MAX_INTR_INTERVAL 128
+
+/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table
+   must be "invalid". By this we mean that we shouldn't care about epid attentions
+   for this epid, or at least handle them differently from epid attentions for "valid"
+   epids. This define determines which one to use (don't change it). */
+#define INVALID_EPID     31
+/* A special epid for the bulk dummys. */
+#define DUMMY_EPID       30
+
+/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */
+static __u32 epid_usage_bitmask;
+
+/* A bitfield to keep information on in/out traffic is needed to uniquely identify
+   an endpoint on a device, since the most significant bit which indicates traffic
+   direction is lacking in the ep_id field (ETRAX epids can handle both in and
+   out traffic on endpoints that are otherwise identical). The USB framework, however,
+   relies on them to be handled separately.  For example, bulk IN and OUT urbs cannot
+   be queued in the same list, since they would block each other. */
+static __u32 epid_out_traffic;
+
+/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
+   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */
+static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
+static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
+
+/* Pointers into RxDescList. */
+static volatile USB_IN_Desc_t *myNextRxDesc;
+static volatile USB_IN_Desc_t *myLastRxDesc;
+static volatile USB_IN_Desc_t *myPrevRxDesc;
+
+/* EP descriptors must be 32-bit aligned. */
+static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,
+   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
+   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
+   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
+   in each frame. */
+static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
+
+static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
+static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));
+
+static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
+static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
+
+/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting
+   this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0
+   results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point
+   it to this buffer. */
+static int zout_buffer[4] __attribute__ ((aligned (4)));
+
+/* Cache for allocating new EP and SB descriptors. */
+static kmem_cache_t *usb_desc_cache;
+
+/* Cache for the registers allocated in the top half. */
+static kmem_cache_t *top_half_reg_cache;
+
+/* Cache for the data allocated in the isoc descr top half. */
+static kmem_cache_t *isoc_compl_cache;
+
+static struct usb_bus *etrax_usb_bus;
+
+/* This is a circular (double-linked) list of the active urbs for each epid.
+   The head is never removed, and new urbs are linked onto the list as
+   urb_entry_t elements. Don't reference urb_list directly; use the wrapper
+   functions instead. Note that working with these lists might require spinlock
+   protection. */
+static struct list_head urb_list[NBR_OF_EPIDS];
+
+/* Read about the need and usage of this lock in submit_ctrl_urb. */
+static spinlock_t urb_list_lock;
+
+/* Used when unlinking asynchronously. */
+static struct list_head urb_unlink_list;
+
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+       int retval;
+
+       for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+               *utf++ = *ascii++ & 0x7f;
+               *utf++ = 0;
+       }
+       return retval;
+}
+
+static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+       char buf [30];
+
+       // assert (len > (2 * (sizeof (buf) + 1)));
+       // assert (strlen (type) <= 8);
+
+       // language ids
+       if (id == 0) {
+               *data++ = 4; *data++ = 3;       /* 4 bytes data */
+               *data++ = 0; *data++ = 0;       /* some language id */
+               return 4;
+
+       // serial number
+       } else if (id == 1) {
+               sprintf (buf, "%x", serial);
+
+       // product description
+       } else if (id == 2) {
+               sprintf (buf, "USB %s Root Hub", type);
+
+       // id 3 == vendor description
+
+       // unsupported IDs --> "stall"
+       } else
+           return 0;
+
+       data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+       data [1] = 3;
+       return data [0];
+}
+
+/* Wrappers around the list functions (include/linux/list.h). */
+
+static inline int urb_list_empty(int epid)
+{
+       return list_empty(&urb_list[epid]);
+}
+
+/* Returns first urb for this epid, or NULL if list is empty. */
+static inline struct urb *urb_list_first(int epid)
+{
+       struct urb *first_urb = 0;
+
+       if (!urb_list_empty(epid)) {
+               /* Get the first urb (i.e. head->next). */
+               urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
+               first_urb = urb_entry->urb;
+       }
+       return first_urb;
+}
+
+/* Adds an urb_entry last in the list for this epid. */
+static inline void urb_list_add(struct urb *urb, int epid)
+{
+       urb_entry_t *urb_entry = (urb_entry_t *)kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
+       assert(urb_entry);
+
+       urb_entry->urb = urb;
+       list_add_tail(&urb_entry->list, &urb_list[epid]);
+}
+
+/* Search through the list for an element that contains this urb. (The list
+   is expected to be short and the one we are about to delete will often be
+   the first in the list.) */
+static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid)
+{
+       struct list_head *entry;
+       struct list_head *tmp;
+       urb_entry_t *urb_entry;
+
+       list_for_each_safe(entry, tmp, &urb_list[epid]) {
+               urb_entry = list_entry(entry, urb_entry_t, list);
+               assert(urb_entry);
+               assert(urb_entry->urb);
+
+               if (urb_entry->urb == urb) {
+                       return urb_entry;
+               }
+       }
+       return 0;
+}
+
+/* Delete an urb from the list. */
+static inline void urb_list_del(struct urb *urb, int epid)
+{
+       urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+       assert(urb_entry);
+
+       /* Delete entry and free. */
+       list_del(&urb_entry->list);
+       kfree(urb_entry);
+}
+
+/* Move an urb to the end of the list. */
+static inline void urb_list_move_last(struct urb *urb, int epid)
+{
+       urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+       assert(urb_entry);
+
+       list_del(&urb_entry->list);
+       list_add_tail(&urb_entry->list, &urb_list[epid]);
+}
+
+/* Get the next urb in the list. */
+static inline struct urb *urb_list_next(struct urb *urb, int epid)
+{
+       urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
+
+       assert(urb_entry);
+
+       if (urb_entry->list.next != &urb_list[epid]) {
+               struct list_head *elem = urb_entry->list.next;
+               urb_entry = list_entry(elem, urb_entry_t, list);
+               return urb_entry->urb;
+       } else {
+               return NULL;
+       }
+}
+
+
+
+/* For debug purposes only. */
+static inline void urb_list_dump(int epid)
+{
+       struct list_head *entry;
+       struct list_head *tmp;
+       urb_entry_t *urb_entry;
+       int i = 0;
+
+       info("Dumping urb list for epid %d", epid);
+
+       list_for_each_safe(entry, tmp, &urb_list[epid]) {
+               urb_entry = list_entry(entry, urb_entry_t, list);
+               info("   entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb);
+       }
+}
+
+static void init_rx_buffers(void);
+static int etrax_rh_unlink_urb(struct urb *urb);
+static void etrax_rh_send_irq(struct urb *urb);
+static void etrax_rh_init_int_timer(struct urb *urb);
+static void etrax_rh_int_timer_do(unsigned long ptr);
+
+static int etrax_usb_setup_epid(struct urb *urb);
+static int etrax_usb_lookup_epid(struct urb *urb);
+static int etrax_usb_allocate_epid(void);
+static void etrax_usb_free_epid(int epid);
+
+static int etrax_remove_from_sb_list(struct urb *urb);
+
+static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma);
+static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);
+
+static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid);
+static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid);
+
+static int etrax_usb_submit_bulk_urb(struct urb *urb);
+static int etrax_usb_submit_ctrl_urb(struct urb *urb);
+static int etrax_usb_submit_intr_urb(struct urb *urb);
+static int etrax_usb_submit_isoc_urb(struct urb *urb);
+
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags);
+static int etrax_usb_unlink_urb(struct urb *urb, int status);
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
+static int etrax_usb_allocate_dev(struct usb_device *usb_dev);
+static int etrax_usb_deallocate_dev(struct usb_device *usb_dev);
+
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
+static void etrax_usb_hc_interrupt_bottom_half(void *data);
+
+static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
+
+
+/* The following is a list of interrupt handlers for the host controller interrupts we use.
+   They are called from etrax_usb_hc_interrupt_bottom_half. */
+static void etrax_usb_hc_isoc_eof_interrupt(void);
+static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);
+static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);
+static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);
+static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);
+
+static int etrax_rh_submit_urb (struct urb *urb);
+
+/* Forward declaration needed because they are used in the rx interrupt routine. */
+static void etrax_usb_complete_urb(struct urb *urb, int status);
+static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);
+static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);
+static void etrax_usb_complete_intr_urb(struct urb *urb, int status);
+static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);
+
+static int etrax_usb_hc_init(void);
+static void etrax_usb_hc_cleanup(void);
+
+static struct usb_operations etrax_usb_device_operations =
+{
+       .allocate = etrax_usb_allocate_dev,
+       .deallocate = etrax_usb_deallocate_dev,
+       .get_frame_number = etrax_usb_get_frame_number,
+       .submit_urb = etrax_usb_submit_urb,
+       .unlink_urb = etrax_usb_unlink_urb,
+        .buffer_alloc = etrax_usb_buffer_alloc,
+        .buffer_free = etrax_usb_buffer_free
+};
+
+/* Note that these functions are always available in their "__" variants, for use in
+   error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/
+   USB_DEBUG_URB macros. */
+static void __dump_urb(struct urb* purb)
+{
+       printk("\nurb                  :0x%08lx\n", (unsigned long)purb);
+       printk("dev                   :0x%08lx\n", (unsigned long)purb->dev);
+       printk("pipe                  :0x%08x\n", purb->pipe);
+       printk("status                :%d\n", purb->status);
+       printk("transfer_flags        :0x%08x\n", purb->transfer_flags);
+       printk("transfer_buffer       :0x%08lx\n", (unsigned long)purb->transfer_buffer);
+       printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
+       printk("actual_length         :%d\n", purb->actual_length);
+       printk("setup_packet          :0x%08lx\n", (unsigned long)purb->setup_packet);
+       printk("start_frame           :%d\n", purb->start_frame);
+       printk("number_of_packets     :%d\n", purb->number_of_packets);
+       printk("interval              :%d\n", purb->interval);
+       printk("error_count           :%d\n", purb->error_count);
+       printk("context               :0x%08lx\n", (unsigned long)purb->context);
+       printk("complete              :0x%08lx\n\n", (unsigned long)purb->complete);
+}
+
+static void __dump_in_desc(volatile USB_IN_Desc_t *in)
+{
+       printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
+       printk("  sw_len  : 0x%04x (%d)\n", in->sw_len, in->sw_len);
+       printk("  command : 0x%04x\n", in->command);
+       printk("  next    : 0x%08lx\n", in->next);
+       printk("  buf     : 0x%08lx\n", in->buf);
+       printk("  hw_len  : 0x%04x (%d)\n", in->hw_len, in->hw_len);
+       printk("  status  : 0x%04x\n\n", in->status);
+}
+
+static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
+{
+       char tt = (sb->command & 0x30) >> 4;
+       char *tt_string;
+
+       switch (tt) {
+       case 0:
+               tt_string = "zout";
+               break;
+       case 1:
+               tt_string = "in";
+               break;
+       case 2:
+               tt_string = "out";
+               break;
+       case 3:
+               tt_string = "setup";
+               break;
+       default:
+               tt_string = "unknown (weird)";
+       }
+
+       printk("\n   USB_SB_Desc at 0x%08lx\n", (unsigned long)sb);
+       printk("     command : 0x%04x\n", sb->command);
+       printk("        rem     : %d\n", (sb->command & 0x3f00) >> 8);
+       printk("        full    : %d\n", (sb->command & 0x40) >> 6);
+       printk("        tt      : %d (%s)\n", tt, tt_string);
+       printk("        intr    : %d\n", (sb->command & 0x8) >> 3);
+       printk("        eot     : %d\n", (sb->command & 0x2) >> 1);
+       printk("        eol     : %d\n", sb->command & 0x1);
+       printk("     sw_len  : 0x%04x (%d)\n", sb->sw_len, sb->sw_len);
+       printk("     next    : 0x%08lx\n", sb->next);
+       printk("     buf     : 0x%08lx\n\n", sb->buf);
+}
+
+
+static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
+{
+       printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep);
+       printk("  command : 0x%04x\n", ep->command);
+       printk("     ep_id   : %d\n", (ep->command & 0x1f00) >> 8);
+       printk("     enable  : %d\n", (ep->command & 0x10) >> 4);
+       printk("     intr    : %d\n", (ep->command & 0x8) >> 3);
+       printk("     eof     : %d\n", (ep->command & 0x2) >> 1);
+       printk("     eol     : %d\n", ep->command & 0x1);
+       printk("  hw_len  : 0x%04x (%d)\n", ep->hw_len, ep->hw_len);
+       printk("  next    : 0x%08lx\n", ep->next);
+       printk("  sub     : 0x%08lx\n\n", ep->sub);
+}
+
+static inline void __dump_ep_list(int pipe_type)
+{
+       volatile USB_EP_Desc_t *ep;
+       volatile USB_EP_Desc_t *first_ep;
+       volatile USB_SB_Desc_t *sb;
+
+       switch (pipe_type)
+       {
+       case PIPE_BULK:
+               first_ep = &TxBulkEPList[0];
+               break;
+       case PIPE_CONTROL:
+               first_ep = &TxCtrlEPList[0];
+               break;
+       case PIPE_INTERRUPT:
+               first_ep = &TxIntrEPList[0];
+               break;
+       case PIPE_ISOCHRONOUS:
+               first_ep = &TxIsocEPList[0];
+               break;
+       default:
+               warn("Cannot dump unknown traffic type");
+               return;
+       }
+       ep = first_ep;
+
+       printk("\n\nDumping EP list...\n\n");
+
+       do {
+               __dump_ep_desc(ep);
+               /* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
+               sb = ep->sub ? phys_to_virt(ep->sub) : 0;
+               while (sb) {
+                       __dump_sb_desc(sb);
+                       sb = sb->next ? phys_to_virt(sb->next) : 0;
+               }
+               ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next));
+
+       } while (ep != first_ep);
+}
+
+static inline void __dump_ept_data(int epid)
+{
+       unsigned long flags;
+       __u32 r_usb_ept_data;
+
+       if (epid < 0 || epid > 31) {
+               printk("Cannot dump ept data for invalid epid %d\n", epid);
+               return;
+       }
+
+       save_flags(flags);
+       cli();
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+       r_usb_ept_data = *R_USB_EPT_DATA;
+       restore_flags(flags);
+
+       printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
+       if (r_usb_ept_data == 0) {
+               /* No need for more detailed printing. */
+               return;
+       }
+       printk("  valid           : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
+       printk("  hold            : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
+       printk("  error_count_in  : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
+       printk("  t_in            : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
+       printk("  low_speed       : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
+       printk("  port            : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
+       printk("  error_code      : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
+       printk("  t_out           : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
+       printk("  error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
+       printk("  max_len         : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
+       printk("  ep              : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
+       printk("  dev             : %d\n", (r_usb_ept_data & 0x0000003f));
+}
+
+static inline void __dump_ept_data_list(void)
+{
+       int i;
+
+       printk("Dumping the whole R_USB_EPT_DATA list\n");
+
+       for (i = 0; i < 32; i++) {
+               __dump_ept_data(i);
+       }
+}
+#ifdef USB_DEBUG_DESC
+#define dump_in_desc(...) __dump_in_desc(...)
+#define dump_sb_desc(...) __dump_sb_desc(...)
+#define dump_ep_desc(...) __dump_ep_desc(...)
+#else
+#define dump_in_desc(...) do {} while (0)
+#define dump_sb_desc(...) do {} while (0)
+#define dump_ep_desc(...) do {} while (0)
+#endif
+
+#ifdef USB_DEBUG_URB
+#define dump_urb(x)     __dump_urb(x)
+#else
+#define dump_urb(x)     do {} while (0)
+#endif
+
+static void init_rx_buffers(void)
+{
+       int i;
+
+       DBFENTER;
+
+       for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+               RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+               RxDescList[i].command = 0;
+               RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
+               RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+               RxDescList[i].hw_len = 0;
+               RxDescList[i].status = 0;
+
+               /* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc
+                  for the relevant fields.) */
+               prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
+
+       }
+
+       RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+       RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
+       RxDescList[i].next = virt_to_phys(&RxDescList[0]);
+       RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
+       RxDescList[i].hw_len = 0;
+       RxDescList[i].status = 0;
+
+       myNextRxDesc = &RxDescList[0];
+       myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+       myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+
+       *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
+       *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
+
+       DBFEXIT;
+}
+
+static void init_tx_bulk_ep(void)
+{
+       int i;
+
+       DBFENTER;
+
+       for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+               CHECK_ALIGN(&TxBulkEPList[i]);
+               TxBulkEPList[i].hw_len = 0;
+               TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+               TxBulkEPList[i].sub = 0;
+               TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]);
+
+               /* Initiate two EPs, disabled and with the eol flag set. No need for any
+                  preserved epid. */
+
+               /* The first one has the intr flag set so we get an interrupt when the DMA
+                  channel is about to become disabled. */
+               CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
+               TxBulkDummyEPList[i][0].hw_len = 0;
+               TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
+                                                  IO_STATE(USB_EP_command, eol, yes) |
+                                                  IO_STATE(USB_EP_command, intr, yes));
+               TxBulkDummyEPList[i][0].sub = 0;
+               TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
+
+               /* The second one. */
+               CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
+               TxBulkDummyEPList[i][1].hw_len = 0;
+               TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
+                                                  IO_STATE(USB_EP_command, eol, yes));
+               TxBulkDummyEPList[i][1].sub = 0;
+               /* The last dummy's next pointer is the same as the current EP's next pointer. */
+               TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
+       }
+
+       /* Configure the last one. */
+       CHECK_ALIGN(&TxBulkEPList[i]);
+       TxBulkEPList[i].hw_len = 0;
+       TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
+                                  IO_FIELD(USB_EP_command, epid, i));
+       TxBulkEPList[i].sub = 0;
+       TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]);
+
+       /* No need configuring dummy EPs for the last one as it will never be used for
+          bulk traffic (i == INVALD_EPID at this point). */
+
+       /* Set up to start on the last EP so we will enable it when inserting traffic
+          for the first time (imitating the situation where the DMA has stopped
+          because there was no more traffic). */
+       *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
+       /* No point in starting the bulk channel yet.
+        *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
+       DBFEXIT;
+}
+
+static void init_tx_ctrl_ep(void)
+{
+       int i;
+
+       DBFENTER;
+
+       for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+               CHECK_ALIGN(&TxCtrlEPList[i]);
+               TxCtrlEPList[i].hw_len = 0;
+               TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+               TxCtrlEPList[i].sub = 0;
+               TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]);
+       }
+
+       CHECK_ALIGN(&TxCtrlEPList[i]);
+       TxCtrlEPList[i].hw_len = 0;
+       TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
+                                  IO_FIELD(USB_EP_command, epid, i));
+
+       TxCtrlEPList[i].sub = 0;
+       TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
+
+       *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
+       *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+
+       DBFEXIT;
+}
+
+
+static void init_tx_intr_ep(void)
+{
+       int i;
+
+       DBFENTER;
+
+       /* Read comment at zout_buffer declaration for an explanation to this. */
+       TxIntrSB_zout.sw_len = 1;
+       TxIntrSB_zout.next = 0;
+       TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
+       TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                IO_STATE(USB_SB_command, tt, zout) |
+                                IO_STATE(USB_SB_command, full, yes) |
+                                IO_STATE(USB_SB_command, eot, yes) |
+                                IO_STATE(USB_SB_command, eol, yes));
+
+       for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
+               CHECK_ALIGN(&TxIntrEPList[i]);
+               TxIntrEPList[i].hw_len = 0;
+               TxIntrEPList[i].command =
+                       (IO_STATE(USB_EP_command, eof, yes) |
+                        IO_STATE(USB_EP_command, enable, yes) |
+                        IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+               TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+               TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
+       }
+
+       CHECK_ALIGN(&TxIntrEPList[i]);
+       TxIntrEPList[i].hw_len = 0;
+       TxIntrEPList[i].command =
+               (IO_STATE(USB_EP_command, eof, yes) |
+                IO_STATE(USB_EP_command, eol, yes) |
+                IO_STATE(USB_EP_command, enable, yes) |
+                IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+       TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
+       TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
+
+       *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
+       *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+       DBFEXIT;
+}
+
+static void init_tx_isoc_ep(void)
+{
+       int i;
+
+       DBFENTER;
+
+       /* Read comment at zout_buffer declaration for an explanation to this. */
+       TxIsocSB_zout.sw_len = 1;
+       TxIsocSB_zout.next = 0;
+       TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
+       TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                IO_STATE(USB_SB_command, tt, zout) |
+                                IO_STATE(USB_SB_command, full, yes) |
+                                IO_STATE(USB_SB_command, eot, yes) |
+                                IO_STATE(USB_SB_command, eol, yes));
+
+       /* The last isochronous EP descriptor is a dummy. */
+
+       for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
+               CHECK_ALIGN(&TxIsocEPList[i]);
+               TxIsocEPList[i].hw_len = 0;
+               TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
+               TxIsocEPList[i].sub = 0;
+               TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
+       }
+
+       CHECK_ALIGN(&TxIsocEPList[i]);
+       TxIsocEPList[i].hw_len = 0;
+
+       /* Must enable the last EP descr to get eof interrupt. */
+       TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
+                                  IO_STATE(USB_EP_command, eof, yes) |
+                                  IO_STATE(USB_EP_command, eol, yes) |
+                                  IO_FIELD(USB_EP_command, epid, INVALID_EPID));
+       TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
+       TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
+
+       *R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
+       *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
+
+       DBFEXIT;
+}
+
+static void etrax_usb_unlink_intr_urb(struct urb *urb)
+{
+       volatile USB_EP_Desc_t *first_ep;  /* First EP in the list. */
+       volatile USB_EP_Desc_t *curr_ep;   /* Current EP, the iterator. */
+       volatile USB_EP_Desc_t *next_ep;   /* The EP after current. */
+       volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */
+
+       int epid;
+
+       /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */
+
+       DBFENTER;
+
+       epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;
+
+       first_ep = &TxIntrEPList[0];
+       curr_ep = first_ep;
+
+
+       /* Note that this loop removes all EP descriptors with this epid. This assumes
+          that all EP descriptors belong to the one and only urb for this epid. */
+
+       do {
+               next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);
+
+               if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
+
+                       dbg_intr("Found EP to unlink for epid %d", epid);
+
+                       /* This is the one we should unlink. */
+                       unlink_ep = next_ep;
+
+                       /* Actually unlink the EP from the DMA list. */
+                       curr_ep->next = unlink_ep->next;
+
+                       /* Wait until the DMA is no longer at this descriptor. */
+                       while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));
+
+                       /* Now we are free to remove it and its SB descriptor.
+                          Note that it is assumed here that there is only one sb in the
+                          sb list for this ep. */
+                       kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));
+                       kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);
+               }
+
+               curr_ep = phys_to_virt(curr_ep->next);
+
+       } while (curr_ep != first_ep);
+        urb->hcpriv = NULL;
+}
+
+void etrax_usb_do_intr_recover(int epid)
+{
+       USB_EP_Desc_t *first_ep, *tmp_ep;
+
+       DBFENTER;
+
+       first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
+       tmp_ep = first_ep;
+
+       /* What this does is simply to walk the list of interrupt
+          ep descriptors and enable those that are disabled. */
+
+       do {
+               if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
+                   !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
+                       tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
+               }
+
+               tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
+
+       } while (tmp_ep != first_ep);
+
+
+       DBFEXIT;
+}
+
+static int etrax_rh_unlink_urb (struct urb *urb)
+{
+       etrax_hc_t *hc;
+
+       DBFENTER;
+
+       hc = urb->dev->bus->hcpriv;
+
+       if (hc->rh.urb == urb) {
+               hc->rh.send = 0;
+               del_timer(&hc->rh.rh_int_timer);
+       }
+
+       DBFEXIT;
+       return 0;
+}
+
+static void etrax_rh_send_irq(struct urb *urb)
+{
+       __u16 data = 0;
+       etrax_hc_t *hc = urb->dev->bus->hcpriv;
+       DBFENTER;
+
+/*
+  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);
+  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
+*/
+
+       data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
+       data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
+
+       *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
+       /* FIXME: Why is actual_length set to 1 when data is 2 bytes?
+          Since only 1 byte is used, why not declare data as __u8? */
+       urb->actual_length = 1;
+       urb->status = 0;
+
+       if (hc->rh.send && urb->complete) {
+               dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);
+               dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
+
+               urb->complete(urb, NULL);
+       }
+
+       DBFEXIT;
+}
+
+static void etrax_rh_init_int_timer(struct urb *urb)
+{
+       etrax_hc_t *hc;
+
+       DBFENTER;
+
+       hc = urb->dev->bus->hcpriv;
+       hc->rh.interval = urb->interval;
+       init_timer(&hc->rh.rh_int_timer);
+       hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
+       hc->rh.rh_int_timer.data = (unsigned long)urb;
+       /* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped
+          to 0, and the rest to the nearest lower 10 ms. */
+       hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
+       add_timer(&hc->rh.rh_int_timer);
+
+       DBFEXIT;
+}
+
+static void etrax_rh_int_timer_do(unsigned long ptr)
+{
+       struct urb *urb;
+       etrax_hc_t *hc;
+
+       DBFENTER;
+
+       urb = (struct urb*)ptr;
+       hc = urb->dev->bus->hcpriv;
+
+       if (hc->rh.send) {
+               etrax_rh_send_irq(urb);
+       }
+
+       DBFEXIT;
+}
+
+static int etrax_usb_setup_epid(struct urb *urb)
+{
+       int epid;
+       char devnum, endpoint, out_traffic, slow;
+       int maxlen;
+       unsigned long flags;
+
+       DBFENTER;
+
+       epid = etrax_usb_lookup_epid(urb);
+       if ((epid != -1)){
+               /* An epid that fits this urb has been found. */
+               DBFEXIT;
+               return epid;
+       }
+
+       /* We must find and initiate a new epid for this urb. */
+       epid = etrax_usb_allocate_epid();
+
+       if (epid == -1) {
+               /* Failed to allocate a new epid. */
+               DBFEXIT;
+               return epid;
+       }
+
+       /* We now have a new epid to use. Initiate it. */
+       set_bit(epid, (void *)&epid_usage_bitmask);
+
+       devnum = usb_pipedevice(urb->pipe);
+       endpoint = usb_pipeendpoint(urb->pipe);
+       slow = usb_pipeslow(urb->pipe);
+       maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+               /* We want both IN and OUT control traffic to be put on the same EP/SB list. */
+               out_traffic = 1;
+       } else {
+               out_traffic = usb_pipeout(urb->pipe);
+       }
+
+       save_flags(flags);
+       cli();
+
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               *R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
+                       /* FIXME: Change any to the actual port? */
+                       IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
+                       IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
+                       IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
+                       IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
+       } else {
+               *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
+                       IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
+                       /* FIXME: Change any to the actual port? */
+                       IO_STATE(R_USB_EPT_DATA, port, any) |
+                       IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
+                       IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
+                       IO_FIELD(R_USB_EPT_DATA, dev, devnum);
+       }
+
+       restore_flags(flags);
+
+       if (out_traffic) {
+               set_bit(epid, (void *)&epid_out_traffic);
+       } else {
+               clear_bit(epid, (void *)&epid_out_traffic);
+       }
+
+       dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",
+                epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");
+
+       DBFEXIT;
+       return epid;
+}
+
+static void etrax_usb_free_epid(int epid)
+{
+       unsigned long flags;
+
+       DBFENTER;
+
+       if (!test_bit(epid, (void *)&epid_usage_bitmask)) {
+               warn("Trying to free unused epid %d", epid);
+               DBFEXIT;
+               return;
+       }
+
+       save_flags(flags);
+       cli();
+
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+       while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));
+       /* This will, among other things, set the valid field to 0. */
+       *R_USB_EPT_DATA = 0;
+       restore_flags(flags);
+
+       clear_bit(epid, (void *)&epid_usage_bitmask);
+
+
+       dbg_epid("Freed epid %d", epid);
+
+       DBFEXIT;
+}
+
+static int etrax_usb_lookup_epid(struct urb *urb)
+{
+       int i;
+       __u32 data;
+       char devnum, endpoint, slow, out_traffic;
+       int maxlen;
+       unsigned long flags;
+
+       DBFENTER;
+
+       devnum = usb_pipedevice(urb->pipe);
+       endpoint = usb_pipeendpoint(urb->pipe);
+       slow = usb_pipeslow(urb->pipe);
+       maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+               /* We want both IN and OUT control traffic to be put on the same EP/SB list. */
+               out_traffic = 1;
+       } else {
+               out_traffic = usb_pipeout(urb->pipe);
+       }
+
+       /* Step through att epids. */
+       for (i = 0; i < NBR_OF_EPIDS; i++) {
+               if (test_bit(i, (void *)&epid_usage_bitmask) &&
+                   test_bit(i, (void *)&epid_out_traffic) == out_traffic) {
+
+                       save_flags(flags);
+                       cli();
+                       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
+                       nop();
+
+                       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                               data = *R_USB_EPT_DATA_ISO;
+                               restore_flags(flags);
+
+                               if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {
+                                       dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
+                                                i, devnum, endpoint, out_traffic ? "OUT" : "IN");
+                                       DBFEXIT;
+                                       return i;
+                               }
+                       } else {
+                               data = *R_USB_EPT_DATA;
+                               restore_flags(flags);
+
+                               if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {
+                                       dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
+                                                i, devnum, endpoint, out_traffic ? "OUT" : "IN");
+                                       DBFEXIT;
+                                       return i;
+                               }
+                       }
+               }
+       }
+
+       DBFEXIT;
+       return -1;
+}
+
+static int etrax_usb_allocate_epid(void)
+{
+       int i;
+
+       DBFENTER;
+
+       for (i = 0; i < NBR_OF_EPIDS; i++) {
+               if (!test_bit(i, (void *)&epid_usage_bitmask)) {
+                       dbg_epid("Found free epid %d", i);
+                       DBFEXIT;
+                       return i;
+               }
+       }
+
+       dbg_epid("Found no free epids");
+       DBFEXIT;
+       return -1;
+}
+
+static int etrax_usb_submit_urb(struct urb *urb, int mem_flags)
+{
+       etrax_hc_t *hc;
+       int ret = -EINVAL;
+
+       DBFENTER;
+
+       if (!urb->dev || !urb->dev->bus) {
+               return -ENODEV;
+       }
+       if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
+               info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe);
+               return -EMSGSIZE;
+       }
+
+       if (urb->timeout) {
+               /* FIXME. */
+               warn("urb->timeout specified, ignoring.");
+       }
+
+       hc = (etrax_hc_t*)urb->dev->bus->hcpriv;
+
+       if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+               /* This request is for the Virtual Root Hub. */
+               ret = etrax_rh_submit_urb(urb);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+               ret = etrax_usb_submit_bulk_urb(urb);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+               ret = etrax_usb_submit_ctrl_urb(urb);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+               int bustime;
+
+               if (urb->bandwidth == 0) {
+                       bustime = usb_check_bandwidth(urb->dev, urb);
+                       if (bustime < 0) {
+                               ret = bustime;
+                       } else {
+                               ret = etrax_usb_submit_intr_urb(urb);
+                               if (ret == 0)
+                                       usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+                       }
+               } else {
+                       /* Bandwidth already set. */
+                       ret = etrax_usb_submit_intr_urb(urb);
+               }
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               int bustime;
+
+               if (urb->bandwidth == 0) {
+                       bustime = usb_check_bandwidth(urb->dev, urb);
+                       if (bustime < 0) {
+                               ret = bustime;
+                       } else {
+                               ret = etrax_usb_submit_isoc_urb(urb);
+                               if (ret == 0)
+                                       usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+                       }
+               } else {
+                       /* Bandwidth already set. */
+                       ret = etrax_usb_submit_isoc_urb(urb);
+               }
+       }
+
+       DBFEXIT;
+
+        if (ret != 0)
+          printk("Submit URB error %d\n", ret);
+
+       return ret;
+}
+
+static int etrax_usb_unlink_urb(struct urb *urb, int status)
+{
+       etrax_hc_t *hc;
+       etrax_urb_priv_t *urb_priv;
+       int epid;
+       unsigned int flags;
+
+       DBFENTER;
+
+       if (!urb) {
+               return -EINVAL;
+       }
+
+       /* Disable interrupts here since a descriptor interrupt for the isoc epid
+          will modify the sb list.  This could possibly be done more granular, but
+          unlink_urb should not be used frequently anyway.
+       */
+
+       save_flags(flags);
+       cli();
+
+       if (!urb->dev || !urb->dev->bus) {
+               restore_flags(flags);
+               return -ENODEV;
+       }
+       if (!urb->hcpriv) {
+               /* This happens if a device driver calls unlink on an urb that
+                  was never submitted (lazy driver) or if the urb was completed
+                  while unlink was being called. */
+               restore_flags(flags);
+               return 0;
+       }
+       if (urb->transfer_flags & URB_ASYNC_UNLINK) {
+               /* FIXME. */
+               /* If URB_ASYNC_UNLINK is set:
+                  unlink
+                  move to a separate urb list
+                  call complete at next sof with ECONNRESET
+
+                  If not:
+                  wait 1 ms
+                  unlink
+                  call complete with ENOENT
+               */
+               warn("URB_ASYNC_UNLINK set, ignoring.");
+       }
+
+       /* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking,
+          but that doesn't work for interrupt and isochronous traffic since they are completed
+          repeatedly, and urb->status is set then. That may in itself be a bug though. */
+
+       hc = urb->dev->bus->hcpriv;
+       urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       epid = urb_priv->epid;
+
+       /* Set the urb status (synchronous unlink). */
+       urb->status = -ENOENT;
+       urb_priv->urb_state = UNLINK;
+
+       if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
+               int ret;
+               ret = etrax_rh_unlink_urb(urb);
+               DBFEXIT;
+               restore_flags(flags);
+               return ret;
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+               dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb);
+
+               if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+                       /* The EP was enabled, disable it and wait. */
+                       TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+                       /* Ah, the luxury of busy-wait. */
+                       while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));
+               }
+               /* Kicking dummy list out of the party. */
+               TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+               dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb);
+
+               if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+                       /* The EP was enabled, disable it and wait. */
+                       TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+                       /* Ah, the luxury of busy-wait. */
+                       while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));
+               }
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+
+               dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb);
+
+               /* Separate function because it's a tad more complicated. */
+               etrax_usb_unlink_intr_urb(urb);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+               dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb);
+
+               if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+                       /* The EP was enabled, disable it and wait. */
+                       TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+                       /* Ah, the luxury of busy-wait. */
+                       while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
+               }
+       }
+
+       /* Note that we need to remove the urb from the urb list *before* removing its SB
+          descriptors. (This means that the isoc eof handler might get a null urb when we
+          are unlinking the last urb.) */
+
+       if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+
+               urb_list_del(urb, epid);
+               TxBulkEPList[epid].sub = 0;
+               etrax_remove_from_sb_list(urb);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+
+               urb_list_del(urb, epid);
+               TxCtrlEPList[epid].sub = 0;
+               etrax_remove_from_sb_list(urb);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+
+               urb_list_del(urb, epid);
+               /* Sanity check (should never happen). */
+               assert(urb_list_empty(epid));
+
+               /* Release allocated bandwidth. */
+               usb_release_bandwidth(urb->dev, urb, 0);
+
+       } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+               if (usb_pipeout(urb->pipe)) {
+
+                       USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb;
+
+                       if (__urb_list_entry(urb, epid)) {
+
+                               urb_list_del(urb, epid);
+                               iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
+                               prev_sb = 0;
+                               while (iter_sb && (iter_sb != urb_priv->first_sb)) {
+                                       prev_sb = iter_sb;
+                                       iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+                               }
+
+                               if (iter_sb == 0) {
+                                       /* Unlink of the URB currently being transmitted. */
+                                       prev_sb = 0;
+                                       iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
+                               }
+
+                               while (iter_sb && (iter_sb != urb_priv->last_sb)) {
+                                       iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+                               }
+                               if (iter_sb) {
+                                       next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
+                               } else {
+                                       /* This should only happen if the DMA has completed
+                                          processing the SB list for this EP while interrupts
+                                          are disabled. */
+                                       dbg_isoc("Isoc urb not found, already sent?");
+                                       next_sb = 0;
+                               }
+                               if (prev_sb) {
+                                       prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
+                               } else {
+                                       TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
+                               }
+
+                               etrax_remove_from_sb_list(urb);
+                               if (urb_list_empty(epid)) {
+                                       TxIsocEPList[epid].sub = 0;
+                                       dbg_isoc("Last isoc out urb epid %d", epid);
+                               } else if (next_sb || prev_sb) {
+                                       dbg_isoc("Re-enable isoc out epid %d", epid);
+
+                                       TxIsocEPList[epid].hw_len = 0;
+                                       TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+                               } else {
+                                       TxIsocEPList[epid].sub = 0;
+                                       dbg_isoc("URB list non-empty and no SB list, EP disabled");
+                               }
+                       } else {
+                               dbg_isoc("Urb 0x%p not found, completed already?", urb);
+                       }
+               } else {
+
+                       urb_list_del(urb, epid);
+
+                       /* For in traffic there is only one SB descriptor for each EP even
+                          though there may be several urbs (all urbs point at the same SB). */
+                       if (urb_list_empty(epid)) {
+                               /* No more urbs, remove the SB. */
+                               TxIsocEPList[epid].sub = 0;
+                               etrax_remove_from_sb_list(urb);
+                       } else {
+                               TxIsocEPList[epid].hw_len = 0;
+                               TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+                       }
+               }
+               /* Release allocated bandwidth. */
+               usb_release_bandwidth(urb->dev, urb, 1);
+       }
+       /* Free the epid if urb list is empty. */
+       if (urb_list_empty(epid)) {
+               etrax_usb_free_epid(epid);
+       }
+       restore_flags(flags);
+
+       /* Must be done before calling completion handler. */
+       kfree(urb_priv);
+       urb->hcpriv = 0;
+
+       if (urb->complete) {
+               urb->complete(urb, NULL);
+       }
+
+       DBFEXIT;
+       return 0;
+}
+
+static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
+{
+       DBFENTER;
+       DBFEXIT;
+       return (*R_USB_FM_NUMBER & 0x7ff);
+}
+
+static int etrax_usb_allocate_dev(struct usb_device *usb_dev)
+{
+       DBFENTER;
+       DBFEXIT;
+       return 0;
+}
+
+static int etrax_usb_deallocate_dev(struct usb_device *usb_dev)
+{
+       DBFENTER;
+       DBFEXIT;
+       return 0;
+}
+
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+       DBFENTER;
+
+       /* This interrupt handler could be used when unlinking EP descriptors. */
+
+       if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
+               USB_EP_Desc_t *ep;
+
+               //dbg_bulk("dma8_sub0_descr (BULK) intr.");
+
+               /* It should be safe clearing the interrupt here, since we don't expect to get a new
+                  one until we restart the bulk channel. */
+               *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
+
+               /* Wait while the DMA is running (though we don't expect it to be). */
+               while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));
+
+               /* Advance the DMA to the next EP descriptor. */
+               ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
+
+               //dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);
+
+               /* ep->next is already a physical address; no need for a virt_to_phys. */
+               *R_DMA_CH8_SUB0_EP = ep->next;
+
+               /* Start the DMA bulk channel again. */
+               *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+       }
+       if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
+               struct urb *urb;
+               int epid;
+               etrax_urb_priv_t *urb_priv;
+               unsigned long int flags;
+
+               dbg_ctrl("dma8_sub1_descr (CTRL) intr.");
+               *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
+
+               /* The complete callback gets called so we cli. */
+               save_flags(flags);
+               cli();
+
+               for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+                       if ((TxCtrlEPList[epid].sub == 0) ||
+                           (epid == DUMMY_EPID) ||
+                           (epid == INVALID_EPID)) {
+                               /* Nothing here to see. */
+                               continue;
+                       }
+
+                       /* Get the first urb (if any). */
+                       urb = urb_list_first(epid);
+
+                       if (urb) {
+
+                               /* Sanity check. */
+                               assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);
+
+                               urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+                               assert(urb_priv);
+
+                               if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {
+                                       assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+
+                                       etrax_usb_complete_urb(urb, 0);
+                               }
+                       }
+               }
+               restore_flags(flags);
+       }
+       if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
+               dbg_intr("dma8_sub2_descr (INTR) intr.");
+               *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
+       }
+       if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
+               struct urb *urb;
+               int epid;
+               int epid_done;
+               etrax_urb_priv_t *urb_priv;
+               USB_SB_Desc_t *sb_desc;
+
+               usb_isoc_complete_data_t *comp_data = NULL;
+
+               /* One or more isoc out transfers are done. */
+               dbg_isoc("dma8_sub3_descr (ISOC) intr.");
+
+               /* For each isoc out EP search for the first sb_desc with the intr flag
+                  set.  This descriptor must be the last packet from an URB.  Then
+                  traverse the URB list for the EP until the URB with urb_priv->last_sb
+                  matching the intr-marked sb_desc is found.  All URBs before this have
+                  been sent.
+               */
+
+               for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+                       /* Skip past epids with no SB lists, epids used for in traffic,
+                          and special (dummy, invalid) epids. */
+                       if ((TxIsocEPList[epid].sub == 0) ||
+                           (test_bit(epid, (void *)&epid_out_traffic) == 0) ||
+                           (epid == DUMMY_EPID) ||
+                           (epid == INVALID_EPID)) {
+                               /* Nothing here to see. */
+                               continue;
+                       }
+                       sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
+
+                       /* Find the last descriptor of the currently active URB for this ep.
+                          This is the first descriptor in the sub list marked for a descriptor
+                          interrupt. */
+                       while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
+                               sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
+                       }
+                       assert(sb_desc);
+
+                       dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",
+                                epid,
+                                phys_to_virt(TxIsocEPList[epid].sub),
+                                sb_desc);
+
+                       epid_done = 0;
+
+                       /* Get the first urb (if any). */
+                       urb = urb_list_first(epid);
+                       assert(urb);
+
+                       while (urb && !epid_done) {
+
+                               /* Sanity check. */
+                               assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
+
+                               if (!usb_pipeout(urb->pipe)) {
+                                       /* descr interrupts are generated only for out pipes. */
+                                       epid_done = 1;
+                                       continue;
+                               }
+
+                               urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+                               assert(urb_priv);
+
+                               if (sb_desc != urb_priv->last_sb) {
+
+                                       /* This urb has been sent. */
+                                       dbg_isoc("out URB 0x%p sent", urb);
+
+                                       urb_priv->urb_state = TRANSFER_DONE;
+
+                               } else if ((sb_desc == urb_priv->last_sb) &&
+                                          !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+
+                                       assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));
+                                       assert(sb_desc->next == 0);
+
+                                       dbg_isoc("out URB 0x%p last in list, epid disabled", urb);
+                                       TxIsocEPList[epid].sub = 0;
+                                       TxIsocEPList[epid].hw_len = 0;
+                                       urb_priv->urb_state = TRANSFER_DONE;
+
+                                       epid_done = 1;
+
+                               } else {
+                                       epid_done = 1;
+                               }
+                               if (!epid_done) {
+                                       urb = urb_list_next(urb, epid);
+                               }
+                       }
+
+               }
+
+               *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
+
+               comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC);
+               assert(comp_data != NULL);
+
+                INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);
+                schedule_work(&comp_data->usb_bh);
+       }
+
+       DBFEXIT;
+        return IRQ_HANDLED;
+}
+
+static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
+{
+       usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;
+
+       struct urb *urb;
+       int epid;
+       int epid_done;
+       etrax_urb_priv_t *urb_priv;
+
+       DBFENTER;
+
+       dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");
+
+       for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+               unsigned long flags;
+
+               save_flags(flags);
+               cli();
+
+               epid_done = 0;
+
+               /* The descriptor interrupt handler has marked all transmitted isoch. out
+                  URBs with TRANSFER_DONE.  Now we traverse all epids and for all that
+                  have isoch. out traffic traverse its URB list and complete the
+                  transmitted URB.
+               */
+
+               while (!epid_done) {
+
+                       /* Get the first urb (if any). */
+                       urb = urb_list_first(epid);
+                       if (urb == 0) {
+                               epid_done = 1;
+                               continue;
+                       }
+
+                       if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
+                                       epid_done = 1;
+                                       continue;
+                       }
+
+                       if (!usb_pipeout(urb->pipe)) {
+                               /* descr interrupts are generated only for out pipes. */
+                               epid_done = 1;
+                               continue;
+                       }
+
+                       dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);
+
+                       urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+                       assert(urb_priv);
+
+                       if (urb_priv->urb_state == TRANSFER_DONE) {
+                               int i;
+                               struct usb_iso_packet_descriptor *packet;
+
+                               /* This urb has been sent. */
+                               dbg_isoc("Completing isoc out URB 0x%p", urb);
+
+                               for (i = 0; i < urb->number_of_packets; i++) {
+                                       packet = &urb->iso_frame_desc[i];
+                                       packet->status = 0;
+                                       packet->actual_length = packet->length;
+                               }
+
+                               etrax_usb_complete_isoc_urb(urb, 0);
+
+                               if (urb_list_empty(epid)) {
+                                       etrax_usb_free_epid(epid);
+                                       epid_done = 1;
+                               }
+                       } else {
+                               epid_done = 1;
+                       }
+               }
+               restore_flags(flags);
+
+       }
+       kmem_cache_free(isoc_compl_cache, comp_data);
+
+       DBFEXIT;
+}
+
+
+
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+{
+       struct urb *urb;
+       etrax_urb_priv_t *urb_priv;
+       int epid = 0;
+       unsigned long flags;
+
+       /* Isoc diagnostics. */
+       static int curr_fm = 0;
+       static int prev_fm = 0;
+
+       DBFENTER;
+
+       /* Clear this interrupt. */
+       *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
+
+       /* Note that this while loop assumes that all packets span only
+          one rx descriptor. */
+
+       /* The reason we cli here is that we call the driver's callback functions. */
+       save_flags(flags);
+       cli();
+
+       while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
+
+               epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
+               urb = urb_list_first(epid);
+
+               //printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);
+
+               if (!urb) {
+                       err("No urb for epid %d in rx interrupt", epid);
+                       __dump_ept_data(epid);
+                       goto skip_out;
+               }
+
+               /* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since
+                  ctrl pipes are not. */
+
+               if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
+                       __u32 r_usb_ept_data;
+                       int no_error = 0;
+
+                       assert(test_bit(epid, (void *)&epid_usage_bitmask));
+
+                       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+                       nop();
+                       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                               r_usb_ept_data = *R_USB_EPT_DATA_ISO;
+
+                               if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
+                                   (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
+                                       /* Not an error, just a failure to receive an expected iso
+                                          in packet in this frame.  This is not documented
+                                          in the designers reference.
+                                       */
+                                       no_error++;
+                               } else {
+                                       warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);
+                               }
+                       } else {
+                               r_usb_ept_data = *R_USB_EPT_DATA;
+                               warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);
+                       }
+
+                       if (!no_error){
+                               warn("error in rx desc->status, epid %d, first urb = 0x%lx",
+                                    epid, (unsigned long)urb);
+                               __dump_in_desc(myNextRxDesc);
+
+                               warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);
+
+                               /* Check that ept was disabled when error occurred. */
+                               switch (usb_pipetype(urb->pipe)) {
+                               case PIPE_BULK:
+                                       assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+                                       break;
+                               case PIPE_CONTROL:
+                                       assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+                                       break;
+                               case PIPE_INTERRUPT:
+                                       assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+                                       break;
+                               case PIPE_ISOCHRONOUS:
+                                       assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+                                       break;
+                               default:
+                                       warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",
+                                            usb_pipetype(urb->pipe),
+                                            urb);
+                               }
+                               etrax_usb_complete_urb(urb, -EPROTO);
+                               goto skip_out;
+                       }
+               }
+
+               urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+               assert(urb_priv);
+
+               if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
+                   (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
+                   (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+
+                       if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+                               /* We get nodata for empty data transactions, and the rx descriptor's
+                                  hw_len field is not valid in that case. No data to copy in other
+                                  words. */
+                       } else {
+                               /* Make sure the data fits in the buffer. */
+                               assert(urb_priv->rx_offset + myNextRxDesc->hw_len
+                                      <= urb->transfer_buffer_length);
+
+                               memcpy(urb->transfer_buffer + urb_priv->rx_offset,
+                                      phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
+                               urb_priv->rx_offset += myNextRxDesc->hw_len;
+                       }
+
+                       if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
+                               if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&
+                                   ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==
+                                    IO_STATE(USB_EP_command, enable, yes))) {
+                                       /* The EP is still enabled, so the OUT packet used to ack
+                                          the in data is probably not processed yet.  If the EP
+                                          sub pointer has not moved beyond urb_priv->last_sb mark
+                                          it for a descriptor interrupt and complete the urb in
+                                          the descriptor interrupt handler.
+                                       */
+                                       USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;
+
+                                       while ((sub != NULL) && (sub != urb_priv->last_sb)) {
+                                               sub = sub->next ? phys_to_virt(sub->next) : 0;
+                                       }
+                                       if (sub != NULL) {
+                                               /* The urb has not been fully processed. */
+                                               urb_priv->urb_state = WAITING_FOR_DESCR_INTR;
+                                       } else {
+                                               warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);
+                                               etrax_usb_complete_urb(urb, 0);
+                                       }
+                               } else {
+                                       etrax_usb_complete_urb(urb, 0);
+                               }
+                       }
+
+               } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+
+                       struct usb_iso_packet_descriptor *packet;
+
+                       if (urb_priv->urb_state == UNLINK) {
+                               info("Ignoring rx data for urb being unlinked.");
+                               goto skip_out;
+                       } else if (urb_priv->urb_state == NOT_STARTED) {
+                               info("What? Got rx data for urb that isn't started?");
+                               goto skip_out;
+                       }
+
+                       packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
+                       packet->status = 0;
+
+                       if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
+                               /* We get nodata for empty data transactions, and the rx descriptor's
+                                  hw_len field is not valid in that case. We copy 0 bytes however to
+                                  stay in synch. */
+                               packet->actual_length = 0;
+                       } else {
+                               packet->actual_length = myNextRxDesc->hw_len;
+                               /* Make sure the data fits in the buffer. */
+                               assert(packet->actual_length <= packet->length);
+                               memcpy(urb->transfer_buffer + packet->offset,
+                                      phys_to_virt(myNextRxDesc->buf), packet->actual_length);
+                       }
+
+                       /* Increment the packet counter. */
+                       urb_priv->isoc_packet_counter++;
+
+                       /* Note that we don't care about the eot field in the rx descriptor's status.
+                          It will always be set for isoc traffic. */
+                       if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
+
+                               /* Out-of-synch diagnostics. */
+                               curr_fm = (*R_USB_FM_NUMBER & 0x7ff);
+                               if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {
+                                       /* This test is wrong, if there is more than one isoc
+                                          in endpoint active it will always calculate wrong
+                                          since prev_fm is shared by all endpoints.
+
+                                          FIXME Make this check per URB using urb->start_frame.
+                                       */
+                                       dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",
+                                                prev_fm, curr_fm);
+
+                               }
+                               prev_fm = curr_fm;
+
+                               /* Complete the urb with status OK. */
+                               etrax_usb_complete_isoc_urb(urb, 0);
+                       }
+               }
+
+       skip_out:
+
+               /* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr
+                  has the same layout as USB_IN_Desc for the relevant fields.) */
+               prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);
+
+               myPrevRxDesc = myNextRxDesc;
+               myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
+               myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
+               myLastRxDesc = myPrevRxDesc;
+
+               myNextRxDesc->status = 0;
+               myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+       }
+
+       restore_flags(flags);
+
+       DBFEXIT;
+
+        return IRQ_HANDLED;
+}
+
+
+/* This function will unlink the SB descriptors associated with this urb. */
+static int etrax_remove_from_sb_list(struct urb *urb)
+{
+       USB_SB_Desc_t *next_sb, *first_sb, *last_sb;
+       etrax_urb_priv_t *urb_priv;
+       int i = 0;
+
+       DBFENTER;
+
+       urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       assert(urb_priv);
+
+       /* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor
+          doesn't really need to be disabled, it's just that we expect it to be. */
+       if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+               assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+       } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
+               assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
+       }
+
+       first_sb = urb_priv->first_sb;
+       last_sb = urb_priv->last_sb;
+
+       assert(first_sb);
+       assert(last_sb);
+
+       while (first_sb != last_sb) {
+               next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);
+               kmem_cache_free(usb_desc_cache, first_sb);
+               first_sb = next_sb;
+               i++;
+       }
+       kmem_cache_free(usb_desc_cache, last_sb);
+       i++;
+       dbg_sb("%d SB descriptors freed", i);
+       /* Compare i with urb->number_of_packets for Isoc traffic.
+          Should be same when calling unlink_urb */
+
+       DBFEXIT;
+
+       return i;
+}
+
+static int etrax_usb_submit_bulk_urb(struct urb *urb)
+{
+       int epid;
+       int empty;
+       unsigned long flags;
+       etrax_urb_priv_t *urb_priv;
+
+       DBFENTER;
+
+       /* Epid allocation, empty check and list add must be protected.
+          Read about this in etrax_usb_submit_ctrl_urb. */
+
+       spin_lock_irqsave(&urb_list_lock, flags);
+       epid = etrax_usb_setup_epid(urb);
+       if (epid == -1) {
+               DBFEXIT;
+               spin_unlock_irqrestore(&urb_list_lock, flags);
+               return -ENOMEM;
+       }
+       empty = urb_list_empty(epid);
+       urb_list_add(urb, epid);
+       spin_unlock_irqrestore(&urb_list_lock, flags);
+
+       dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",
+                usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);
+
+       /* Mark the urb as being in progress. */
+       urb->status = -EINPROGRESS;
+
+       /* Setup the hcpriv data. */
+       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+       assert(urb_priv != NULL);
+       /* This sets rx_offset to 0. */
+       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+       urb_priv->urb_state = NOT_STARTED;
+       urb->hcpriv = urb_priv;
+
+       if (empty) {
+               etrax_usb_add_to_bulk_sb_list(urb, epid);
+       }
+
+       DBFEXIT;
+
+       return 0;
+}
+
+static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
+{
+       USB_SB_Desc_t *sb_desc;
+       etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       unsigned long flags;
+       char maxlen;
+
+       DBFENTER;
+
+       dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);
+
+       maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+       sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+       assert(sb_desc != NULL);
+       memset(sb_desc, 0, sizeof(USB_SB_Desc_t));
+
+
+       if (usb_pipeout(urb->pipe)) {
+
+               dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);
+
+               /* This is probably a sanity check of the bulk transaction length
+                  not being larger than 64 kB. */
+               if (urb->transfer_buffer_length > 0xffff) {
+                       panic("urb->transfer_buffer_length > 0xffff");
+               }
+
+               sb_desc->sw_len = urb->transfer_buffer_length;
+
+               /* The rem field is don't care if it's not a full-length transfer, so setting
+                  it shouldn't hurt. Also, rem isn't used for OUT traffic. */
+               sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                   IO_STATE(USB_SB_command, tt, out) |
+                                   IO_STATE(USB_SB_command, eot, yes) |
+                                   IO_STATE(USB_SB_command, eol, yes));
+
+               /* The full field is set to yes, even if we don't actually check that this is
+                  a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).
+                  Setting full prevents the USB controller from sending an empty packet in
+                  that case.  However, if URB_ZERO_PACKET was set we want that. */
+               if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
+                       sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
+               }
+
+               sb_desc->buf = virt_to_phys(urb->transfer_buffer);
+               sb_desc->next = 0;
+
+       } else if (usb_pipein(urb->pipe)) {
+
+               dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);
+
+               sb_desc->sw_len = urb->transfer_buffer_length ?
+                       (urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+
+               /* The rem field is don't care if it's not a full-length transfer, so setting
+                  it shouldn't hurt. */
+               sb_desc->command =
+                       (IO_FIELD(USB_SB_command, rem,
+                                 urb->transfer_buffer_length % maxlen) |
+                        IO_STATE(USB_SB_command, tt, in) |
+                        IO_STATE(USB_SB_command, eot, yes) |
+                        IO_STATE(USB_SB_command, eol, yes));
+
+               sb_desc->buf = 0;
+               sb_desc->next = 0;
+       }
+
+       urb_priv->first_sb = sb_desc;
+       urb_priv->last_sb = sb_desc;
+       urb_priv->epid = epid;
+
+       urb->hcpriv = urb_priv;
+
+       /* Reset toggle bits and reset error count. */
+       save_flags(flags);
+       cli();
+
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+
+       /* FIXME: Is this a special case since the hold field is checked,
+          or should we check hold in a lot of other cases as well? */
+       if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+               panic("Hold was set in %s", __FUNCTION__);
+       }
+
+       /* Reset error counters (regardless of which direction this traffic is). */
+       *R_USB_EPT_DATA &=
+               ~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+                 IO_MASK(R_USB_EPT_DATA, error_count_out));
+
+       /* Software must preset the toggle bits. */
+       if (usb_pipeout(urb->pipe)) {
+               char toggle =
+                       usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+               *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
+               *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
+       } else {
+               char toggle =
+                       usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+               *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
+               *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
+       }
+
+       /* Assert that the EP descriptor is disabled. */
+       assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+
+       /* The reason we set the EP's sub pointer directly instead of
+          walking the SB list and linking it last in the list is that we only
+          have one active urb at a time (the rest are queued). */
+
+       /* Note that we cannot have interrupts running when we have set the SB descriptor
+          but the EP is not yet enabled.  If a bulk eot happens for another EP, we will
+          find this EP disabled and with a SB != 0, which will make us think that it's done. */
+       TxBulkEPList[epid].sub = virt_to_phys(sb_desc);
+       TxBulkEPList[epid].hw_len = 0;
+       /* Note that we don't have to fill in the ep_id field since this
+          was done when we allocated the EP descriptors in init_tx_bulk_ep. */
+
+       /* Check if the dummy list is already with us (if several urbs were queued). */
+       if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {
+
+               dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d",
+                        (unsigned long)urb, epid);
+
+               /* The last EP in the dummy list already has its next pointer set to
+                  TxBulkEPList[epid].next. */
+
+               /* We don't need to check if the DMA is at this EP or not before changing the
+                  next pointer, since we will do it in one 32-bit write (EP descriptors are
+                  32-bit aligned). */
+               TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
+       }
+       /* Enable the EP descr. */
+       dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);
+       TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+       /* Everything is set up, safe to enable interrupts again. */
+       restore_flags(flags);
+
+       /* If the DMA bulk channel isn't running, we need to restart it if it
+          has stopped at the last EP descriptor (DMA stopped because there was
+          no more traffic) or if it has stopped at a dummy EP with the intr flag
+          set (DMA stopped because we were too slow in inserting new traffic). */
+       if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+
+               USB_EP_Desc_t *ep;
+               ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
+               dbg_bulk("DMA channel not running in add");
+               dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);
+
+               if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||
+                   (ep->command & 0x8) >> 3) {
+                       *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+                       /* Update/restart the bulk start timer since we just started the channel. */
+                       mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
+                       /* Update/restart the bulk eot timer since we just inserted traffic. */
+                       mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+               }
+       }
+
+       DBFEXIT;
+}
+
+static void etrax_usb_complete_bulk_urb(struct urb *urb, int status)
+{
+       etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       int epid = urb_priv->epid;
+       unsigned long flags;
+
+       DBFENTER;
+
+       if (status)
+               warn("Completing bulk urb with status %d.", status);
+
+       dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid);
+
+       /* Update the urb list. */
+       urb_list_del(urb, epid);
+
+       /* For an IN pipe, we always set the actual length, regardless of whether there was
+          an error or not (which means the device driver can use the data if it wants to). */
+       if (usb_pipein(urb->pipe)) {
+               urb->actual_length = urb_priv->rx_offset;
+       } else {
+               /* Set actual_length for OUT urbs also; the USB mass storage driver seems
+                  to want that. We wouldn't know of any partial writes if there was an error. */
+               if (status == 0) {
+                       urb->actual_length = urb->transfer_buffer_length;
+               } else {
+                       urb->actual_length = 0;
+               }
+       }
+
+       /* FIXME: Is there something of the things below we shouldn't do if there was an error?
+          Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */
+
+       save_flags(flags);
+       cli();
+
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+
+       /* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */
+       if (usb_pipeout(urb->pipe)) {
+               char toggle =
+                       IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                             usb_pipeout(urb->pipe), toggle);
+       } else {
+               char toggle =
+                       IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                             usb_pipeout(urb->pipe), toggle);
+       }
+       restore_flags(flags);
+
+       /* Remember to free the SBs. */
+       etrax_remove_from_sb_list(urb);
+       kfree(urb_priv);
+       urb->hcpriv = 0;
+
+       /* If there are any more urb's in the list we'd better start sending */
+       if (!urb_list_empty(epid)) {
+
+               struct urb *new_urb;
+
+               /* Get the first urb. */
+               new_urb = urb_list_first(epid);
+               assert(new_urb);
+
+               dbg_bulk("More bulk for epid %d", epid);
+
+               etrax_usb_add_to_bulk_sb_list(new_urb, epid);
+       }
+
+       urb->status = status;
+
+       /* We let any non-zero status from the layer above have precedence. */
+       if (status == 0) {
+               /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+                  is to be treated as an error. */
+               if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+                       if (usb_pipein(urb->pipe) &&
+                           (urb->actual_length !=
+                            usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
+                               urb->status = -EREMOTEIO;
+                       }
+               }
+       }
+
+       if (urb->complete) {
+               urb->complete(urb, NULL);
+       }
+
+       if (urb_list_empty(epid)) {
+               /* This means that this EP is now free, deconfigure it. */
+               etrax_usb_free_epid(epid);
+
+               /* No more traffic; time to clean up.
+                  Must set sub pointer to 0, since we look at the sub pointer when handling
+                  the bulk eot interrupt. */
+
+               dbg_bulk("No bulk for epid %d", epid);
+
+               TxBulkEPList[epid].sub = 0;
+
+               /* Unlink the dummy list. */
+
+               dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d",
+                        (unsigned long)urb, epid);
+
+               /* No need to wait for the DMA before changing the next pointer.
+                  The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
+                  the last one (INVALID_EPID) for actual traffic. */
+               TxBulkEPList[epid].next =
+                       virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
+       }
+
+       DBFEXIT;
+}
+
+static int etrax_usb_submit_ctrl_urb(struct urb *urb)
+{
+       int epid;
+       int empty;
+       unsigned long flags;
+       etrax_urb_priv_t *urb_priv;
+
+       DBFENTER;
+
+       /* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */
+
+       /* Epid allocation, empty check and list add must be protected.
+
+          Epid allocation because if we find an existing epid for this endpoint an urb might be
+          completed (emptying the list) before we add the new urb to the list, causing the epid
+          to be de-allocated. We would then start the transfer with an invalid epid -> epid attn.
+
+          Empty check and add because otherwise we might conclude that the list is not empty,
+          after which it becomes empty before we add the new urb to the list, causing us not to
+          insert the new traffic into the SB list. */
+
+       spin_lock_irqsave(&urb_list_lock, flags);
+       epid = etrax_usb_setup_epid(urb);
+       if (epid == -1) {
+               spin_unlock_irqrestore(&urb_list_lock, flags);
+               DBFEXIT;
+               return -ENOMEM;
+       }
+       empty = urb_list_empty(epid);
+       urb_list_add(urb, epid);
+       spin_unlock_irqrestore(&urb_list_lock, flags);
+
+       dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d",
+                (unsigned long)urb, empty ? "empty" : "", epid);
+
+       /* Mark the urb as being in progress. */
+       urb->status = -EINPROGRESS;
+
+       /* Setup the hcpriv data. */
+       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+       assert(urb_priv != NULL);
+       /* This sets rx_offset to 0. */
+       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+       urb_priv->urb_state = NOT_STARTED;
+       urb->hcpriv = urb_priv;
+
+       if (empty) {
+               etrax_usb_add_to_ctrl_sb_list(urb, epid);
+       }
+
+       DBFEXIT;
+
+       return 0;
+}
+
+static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid)
+{
+       USB_SB_Desc_t *sb_desc_setup;
+       USB_SB_Desc_t *sb_desc_data;
+       USB_SB_Desc_t *sb_desc_status;
+
+       etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+
+       unsigned long flags;
+       char maxlen;
+
+       DBFENTER;
+
+       maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+       sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+       assert(sb_desc_setup != NULL);
+       sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+       assert(sb_desc_status != NULL);
+
+       /* Initialize the mandatory setup SB descriptor (used only in control transfers) */
+       sb_desc_setup->sw_len = 8;
+       sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                 IO_STATE(USB_SB_command, tt, setup) |
+                                 IO_STATE(USB_SB_command, full, yes) |
+                                 IO_STATE(USB_SB_command, eot, yes));
+
+       sb_desc_setup->buf = virt_to_phys(urb->setup_packet);
+
+       if (usb_pipeout(urb->pipe)) {
+               dbg_ctrl("Transfer for epid %d is OUT", epid);
+
+               /* If this Control OUT transfer has an optional data stage we add an OUT token
+                  before the mandatory IN (status) token, hence the reordered SB list */
+
+               sb_desc_setup->next = virt_to_phys(sb_desc_status);
+               if (urb->transfer_buffer) {
+
+                       dbg_ctrl("This OUT transfer has an extra data stage");
+
+                       sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+                       assert(sb_desc_data != NULL);
+
+                       sb_desc_setup->next = virt_to_phys(sb_desc_data);
+
+                       sb_desc_data->sw_len = urb->transfer_buffer_length;
+                       sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) |
+                                                IO_STATE(USB_SB_command, full, yes) |
+                                                IO_STATE(USB_SB_command, eot, yes));
+                       sb_desc_data->buf = virt_to_phys(urb->transfer_buffer);
+                       sb_desc_data->next = virt_to_phys(sb_desc_status);
+               }
+
+               sb_desc_status->sw_len = 1;
+               sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                          IO_STATE(USB_SB_command, tt, in) |
+                                          IO_STATE(USB_SB_command, eot, yes) |
+                                          IO_STATE(USB_SB_command, intr, yes) |
+                                          IO_STATE(USB_SB_command, eol, yes));
+
+               sb_desc_status->buf = 0;
+               sb_desc_status->next = 0;
+
+       } else if (usb_pipein(urb->pipe)) {
+
+               dbg_ctrl("Transfer for epid %d is IN", epid);
+               dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
+               dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
+
+               sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+               assert(sb_desc_data != NULL);
+
+               sb_desc_setup->next = virt_to_phys(sb_desc_data);
+
+               sb_desc_data->sw_len = urb->transfer_buffer_length ?
+                       (urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+               dbg_ctrl("sw_len got %d", sb_desc_data->sw_len);
+
+               sb_desc_data->command =
+                       (IO_FIELD(USB_SB_command, rem,
+                                 urb->transfer_buffer_length % maxlen) |
+                        IO_STATE(USB_SB_command, tt, in) |
+                        IO_STATE(USB_SB_command, eot, yes));
+
+               sb_desc_data->buf = 0;
+               sb_desc_data->next = virt_to_phys(sb_desc_status);
+
+               /* Read comment at zout_buffer declaration for an explanation to this. */
+               sb_desc_status->sw_len = 1;
+               sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                          IO_STATE(USB_SB_command, tt, zout) |
+                                          IO_STATE(USB_SB_command, full, yes) |
+                                          IO_STATE(USB_SB_command, eot, yes) |
+                                          IO_STATE(USB_SB_command, intr, yes) |
+                                          IO_STATE(USB_SB_command, eol, yes));
+
+               sb_desc_status->buf = virt_to_phys(&zout_buffer[0]);
+               sb_desc_status->next = 0;
+       }
+
+       urb_priv->first_sb = sb_desc_setup;
+       urb_priv->last_sb = sb_desc_status;
+       urb_priv->epid = epid;
+
+       urb_priv->urb_state = STARTED;
+
+       /* Reset toggle bits and reset error count, remember to di and ei */
+       /* Warning: it is possible that this locking doesn't work with bottom-halves */
+
+       save_flags(flags);
+       cli();
+
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+       if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
+               panic("Hold was set in %s", __FUNCTION__);
+       }
+
+
+       /* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits
+          are set to a specific value. Why the difference? Read "Transfer and Toggle Bits
+          in Designer's Reference, p. 8 - 11. */
+       *R_USB_EPT_DATA &=
+               ~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
+                 IO_MASK(R_USB_EPT_DATA, error_count_out) |
+                 IO_MASK(R_USB_EPT_DATA, t_in) |
+                 IO_MASK(R_USB_EPT_DATA, t_out));
+
+       /* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now
+          (i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */
+       restore_flags(flags);
+
+       /* Assert that the EP descriptor is disabled. */
+       assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
+
+       /* Set up and enable the EP descriptor. */
+       TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup);
+       TxCtrlEPList[epid].hw_len = 0;
+       TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+       /* We start the DMA sub channel without checking if it's running or not, because:
+          1) If it's already running, issuing the start command is a nop.
+          2) We avoid a test-and-set race condition. */
+       *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
+
+       DBFEXIT;
+}
+
+static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status)
+{
+       etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       int epid = urb_priv->epid;
+
+       DBFENTER;
+
+       if (status)
+               warn("Completing ctrl urb with status %d.", status);
+
+       dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb);
+
+       /* Remove this urb from the list. */
+       urb_list_del(urb, epid);
+
+       /* For an IN pipe, we always set the actual length, regardless of whether there was
+          an error or not (which means the device driver can use the data if it wants to). */
+       if (usb_pipein(urb->pipe)) {
+               urb->actual_length = urb_priv->rx_offset;
+       }
+
+       /* FIXME: Is there something of the things below we shouldn't do if there was an error?
+          Like, maybe we shouldn't insert more traffic. */
+
+       /* Remember to free the SBs. */
+       etrax_remove_from_sb_list(urb);
+       kfree(urb_priv);
+       urb->hcpriv = 0;
+
+       /* If there are any more urbs in the list we'd better start sending. */
+       if (!urb_list_empty(epid)) {
+               struct urb *new_urb;
+
+               /* Get the first urb. */
+               new_urb = urb_list_first(epid);
+               assert(new_urb);
+
+               dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb);
+
+               etrax_usb_add_to_ctrl_sb_list(new_urb, epid);
+       }
+
+       urb->status = status;
+
+       /* We let any non-zero status from the layer above have precedence. */
+       if (status == 0) {
+               /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+                  is to be treated as an error. */
+               if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+                       if (usb_pipein(urb->pipe) &&
+                           (urb->actual_length !=
+                            usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
+                               urb->status = -EREMOTEIO;
+                       }
+               }
+       }
+
+       if (urb->complete) {
+               urb->complete(urb, NULL);
+       }
+
+       if (urb_list_empty(epid)) {
+               /* No more traffic. Time to clean up. */
+               etrax_usb_free_epid(epid);
+               /* Must set sub pointer to 0. */
+               dbg_ctrl("No ctrl for epid %d", epid);
+               TxCtrlEPList[epid].sub = 0;
+       }
+
+       DBFEXIT;
+}
+
+static int etrax_usb_submit_intr_urb(struct urb *urb)
+{
+
+       int epid;
+
+       DBFENTER;
+
+       if (usb_pipeout(urb->pipe)) {
+               /* Unsupported transfer type.
+                  We don't support interrupt out traffic. (If we do, we can't support
+                  intervals for neither in or out traffic, but are forced to schedule all
+                  interrupt traffic in one frame.) */
+               return -EINVAL;
+       }
+
+       epid = etrax_usb_setup_epid(urb);
+       if (epid == -1) {
+               DBFEXIT;
+               return -ENOMEM;
+       }
+
+       if (!urb_list_empty(epid)) {
+               /* There is already a queued urb for this endpoint. */
+               etrax_usb_free_epid(epid);
+               return -ENXIO;
+       }
+
+       urb->status = -EINPROGRESS;
+
+       dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid);
+
+       urb_list_add(urb, epid);
+       etrax_usb_add_to_intr_sb_list(urb, epid);
+
+       return 0;
+
+       DBFEXIT;
+}
+
+static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
+{
+
+       volatile USB_EP_Desc_t *tmp_ep;
+       volatile USB_EP_Desc_t *first_ep;
+
+       char maxlen;
+       int interval;
+       int i;
+
+       etrax_urb_priv_t *urb_priv;
+
+       DBFENTER;
+
+       maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+       interval = urb->interval;
+
+       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+       assert(urb_priv != NULL);
+       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+       urb->hcpriv = urb_priv;
+
+       first_ep = &TxIntrEPList[0];
+
+       /* Round of the interval to 2^n, it is obvious that this code favours
+          smaller numbers, but that is actually a good thing */
+       /* FIXME: The "rounding error" for larger intervals will be quite
+          large. For in traffic this shouldn't be a problem since it will only
+          mean that we "poll" more often. */
+       for (i = 0; interval; i++) {
+               interval = interval >> 1;
+       }
+       interval = 1 << (i - 1);
+
+       dbg_intr("Interval rounded to %d", interval);
+
+       tmp_ep = first_ep;
+       i = 0;
+       do {
+               if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
+                       if ((i % interval) == 0) {
+                               /* Insert the traffic ep after tmp_ep */
+                               USB_EP_Desc_t *ep_desc;
+                               USB_SB_Desc_t *sb_desc;
+
+                               dbg_intr("Inserting EP for epid %d", epid);
+
+                               ep_desc = (USB_EP_Desc_t *)
+                                       kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+                               sb_desc = (USB_SB_Desc_t *)
+                                       kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+                               assert(ep_desc != NULL);
+                               CHECK_ALIGN(ep_desc);
+                               assert(sb_desc != NULL);
+
+                               ep_desc->sub = virt_to_phys(sb_desc);
+                               ep_desc->hw_len = 0;
+                               ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
+                                                   IO_STATE(USB_EP_command, enable, yes));
+
+
+                               /* Round upwards the number of packets of size maxlen
+                                  that this SB descriptor should receive. */
+                               sb_desc->sw_len = urb->transfer_buffer_length ?
+                                       (urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
+                               sb_desc->next = 0;
+                               sb_desc->buf = 0;
+                               sb_desc->command =
+                                       (IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) |
+                                        IO_STATE(USB_SB_command, tt, in) |
+                                        IO_STATE(USB_SB_command, eot, yes) |
+                                        IO_STATE(USB_SB_command, eol, yes));
+
+                               ep_desc->next = tmp_ep->next;
+                               tmp_ep->next = virt_to_phys(ep_desc);
+                       }
+                       i++;
+               }
+               tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
+       } while (tmp_ep != first_ep);
+
+
+       /* Note that first_sb/last_sb doesn't apply to interrupt traffic. */
+       urb_priv->epid = epid;
+
+       /* We start the DMA sub channel without checking if it's running or not, because:
+          1) If it's already running, issuing the start command is a nop.
+          2) We avoid a test-and-set race condition. */
+       *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
+
+       DBFEXIT;
+}
+
+
+
+static void etrax_usb_complete_intr_urb(struct urb *urb, int status)
+{
+       etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       int epid = urb_priv->epid;
+
+       DBFENTER;
+
+       if (status)
+               warn("Completing intr urb with status %d.", status);
+
+       dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb);
+
+       urb->status = status;
+       urb->actual_length = urb_priv->rx_offset;
+
+       dbg_intr("interrupt urb->actual_length = %d", urb->actual_length);
+
+       /* We let any non-zero status from the layer above have precedence. */
+       if (status == 0) {
+               /* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
+                  is to be treated as an error. */
+               if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+                       if (urb->actual_length !=
+                           usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
+                               urb->status = -EREMOTEIO;
+                       }
+               }
+       }
+
+       /* The driver will resubmit the URB so we need to remove it first */
+        etrax_usb_unlink_urb(urb, 0);
+       if (urb->complete) {
+               urb->complete(urb, NULL);
+       }
+
+       DBFEXIT;
+}
+
+
+static int etrax_usb_submit_isoc_urb(struct urb *urb)
+{
+       int epid;
+       unsigned long flags;
+
+       DBFENTER;
+
+       dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb);
+
+       /* Epid allocation, empty check and list add must be protected.
+          Read about this in etrax_usb_submit_ctrl_urb. */
+
+       spin_lock_irqsave(&urb_list_lock, flags);
+       /* Is there an active epid for this urb ? */
+       epid = etrax_usb_setup_epid(urb);
+       if (epid == -1) {
+               DBFEXIT;
+               spin_unlock_irqrestore(&urb_list_lock, flags);
+               return -ENOMEM;
+       }
+
+       /* Ok, now we got valid endpoint, lets insert some traffic */
+
+       urb->status = -EINPROGRESS;
+
+       /* Find the last urb in the URB_List and add this urb after that one.
+          Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list.  This
+          is important to make this in "real time" since isochronous traffic is
+          time sensitive. */
+
+       dbg_isoc("Adding isoc urb to (possibly empty) list");
+       urb_list_add(urb, epid);
+       etrax_usb_add_to_isoc_sb_list(urb, epid);
+       spin_unlock_irqrestore(&urb_list_lock, flags);
+
+       DBFEXIT;
+
+       return 0;
+}
+
+static void etrax_usb_check_error_isoc_ep(const int epid)
+{
+       unsigned long int flags;
+       int error_code;
+       __u32 r_usb_ept_data;
+
+       /* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof,
+          bulk_eot and epid_attn interrupts.  So we just check the status of
+          the epid without testing if for it in R_USB_EPID_ATTN. */
+
+
+       save_flags(flags);
+       cli();
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+       nop();
+       /* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
+          registers, they are located at the same address and are of the same size.
+          In other words, this read should be ok for isoc also. */
+       r_usb_ept_data = *R_USB_EPT_DATA;
+       restore_flags(flags);
+
+       error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
+
+       if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+               warn("Hold was set for epid %d.", epid);
+               return;
+       }
+
+       if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) {
+
+               /* This indicates that the SB list of the ept was completed before
+                  new data was appended to it.  This is not an error, but indicates
+                  large system or USB load and could possibly cause trouble for
+                  very timing sensitive USB device drivers so we log it.
+               */
+               info("Isoc. epid %d disabled with no error", epid);
+               return;
+
+       } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) {
+               /* Not really a protocol error, just says that the endpoint gave
+                  a stall response. Note that error_code cannot be stall for isoc. */
+               panic("Isoc traffic cannot stall");
+
+       } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) {
+               /* Two devices responded to a transaction request. Must be resolved
+                  by software. FIXME: Reset ports? */
+               panic("Bus error for epid %d."
+                     " Two devices responded to transaction request",
+                     epid);
+
+       } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+               /* DMA overrun or underrun. */
+               warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+
+               /* It seems that error_code = buffer_error in
+                  R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
+                  are the same error. */
+       }
+}
+
+
+static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
+{
+
+       int i = 0;
+
+       etrax_urb_priv_t *urb_priv;
+       USB_SB_Desc_t *prev_sb_desc,  *next_sb_desc, *temp_sb_desc;
+
+       DBFENTER;
+
+       prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
+
+       urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+       assert(urb_priv != NULL);
+       memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
+
+       urb->hcpriv = urb_priv;
+       urb_priv->epid = epid;
+
+       if (usb_pipeout(urb->pipe)) {
+
+               if (urb->number_of_packets == 0) panic("etrax_usb_add_to_isoc_sb_list 0 packets\n");
+
+               dbg_isoc("Transfer for epid %d is OUT", epid);
+               dbg_isoc("%d packets in URB", urb->number_of_packets);
+
+               /* Create one SB descriptor for each packet and link them together. */
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       if (!urb->iso_frame_desc[i].length)
+                               continue;
+
+                       next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
+                       assert(next_sb_desc != NULL);
+
+                       if (urb->iso_frame_desc[i].length > 0) {
+
+                               next_sb_desc->command = (IO_STATE(USB_SB_command, tt, out) |
+                                                        IO_STATE(USB_SB_command, eot, yes));
+
+                               next_sb_desc->sw_len = urb->iso_frame_desc[i].length;
+                               next_sb_desc->buf = virt_to_phys((char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset);
+
+                               /* Check if full length transfer. */
+                               if (urb->iso_frame_desc[i].length ==
+                                   usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
+                                       next_sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
+                               }
+                       } else {
+                               dbg_isoc("zero len packet");
+                               next_sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
+                                                        IO_STATE(USB_SB_command, tt, zout) |
+                                                        IO_STATE(USB_SB_command, eot, yes) |
+                                                        IO_STATE(USB_SB_command, full, yes));
+
+                               next_sb_desc->sw_len = 1;
+                               next_sb_desc->buf = virt_to_phys(&zout_buffer[0]);
+                       }
+
+                       /* First SB descriptor that belongs to this urb */
+                       if (i == 0)
+                               urb_priv->first_sb = next_sb_desc;
+                       else
+                               prev_sb_desc->next = virt_to_phys(next_sb_desc);
+
+                       prev_sb_desc = next_sb_desc;
+               }
+
+               next_sb_desc->command |= (IO_STATE(USB_SB_command, intr, yes) |
+                                         IO_STATE(USB_SB_command, eol, yes));
+               next_sb_desc->next = 0;
+               urb_priv->last_sb = next_sb_desc;
+
+       } else if (usb_pipein(urb->pipe)) {
+
+               dbg_isoc("Transfer for epid %d is IN", epid);
+               dbg_isoc("transfer_buffer_length = %d", urb->transfer_buffer_length);
+               dbg_isoc("rem is calculated to %d", urb->iso_frame_desc[urb->number_of_packets - 1].length);
+
+               /* Note that in descriptors for periodic traffic are not consumed. This means that
+                  the USB controller never propagates in the SB list. In other words, if there already
+                  is an SB descriptor in the list for this EP we don't have to do anything. */
+               if (TxIsocEPList[epid].sub == 0) {
+                       dbg_isoc("Isoc traffic not already running, allocating SB");
+
+                       next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC);
+                       assert(next_sb_desc != NULL);
+
+                       next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) |
+                                                IO_STATE(USB_SB_command, eot, yes) |
+                                                IO_STATE(USB_SB_command, eol, yes));
+
+                       next_sb_desc->next = 0;
+                       next_sb_desc->sw_len = 1; /* Actual number of packets is not relevant
+                                                    for periodic in traffic as long as it is more
+                                                    than zero.  Set to 1 always. */
+                       next_sb_desc->buf = 0;
+
+                       /* The rem field is don't care for isoc traffic, so we don't set it. */
+
+                       /* Only one SB descriptor that belongs to this urb. */
+                       urb_priv->first_sb = next_sb_desc;
+                       urb_priv->last_sb = next_sb_desc;
+
+               } else {
+
+                       dbg_isoc("Isoc traffic already running, just setting first/last_sb");
+
+                       /* Each EP for isoc in will have only one SB descriptor, setup when submitting the
+                          already active urb. Note that even though we may have several first_sb/last_sb
+                          pointing at the same SB descriptor, they are freed only once (when the list has
+                          become empty). */
+                       urb_priv->first_sb = phys_to_virt(TxIsocEPList[epid].sub);
+                       urb_priv->last_sb = phys_to_virt(TxIsocEPList[epid].sub);
+                       return;
+               }
+
+       }
+
+       /* Find the spot to insert this urb and add it. */
+       if (TxIsocEPList[epid].sub == 0) {
+               /* First SB descriptor inserted in this list (in or out). */
+               dbg_isoc("Inserting SB desc first in list");
+               TxIsocEPList[epid].hw_len = 0;
+               TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
+
+       } else {
+               /* Isochronous traffic is already running, insert new traffic last (only out). */
+               dbg_isoc("Inserting SB desc last in list");
+               temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
+               while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
+                      IO_STATE(USB_SB_command, eol, yes)) {
+                       assert(temp_sb_desc->next);
+                       temp_sb_desc = phys_to_virt(temp_sb_desc->next);
+               }
+               dbg_isoc("Appending list on desc 0x%p", temp_sb_desc);
+
+               /* Next pointer must be set before eol is removed. */
+               temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
+               /* Clear the previous end of list flag since there is a new in the
+                  added SB descriptor list. */
+               temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
+
+               if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
+                       /* 8.8.5 in Designer's Reference says we should check for and correct
+                          any errors in the EP here.  That should not be necessary if epid_attn
+                          is handled correctly, so we assume all is ok. */
+                       dbg_isoc("EP disabled");
+                       etrax_usb_check_error_isoc_ep(epid);
+
+                       /* The SB list was exhausted. */
+                       if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
+                               /* The new sublist did not get processed before the EP was
+                                  disabled.  Setup the EP again. */
+                               dbg_isoc("Set EP sub to new list");
+                               TxIsocEPList[epid].hw_len = 0;
+                               TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
+                       }
+               }
+       }
+
+       if (urb->transfer_flags & URB_ISO_ASAP) {
+               /* The isoc transfer should be started as soon as possible. The start_frame
+                  field is a return value if URB_ISO_ASAP was set. Comparing R_USB_FM_NUMBER
+                  with a USB Chief trace shows that the first isoc IN token is sent 2 frames
+                  later. I'm not sure how this affects usage of the start_frame field by the
+                  device driver, or how it affects things when USB_ISO_ASAP is not set, so
+                  therefore there's no compensation for the 2 frame "lag" here. */
+               urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
+               TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+               urb_priv->urb_state = STARTED;
+               dbg_isoc("URB_ISO_ASAP set, urb->start_frame set to %d", urb->start_frame);
+       } else {
+               /* Not started yet. */
+               urb_priv->urb_state = NOT_STARTED;
+               dbg_isoc("urb_priv->urb_state set to NOT_STARTED");
+       }
+
+       /* We start the DMA sub channel without checking if it's running or not, because:
+         1) If it's already running, issuing the start command is a nop.
+         2) We avoid a test-and-set race condition. */
+       *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
+
+       DBFEXIT;
+}
+
+static void etrax_usb_complete_isoc_urb(struct urb *urb, int status)
+{
+       etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+       int epid = urb_priv->epid;
+       int auto_resubmit = 0;
+
+       DBFENTER;
+       dbg_isoc("complete urb 0x%p, status %d", urb, status);
+
+       if (status)
+               warn("Completing isoc urb with status %d.", status);
+
+       if (usb_pipein(urb->pipe)) {
+               int i;
+
+               /* Make that all isoc packets have status and length set before
+                  completing the urb. */
+               for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++) {
+                       urb->iso_frame_desc[i].actual_length = 0;
+                       urb->iso_frame_desc[i].status = -EPROTO;
+               }
+
+               urb_list_del(urb, epid);
+
+               if (!list_empty(&urb_list[epid])) {
+                       ((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
+               } else {
+                       unsigned long int flags;
+                       if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+                               /* The EP was enabled, disable it and wait. */
+                               TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
+
+                               /* Ah, the luxury of busy-wait. */
+                               while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
+                       }
+
+                       etrax_remove_from_sb_list(urb);
+                       TxIsocEPList[epid].sub = 0;
+                       TxIsocEPList[epid].hw_len = 0;
+
+                       save_flags(flags);
+                       cli();
+                       etrax_usb_free_epid(epid);
+                       restore_flags(flags);
+               }
+
+               urb->hcpriv = 0;
+               kfree(urb_priv);
+
+               /* Release allocated bandwidth. */
+               usb_release_bandwidth(urb->dev, urb, 0);
+       } else if (usb_pipeout(urb->pipe)) {
+               int freed_descr;
+
+               dbg_isoc("Isoc out urb complete 0x%p", urb);
+
+               /* Update the urb list. */
+               urb_list_del(urb, epid);
+
+               freed_descr = etrax_remove_from_sb_list(urb);
+               dbg_isoc("freed %d descriptors of %d packets", freed_descr, urb->number_of_packets);
+               assert(freed_descr == urb->number_of_packets);
+               urb->hcpriv = 0;
+               kfree(urb_priv);
+
+               /* Release allocated bandwidth. */
+               usb_release_bandwidth(urb->dev, urb, 0);
+       }
+
+       urb->status = status;
+       if (urb->complete) {
+               urb->complete(urb, NULL);
+       }
+
+       if (auto_resubmit) {
+               /* Check that urb was not unlinked by the complete callback. */
+               if (__urb_list_entry(urb, epid)) {
+                       /* Move this one down the list. */
+                       urb_list_move_last(urb, epid);
+
+                       /* Mark the now first urb as started (may already be). */
+                       ((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
+
+                       /* Must set this to 0 since this urb is still active after
+                          completion. */
+                       urb_priv->isoc_packet_counter = 0;
+               } else {
+                       warn("(ISOC) automatic resubmit urb 0x%p removed by complete.", urb);
+               }
+       }
+
+       DBFEXIT;
+}
+
+static void etrax_usb_complete_urb(struct urb *urb, int status)
+{
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_BULK:
+               etrax_usb_complete_bulk_urb(urb, status);
+               break;
+       case PIPE_CONTROL:
+               etrax_usb_complete_ctrl_urb(urb, status);
+               break;
+       case PIPE_INTERRUPT:
+               etrax_usb_complete_intr_urb(urb, status);
+               break;
+       case PIPE_ISOCHRONOUS:
+               etrax_usb_complete_isoc_urb(urb, status);
+               break;
+       default:
+               err("Unknown pipetype");
+       }
+}
+
+
+
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs)
+{
+       usb_interrupt_registers_t *reg;
+       unsigned long flags;
+       __u32 irq_mask;
+       __u8 status;
+       __u32 epid_attn;
+       __u16 port_status_1;
+       __u16 port_status_2;
+       __u32 fm_number;
+
+       DBFENTER;
+
+       /* Read critical registers into local variables, do kmalloc afterwards. */
+       save_flags(flags);
+       cli();
+
+       irq_mask = *R_USB_IRQ_MASK_READ;
+       /* Reading R_USB_STATUS clears the ctl_status interrupt. Note that R_USB_STATUS
+          must be read before R_USB_EPID_ATTN since reading the latter clears the
+          ourun and perror fields of R_USB_STATUS. */
+       status = *R_USB_STATUS;
+
+       /* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn interrupts. */
+       epid_attn = *R_USB_EPID_ATTN;
+
+       /* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
+          port_status interrupt. */
+       port_status_1 = *R_USB_RH_PORT_STATUS_1;
+       port_status_2 = *R_USB_RH_PORT_STATUS_2;
+
+       /* Reading R_USB_FM_NUMBER clears the sof interrupt. */
+       /* Note: the lower 11 bits contain the actual frame number, sent with each sof. */
+       fm_number = *R_USB_FM_NUMBER;
+
+       restore_flags(flags);
+
+       reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, SLAB_ATOMIC);
+
+       assert(reg != NULL);
+
+       reg->hc = (etrax_hc_t *)vhc;
+
+       /* Now put register values into kmalloc'd area. */
+       reg->r_usb_irq_mask_read = irq_mask;
+       reg->r_usb_status = status;
+       reg->r_usb_epid_attn = epid_attn;
+       reg->r_usb_rh_port_status_1 = port_status_1;
+       reg->r_usb_rh_port_status_2 = port_status_2;
+       reg->r_usb_fm_number = fm_number;
+
+        INIT_WORK(&reg->usb_bh, etrax_usb_hc_interrupt_bottom_half, reg);
+        schedule_work(&reg->usb_bh);
+
+       DBFEXIT;
+
+        return IRQ_HANDLED;
+}
+
+static void etrax_usb_hc_interrupt_bottom_half(void *data)
+{
+       usb_interrupt_registers_t *reg = (usb_interrupt_registers_t *)data;
+       __u32 irq_mask = reg->r_usb_irq_mask_read;
+
+       DBFENTER;
+
+       /* Interrupts are handled in order of priority. */
+       if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
+               etrax_usb_hc_epid_attn_interrupt(reg);
+       }
+       if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
+               etrax_usb_hc_port_status_interrupt(reg);
+       }
+       if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
+               etrax_usb_hc_ctl_status_interrupt(reg);
+       }
+       if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
+               etrax_usb_hc_isoc_eof_interrupt();
+       }
+       if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
+               /* Update/restart the bulk start timer since obviously the channel is running. */
+               mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
+               /* Update/restart the bulk eot timer since we just received an bulk eot interrupt. */
+               mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+
+               etrax_usb_hc_bulk_eot_interrupt(0);
+       }
+
+       kmem_cache_free(top_half_reg_cache, reg);
+
+       DBFEXIT;
+}
+
+
+void etrax_usb_hc_isoc_eof_interrupt(void)
+{
+       struct urb *urb;
+       etrax_urb_priv_t *urb_priv;
+       int epid;
+       unsigned long flags;
+
+       DBFENTER;
+
+       /* Do not check the invalid epid (it has a valid sub pointer). */
+       for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
+
+               /* Do not check the invalid epid (it has a valid sub pointer). */
+               if ((epid == DUMMY_EPID) || (epid == INVALID_EPID))
+                       continue;
+
+               /* Disable interrupts to block the isoc out descriptor interrupt handler
+                  from being called while the isoc EPID list is being checked.
+               */
+               save_flags(flags);
+               cli();
+
+               if (TxIsocEPList[epid].sub == 0) {
+                       /* Nothing here to see. */
+                       restore_flags(flags);
+                       continue;
+               }
+
+               /* Get the first urb (if any). */
+               urb = urb_list_first(epid);
+               if (urb == 0) {
+                       warn("Ignoring NULL urb");
+                       restore_flags(flags);
+                       continue;
+               }
+               if (usb_pipein(urb->pipe)) {
+
+                       /* Sanity check. */
+                       assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
+
+                       urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+                       assert(urb_priv);
+
+                       if (urb_priv->urb_state == NOT_STARTED) {
+
+                               /* If ASAP is not set and urb->start_frame is the current frame,
+                                  start the transfer. */
+                               if (!(urb->transfer_flags & URB_ISO_ASAP) &&
+                                   (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
+
+                                       dbg_isoc("Enabling isoc IN EP descr for epid %d", epid);
+                                       TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
+
+                                       /* This urb is now active. */
+                                       urb_priv->urb_state = STARTED;
+                                       continue;
+                               }
+                       }
+               }
+               restore_flags(flags);
+       }
+
+       DBFEXIT;
+
+}
+
+void etrax_usb_hc_bulk_eot_interrupt(int timer_induced)
+{
+       int epid;
+
+       /* The technique is to run one urb at a time, wait for the eot interrupt at which
+          point the EP descriptor has been disabled. */
+
+       DBFENTER;
+       dbg_bulk("bulk eot%s", timer_induced ? ", called by timer" : "");
+
+       for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+
+               if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
+                   (TxBulkEPList[epid].sub != 0)) {
+
+                       struct urb *urb;
+                       etrax_urb_priv_t *urb_priv;
+                       unsigned long flags;
+                       __u32 r_usb_ept_data;
+
+                       /* Found a disabled EP descriptor which has a non-null sub pointer.
+                          Verify that this ctrl EP descriptor got disabled no errors.
+                          FIXME: Necessary to check error_code? */
+                       dbg_bulk("for epid %d?", epid);
+
+                       /* Get the first urb. */
+                       urb = urb_list_first(epid);
+
+                       /* FIXME: Could this happen for valid reasons? Why did it disappear? Because of
+                          wrong unlinking? */
+                       if (!urb) {
+                               warn("NULL urb for epid %d", epid);
+                               continue;
+                       }
+
+                       assert(urb);
+                       urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
+                       assert(urb_priv);
+
+                       /* Sanity checks. */
+                       assert(usb_pipetype(urb->pipe) == PIPE_BULK);
+                       if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
+                               err("bulk endpoint got disabled before reaching last sb");
+                       }
+
+                       /* For bulk IN traffic, there seems to be a race condition between
+                          between the bulk eot and eop interrupts, or rather an uncertainty regarding
+                          the order in which they happen. Normally we expect the eop interrupt from
+                          DMA channel 9 to happen before the eot interrupt.
+
+                          Therefore, we complete the bulk IN urb in the rx interrupt handler instead. */
+
+                       if (usb_pipein(urb->pipe)) {
+                               dbg_bulk("in urb, continuing");
+                               continue;
+                       }
+
+                       save_flags(flags);
+                       cli();
+                       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+                       nop();
+                       r_usb_ept_data = *R_USB_EPT_DATA;
+                       restore_flags(flags);
+
+                       if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
+                           IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+                               /* This means that the endpoint has no error, is disabled
+                                  and had inserted traffic, i.e. transfer successfully completed. */
+                               etrax_usb_complete_bulk_urb(urb, 0);
+                       } else {
+                               /* Shouldn't happen. We expect errors to be caught by epid attention. */
+                               err("Found disabled bulk EP desc, error_code != no_error");
+                       }
+               }
+       }
+
+       /* Normally, we should find (at least) one disabled EP descriptor with a valid sub pointer.
+          However, because of the uncertainty in the deliverance of the eop/eot interrupts, we may
+          not.  Also, we might find two disabled EPs when handling an eot interrupt, and then find
+          none the next time. */
+
+       DBFEXIT;
+
+}
+
+void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg)
+{
+       /* This function handles the epid attention interrupt.  There are a variety of reasons
+          for this interrupt to happen (Designer's Reference, p. 8 - 22 for the details):
+
+          invalid ep_id  - Invalid epid in an EP (EP disabled).
+          stall          - Not strictly an error condition (EP disabled).
+          3rd error      - Three successive transaction errors  (EP disabled).
+          buffer ourun   - Buffer overrun or underrun (EP disabled).
+          past eof1      - Intr or isoc transaction proceeds past EOF1.
+          near eof       - Intr or isoc transaction would not fit inside the frame.
+          zout transfer  - If zout transfer for a bulk endpoint (EP disabled).
+          setup transfer - If setup transfer for a non-ctrl endpoint (EP disabled). */
+
+       int epid;
+
+
+       DBFENTER;
+
+       assert(reg != NULL);
+
+       /* Note that we loop through all epids. We still want to catch errors for
+          the invalid one, even though we might handle them differently. */
+       for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+
+               if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
+
+                       struct urb *urb;
+                       __u32 r_usb_ept_data;
+                       unsigned long flags;
+                       int error_code;
+
+                       save_flags(flags);
+                       cli();
+                       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
+                       nop();
+                       /* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
+                          registers, they are located at the same address and are of the same size.
+                          In other words, this read should be ok for isoc also. */
+                       r_usb_ept_data = *R_USB_EPT_DATA;
+                       restore_flags(flags);
+
+                       /* First some sanity checks. */
+                       if (epid == INVALID_EPID) {
+                               /* FIXME: What if it became disabled? Could seriously hurt interrupt
+                                  traffic. (Use do_intr_recover.) */
+                               warn("Got epid_attn for INVALID_EPID (%d).", epid);
+                               err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
+                               err("R_USB_STATUS = 0x%x", reg->r_usb_status);
+                               continue;
+                       } else  if (epid == DUMMY_EPID) {
+                               /* We definitely don't care about these ones. Besides, they are
+                                  always disabled, so any possible disabling caused by the
+                                  epid attention interrupt is irrelevant. */
+                               warn("Got epid_attn for DUMMY_EPID (%d).", epid);
+                               continue;
+                       }
+
+                       /* Get the first urb in the urb list for this epid. We blatantly assume
+                          that only the first urb could have caused the epid attention.
+                          (For bulk and ctrl, only one urb is active at any one time. For intr
+                          and isoc we remove them once they are completed.) */
+                       urb = urb_list_first(epid);
+
+                       if (urb == NULL) {
+                               err("Got epid_attn for epid %i with no urb.", epid);
+                               err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
+                               err("R_USB_STATUS = 0x%x", reg->r_usb_status);
+                               continue;
+                       }
+
+                       switch (usb_pipetype(urb->pipe)) {
+                       case PIPE_BULK:
+                               warn("Got epid attn for bulk endpoint, epid %d", epid);
+                               break;
+                       case PIPE_CONTROL:
+                               warn("Got epid attn for control endpoint, epid %d", epid);
+                               break;
+                       case PIPE_INTERRUPT:
+                               warn("Got epid attn for interrupt endpoint, epid %d", epid);
+                               break;
+                       case PIPE_ISOCHRONOUS:
+                               warn("Got epid attn for isochronous endpoint, epid %d", epid);
+                               break;
+                       }
+
+                       if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
+                               if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
+                                       warn("Hold was set for epid %d.", epid);
+                                       continue;
+                               }
+                       }
+
+                       /* Even though error_code occupies bits 22 - 23 in both R_USB_EPT_DATA and
+                          R_USB_EPT_DATA_ISOC, we separate them here so we don't forget in other places. */
+                       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                               error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
+                       } else {
+                               error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data);
+                       }
+
+                       /* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
+                       if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
+
+                               /* Isoc traffic doesn't have error_count_in/error_count_out. */
+                               if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
+                                   (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3 ||
+                                    IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3)) {
+                                       /* 3rd error. */
+                                       warn("3rd error for epid %i", epid);
+                                       etrax_usb_complete_urb(urb, -EPROTO);
+
+                               } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+
+                                       warn("Perror for epid %d", epid);
+
+                                       if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
+                                               /* invalid ep_id */
+                                               panic("Perror because of invalid epid."
+                                                     " Deconfigured too early?");
+                                       } else {
+                                               /* past eof1, near eof, zout transfer, setup transfer */
+
+                                               /* Dump the urb and the relevant EP descriptor list. */
+
+                                               __dump_urb(urb);
+                                               __dump_ept_data(epid);
+                                               __dump_ep_list(usb_pipetype(urb->pipe));
+
+                                               panic("Something wrong with DMA descriptor contents."
+                                                     " Too much traffic inserted?");
+                                       }
+                               } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+                                       /* buffer ourun */
+                                       panic("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+                               }
+
+                       } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) {
+                               /* Not really a protocol error, just says that the endpoint gave
+                                  a stall response. Note that error_code cannot be stall for isoc. */
+                               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                                       panic("Isoc traffic cannot stall");
+                               }
+
+                               warn("Stall for epid %d", epid);
+                               etrax_usb_complete_urb(urb, -EPIPE);
+
+                       } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) {
+                               /* Two devices responded to a transaction request. Must be resolved
+                                  by software. FIXME: Reset ports? */
+                               panic("Bus error for epid %d."
+                                     " Two devices responded to transaction request",
+                                     epid);
+
+                       } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
+                               /* DMA overrun or underrun. */
+                               warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
+
+                               /* It seems that error_code = buffer_error in
+                                  R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
+                                  are the same error. */
+                               etrax_usb_complete_urb(urb, -EPROTO);
+                       }
+               }
+       }
+
+       DBFEXIT;
+
+}
+
+void etrax_usb_bulk_start_timer_func(unsigned long dummy)
+{
+
+       /* We might enable an EP descriptor behind the current DMA position when it's about
+          to decide that there are no more bulk traffic and it should stop the bulk channel.
+          Therefore we periodically check if the bulk channel is stopped and there is an
+          enabled bulk EP descriptor, in which case we start the bulk channel. */
+       dbg_bulk("bulk_start_timer timed out.");
+
+       if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
+               int epid;
+
+               dbg_bulk("Bulk DMA channel not running.");
+
+               for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
+                       if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
+                               dbg_bulk("Found enabled EP for epid %d, starting bulk channel.\n",
+                                        epid);
+                               *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
+
+                               /* Restart the bulk eot timer since we just started the bulk channel. */
+                               mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
+
+                               /* No need to search any further. */
+                               break;
+                       }
+               }
+       } else {
+               dbg_bulk("Bulk DMA channel running.");
+       }
+}
+
+void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg)
+{
+       etrax_hc_t *hc = reg->hc;
+       __u16 r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1;
+       __u16 r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2;
+
+       DBFENTER;
+
+       /* The Etrax RH does not include a wPortChange register, so this has to be handled in software
+          (by saving the old port status value for comparison when the port status interrupt happens).
+          See section 11.16.2.6.2 in the USB 1.1 spec for details. */
+
+       dbg_rh("hc->rh.prev_wPortStatus_1 = 0x%x", hc->rh.prev_wPortStatus_1);
+       dbg_rh("hc->rh.prev_wPortStatus_2 = 0x%x", hc->rh.prev_wPortStatus_2);
+       dbg_rh("r_usb_rh_port_status_1 = 0x%x", r_usb_rh_port_status_1);
+       dbg_rh("r_usb_rh_port_status_2 = 0x%x", r_usb_rh_port_status_2);
+
+       /* C_PORT_CONNECTION is set on any transition. */
+       hc->rh.wPortChange_1 |=
+               ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) !=
+                (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ?
+               (1 << RH_PORT_CONNECTION) : 0;
+
+       hc->rh.wPortChange_2 |=
+               ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) !=
+                (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ?
+               (1 << RH_PORT_CONNECTION) : 0;
+
+       /* C_PORT_ENABLE is _only_ set on a one to zero transition, i.e. when
+          the port is disabled, not when it's enabled. */
+       hc->rh.wPortChange_1 |=
+               ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE))
+                && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
+               (1 << RH_PORT_ENABLE) : 0;
+
+       hc->rh.wPortChange_2 |=
+               ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE))
+                && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
+               (1 << RH_PORT_ENABLE) : 0;
+
+       /* C_PORT_SUSPEND is set to one when the device has transitioned out
+          of the suspended state, i.e. when suspend goes from one to zero. */
+       hc->rh.wPortChange_1 |=
+               ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_SUSPEND))
+                && !(r_usb_rh_port_status_1 & (1 << RH_PORT_SUSPEND))) ?
+               (1 << RH_PORT_SUSPEND) : 0;
+
+       hc->rh.wPortChange_2 |=
+               ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_SUSPEND))
+                && !(r_usb_rh_port_status_2 & (1 << RH_PORT_SUSPEND))) ?
+               (1 << RH_PORT_SUSPEND) : 0;
+
+
+       /* C_PORT_RESET is set when reset processing on this port is complete. */
+       hc->rh.wPortChange_1 |=
+               ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET))
+                && !(r_usb_rh_port_status_1 & (1 << RH_PORT_RESET))) ?
+               (1 << RH_PORT_RESET) : 0;
+
+       hc->rh.wPortChange_2 |=
+               ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET))
+                && !(r_usb_rh_port_status_2 & (1 << RH_PORT_RESET))) ?
+               (1 << RH_PORT_RESET) : 0;
+
+       /* Save the new values for next port status change. */
+       hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1;
+       hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2;
+
+       dbg_rh("hc->rh.wPortChange_1 set to 0x%x", hc->rh.wPortChange_1);
+       dbg_rh("hc->rh.wPortChange_2 set to 0x%x", hc->rh.wPortChange_2);
+
+       DBFEXIT;
+
+}
+
+void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg)
+{
+       DBFENTER;
+
+       /* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
+          list for the corresponding epid? */
+       if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
+               panic("USB controller got ourun.");
+       }
+       if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
+
+               /* Before, etrax_usb_do_intr_recover was called on this epid if it was
+                  an interrupt pipe. I don't see how re-enabling all EP descriptors
+                  will help if there was a programming error. */
+               panic("USB controller got perror.");
+       }
+
+       if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
+               /* We should never operate in device mode. */
+               panic("USB controller in device mode.");
+       }
+
+       /* These if-statements could probably be nested. */
+       if (reg->r_usb_status & IO_MASK(R_USB_STATUS, host_mode)) {
+               info("USB controller in host mode.");
+       }
+       if (reg->r_usb_status & IO_MASK(R_USB_STATUS, started)) {
+               info("USB controller started.");
+       }
+       if (reg->r_usb_status & IO_MASK(R_USB_STATUS, running)) {
+               info("USB controller running.");
+       }
+
+       DBFEXIT;
+
+}
+
+
+static int etrax_rh_submit_urb(struct urb *urb)
+{
+       struct usb_device *usb_dev = urb->dev;
+       etrax_hc_t *hc = usb_dev->bus->hcpriv;
+       unsigned int pipe = urb->pipe;
+       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+       void *data = urb->transfer_buffer;
+       int leni = urb->transfer_buffer_length;
+       int len = 0;
+       int stat = 0;
+
+       __u16 bmRType_bReq;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+
+       DBFENTER;
+
+       /* FIXME: What is this interrupt urb that is sent to the root hub? */
+       if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+               dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval);
+               hc->rh.urb = urb;
+               hc->rh.send = 1;
+               /* FIXME: We could probably remove this line since it's done
+                  in etrax_rh_init_int_timer. (Don't remove it from
+                  etrax_rh_init_int_timer though.) */
+               hc->rh.interval = urb->interval;
+               etrax_rh_init_int_timer(urb);
+               DBFEXIT;
+
+               return 0;
+       }
+
+       bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+       wValue = le16_to_cpu(cmd->wValue);
+       wIndex = le16_to_cpu(cmd->wIndex);
+       wLength = le16_to_cpu(cmd->wLength);
+
+       dbg_rh("bmRType_bReq : 0x%04x (%d)", bmRType_bReq, bmRType_bReq);
+       dbg_rh("wValue       : 0x%04x (%d)", wValue, wValue);
+       dbg_rh("wIndex       : 0x%04x (%d)", wIndex, wIndex);
+       dbg_rh("wLength      : 0x%04x (%d)", wLength, wLength);
+
+       switch (bmRType_bReq) {
+
+               /* Request Destination:
+                  without flags: Device,
+                  RH_INTERFACE: interface,
+                  RH_ENDPOINT: endpoint,
+                  RH_CLASS means HUB here,
+                  RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+                */
+
+       case RH_GET_STATUS:
+               *(__u16 *) data = cpu_to_le16 (1);
+               OK (2);
+
+       case RH_GET_STATUS | RH_INTERFACE:
+               *(__u16 *) data = cpu_to_le16 (0);
+               OK (2);
+
+       case RH_GET_STATUS | RH_ENDPOINT:
+               *(__u16 *) data = cpu_to_le16 (0);
+               OK (2);
+
+       case RH_GET_STATUS | RH_CLASS:
+               *(__u32 *) data = cpu_to_le32 (0);
+               OK (4);         /* hub power ** */
+
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+               if (wIndex == 1) {
+                       *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
+                       *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
+               } else if (wIndex == 2) {
+                       *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
+                       *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
+               } else {
+                       dbg_rh("RH_GET_STATUS whith invalid wIndex!");
+                       OK(0);
+               }
+
+               OK(4);
+
+       case RH_CLEAR_FEATURE | RH_ENDPOINT:
+               switch (wValue) {
+               case (RH_ENDPOINT_STALL):
+                       OK (0);
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_CLASS:
+               switch (wValue) {
+               case (RH_C_HUB_OVER_CURRENT):
+                       OK (0); /* hub power over current ** */
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+               case (RH_PORT_ENABLE):
+                       if (wIndex == 1) {
+
+                               dbg_rh("trying to do disable port 1");
+
+                               *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
+
+                               while (hc->rh.prev_wPortStatus_1 &
+                                      IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes));
+                               *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+                               dbg_rh("Port 1 is disabled");
+
+                       } else if (wIndex == 2) {
+
+                               dbg_rh("trying to do disable port 2");
+
+                               *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
+
+                               while (hc->rh.prev_wPortStatus_2 &
+                                      IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes));
+                               *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+                               dbg_rh("Port 2 is disabled");
+
+                       } else {
+                               dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE "
+                                      "with invalid wIndex == %d!", wIndex);
+                       }
+
+                       OK (0);
+               case (RH_PORT_SUSPEND):
+                       /* Opposite to suspend should be resume, so we'll do a resume. */
+                       /* FIXME: USB 1.1, 11.16.2.2 says:
+                          "Clearing the PORT_SUSPEND feature causes a host-initiated resume
+                          on the specified port. If the port is not in the Suspended state,
+                          the hub should treat this request as a functional no-operation."
+                          Shouldn't we check if the port is in a suspended state before
+                          resuming? */
+
+                       /* Make sure the controller isn't busy. */
+                       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+                       if (wIndex == 1) {
+                               *R_USB_COMMAND =
+                                       IO_STATE(R_USB_COMMAND, port_sel, port1) |
+                                       IO_STATE(R_USB_COMMAND, port_cmd, resume) |
+                                       IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+                       } else if (wIndex == 2) {
+                               *R_USB_COMMAND =
+                                       IO_STATE(R_USB_COMMAND, port_sel, port2) |
+                                       IO_STATE(R_USB_COMMAND, port_cmd, resume) |
+                                       IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+                       } else {
+                               dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND "
+                                      "with invalid wIndex == %d!", wIndex);
+                       }
+
+                       OK (0);
+               case (RH_PORT_POWER):
+                       OK (0); /* port power ** */
+               case (RH_C_PORT_CONNECTION):
+                       if (wIndex == 1) {
+                               hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
+                       } else if (wIndex == 2) {
+                               hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
+                       } else {
+                               dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
+                                      "with invalid wIndex == %d!", wIndex);
+                       }
+
+                       OK (0);
+               case (RH_C_PORT_ENABLE):
+                       if (wIndex == 1) {
+                               hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE);
+                       } else if (wIndex == 2) {
+                               hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE);
+                       } else {
+                               dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE "
+                                      "with invalid wIndex == %d!", wIndex);
+                       }
+                       OK (0);
+               case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+                       OK (0);
+               case (RH_C_PORT_OVER_CURRENT):
+                       OK (0); /* port power over current ** */
+               case (RH_C_PORT_RESET):
+                       if (wIndex == 1) {
+                               hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET);
+                       } else if (wIndex == 2) {
+                               hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET);
+                       } else {
+                               dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET "
+                                      "with invalid index == %d!", wIndex);
+                       }
+
+                       OK (0);
+
+               }
+               break;
+
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+               case (RH_PORT_SUSPEND):
+
+                       /* Make sure the controller isn't busy. */
+                       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+                       if (wIndex == 1) {
+                               *R_USB_COMMAND =
+                                       IO_STATE(R_USB_COMMAND, port_sel, port1) |
+                                       IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+                                       IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+                       } else if (wIndex == 2) {
+                               *R_USB_COMMAND =
+                                       IO_STATE(R_USB_COMMAND, port_sel, port2) |
+                                       IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
+                                       IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+                       } else {
+                               dbg_rh("RH_SET_FEATURE->RH_PORT_SUSPEND "
+                                      "with invalid wIndex == %d!", wIndex);
+                       }
+
+                       OK (0);
+               case (RH_PORT_RESET):
+                       if (wIndex == 1) {
+
+                       port_1_reset:
+                               dbg_rh("Doing reset of port 1");
+
+                               /* Make sure the controller isn't busy. */
+                               while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+                               *R_USB_COMMAND =
+                                       IO_STATE(R_USB_COMMAND, port_sel, port1) |
+                                       IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+                                       IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+
+                               /* We must wait at least 10 ms for the device to recover.
+                                  15 ms should be enough. */
+                               udelay(15000);
+
+                               /* Wait for reset bit to go low (should be done by now). */
+                               while (hc->rh.prev_wPortStatus_1 &
+                                      IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes));
+
+                               /* If the port status is
+                                  1) connected and enabled then there is a device and everything is fine
+                                  2) neither connected nor enabled then there is no device, also fine
+                                  3) connected and not enabled then we try again
+                                  (Yes, there are other port status combinations besides these.) */
+
+                               if ((hc->rh.prev_wPortStatus_1 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
+                                   (hc->rh.prev_wPortStatus_1 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
+                                       dbg_rh("Connected device on port 1, but port not enabled?"
+                                              " Trying reset again.");
+                                       goto port_2_reset;
+                               }
+
+                               /* Diagnostic printouts. */
+                               if ((hc->rh.prev_wPortStatus_1 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_1, connected, no)) &&
+                                   (hc->rh.prev_wPortStatus_1 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
+                                       dbg_rh("No connected device on port 1");
+                               } else if ((hc->rh.prev_wPortStatus_1 &
+                                           IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
+                                          (hc->rh.prev_wPortStatus_1 &
+                                           IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) {
+                                       dbg_rh("Connected device on port 1, port 1 enabled");
+                               }
+
+                       } else if (wIndex == 2) {
+
+                       port_2_reset:
+                               dbg_rh("Doing reset of port 2");
+
+                               /* Make sure the controller isn't busy. */
+                               while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+                               /* Issue the reset command. */
+                               *R_USB_COMMAND =
+                                       IO_STATE(R_USB_COMMAND, port_sel, port2) |
+                                       IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+                                       IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
+
+                               /* We must wait at least 10 ms for the device to recover.
+                                  15 ms should be enough. */
+                               udelay(15000);
+
+                               /* Wait for reset bit to go low (should be done by now). */
+                               while (hc->rh.prev_wPortStatus_2 &
+                                      IO_STATE(R_USB_RH_PORT_STATUS_2, reset, yes));
+
+                               /* If the port status is
+                                  1) connected and enabled then there is a device and everything is fine
+                                  2) neither connected nor enabled then there is no device, also fine
+                                  3) connected and not enabled then we try again
+                                  (Yes, there are other port status combinations besides these.) */
+
+                               if ((hc->rh.prev_wPortStatus_2 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
+                                   (hc->rh.prev_wPortStatus_2 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
+                                       dbg_rh("Connected device on port 2, but port not enabled?"
+                                              " Trying reset again.");
+                                       goto port_2_reset;
+                               }
+
+                               /* Diagnostic printouts. */
+                               if ((hc->rh.prev_wPortStatus_2 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_2, connected, no)) &&
+                                   (hc->rh.prev_wPortStatus_2 &
+                                    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
+                                       dbg_rh("No connected device on port 2");
+                               } else if ((hc->rh.prev_wPortStatus_2 &
+                                           IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
+                                          (hc->rh.prev_wPortStatus_2 &
+                                           IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) {
+                                       dbg_rh("Connected device on port 2, port 2 enabled");
+                               }
+
+                       } else {
+                               dbg_rh("RH_SET_FEATURE->RH_PORT_RESET with invalid wIndex = %d", wIndex);
+                       }
+
+                       /* Make sure the controller isn't busy. */
+                       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+                       /* If all enabled ports were disabled the host controller goes down into
+                          started mode, so we need to bring it back into the running state.
+                          (This is safe even if it's already in the running state.) */
+                       *R_USB_COMMAND =
+                               IO_STATE(R_USB_COMMAND, port_sel, nop) |
+                               IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+                               IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+
+                       dbg_rh("...Done");
+                       OK(0);
+
+               case (RH_PORT_POWER):
+                       OK (0); /* port power ** */
+               case (RH_PORT_ENABLE):
+                       /* There is no port enable command in the host controller, so if the
+                          port is already enabled, we do nothing. If not, we reset the port
+                          (with an ugly goto). */
+
+                       if (wIndex == 1) {
+                               if (hc->rh.prev_wPortStatus_1 &
+                                   IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no)) {
+                                       goto port_1_reset;
+                               }
+                       } else if (wIndex == 2) {
+                               if (hc->rh.prev_wPortStatus_2 &
+                                   IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no)) {
+                                       goto port_2_reset;
+                               }
+                       } else {
+                               dbg_rh("RH_SET_FEATURE->RH_GET_STATUS with invalid wIndex = %d", wIndex);
+                       }
+                       OK (0);
+               }
+               break;
+
+       case RH_SET_ADDRESS:
+               hc->rh.devnum = wValue;
+               dbg_rh("RH address set to: %d", hc->rh.devnum);
+               OK (0);
+
+       case RH_GET_DESCRIPTOR:
+               switch ((wValue & 0xff00) >> 8) {
+               case (0x01):    /* device descriptor */
+                       len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength));
+                       memcpy (data, root_hub_dev_des, len);
+                       OK (len);
+               case (0x02):    /* configuration descriptor */
+                       len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength));
+                       memcpy (data, root_hub_config_des, len);
+                       OK (len);
+               case (0x03):    /* string descriptors */
+                       len = usb_root_hub_string (wValue & 0xff,
+                                                  0xff, "ETRAX 100LX",
+                                                  data, wLength);
+                       if (len > 0) {
+                               OK(min(leni, len));
+                       } else {
+                               stat = -EPIPE;
+                       }
+
+               }
+               break;
+
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+               root_hub_hub_des[2] = hc->rh.numports;
+               len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
+               memcpy (data, root_hub_hub_des, len);
+               OK (len);
+
+       case RH_GET_CONFIGURATION:
+               *(__u8 *) data = 0x01;
+               OK (1);
+
+       case RH_SET_CONFIGURATION:
+               OK (0);
+
+       default:
+               stat = -EPIPE;
+       }
+
+       urb->actual_length = len;
+       urb->status = stat;
+       urb->dev = NULL;
+       if (urb->complete) {
+               urb->complete(urb, NULL);
+       }
+       DBFEXIT;
+
+       return 0;
+}
+
+static void
+etrax_usb_bulk_eot_timer_func(unsigned long dummy)
+{
+       /* Because of a race condition in the top half, we might miss a bulk eot.
+          This timer "simulates" a bulk eot if we don't get one for a while, hopefully
+          correcting the situation. */
+       dbg_bulk("bulk_eot_timer timed out.");
+       etrax_usb_hc_bulk_eot_interrupt(1);
+}
+
+static void*
+etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma)
+{
+  return kmalloc(size, mem_flags);
+}
+
+static void
+etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma)
+{
+  kfree(addr);
+}
+
+
+static struct device fake_device;
+
+static int __init etrax_usb_hc_init(void)
+{
+       static etrax_hc_t *hc;
+       struct usb_bus *bus;
+       struct usb_device *usb_rh;
+       int i;
+
+       DBFENTER;
+
+       info("ETRAX 100LX USB-HCD %s (c) 2001-2003 Axis Communications AB\n", usb_hcd_version);
+
+       hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL);
+       assert(hc != NULL);
+
+       /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
+       /* Note that we specify sizeof(USB_EP_Desc_t) as the size, but also allocate
+          SB descriptors from this cache. This is ok since sizeof(USB_EP_Desc_t) ==
+          sizeof(USB_SB_Desc_t). */
+
+       usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0,
+                                          SLAB_HWCACHE_ALIGN, 0, 0);
+       assert(usb_desc_cache != NULL);
+
+       top_half_reg_cache = kmem_cache_create("top_half_reg_cache",
+                                              sizeof(usb_interrupt_registers_t),
+                                              0, SLAB_HWCACHE_ALIGN, 0, 0);
+       assert(top_half_reg_cache != NULL);
+
+       isoc_compl_cache = kmem_cache_create("isoc_compl_cache",
+                                               sizeof(usb_isoc_complete_data_t),
+                                               0, SLAB_HWCACHE_ALIGN, 0, 0);
+       assert(isoc_compl_cache != NULL);
+
+       etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
+       hc->bus = bus;
+       bus->bus_name="ETRAX 100LX";
+       bus->hcpriv = hc;
+
+       /* Initalize RH to the default address.
+          And make sure that we have no status change indication */
+       hc->rh.numports = 2;  /* The RH has two ports */
+       hc->rh.devnum = 1;
+       hc->rh.wPortChange_1 = 0;
+       hc->rh.wPortChange_2 = 0;
+
+       /* Also initate the previous values to zero */
+       hc->rh.prev_wPortStatus_1 = 0;
+       hc->rh.prev_wPortStatus_2 = 0;
+
+       /* Initialize the intr-traffic flags */
+       /* FIXME: This isn't used. (Besides, the error field isn't initialized.) */
+       hc->intr.sleeping = 0;
+       hc->intr.wq = NULL;
+
+       epid_usage_bitmask = 0;
+       epid_out_traffic = 0;
+
+       /* Mark the invalid epid as being used. */
+       set_bit(INVALID_EPID, (void *)&epid_usage_bitmask);
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, INVALID_EPID);
+       nop();
+       /* The valid bit should still be set ('invalid' is in our world; not the hardware's). */
+       *R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, yes) |
+                          IO_FIELD(R_USB_EPT_DATA, max_len, 1));
+
+       /* Mark the dummy epid as being used. */
+       set_bit(DUMMY_EPID, (void *)&epid_usage_bitmask);
+       *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, DUMMY_EPID);
+       nop();
+       *R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, no) |
+                          IO_FIELD(R_USB_EPT_DATA, max_len, 1));
+
+       /* Initialize the urb list by initiating a head for each list. */
+       for (i = 0; i < NBR_OF_EPIDS; i++) {
+               INIT_LIST_HEAD(&urb_list[i]);
+       }
+       spin_lock_init(&urb_list_lock);
+
+       INIT_LIST_HEAD(&urb_unlink_list);
+
+
+       /* Initiate the bulk start timer. */
+       init_timer(&bulk_start_timer);
+       bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
+       bulk_start_timer.function = etrax_usb_bulk_start_timer_func;
+       add_timer(&bulk_start_timer);
+
+
+       /* Initiate the bulk eot timer. */
+       init_timer(&bulk_eot_timer);
+       bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
+       bulk_eot_timer.function = etrax_usb_bulk_eot_timer_func;
+       add_timer(&bulk_eot_timer);
+
+       /* Set up the data structures for USB traffic. Note that this must be done before
+          any interrupt that relies on sane DMA list occurrs. */
+       init_rx_buffers();
+       init_tx_bulk_ep();
+       init_tx_ctrl_ep();
+       init_tx_intr_ep();
+       init_tx_isoc_ep();
+
+        device_initialize(&fake_device);
+        kobject_set_name(&fake_device.kobj, "etrax_usb");
+        kobject_add(&fake_device.kobj);
+        hc->bus->controller = &fake_device;
+       usb_register_bus(hc->bus);
+
+       *R_IRQ_MASK2_SET =
+               /* Note that these interrupts are not used. */
+               IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
+               /* Sub channel 1 (ctrl) descr. interrupts are used. */
+               IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
+               IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
+               /* Sub channel 3 (isoc) descr. interrupts are used. */
+               IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
+
+       /* Note that the dma9_descr interrupt is not used. */
+       *R_IRQ_MASK2_SET =
+               IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
+               IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
+
+       /* FIXME: Enable iso_eof only when isoc traffic is running. */
+       *R_USB_IRQ_MASK_SET =
+               IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) |
+               IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
+               IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
+               IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
+               IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
+
+
+       if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_interrupt_top_half, 0,
+                       "ETRAX 100LX built-in USB (HC)", hc)) {
+               err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
+               etrax_usb_hc_cleanup();
+               DBFEXIT;
+               return -1;
+       }
+
+       if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0,
+                       "ETRAX 100LX built-in USB (Rx)", hc)) {
+               err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
+               etrax_usb_hc_cleanup();
+               DBFEXIT;
+               return -1;
+       }
+
+       if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0,
+                       "ETRAX 100LX built-in USB (Tx)", hc)) {
+               err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
+               etrax_usb_hc_cleanup();
+               DBFEXIT;
+               return -1;
+       }
+
+       /* R_USB_COMMAND:
+          USB commands in host mode. The fields in this register should all be
+          written to in one write. Do not read-modify-write one field at a time. A
+          write to this register will trigger events in the USB controller and an
+          incomplete command may lead to unpredictable results, and in worst case
+          even to a deadlock in the controller.
+          (Note however that the busy field is read-only, so no need to write to it.) */
+
+       /* Check the busy bit before writing to R_USB_COMMAND. */
+
+       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+       /* Reset the USB interface. */
+       *R_USB_COMMAND =
+               IO_STATE(R_USB_COMMAND, port_sel, nop) |
+               IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+               IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
+
+       /* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to 0x2A30 (10800),
+          to guarantee that control traffic gets 10% of the bandwidth, and periodic transfer may
+          allocate the rest (90%). This doesn't work though. Read on for a lenghty explanation.
+
+          While there is a difference between rev. 2 and rev. 3 of the ETRAX 100LX regarding the NAK
+          behaviour, it doesn't solve this problem. What happens is that a control transfer will not
+          be interrupted in its data stage when PSTART happens (the point at which periodic traffic
+          is started). Thus, if PSTART is set to 10800 and its IN or OUT token is NAKed until just before
+          PSTART happens, it will continue the IN/OUT transfer as long as it's ACKed. After it's done,
+          there may be too little time left for an isochronous transfer, causing an epid attention
+          interrupt due to perror. The work-around for this is to let the control transfers run at the
+          end of the frame instead of at the beginning, and will be interrupted just fine if it doesn't
+          fit into the frame. However, since there will *always* be a control transfer at the beginning
+          of the frame, regardless of what we set PSTART to, that transfer might be a 64-byte transfer
+          which consumes up to 15% of the frame, leaving only 85% for periodic traffic. The solution to
+          this would be to 'dummy allocate' 5% of the frame with the usb_claim_bandwidth function to make
+          sure that the periodic transfers that are inserted will always fit in the frame.
+
+          The idea was suggested that a control transfer could be split up into several 8 byte transfers,
+          so that it would be interrupted by PSTART, but since this can't be done for an IN transfer this
+          hasn't been implemented.
+
+          The value 11960 is chosen to be just after the SOF token, with a couple of bit times extra
+          for possible bit stuffing. */
+
+       *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT1
+       *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
+#endif
+
+#ifdef CONFIG_ETRAX_USB_HOST_PORT2
+       *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
+#endif
+
+       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+       /* Configure the USB interface as a host controller. */
+       *R_USB_COMMAND =
+               IO_STATE(R_USB_COMMAND, port_sel, nop) |
+               IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+               IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
+
+       /* Note: Do not reset any ports here. Await the port status interrupts, to have a controlled
+          sequence of resetting the ports. If we reset both ports now, and there are devices
+          on both ports, we will get a bus error because both devices will answer the set address
+          request. */
+
+       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+       /* Start processing of USB traffic. */
+       *R_USB_COMMAND =
+               IO_STATE(R_USB_COMMAND, port_sel, nop) |
+               IO_STATE(R_USB_COMMAND, port_cmd, reset) |
+               IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
+
+       while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
+
+       usb_rh = usb_alloc_dev(NULL, hc->bus, 0);
+       hc->bus->root_hub = usb_rh;
+        usb_rh->state = USB_STATE_ADDRESS;
+        usb_rh->speed = USB_SPEED_FULL;
+        usb_rh->devnum = 1;
+        hc->bus->devnum_next = 2;
+        usb_rh->epmaxpacketin[0] = usb_rh->epmaxpacketout[0] = 64;
+        usb_get_device_descriptor(usb_rh, USB_DT_DEVICE_SIZE);
+       usb_new_device(usb_rh);
+
+       DBFEXIT;
+
+       return 0;
+}
+
+static void etrax_usb_hc_cleanup(void)
+{
+       DBFENTER;
+
+       free_irq(ETRAX_USB_HC_IRQ, NULL);
+       free_irq(ETRAX_USB_RX_IRQ, NULL);
+       free_irq(ETRAX_USB_TX_IRQ, NULL);
+
+       usb_deregister_bus(etrax_usb_bus);
+
+       /* FIXME: call kmem_cache_destroy here? */
+
+       DBFEXIT;
+}
+
+module_init(etrax_usb_hc_init);
+module_exit(etrax_usb_hc_cleanup);
diff --git a/drivers/usb/host/hc_crisv10.h b/drivers/usb/host/hc_crisv10.h
new file mode 100644 (file)
index 0000000..62f7711
--- /dev/null
@@ -0,0 +1,289 @@
+#ifndef __LINUX_ETRAX_USB_H
+#define __LINUX_ETRAX_USB_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+typedef struct USB_IN_Desc {
+       volatile __u16 sw_len;
+       volatile __u16 command;
+       volatile unsigned long next;
+       volatile unsigned long buf;
+       volatile __u16 hw_len;
+       volatile __u16 status;
+} USB_IN_Desc_t;
+
+typedef struct USB_SB_Desc {
+       volatile __u16 sw_len;
+       volatile __u16 command;
+       volatile unsigned long next;
+       volatile unsigned long buf;
+       __u32 dummy;
+} USB_SB_Desc_t;
+
+typedef struct USB_EP_Desc {
+       volatile __u16 hw_len;
+       volatile __u16 command;
+       volatile unsigned long sub;
+       volatile unsigned long next;
+       __u32 dummy;
+} USB_EP_Desc_t;
+
+struct virt_root_hub {
+       int devnum;
+       void *urb;
+       void *int_addr;
+       int send;
+       int interval;
+       int numports;
+       struct timer_list rh_int_timer;
+       volatile __u16 wPortChange_1;
+       volatile __u16 wPortChange_2;
+       volatile __u16 prev_wPortStatus_1;
+       volatile __u16 prev_wPortStatus_2;
+};
+
+struct etrax_usb_intr_traffic {
+       int sleeping;
+       int error;
+       struct wait_queue *wq;
+};
+
+typedef struct etrax_usb_hc {
+       struct usb_bus *bus;
+       struct virt_root_hub rh;
+       struct etrax_usb_intr_traffic intr;
+} etrax_hc_t;
+
+typedef enum {
+       STARTED,
+       NOT_STARTED,
+       UNLINK,
+       TRANSFER_DONE,
+       WAITING_FOR_DESCR_INTR
+} etrax_usb_urb_state_t;
+
+
+
+typedef struct etrax_usb_urb_priv {
+       /* The first_sb field is used for freeing all SB descriptors belonging
+          to an urb. The corresponding ep descriptor's sub pointer cannot be
+          used for this since the DMA advances the sub pointer as it processes
+          the sb list. */
+       USB_SB_Desc_t *first_sb;
+       /* The last_sb field referes to the last SB descriptor that belongs to
+          this urb. This is important to know so we can free the SB descriptors
+          that ranges between first_sb and last_sb. */
+       USB_SB_Desc_t *last_sb;
+
+       /* The rx_offset field is used in ctrl and bulk traffic to keep track
+          of the offset in the urb's transfer_buffer where incoming data should be
+          copied to. */
+       __u32 rx_offset;
+
+       /* Counter used in isochronous transfers to keep track of the
+          number of packets received/transmitted.  */
+       __u32 isoc_packet_counter;
+
+       /* This field is used to pass information about the urb's current state between
+          the various interrupt handlers (thus marked volatile). */
+       volatile etrax_usb_urb_state_t urb_state;
+
+       /* Connection between the submitted urb and ETRAX epid number */
+       __u8 epid;
+
+       /* The rx_data_list field is used for periodic traffic, to hold
+          received data for later processing in the the complete_urb functions,
+          where the data us copied to the urb's transfer_buffer. Basically, we
+          use this intermediate storage because we don't know when it's safe to
+          reuse the transfer_buffer (FIXME?). */
+       struct list_head rx_data_list;
+} etrax_urb_priv_t;
+
+/* This struct is for passing data from the top half to the bottom half. */
+typedef struct usb_interrupt_registers
+{
+       etrax_hc_t *hc;
+       __u32 r_usb_epid_attn;
+       __u8 r_usb_status;
+       __u16 r_usb_rh_port_status_1;
+       __u16 r_usb_rh_port_status_2;
+       __u32 r_usb_irq_mask_read;
+       __u32 r_usb_fm_number;
+       struct work_struct usb_bh;
+} usb_interrupt_registers_t;
+
+/* This struct is for passing data from the isoc top half to the isoc bottom half. */
+typedef struct usb_isoc_complete_data
+{
+       struct urb *urb;
+       struct work_struct usb_bh;
+} usb_isoc_complete_data_t;
+
+/* This struct holds data we get from the rx descriptors for DMA channel 9
+   for periodic traffic (intr and isoc). */
+typedef struct rx_data
+{
+       void *data;
+       int length;
+       struct list_head list;
+} rx_data_t;
+
+typedef struct urb_entry
+{
+       struct urb *urb;
+       struct list_head list;
+} urb_entry_t;
+
+/* ---------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS         0x0500
+#define RH_GET_DESCRIPTOR      0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION   0x0880
+#define RH_SET_CONFIGURATION   0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+/* Field definitions for */
+
+#define USB_IN_command__eol__BITNR      0 /* command macros */
+#define USB_IN_command__eol__WIDTH      1
+#define USB_IN_command__eol__no         0
+#define USB_IN_command__eol__yes        1
+
+#define USB_IN_command__intr__BITNR     3
+#define USB_IN_command__intr__WIDTH     1
+#define USB_IN_command__intr__no        0
+#define USB_IN_command__intr__yes       1
+
+#define USB_IN_status__eop__BITNR       1 /* status macros. */
+#define USB_IN_status__eop__WIDTH       1
+#define USB_IN_status__eop__no          0
+#define USB_IN_status__eop__yes         1
+
+#define USB_IN_status__eot__BITNR       5
+#define USB_IN_status__eot__WIDTH       1
+#define USB_IN_status__eot__no          0
+#define USB_IN_status__eot__yes         1
+
+#define USB_IN_status__error__BITNR     6
+#define USB_IN_status__error__WIDTH     1
+#define USB_IN_status__error__no        0
+#define USB_IN_status__error__yes       1
+
+#define USB_IN_status__nodata__BITNR    7
+#define USB_IN_status__nodata__WIDTH    1
+#define USB_IN_status__nodata__no       0
+#define USB_IN_status__nodata__yes      1
+
+#define USB_IN_status__epid__BITNR      8
+#define USB_IN_status__epid__WIDTH      5
+
+#define USB_EP_command__eol__BITNR      0
+#define USB_EP_command__eol__WIDTH      1
+#define USB_EP_command__eol__no         0
+#define USB_EP_command__eol__yes        1
+
+#define USB_EP_command__eof__BITNR      1
+#define USB_EP_command__eof__WIDTH      1
+#define USB_EP_command__eof__no         0
+#define USB_EP_command__eof__yes        1
+
+#define USB_EP_command__intr__BITNR     3
+#define USB_EP_command__intr__WIDTH     1
+#define USB_EP_command__intr__no        0
+#define USB_EP_command__intr__yes       1
+
+#define USB_EP_command__enable__BITNR   4
+#define USB_EP_command__enable__WIDTH   1
+#define USB_EP_command__enable__no      0
+#define USB_EP_command__enable__yes     1
+
+#define USB_EP_command__hw_valid__BITNR 5
+#define USB_EP_command__hw_valid__WIDTH 1
+#define USB_EP_command__hw_valid__no    0
+#define USB_EP_command__hw_valid__yes   1
+
+#define USB_EP_command__epid__BITNR     8
+#define USB_EP_command__epid__WIDTH     5
+
+#define USB_SB_command__eol__BITNR      0 /* command macros. */
+#define USB_SB_command__eol__WIDTH      1
+#define USB_SB_command__eol__no         0
+#define USB_SB_command__eol__yes        1
+
+#define USB_SB_command__eot__BITNR      1
+#define USB_SB_command__eot__WIDTH      1
+#define USB_SB_command__eot__no         0
+#define USB_SB_command__eot__yes        1
+
+#define USB_SB_command__intr__BITNR     3
+#define USB_SB_command__intr__WIDTH     1
+#define USB_SB_command__intr__no        0
+#define USB_SB_command__intr__yes       1
+
+#define USB_SB_command__tt__BITNR       4
+#define USB_SB_command__tt__WIDTH       2
+#define USB_SB_command__tt__zout        0
+#define USB_SB_command__tt__in          1
+#define USB_SB_command__tt__out         2
+#define USB_SB_command__tt__setup       3
+
+
+#define USB_SB_command__rem__BITNR      8
+#define USB_SB_command__rem__WIDTH      6
+
+#define USB_SB_command__full__BITNR     6
+#define USB_SB_command__full__WIDTH     1
+#define USB_SB_command__full__no        0
+#define USB_SB_command__full__yes       1
+
+#endif
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
new file mode 100644 (file)
index 0000000..44582d0
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for pxa27x
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Russell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * Modified for pxa27x from ohci-lh7a404.c
+ *  by Nick Bane <nick@cecomputing.co.uk> 26-8-2004
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/device.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+
+#define PMM_NPS_MODE           1
+#define PMM_GLOBAL_MODE        2
+#define PMM_PERPORT_MODE       3
+
+#define PXA_UHC_MAX_PORTNUM    3
+
+#define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
+
+static int pxa27x_ohci_pmm_state;
+
+/*
+  PMM_NPS_MODE -- PMM Non-power switching mode
+      Ports are powered continuously.
+
+  PMM_GLOBAL_MODE -- PMM global switching mode
+      All ports are powered at the same time.
+
+  PMM_PERPORT_MODE -- PMM per port switching mode
+      Ports are powered individually.
+ */
+static int pxa27x_ohci_select_pmm( int mode )
+{
+       pxa27x_ohci_pmm_state = mode;
+
+       switch ( mode ) {
+       case PMM_NPS_MODE:
+               UHCRHDA |= RH_A_NPS;
+               break; 
+       case PMM_GLOBAL_MODE:
+               UHCRHDA &= ~(RH_A_NPS & RH_A_PSM);
+               break;
+       case PMM_PERPORT_MODE:
+               UHCRHDA &= ~(RH_A_NPS);
+               UHCRHDA |= RH_A_PSM;
+
+               /* Set port power control mask bits, only 3 ports. */
+               UHCRHDB |= (0x7<<17);
+               break;
+       default:
+               printk( KERN_ERR
+                       "Invalid mode %d, set to non-power switch mode.\n", 
+                       mode );
+
+               pxa27x_ohci_pmm_state = PMM_NPS_MODE;
+               UHCRHDA |= RH_A_NPS;
+       }
+
+       return 0;
+}
+
+/*
+  If you select PMM_PERPORT_MODE, you should set the port power
+ */
+static int pxa27x_ohci_set_port_power( int port )
+{
+       if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
+            && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
+               UHCRHPS(port) |= 0x100;
+               return 0;
+       }
+       return -1;
+}
+
+/*
+  If you select PMM_PERPORT_MODE, you should set the port power
+ */
+static int pxa27x_ohci_clear_port_power( int port )
+{
+       if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE) 
+            && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
+               UHCRHPS(port) |= 0x200;
+               return 0;
+       }
+        
+       return -1;
+}
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void pxa27x_start_hc(struct platform_device *dev)
+{
+       pxa_set_cken(CKEN10_USBHOST, 1);
+
+       UHCHR |= UHCHR_FHR;
+       udelay(11);
+       UHCHR &= ~UHCHR_FHR;
+
+       UHCHR |= UHCHR_FSBIR;
+       while (UHCHR & UHCHR_FSBIR)
+               cpu_relax();
+
+       /* This could be properly abstracted away through the
+          device data the day more machines are supported and
+          their differences can be figured out correctly. */
+       if (machine_is_mainstone()) {
+               /* setup Port1 GPIO pin. */
+               pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN);  /* USBHPWR1 */
+               pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */
+
+               /* Set the Power Control Polarity Low and Power Sense
+                  Polarity Low to active low. Supply power to USB ports. */
+               UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
+                       ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
+       }
+
+       UHCHR &= ~UHCHR_SSE;
+
+       UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE);
+}
+
+static void pxa27x_stop_hc(struct platform_device *dev)
+{
+       UHCHR |= UHCHR_FHR;
+       udelay(11);
+       UHCHR &= ~UHCHR_FHR;
+
+       UHCCOMS |= 1;
+       udelay(10);
+
+       pxa_set_cken(CKEN10_USBHOST, 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+void usb_hcd_pxa27x_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_pxa27x_probe - initialize pxa27x-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
+                         struct usb_hcd **hcd_out,
+                         struct platform_device *dev)
+{
+       int retval;
+       struct usb_hcd *hcd = 0;
+
+       unsigned int *addr = NULL;
+
+       if (!request_mem_region(dev->resource[0].start,
+                               dev->resource[0].end
+                               - dev->resource[0].start + 1, hcd_name)) {
+               pr_debug("request_mem_region failed");
+               return -EBUSY;
+       }
+
+       pxa27x_start_hc(dev);
+
+       /* Select Power Management Mode */
+       pxa27x_ohci_select_pmm( PMM_PERPORT_MODE );
+
+       /* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */
+       if (pxa27x_ohci_set_port_power(1) < 0)
+               printk(KERN_ERR "Setting port 1 power failed.\n");
+
+       if (pxa27x_ohci_clear_port_power(2) < 0)
+               printk(KERN_ERR "Setting port 2 power failed.\n");
+
+       if (pxa27x_ohci_clear_port_power(3) < 0)
+               printk(KERN_ERR "Setting port 3 power failed.\n");
+
+       addr = ioremap(dev->resource[0].start,
+                      dev->resource[0].end - dev->resource[0].start + 1);
+       if (!addr) {
+               pr_debug("ioremap failed");
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       hcd = driver->hcd_alloc ();
+       if (hcd == NULL){
+               pr_debug ("hcd_alloc failed");
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       if(dev->resource[1].flags != IORESOURCE_IRQ){
+               pr_debug ("resource[1] is not IORESOURCE_IRQ");
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       hcd->driver = (struct hc_driver *) driver;
+       hcd->description = driver->description;
+       hcd->irq = dev->resource[1].start;
+       hcd->regs = addr;
+       hcd->self.controller = &dev->dev;
+
+       retval = hcd_buffer_create (hcd);
+       if (retval != 0) {
+               pr_debug ("pool alloc fail");
+               goto err1;
+       }
+
+       retval = request_irq (hcd->irq, usb_hcd_irq, SA_INTERRUPT,
+                             hcd->description, hcd);
+       if (retval != 0) {
+               pr_debug("request_irq(%d) failed with retval %d\n",hcd->irq,retval);
+               retval = -EBUSY;
+               goto err2;
+       }
+
+       pr_debug ("%s (pxa27x) at 0x%p, irq %d",
+            hcd->description, hcd->regs, hcd->irq);
+
+       usb_bus_init (&hcd->self);
+       hcd->self.op = &usb_hcd_operations;
+       hcd->self.release = &usb_hcd_release;
+       hcd->self.hcpriv = (void *) hcd;
+       hcd->self.bus_name = "pxa27x";
+       hcd->product_desc = "PXA27x OHCI";
+
+       INIT_LIST_HEAD (&hcd->dev_list);
+
+       usb_register_bus (&hcd->self);
+
+       if ((retval = driver->start (hcd)) < 0) {
+               usb_hcd_pxa27x_remove(hcd, dev);
+               return retval;
+       }
+
+       *hcd_out = hcd;
+       return 0;
+
+ err2:
+       hcd_buffer_destroy (hcd);
+ err1:
+       kfree(hcd);
+       pxa27x_stop_hc(dev);
+       release_mem_region(dev->resource[0].start,
+                               dev->resource[0].end
+                          - dev->resource[0].start + 1);
+       return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pxa27x_remove - shutdown processing for pxa27x-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pxa27x_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+       pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+       if (in_interrupt ())
+               BUG ();
+
+       hcd->state = USB_STATE_QUIESCING;
+
+       pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
+       usb_disconnect (&hcd->self.root_hub);
+
+       hcd->driver->stop (hcd);
+       hcd->state = USB_STATE_HALT;
+
+       free_irq (hcd->irq, hcd);
+       hcd_buffer_destroy (hcd);
+
+       usb_deregister_bus (&hcd->self);
+
+       pxa27x_stop_hc(dev);
+       release_mem_region(dev->resource[0].start,
+                          dev->resource[0].end - dev->resource[0].start + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_pxa27x_start (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ret;
+
+       ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
+
+       if ((ret = ohci_init(ohci)) < 0)
+               return ret;
+
+       if ((ret = ohci_run (ohci)) < 0) {
+               err ("can't start %s", ohci->hcd.self.bus_name);
+               ohci_stop (hcd);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pxa27x_hc_driver = {
+       .description =          hcd_name,
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_pxa27x_start,
+       .stop =                 ohci_stop,
+
+       /*
+        * memory lifecycle (except per-request)
+        */
+       .hcd_alloc =            ohci_hcd_alloc,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+#ifdef  CONFIG_USB_SUSPEND
+       .hub_suspend =          ohci_hub_suspend,
+       .hub_resume =           ohci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_pxa27x_drv_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct usb_hcd *hcd = NULL;
+       int ret;
+
+       pr_debug ("In ohci_hcd_pxa27x_drv_probe");
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, &hcd, pdev);
+
+       if (ret == 0)
+               dev_set_drvdata(dev, hcd);
+
+       return ret;
+}
+
+static int ohci_hcd_pxa27x_drv_remove(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       usb_hcd_pxa27x_remove(hcd, pdev);
+       dev_set_drvdata(dev, NULL);
+       return 0;
+}
+
+static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+//     struct platform_device *pdev = to_platform_device(dev);
+//     struct usb_hcd *hcd = dev_get_drvdata(dev);
+       printk("%s: not implemented yet\n", __FUNCTION__);
+
+       return 0;
+}
+
+static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 state)
+{
+//     struct platform_device *pdev = to_platform_device(dev);
+//     struct usb_hcd *hcd = dev_get_drvdata(dev);
+       printk("%s: not implemented yet\n", __FUNCTION__);
+
+       return 0;
+}
+
+
+static struct device_driver ohci_hcd_pxa27x_driver = {
+       .name           = "pxa27x-ohci",
+       .bus            = &platform_bus_type,
+       .probe          = ohci_hcd_pxa27x_drv_probe,
+       .remove         = ohci_hcd_pxa27x_drv_remove,
+       .suspend        = ohci_hcd_pxa27x_drv_suspend, 
+       .resume         = ohci_hcd_pxa27x_drv_resume, 
+};
+
+static int __init ohci_hcd_pxa27x_init (void)
+{
+       pr_debug (DRIVER_INFO " (pxa27x)");
+       pr_debug ("block sizes: ed %d td %d\n",
+               sizeof (struct ed), sizeof (struct td));
+
+       return driver_register(&ohci_hcd_pxa27x_driver);
+}
+
+static void __exit ohci_hcd_pxa27x_cleanup (void)
+{
+       driver_unregister(&ohci_hcd_pxa27x_driver);
+}
+
+module_init (ohci_hcd_pxa27x_init);
+module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
new file mode 100644 (file)
index 0000000..ac8f899
--- /dev/null
@@ -0,0 +1,1905 @@
+/*
+ * SL811HS HCD (Host Controller Driver) for USB.
+ *
+ * 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 SL811HS controller handles host side USB (like the SL11H, but with
+ * another register set and SOF generation) as well as peripheral side USB
+ * (like the SL811S).  This driver version doesn't implement the Gadget API
+ * for the peripheral role; or OTG (that'd need much external circuitry).
+ *
+ * For documentation, see the SL811HS spec and the "SL811HS Embedded Host"
+ * document (providing significant pieces missing from that spec); plus
+ * the SL811S spec if you want peripheral side info.
+ */ 
+
+/*
+ * Status:  Passed basic stress testing, works with hubs, mice, keyboards,
+ * and usb-storage.
+ *
+ * TODO:
+ * - usb suspend/resume triggered by sl811 (with USB_SUSPEND)
+ * - various issues noted in the code
+ * - performance work; use both register banks; ...
+ * - use urb->iso_frame_desc[] with ISO transfers
+ */
+
+#undef VERBOSE
+#undef PACKET_TRACE
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+#      define DEBUG
+#else
+#      undef DEBUG
+#endif
+
+#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/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb_sl811.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#include "../core/hcd.h"
+#include "sl811.h"
+
+
+MODULE_DESCRIPTION("SL811HS USB Host Controller Driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_VERSION "06 Dec 2004"
+
+
+#ifndef DEBUG
+#      define  STUB_DEBUG_FILE
+#endif
+
+/* for now, use only one transfer register bank */
+#undef USE_B
+
+/* this doesn't understand urb->iso_frame_desc[], but if you had a driver
+ * that just queued one ISO frame per URB then iso transfers "should" work
+ * using the normal urb status fields.
+ */
+#define        DISABLE_ISO
+
+// #define     QUIRK2
+#define        QUIRK3
+
+static const char hcd_name[] = "sl811-hcd";
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t sl811h_irq(int irq, void *_sl811, struct pt_regs *regs);
+
+static void port_power(struct sl811 *sl811, int is_on)
+{
+       /* hub is inactive unless the port is powered */
+       if (is_on) {
+               if (sl811->port1 & (1 << USB_PORT_FEAT_POWER))
+                       return;
+
+               sl811->port1 = (1 << USB_PORT_FEAT_POWER);
+               sl811->irq_enable = SL11H_INTMASK_INSRMV;
+               sl811->hcd.self.controller->power.power_state = PM_SUSPEND_ON;
+       } else {
+               sl811->port1 = 0;
+               sl811->irq_enable = 0;
+               sl811->hcd.state = USB_STATE_HALT;
+               sl811->hcd.self.controller->power.power_state = PM_SUSPEND_DISK;
+       }
+       sl811->ctrl1 = 0;
+       sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
+       sl811_write(sl811, SL11H_IRQ_STATUS, ~0);
+
+       if (sl811->board && sl811->board->port_power) {
+               /* switch VBUS, at 500mA unless hub power budget gets set */
+               DBG("power %s\n", is_on ? "on" : "off");
+               sl811->board->port_power(sl811->hcd.self.controller, is_on);
+       }
+
+       /* reset as thoroughly as we can */
+       if (sl811->board && sl811->board->reset)
+               sl811->board->reset(sl811->hcd.self.controller);
+
+       sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
+       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+       sl811_write(sl811, SL811HS_CTLREG2, SL811HS_CTL2_INIT);
+       sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+
+       // if !is_on, put into lowpower mode now
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* This is a PIO-only HCD.  Queueing appends URBs to the endpoint's queue,
+ * and may start I/O.  Endpoint queues are scanned during completion irq
+ * handlers (one per packet: ACK, NAK, faults, etc) and urb cancelation.
+ *
+ * Using an external DMA engine to copy a packet at a time could work,
+ * though setup/teardown costs may be too big to make it worthwhile.
+ */
+
+/* SETUP starts a new control request.  Devices are not allowed to
+ * STALL or NAK these; they must cancel any pending control requests.
+ */
+static void setup_packet(
+       struct sl811            *sl811,
+       struct sl811h_ep        *ep,
+       struct urb              *urb,
+       u8                      bank,
+       u8                      control
+)
+{
+       u8                      addr;
+       u8                      len;
+       void __iomem            *data_reg;
+
+       addr = SL811HS_PACKET_BUF(bank == 0);
+       len = sizeof(struct usb_ctrlrequest);
+       data_reg = sl811->data_reg;
+       sl811_write_buf(sl811, addr, urb->setup_packet, len);
+
+       /* autoincrementing */
+       sl811_write(sl811, bank + SL11H_BUFADDRREG, addr);
+       writeb(len, data_reg);
+       writeb(SL_SETUP /* | ep->epnum */, data_reg);
+       writeb(usb_pipedevice(urb->pipe), data_reg);
+
+       /* always OUT/data0 */ ;
+       sl811_write(sl811, bank + SL11H_HOSTCTLREG,
+                       control | SL11H_HCTLMASK_OUT);
+       ep->length = 0;
+       PACKET("SETUP qh%p\n", ep);
+}
+
+/* STATUS finishes control requests, often after IN or OUT data packets */
+static void status_packet(
+       struct sl811            *sl811,
+       struct sl811h_ep        *ep,
+       struct urb              *urb,
+       u8                      bank,
+       u8                      control
+)
+{
+       int                     do_out;
+       void __iomem            *data_reg;
+
+       do_out = urb->transfer_buffer_length && usb_pipein(urb->pipe);
+       data_reg = sl811->data_reg;
+
+       /* autoincrementing */
+       sl811_write(sl811, bank + SL11H_BUFADDRREG, 0);
+       writeb(0, data_reg);
+       writeb((do_out ? SL_OUT : SL_IN) /* | ep->epnum */, data_reg);
+       writeb(usb_pipedevice(urb->pipe), data_reg);
+
+       /* always data1; sometimes IN */
+       control |= SL11H_HCTLMASK_TOGGLE;
+       if (do_out)
+               control |= SL11H_HCTLMASK_OUT;
+       sl811_write(sl811, bank + SL11H_HOSTCTLREG, control);
+       ep->length = 0;
+       PACKET("STATUS%s/%s qh%p\n", ep->nak_count ? "/retry" : "",
+                       do_out ? "out" : "in", ep);
+}
+
+/* IN packets can be used with any type of endpoint. here we just
+ * start the transfer, data from the peripheral may arrive later.
+ * urb->iso_frame_desc is currently ignored here...
+ */
+static void in_packet(
+       struct sl811            *sl811,
+       struct sl811h_ep        *ep,
+       struct urb              *urb,
+       u8                      bank,
+       u8                      control
+)
+{
+       u8                      addr;
+       u8                      len;
+       void __iomem            *data_reg;
+
+       /* avoid losing data on overflow */
+       len = ep->maxpacket;
+       addr = SL811HS_PACKET_BUF(bank == 0);
+       if (!(control & SL11H_HCTLMASK_ISOCH)
+                       && usb_gettoggle(urb->dev, ep->epnum, 0))
+               control |= SL11H_HCTLMASK_TOGGLE;
+       data_reg = sl811->data_reg;
+
+       /* autoincrementing */
+       sl811_write(sl811, bank + SL11H_BUFADDRREG, addr);
+       writeb(len, data_reg);
+       writeb(SL_IN | ep->epnum, data_reg);
+       writeb(usb_pipedevice(urb->pipe), data_reg);
+
+       sl811_write(sl811, bank + SL11H_HOSTCTLREG, control);
+       ep->length = min((int)len,
+                       urb->transfer_buffer_length - urb->actual_length);
+       PACKET("IN%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "",
+                       !!usb_gettoggle(urb->dev, ep->epnum, 0), ep, len);
+}
+
+/* OUT packets can be used with any type of endpoint.
+ * urb->iso_frame_desc is currently ignored here...
+ */
+static void out_packet(
+       struct sl811            *sl811,
+       struct sl811h_ep        *ep,
+       struct urb              *urb,
+       u8                      bank,
+       u8                      control
+)
+{
+       void                    *buf;
+       u8                      addr;
+       u8                      len;
+       void __iomem            *data_reg;
+
+       buf = urb->transfer_buffer + urb->actual_length;
+       prefetch(buf);
+
+       len = min((int)ep->maxpacket,
+                       urb->transfer_buffer_length - urb->actual_length);
+
+       if (!(control & SL11H_HCTLMASK_ISOCH)
+                       && usb_gettoggle(urb->dev, ep->epnum, 1))
+               control |= SL11H_HCTLMASK_TOGGLE;
+       addr = SL811HS_PACKET_BUF(bank == 0);
+       data_reg = sl811->data_reg;
+
+       sl811_write_buf(sl811, addr, buf, len);
+
+       /* autoincrementing */
+       sl811_write(sl811, bank + SL11H_BUFADDRREG, addr);
+       writeb(len, data_reg);
+       writeb(SL_OUT | ep->epnum, data_reg);
+       writeb(usb_pipedevice(urb->pipe), data_reg);
+
+       sl811_write(sl811, bank + SL11H_HOSTCTLREG,
+                       control | SL11H_HCTLMASK_OUT);
+       ep->length = len;
+       PACKET("OUT%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "",
+                       !!usb_gettoggle(urb->dev, ep->epnum, 1), ep, len);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* caller updates on-chip enables later */
+
+static inline void sofirq_on(struct sl811 *sl811)
+{
+       if (sl811->irq_enable & SL11H_INTMASK_SOFINTR)
+               return;
+       VDBG("sof irq on\n");
+       sl811->irq_enable |= SL11H_INTMASK_SOFINTR;
+}
+
+static inline void sofirq_off(struct sl811 *sl811)
+{
+       if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR))
+               return;
+       VDBG("sof irq off\n");
+       sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* pick the next endpoint for a transaction, and issue it.
+ * frames start with periodic transfers (after whatever is pending
+ * from the previous frame), and the rest of the time is async
+ * transfers, scheduled round-robin.
+ */
+static struct sl811h_ep        *start(struct sl811 *sl811, u8 bank)
+{
+       struct sl811h_ep        *ep;
+       struct sl811h_req       *req;
+       struct urb              *urb;
+       int                     fclock;
+       u8                      control;
+
+       /* use endpoint at schedule head */
+       if (sl811->next_periodic) {
+               ep = sl811->next_periodic;
+               sl811->next_periodic = ep->next;
+       } else {
+               if (sl811->next_async)
+                       ep = sl811->next_async;
+               else if (!list_empty(&sl811->async))
+                       ep = container_of(sl811->async.next,
+                                       struct sl811h_ep, schedule);
+               else {
+                       /* could set up the first fullspeed periodic
+                        * transfer for the next frame ...
+                        */
+                       return NULL;
+               }
+
+#ifdef USE_B
+               if ((bank && sl811->active_b == ep) || sl811->active_a == ep)
+                       return NULL;
+#endif
+
+               if (ep->schedule.next == &sl811->async)
+                       sl811->next_async = NULL;
+               else
+                       sl811->next_async = container_of(ep->schedule.next,
+                                       struct sl811h_ep, schedule);
+       }
+
+       if (unlikely(list_empty(&ep->queue))) {
+               DBG("empty %p queue?\n", ep);
+               return NULL;
+       }
+
+       req = container_of(ep->queue.next, struct sl811h_req, queue);
+       urb = req->urb;
+       control = ep->defctrl;
+
+       /* if this frame doesn't have enough time left to transfer this
+        * packet, wait till the next frame.  too-simple algorithm...
+        */
+       fclock = sl811_read(sl811, SL11H_SOFTMRREG) << 6;
+       fclock -= 100;          /* setup takes not much time */
+       if (urb->dev->speed == USB_SPEED_LOW) {
+               if (control & SL11H_HCTLMASK_PREAMBLE) {
+                       /* also note erratum 1: some hubs won't work */
+                       fclock -= 800;
+               }
+               fclock -= ep->maxpacket << 8;
+
+               /* erratum 2: AFTERSOF only works for fullspeed */
+               if (fclock < 0) {
+                       if (ep->period)
+                               sl811->stat_overrun++;
+                       sofirq_on(sl811);
+                       return NULL;
+               }
+       } else {
+               fclock -= 12000 / 19;   /* 19 64byte packets/msec */
+               if (fclock < 0) {
+                       if (ep->period)
+                               sl811->stat_overrun++;
+                       control |= SL11H_HCTLMASK_AFTERSOF;
+
+               /* throttle bulk/control irq noise */
+               } else if (ep->nak_count)
+                       control |= SL11H_HCTLMASK_AFTERSOF;
+       }
+
+
+       switch (ep->nextpid) {
+       case USB_PID_IN:
+               in_packet(sl811, ep, urb, bank, control);
+               break;
+       case USB_PID_OUT:
+               out_packet(sl811, ep, urb, bank, control);
+               break;
+       case USB_PID_SETUP:
+               setup_packet(sl811, ep, urb, bank, control);
+               break;
+       case USB_PID_ACK:               /* for control status */
+               status_packet(sl811, ep, urb, bank, control);
+               break;
+       default:
+               DBG("bad ep%p pid %02x\n", ep, ep->nextpid);
+               ep = NULL;
+       }
+       return ep;
+}
+
+#define MIN_JIFFIES    ((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2)
+
+static inline void start_transfer(struct sl811 *sl811)
+{
+       if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
+               return;
+       if (sl811->active_a == NULL) {
+               sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF));
+               if (sl811->active_a != NULL)
+                       sl811->jiffies_a = jiffies + MIN_JIFFIES;
+       }
+#ifdef USE_B
+       if (sl811->active_b == NULL) {
+               sl811->active_b = start(sl811, SL811_EP_B(SL811_HOST_BUF));
+               if (sl811->active_b != NULL)
+                       sl811->jiffies_b = jiffies + MIN_JIFFIES;
+       }
+#endif
+}
+
+static void finish_request(
+       struct sl811            *sl811,
+       struct sl811h_ep        *ep,
+       struct sl811h_req       *req,
+       struct pt_regs          *regs,
+       int                     status
+) __releases(sl811->lock) __acquires(sl811->lock)
+{
+       unsigned                i;
+       struct urb              *urb = req->urb;
+
+       list_del(&req->queue);
+       kfree(req);
+       urb->hcpriv = NULL;
+
+       if (usb_pipecontrol(urb->pipe))
+               ep->nextpid = USB_PID_SETUP;
+
+       spin_lock(&urb->lock);
+       if (urb->status == -EINPROGRESS)
+               urb->status = status;
+       spin_unlock(&urb->lock);
+
+       spin_unlock(&sl811->lock);
+       usb_hcd_giveback_urb(&sl811->hcd, urb, regs);
+       spin_lock(&sl811->lock);
+
+       /* leave active endpoints in the schedule */
+       if (!list_empty(&ep->queue))
+               return;
+
+       /* async deschedule? */
+       if (!list_empty(&ep->schedule)) {
+               list_del_init(&ep->schedule);
+               if (ep == sl811->next_async)
+                       sl811->next_async = NULL;
+               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 sl811h_ep        *temp;
+               struct sl811h_ep        **prev = &sl811->periodic[i];
+
+               while (*prev && ((temp = *prev) != ep))
+                       prev = &temp->next;
+               if (*prev)
+                       *prev = ep->next;
+               sl811->load[i] -= ep->load;
+       }       
+       ep->branch = PERIODIC_SIZE;
+       sl811->periodic_count--;
+       hcd_to_bus(&sl811->hcd)->bandwidth_allocated
+               -= ep->load / ep->period;
+       if (ep == sl811->next_periodic)
+               sl811->next_periodic = ep->next;
+
+       /* we might turn SOFs back on again for the async schedule */
+       if (sl811->periodic_count == 0)
+               sofirq_off(sl811);
+}
+
+static void
+done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
+{
+       u8                      status;
+       struct sl811h_req       *req;
+       struct urb              *urb;
+       int                     urbstat = -EINPROGRESS;
+
+       if (unlikely(!ep))
+               return;
+
+       status = sl811_read(sl811, bank + SL11H_PKTSTATREG);
+
+       req = container_of(ep->queue.next, struct sl811h_req, queue);
+       urb = req->urb;
+
+       /* we can safely ignore NAKs */
+       if (status & SL11H_STATMASK_NAK) {
+               // PACKET("...NAK_%02x qh%p\n", bank, ep);
+               if (!ep->period)
+                       ep->nak_count++;
+               ep->error_count = 0;
+
+       /* ACK advances transfer, toggle, and maybe queue */
+       } else if (status & SL11H_STATMASK_ACK) {
+               struct usb_device       *udev = urb->dev;
+               int                     len;
+               unsigned char           *buf;
+
+               /* urb->iso_frame_desc is currently ignored here... */
+
+               ep->nak_count = ep->error_count = 0;
+               switch (ep->nextpid) {
+               case USB_PID_OUT:
+                       // PACKET("...ACK/out_%02x qh%p\n", bank, ep);
+                       urb->actual_length += ep->length;
+                       usb_dotoggle(udev, ep->epnum, 1);
+                       if (urb->actual_length
+                                       == urb->transfer_buffer_length) {
+                               if (usb_pipecontrol(urb->pipe))
+                                       ep->nextpid = USB_PID_ACK;
+
+                               /* some bulk protocols terminate OUT transfers
+                                * by a short packet, using ZLPs not padding.
+                                */
+                               else if (ep->length < ep->maxpacket
+                                               || !(urb->transfer_flags
+                                                       & URB_ZERO_PACKET))
+                                       urbstat = 0;
+                       }
+                       break;
+               case USB_PID_IN:
+                       // PACKET("...ACK/in_%02x qh%p\n", bank, ep);
+                       buf = urb->transfer_buffer + urb->actual_length;
+                       prefetchw(buf);
+                       len = ep->maxpacket - sl811_read(sl811,
+                                               bank + SL11H_XFERCNTREG);
+                       if (len > ep->length) {
+                               len = ep->length;
+                               urb->status = -EOVERFLOW;
+                       }
+                       urb->actual_length += len;
+                       sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
+                                       buf, len);
+                       usb_dotoggle(udev, ep->epnum, 0);
+                       if (urb->actual_length == urb->transfer_buffer_length)
+                               urbstat = 0;
+                       else if (len < ep->maxpacket) {
+                               if (urb->transfer_flags & URB_SHORT_NOT_OK)
+                                       urbstat = -EREMOTEIO;
+                               else
+                                       urbstat = 0;
+                       }
+                       if (usb_pipecontrol(urb->pipe)
+                                       && (urbstat == -EREMOTEIO
+                                               || urbstat == 0)) {
+
+                               /* NOTE if the status stage STALLs (why?),
+                                * this reports the wrong urb status.
+                                */
+                               spin_lock(&urb->lock);
+                               if (urb->status == -EINPROGRESS)
+                                       urb->status = urbstat;
+                               spin_unlock(&urb->lock);
+
+                               req = NULL;
+                               ep->nextpid = USB_PID_ACK;
+                       }
+                       break;
+               case USB_PID_SETUP:
+                       // PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
+                       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:
+                       // PACKET("...ACK/status_%02x qh%p\n", bank, ep);
+                       urbstat = 0;
+                       break;
+               }
+
+       /* STALL stops all transfers */
+       } else if (status & SL11H_STATMASK_STALL) {
+               PACKET("...STALL_%02x qh%p\n", bank, ep);
+               ep->nak_count = ep->error_count = 0;
+               urbstat = -EPIPE;
+
+       /* error? retry, until "3 strikes" */
+       } else if (++ep->error_count >= 3) {
+               if (status & SL11H_STATMASK_TMOUT)
+                       urbstat = -ETIMEDOUT;
+               else if (status & SL11H_STATMASK_OVF)
+                       urbstat = -EOVERFLOW;
+               else
+                       urbstat = -EPROTO;
+               ep->error_count = 0;
+               PACKET("...3STRIKES_%02x %02x qh%p stat %d\n",
+                               bank, status, ep, urbstat);
+       }
+
+       if ((urbstat != -EINPROGRESS || urb->status != -EINPROGRESS)
+                       && req)
+               finish_request(sl811, ep, req, regs, urbstat);
+}
+
+static inline u8 checkdone(struct sl811 *sl811)
+{
+       u8      ctl;
+       u8      irqstat = 0;
+
+       if (sl811->active_a && time_before_eq(sl811->jiffies_a, jiffies)) {
+               ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG));
+               if (ctl & SL11H_HCTLMASK_ARM)
+                       sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
+               DBG("%s DONE_A: ctrl %02x sts %02x\n",
+                       (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
+                       ctl,
+                       sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
+               irqstat |= SL11H_INTMASK_DONE_A;
+       }
+#ifdef USE_B
+       if (sl811->active_b && time_before_eq(sl811->jiffies_b, jiffies)) {
+               ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG));
+               if (ctl & SL11H_HCTLMASK_ARM)
+                       sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
+               DBG("%s DONE_B: ctrl %02x sts %02x\n", ctl,
+                       (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
+                       ctl,
+                       sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
+               irqstat |= SL11H_INTMASK_DONE_A;
+       }
+#endif
+       return irqstat;
+}
+
+static irqreturn_t sl811h_irq(int irq, void *_sl811, struct pt_regs *regs)
+{
+       struct sl811    *sl811 = _sl811;
+       u8              irqstat;
+       irqreturn_t     ret = IRQ_NONE;
+       unsigned        retries = 5;
+
+       spin_lock(&sl811->lock);
+
+retry:
+       irqstat = sl811_read(sl811, SL11H_IRQ_STATUS) & ~SL11H_INTMASK_DP;
+       if (irqstat) {
+               sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
+               irqstat &= sl811->irq_enable;
+       }
+
+#ifdef QUIRK2
+       /* this may no longer be necessary ... */
+       if (irqstat == 0 && ret == IRQ_NONE) {
+               irqstat = checkdone(sl811);
+               if (irqstat && irq != ~0)
+                       sl811->stat_lost++;
+       }
+#endif
+
+       /* USB packets, not necessarily handled in the order they're
+        * issued ... that's fine if they're different endpoints.
+        */
+       if (irqstat & SL11H_INTMASK_DONE_A) {
+               done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs);
+               sl811->active_a = NULL;
+               sl811->stat_a++;
+       }
+#ifdef USE_B
+       if (irqstat & SL11H_INTMASK_DONE_B) {
+               done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs);
+               sl811->active_b = NULL;
+               sl811->stat_b++;
+       }
+#endif
+       if (irqstat & SL11H_INTMASK_SOFINTR) {
+               unsigned index;
+
+               index = sl811->frame++ % (PERIODIC_SIZE - 1);
+               sl811->stat_sof++;
+
+               /* be graceful about almost-inevitable periodic schedule
+                * overruns:  continue the previous frame's transfers iff
+                * this one has nothing scheduled.
+                */
+               if (sl811->next_periodic) {
+                       // ERR("overrun to slot %d\n", index);
+                       sl811->stat_overrun++;
+               }
+               if (sl811->periodic[index])
+                       sl811->next_periodic = sl811->periodic[index];
+       }
+
+       /* khubd manages debouncing and wakeup */
+       if (irqstat & SL11H_INTMASK_INSRMV) {
+               sl811->stat_insrmv++;
+
+               /* most stats are reset for each VBUS session */
+               sl811->stat_wake = 0;
+               sl811->stat_sof = 0;
+               sl811->stat_a = 0;
+               sl811->stat_b = 0;
+               sl811->stat_lost = 0;
+
+               sl811->ctrl1 = 0;
+               sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+
+               sl811->irq_enable = SL11H_INTMASK_INSRMV;
+               sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+
+               /* usbcore nukes other pending transactions on disconnect */
+               if (sl811->active_a) {
+                       sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
+                       finish_request(sl811, sl811->active_a,
+                               container_of(sl811->active_a->queue.next,
+                                       struct sl811h_req, queue),
+                               NULL, -ESHUTDOWN);
+                       sl811->active_a = NULL;
+               }
+#ifdef USE_B
+               if (sl811->active_b) {
+                       sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
+                       finish_request(sl811, sl811->active_b,
+                               container_of(sl811->active_b->queue.next,
+                                       struct sl811h_req, queue),
+                               NULL, -ESHUTDOWN);
+                       sl811->active_b = NULL;
+               }
+#endif
+
+               /* port status seems wierd until after reset, so
+                * force the reset and make khubd clean up later.
+                */
+               sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
+                               | (1 << USB_PORT_FEAT_CONNECTION);
+
+       } else if (irqstat & SL11H_INTMASK_RD) {
+               if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {
+                       DBG("wakeup\n");
+                       sl811->port1 |= 1 << USB_PORT_FEAT_C_SUSPEND;
+                       sl811->stat_wake++;
+               } else
+                       irqstat &= ~SL11H_INTMASK_RD;
+       }
+
+       if (irqstat) {
+               if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
+                       start_transfer(sl811);
+               ret = IRQ_HANDLED;
+               sl811->hcd.saw_irq = 1;
+               if (retries--)
+                       goto retry;
+       }
+
+       if (sl811->periodic_count == 0 && list_empty(&sl811->async)) 
+               sofirq_off(sl811);
+       sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+
+       spin_unlock(&sl811->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.
+ */
+#define        MAX_PERIODIC_LOAD       500     /* out of 1000 usec */
+
+static int balance(struct sl811 *sl811, 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 || sl811->load[branch] > sl811->load[i]) {
+                       int     j;
+
+                       for (j = i; j < PERIODIC_SIZE; j += period) {
+                               if ((sl811->load[j] + load)
+                                               > MAX_PERIODIC_LOAD)
+                                       break;
+                       }
+                       if (j < PERIODIC_SIZE)
+                               continue;
+                       branch = i; 
+               }
+       }
+       return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int sl811h_urb_enqueue(
+       struct usb_hcd  *hcd,
+       struct urb      *urb,
+       int             mem_flags
+) {
+       struct sl811            *sl811 = hcd_to_sl811(hcd);
+       struct usb_device       *udev = urb->dev;
+       struct hcd_dev          *hdev = (struct hcd_dev *) udev->hcpriv;
+       unsigned int            pipe = urb->pipe;
+       int                     is_out = !usb_pipein(pipe);
+       int                     type = usb_pipetype(pipe);
+       int                     epnum = usb_pipeendpoint(pipe);
+       struct sl811h_ep        *ep = NULL;
+       struct sl811h_req       *req;
+       unsigned long           flags;
+       int                     i;
+       int                     retval = 0;
+
+#ifdef DISABLE_ISO
+       if (type == PIPE_ISOCHRONOUS)
+               return -ENOSPC;
+#endif
+
+       /* avoid all allocations within spinlocks: request or endpoint */
+       urb->hcpriv = req = kmalloc(sizeof *req, mem_flags);
+       if (!req)
+               return -ENOMEM;
+       req->urb = urb;
+
+       i = epnum << 1;
+       if (i && is_out)
+               i |= 1;
+       if (!hdev->ep[i])
+               ep = kcalloc(1, sizeof *ep, mem_flags);
+
+       spin_lock_irqsave(&sl811->lock, flags);
+
+       /* don't submit to a dead or disabled port */
+       if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
+                       || !HCD_IS_RUNNING(sl811->hcd.state)) {
+               retval = -ENODEV;
+               goto fail;
+       }
+
+       if (hdev->ep[i]) {
+               kfree(ep);
+               ep = hdev->ep[i];
+       } else if (!ep) {
+               retval = -ENOMEM;
+               goto fail;
+
+       } else {
+               INIT_LIST_HEAD(&ep->queue);
+               INIT_LIST_HEAD(&ep->schedule);
+               ep->udev = usb_get_dev(udev);
+               ep->epnum = epnum;
+               ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
+               ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
+               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 (ep->maxpacket > H_MAXPACKET) {
+                       /* iso packets up to 240 bytes could work... */
+                       DBG("dev %d ep%d maxpacket %d\n",
+                               udev->devnum, epnum, ep->maxpacket);
+                       retval = -EINVAL;
+                       goto fail;
+               }
+
+               if (udev->speed == USB_SPEED_LOW) {
+                       /* send preamble for external hub? */
+                       if (!(sl811->ctrl1 & SL11H_CTL1MASK_LSPD))
+                               ep->defctrl |= SL11H_HCTLMASK_PREAMBLE;
+               }
+               switch (type) {
+               case PIPE_ISOCHRONOUS:
+               case PIPE_INTERRUPT:
+                       if (urb->interval > PERIODIC_SIZE)
+                               urb->interval = PERIODIC_SIZE;
+                       ep->period = urb->interval;
+                       ep->branch = PERIODIC_SIZE;
+                       if (type == PIPE_ISOCHRONOUS)
+                               ep->defctrl |= SL11H_HCTLMASK_ISOCH;
+                       ep->load = usb_calc_bus_time(udev->speed, !is_out,
+                               (type == PIPE_ISOCHRONOUS),
+                               usb_maxpacket(udev, pipe, is_out))
+                                       / 1000;
+                       break;
+               }
+
+               hdev->ep[i] = ep;
+       }
+
+       /* maybe put endpoint into schedule */
+       switch (type) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               if (list_empty(&ep->schedule))
+                       list_add_tail(&ep->schedule, &sl811->async);
+               break;
+       case PIPE_ISOCHRONOUS:
+       case PIPE_INTERRUPT:
+               urb->interval = ep->period;
+               if (ep->branch < PERIODIC_SIZE)
+                       break;
+
+               retval = balance(sl811, ep->period, ep->load);
+               if (retval < 0)
+                       goto fail;
+               ep->branch = retval;
+               retval = 0;
+               urb->start_frame = (sl811->frame & (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 sl811h_ep        **prev = &sl811->periodic[i];
+                       struct sl811h_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;
+                       }
+                       sl811->load[i] += ep->load;
+               }
+               sl811->periodic_count++;
+               hcd_to_bus(&sl811->hcd)->bandwidth_allocated
+                               += ep->load / ep->period;
+               sofirq_on(sl811);
+       }
+
+       /* in case of unlink-during-submit */
+       spin_lock(&urb->lock);
+       if (urb->status != -EINPROGRESS) {
+               spin_unlock(&urb->lock);
+               finish_request(sl811, ep, req, NULL, 0);
+               req = NULL;
+               retval = 0;
+               goto fail;
+       }
+       list_add_tail(&req->queue, &ep->queue);
+       spin_unlock(&urb->lock);
+
+       start_transfer(sl811);
+       sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+fail:
+       spin_unlock_irqrestore(&sl811->lock, flags);
+       if (retval)
+               kfree(req);
+       return retval;
+}
+
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+       struct sl811            *sl811 = hcd_to_sl811(hcd);
+       struct usb_device       *udev = urb->dev;
+       struct hcd_dev          *hdev = (struct hcd_dev *) udev->hcpriv;
+       unsigned int            pipe = urb->pipe;
+       int                     is_out = !usb_pipein(pipe);
+       unsigned long           flags;
+       unsigned                i;
+       struct sl811h_ep        *ep;
+       struct sl811h_req       *req = urb->hcpriv;
+       int                     retval = 0;
+
+       i = usb_pipeendpoint(pipe) << 1;
+       if (i && is_out)
+               i |= 1;
+
+       spin_lock_irqsave(&sl811->lock, flags);
+       ep = hdev->ep[i];
+       if (ep) {
+               /* finish right away if this urb can't be active ...
+                * note that some drivers wrongly expect delays
+                */
+               if (ep->queue.next != &req->queue) {
+                       /* not front of queue?  never active */
+
+               /* for active transfers, we expect an IRQ */
+               } else if (sl811->active_a == ep) {
+                       if (time_before_eq(sl811->jiffies_a, jiffies)) {
+                               /* happens a lot with lowspeed?? */
+                               DBG("giveup on DONE_A: ctrl %02x sts %02x\n",
+                                       sl811_read(sl811,
+                                               SL811_EP_A(SL11H_HOSTCTLREG)),
+                                       sl811_read(sl811,
+                                               SL811_EP_A(SL11H_PKTSTATREG)));
+                               sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG),
+                                               0);
+                               sl811->active_a = NULL;
+                       } else
+                               req = NULL;
+#ifdef USE_B
+               } else if (sl811->active_b == ep) {
+                       if (time_before_eq(sl811->jiffies_a, jiffies)) {
+                               /* happens a lot with lowspeed?? */
+                               DBG("giveup on DONE_B: ctrl %02x sts %02x\n",
+                                       sl811_read(sl811,
+                                               SL811_EP_B(SL11H_HOSTCTLREG)),
+                                       sl811_read(sl811,
+                                               SL811_EP_B(SL11H_PKTSTATREG)));
+                               sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG),
+                                               0);
+                               sl811->active_b = NULL;
+                       } else
+                               req = NULL;
+#endif
+               } else {
+                       /* front of queue for inactive endpoint */
+               }
+
+               if (req)
+                       finish_request(sl811, ep, req, NULL, 0);
+               else
+                       VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
+                               (sl811->active_a == ep) ? "A" : "B");
+       } else
+               retval = -EINVAL;
+       spin_unlock_irqrestore(&sl811->lock, flags);
+       return retval;
+}
+
+static void
+sl811h_endpoint_disable(struct usb_hcd *hcd, struct hcd_dev *hdev, int epnum)
+{
+       struct sl811            *sl811 = hcd_to_sl811(hcd);
+       struct sl811h_ep        *ep;
+       unsigned long           flags;
+       int                     i;
+
+       i = (epnum & 0xf) << 1;
+       if (epnum && !(epnum & USB_DIR_IN))
+               i |= 1;
+
+       spin_lock_irqsave(&sl811->lock, flags);
+       ep = hdev->ep[i];
+       hdev->ep[i] = NULL;
+       spin_unlock_irqrestore(&sl811->lock, flags);
+
+       if (ep) {
+               /* assume we'd just wait for the irq */
+               if (!list_empty(&ep->queue))
+                       msleep(3);
+               if (!list_empty(&ep->queue))
+                       WARN("ep %p not empty?\n", ep);
+
+               usb_put_dev(ep->udev);
+               kfree(ep);
+       }
+       return;
+}
+
+static int
+sl811h_get_frame(struct usb_hcd *hcd)
+{
+       struct sl811 *sl811 = hcd_to_sl811(hcd);
+
+       /* wrong except while periodic transfers are scheduled;
+        * never matches the on-the-wire frame;
+        * subject to overruns.
+        */
+       return sl811->frame;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* the virtual root hub timer IRQ checks for hub status */
+static int
+sl811h_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct sl811 *sl811 = hcd_to_sl811(hcd);
+#ifdef QUIRK3
+       unsigned long flags;
+
+       /* non-SMP HACK: use root hub timer as i/o watchdog
+        * this seems essential when SOF IRQs aren't in use...
+        */
+       local_irq_save(flags);
+       if (!timer_pending(&sl811->timer)) {
+               if (sl811h_irq(~0, sl811, NULL) != IRQ_NONE)
+                       sl811->stat_lost++;
+       }
+       local_irq_restore(flags);
+#endif
+
+       if (!(sl811->port1 & (0xffff << 16)))
+               return 0;
+
+       /* tell khubd port 1 changed */
+       *buf = (1 << 1);
+       return 1;
+}
+
+static void
+sl811h_hub_descriptor (
+       struct sl811                    *sl811,
+       struct usb_hub_descriptor       *desc
+) {
+       u16             temp = 0;
+
+       desc->bDescriptorType = 0x29;
+       desc->bHubContrCurrent = 0;
+
+       desc->bNbrPorts = 1;
+       desc->bDescLength = 9;
+
+       /* per-port power switching (gang of one!), or none */
+       desc->bPwrOn2PwrGood = 0;
+       if (sl811->board && sl811->board->port_power) {
+               desc->bPwrOn2PwrGood = sl811->board->potpg;
+               if (!desc->bPwrOn2PwrGood)
+                       desc->bPwrOn2PwrGood = 10;
+               temp = 0x0001;
+       } else
+               temp = 0x0002;
+
+       /* no overcurrent errors detection/handling */
+       temp |= 0x0010;
+
+       desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
+
+       /* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */
+       desc->bitmap[0] = 1 << 1;
+       desc->bitmap[1] = ~0;
+}
+
+static void
+sl811h_timer(unsigned long _sl811)
+{
+       struct sl811    *sl811 = (void *) _sl811;
+       unsigned long   flags;
+       u8              irqstat;
+       u8              signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE;
+       const u32       mask = (1 << USB_PORT_FEAT_CONNECTION)
+                               | (1 << USB_PORT_FEAT_ENABLE)
+                               | (1 << USB_PORT_FEAT_LOWSPEED);
+
+       spin_lock_irqsave(&sl811->lock, flags);
+
+       /* stop special signaling */
+       sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE;
+       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+       udelay(3);
+
+       irqstat = sl811_read(sl811, SL11H_IRQ_STATUS);
+
+       switch (signaling) {
+       case SL11H_CTL1MASK_SE0:
+               DBG("end reset\n");
+               sl811->port1 = (1 << USB_PORT_FEAT_C_RESET)
+                               | (1 << USB_PORT_FEAT_POWER);
+               sl811->ctrl1 = 0;
+               /* don't wrongly ack RD */
+               if (irqstat & SL11H_INTMASK_INSRMV)
+                       irqstat &= ~SL11H_INTMASK_RD;
+               break;
+       case SL11H_CTL1MASK_K:
+               DBG("end resume\n");
+               sl811->port1 &= ~(1 << USB_PORT_FEAT_SUSPEND);
+               break;
+       default:
+               DBG("odd timer signaling: %02x\n", signaling);
+               break;
+       }
+       sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
+
+       if (irqstat & SL11H_INTMASK_RD) {
+               /* usbcore nukes all pending transactions on disconnect */
+               if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION))
+                       sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
+                                       | (1 << USB_PORT_FEAT_C_ENABLE);
+               sl811->port1 &= ~mask;
+               sl811->irq_enable = SL11H_INTMASK_INSRMV;
+       } else {
+               sl811->port1 |= mask;
+               if (irqstat & SL11H_INTMASK_DP)
+                       sl811->port1 &= ~(1 << USB_PORT_FEAT_LOWSPEED);
+               sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD;
+       }
+
+       if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) {
+               u8      ctrl2 = SL811HS_CTL2_INIT;
+
+               sl811->irq_enable |= SL11H_INTMASK_DONE_A;
+#ifdef USE_B
+               sl811->irq_enable |= SL11H_INTMASK_DONE_B;
+#endif
+               if (sl811->port1 & (1 << USB_PORT_FEAT_LOWSPEED)) {
+                       sl811->ctrl1 |= SL11H_CTL1MASK_LSPD;
+                       ctrl2 |= SL811HS_CTL2MASK_DSWAP;
+               }
+
+               /* start SOFs flowing, kickstarting with A registers */
+               sl811->ctrl1 |= SL11H_CTL1MASK_SOF_ENA;
+               sl811_write(sl811, SL11H_SOFLOWREG, 0xe0);
+               sl811_write(sl811, SL811HS_CTLREG2, ctrl2);
+
+               /* autoincrementing */
+               sl811_write(sl811, SL811_EP_A(SL11H_BUFLNTHREG), 0);
+               writeb(SL_SOF, sl811->data_reg);
+               writeb(0, sl811->data_reg);
+               sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG),
+                               SL11H_HCTLMASK_ARM);
+
+               /* khubd provides debounce delay */
+       } else {
+               sl811->ctrl1 = 0;
+       }
+       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+
+       /* reenable irqs */
+       sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
+       spin_unlock_irqrestore(&sl811->lock, flags);
+}
+
+static int
+sl811h_hub_control(
+       struct usb_hcd  *hcd,
+       u16             typeReq,
+       u16             wValue,
+       u16             wIndex,
+       char            *buf,
+       u16             wLength
+) {
+       struct sl811    *sl811 = hcd_to_sl811(hcd);
+       int             retval = 0;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&sl811->lock, flags);
+
+       switch (typeReq) {
+       case ClearHubFeature:
+       case SetHubFeature:
+               switch (wValue) {
+               case C_HUB_OVER_CURRENT:
+               case C_HUB_LOCAL_POWER:
+                       break;
+               default:
+                       goto error;
+               }
+               break;
+       case ClearPortFeature:
+               if (wIndex != 1 || wLength != 0)
+                       goto error;
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       sl811->port1 &= (1 << USB_PORT_FEAT_POWER);
+                       sl811->ctrl1 = 0;
+                       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+                       sl811->irq_enable = SL11H_INTMASK_INSRMV;
+                       sl811_write(sl811, SL11H_IRQ_ENABLE,
+                                               sl811->irq_enable);
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       if (!(sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)))
+                               break;
+
+                       /* 20 msec of resume/K signaling, other irqs blocked */
+                       DBG("start resume...\n");
+                       sl811->irq_enable = 0;
+                       sl811_write(sl811, SL11H_IRQ_ENABLE,
+                                               sl811->irq_enable);
+                       sl811->ctrl1 |= SL11H_CTL1MASK_K;
+                       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+
+                       mod_timer(&sl811->timer, jiffies
+                                       + msecs_to_jiffies(20));
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       port_power(sl811, 0);
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+               case USB_PORT_FEAT_C_SUSPEND:
+               case USB_PORT_FEAT_C_CONNECTION:
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+               case USB_PORT_FEAT_C_RESET:
+                       break;
+               default:
+                       goto error;
+               }
+               sl811->port1 &= ~(1 << wValue);
+               break;
+       case GetHubDescriptor:
+               sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
+               break;
+       case GetHubStatus:
+               *(__le32 *) buf = cpu_to_le32(0);
+               break;
+       case GetPortStatus:
+               if (wIndex != 1)
+                       goto error;
+               *(__le32 *) buf = cpu_to_le32(sl811->port1);
+
+#ifndef        VERBOSE
+       if (*(u16*)(buf+2))     /* only if wPortChange is interesting */
+#endif
+               DBG("GetPortStatus %08x\n", sl811->port1);
+               break;
+       case SetPortFeature:
+               if (wIndex != 1 || wLength != 0)
+                       goto error;
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       if (sl811->port1 & (1 << USB_PORT_FEAT_RESET))
+                               goto error;
+                       if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)))
+                               goto error;
+
+                       DBG("suspend...\n");
+                       sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
+                       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       port_power(sl811, 1);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
+                               goto error;
+                       if (!(sl811->port1 & (1 << USB_PORT_FEAT_POWER)))
+                               break;
+
+                       /* 50 msec of reset/SE0 signaling, irqs blocked */
+                       sl811->irq_enable = 0;
+                       sl811_write(sl811, SL11H_IRQ_ENABLE,
+                                               sl811->irq_enable);
+                       sl811->ctrl1 = SL11H_CTL1MASK_SE0;
+                       sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
+                       sl811->port1 |= (1 << USB_PORT_FEAT_RESET);
+                       mod_timer(&sl811->timer, jiffies
+                                       + msecs_to_jiffies(50));
+                       break;
+               default:
+                       goto error;
+               }
+               sl811->port1 |= 1 << wValue;
+               break;
+
+       default:
+error:
+               /* "protocol stall" on error */
+               retval = -EPIPE;
+       }
+
+       spin_unlock_irqrestore(&sl811->lock, flags);
+       return retval;
+}
+
+#ifdef CONFIG_PM
+
+static int
+sl811h_hub_suspend(struct usb_hcd *hcd)
+{
+       // SOFs off
+       DBG("%s\n", __FUNCTION__);
+       return 0;
+}
+
+static int
+sl811h_hub_resume(struct usb_hcd *hcd)
+{
+       // SOFs on
+       DBG("%s\n", __FUNCTION__);
+       return 0;
+}
+
+#else
+
+#define        sl811h_hub_suspend      NULL
+#define        sl811h_hub_resume       NULL
+
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILE
+
+static inline void create_debug_file(struct sl811 *sl811) { }
+static inline void remove_debug_file(struct sl811 *sl811) { }
+
+#else
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void dump_irq(struct seq_file *s, char *label, u8 mask)
+{
+       seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask,
+               (mask & SL11H_INTMASK_DONE_A) ? " done_a" : "",
+               (mask & SL11H_INTMASK_DONE_B) ? " done_b" : "",
+               (mask & SL11H_INTMASK_SOFINTR) ? " sof" : "",
+               (mask & SL11H_INTMASK_INSRMV) ? " ins/rmv" : "",
+               (mask & SL11H_INTMASK_RD) ? " rd" : "",
+               (mask & SL11H_INTMASK_DP) ? " dp" : "");
+}
+
+static int proc_sl811h_show(struct seq_file *s, void *unused)
+{
+       struct sl811            *sl811 = s->private;
+       struct sl811h_ep        *ep;
+       unsigned                i;
+
+       seq_printf(s, "%s\n%s version %s\nportstatus[1] = %08x\n",
+               sl811->hcd.product_desc,
+               hcd_name, DRIVER_VERSION,
+               sl811->port1);
+
+       seq_printf(s, "insert/remove: %ld\n", sl811->stat_insrmv);
+       seq_printf(s, "current session:  done_a %ld done_b %ld "
+                       "wake %ld sof %ld overrun %ld lost %ld\n\n",
+               sl811->stat_a, sl811->stat_b,
+               sl811->stat_wake, sl811->stat_sof,
+               sl811->stat_overrun, sl811->stat_lost);
+
+       spin_lock_irq(&sl811->lock);
+
+       if (sl811->ctrl1 & SL11H_CTL1MASK_SUSPEND)
+               seq_printf(s, "(suspended)\n\n");
+       else {
+               u8      t = sl811_read(sl811, SL11H_CTLREG1);
+
+               seq_printf(s, "ctrl1 %02x%s%s%s%s\n", t,
+                       (t & SL11H_CTL1MASK_SOF_ENA) ? " sofgen" : "",
+                       ({char *s; switch (t & SL11H_CTL1MASK_FORCE) {
+                       case SL11H_CTL1MASK_NORMAL: s = ""; break;
+                       case SL11H_CTL1MASK_SE0: s = " se0/reset"; break;
+                       case SL11H_CTL1MASK_K: s = " k/resume"; break;
+                       default: s = "j"; break;
+                       }; s; }),
+                       (t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "",
+                       (t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : "");
+
+               dump_irq(s, "irq_enable",
+                               sl811_read(sl811, SL11H_IRQ_ENABLE));
+               dump_irq(s, "irq_status",
+                               sl811_read(sl811, SL11H_IRQ_STATUS));
+               seq_printf(s, "frame clocks remaining:  %d\n",
+                               sl811_read(sl811, SL11H_SOFTMRREG) << 6);
+       }
+
+       seq_printf(s, "A: qh%p ctl %02x sts %02x\n", sl811->active_a,
+               sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)),
+               sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
+       seq_printf(s, "B: qh%p ctl %02x sts %02x\n", sl811->active_b,
+               sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)),
+               sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
+       seq_printf(s, "\n");
+       list_for_each_entry (ep, &sl811->async, schedule) {
+               struct sl811h_req       *req;
+
+               seq_printf(s, "%s%sqh%p, ep%d%s, maxpacket %d"
+                                       " nak %d err %d\n",
+                       (ep == sl811->active_a) ? "(A) " : "",
+                       (ep == sl811->active_b) ? "(B) " : "",
+                       ep, ep->epnum,
+                       ({ char *s; switch (ep->nextpid) {
+                       case USB_PID_IN: s = "in"; break;
+                       case USB_PID_OUT: s = "out"; break;
+                       case USB_PID_SETUP: s = "setup"; break;
+                       case USB_PID_ACK: s = "status"; break;
+                       default: s = "?"; break;
+                       }; s;}),
+                       ep->maxpacket,
+                       ep->nak_count, ep->error_count);
+               list_for_each_entry (req, &ep->queue, queue) {
+                       seq_printf(s, "  urb%p, %d/%d\n", req->urb,
+                               req->urb->actual_length,
+                               req->urb->transfer_buffer_length);
+               }
+       }
+       if (!list_empty(&sl811->async))
+               seq_printf(s, "\n");
+
+       seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE);
+
+       for (i = 0; i < PERIODIC_SIZE; i++) {
+               ep = sl811->periodic[i];
+               if (!ep)
+                       continue;
+               seq_printf(s, "%2d [%3d]:\n", i, sl811->load[i]);
+
+               /* DUMB: prints shared entries multiple times */
+               do {
+                       seq_printf(s,
+                               "   %s%sqh%d/%p (%sdev%d ep%d%s max %d) "
+                                       "err %d\n",
+                               (ep == sl811->active_a) ? "(A) " : "",
+                               (ep == sl811->active_b) ? "(B) " : "",
+                               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->error_count);
+                       ep = ep->next;
+               } while (ep);
+       }
+
+       spin_unlock_irq(&sl811->lock);
+       seq_printf(s, "\n");
+
+       return 0;
+}
+
+static int proc_sl811h_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_sl811h_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+       .open           = proc_sl811h_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/* expect just one sl811 per system */
+static const char proc_filename[] = "driver/sl811h";
+
+static void create_debug_file(struct sl811 *sl811)
+{
+       struct proc_dir_entry *pde;
+
+       pde = create_proc_entry(proc_filename, 0, NULL);
+       if (pde == NULL)
+               return;
+
+       pde->proc_fops = &proc_ops;
+       pde->data = sl811;
+       sl811->pde = pde;
+}
+
+static void remove_debug_file(struct sl811 *sl811)
+{
+       if (sl811->pde)
+               remove_proc_entry(proc_filename, NULL);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void
+sl811h_stop(struct usb_hcd *hcd)
+{
+       struct sl811    *sl811 = hcd_to_sl811(hcd);
+       unsigned long   flags;
+
+       del_timer_sync(&sl811->hcd.rh_timer);
+
+       spin_lock_irqsave(&sl811->lock, flags);
+       port_power(sl811, 0);
+       spin_unlock_irqrestore(&sl811->lock, flags);
+}
+
+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, &sl811->hcd.self, 0);
+       if (!udev)
+               return -ENOMEM;
+
+       udev->speed = USB_SPEED_FULL;
+       hcd->state = USB_STATE_RUNNING;
+
+       if (sl811->board)
+               sl811->hcd.can_wakeup = sl811->board->can_wakeup;
+
+       if (hcd_register_root(udev, &sl811->hcd) != 0) {
+               usb_put_dev(udev);
+               sl811h_stop(hcd);
+               return -ENODEV;
+       }
+
+       if (sl811->board && sl811->board->power)
+               hub_set_power_budget(udev, sl811->board->power * 2);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct hc_driver sl811h_hc_driver = {
+       .description =          hcd_name,
+
+       /*
+        * generic hardware linkage
+        */
+       .flags =                HCD_USB11,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          sl811h_urb_enqueue,
+       .urb_dequeue =          sl811h_urb_dequeue,
+       .endpoint_disable =     sl811h_endpoint_disable,
+
+       /*
+        * periodic schedule support
+        */
+       .get_frame_number =     sl811h_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      sl811h_hub_status_data,
+       .hub_control =          sl811h_hub_control,
+       .hub_suspend =          sl811h_hub_suspend,
+       .hub_resume =           sl811h_hub_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init_or_module
+sl811h_remove(struct device *dev)
+{
+       struct sl811            *sl811 = dev_get_drvdata(dev);
+       struct platform_device  *pdev;
+       struct resource         *res;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       if (HCD_IS_RUNNING(sl811->hcd.state))
+               sl811->hcd.state = USB_STATE_QUIESCING;
+
+       usb_disconnect(&sl811->hcd.self.root_hub);
+       remove_debug_file(sl811);
+       sl811h_stop(&sl811->hcd);
+
+       if (!list_empty(&sl811->hcd.self.bus_list))
+               usb_deregister_bus(&sl811->hcd.self);
+
+       if (sl811->hcd.irq >= 0)
+               free_irq(sl811->hcd.irq, sl811);
+
+       if (sl811->data_reg)
+               iounmap(sl811->data_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       release_mem_region(res->start, 1);
+
+       if (sl811->addr_reg) 
+               iounmap(sl811->addr_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, 1);
+
+       kfree(sl811);
+       return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init
+sl811h_probe(struct device *dev)
+{
+       struct sl811            *sl811;
+       struct platform_device  *pdev;
+       struct resource         *addr, *data;
+       int                     irq;
+       int                     status;
+       u8                      tmp;
+       unsigned long           flags;
+
+       /* basic sanity checks first.  board-specific init logic should
+        * have initialized these three resources and probably board
+        * specific platform_data.  we don't probe for IRQs, and do only
+        * minimal sanity checking.
+        */
+       pdev = container_of(dev, struct platform_device, dev);
+       if (pdev->num_resources < 3)
+               return -ENODEV;
+
+       addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       irq = platform_get_irq(pdev, 0);
+       if (!addr || !data || irq < 0)
+               return -ENODEV;
+
+       /* refuse to confuse usbcore */
+       if (dev->dma_mask) {
+               DBG("no we won't dma\n");
+               return -EINVAL;
+       }
+
+       if (!request_mem_region(addr->start, 1, hcd_name))
+               return -EBUSY;
+       if (!request_mem_region(data->start, 1, hcd_name)) {
+               release_mem_region(addr->start, 1);
+               return -EBUSY;
+       }
+
+       /* allocate and initialize hcd */
+       sl811 = kcalloc(1, sizeof *sl811, GFP_KERNEL);
+       if (!sl811)
+               return 0;
+       dev_set_drvdata(dev, sl811);
+
+       usb_bus_init(&sl811->hcd.self);
+       sl811->hcd.self.controller = dev;
+       sl811->hcd.self.bus_name = dev->bus_id;
+       sl811->hcd.self.op = &usb_hcd_operations;
+       sl811->hcd.self.hcpriv = sl811;
+
+       // NOTE: 2.6.11 starts to change the hcd glue layer some more,
+       // eventually letting us eliminate struct sl811h_req and a
+       // lot of the boilerplate code here 
+
+       INIT_LIST_HEAD(&sl811->hcd.dev_list);
+       sl811->hcd.self.release = &usb_hcd_release;
+
+       sl811->hcd.description = sl811h_hc_driver.description;
+       init_timer(&sl811->hcd.rh_timer);
+       sl811->hcd.driver = &sl811h_hc_driver;
+       sl811->hcd.irq = -1;
+       sl811->hcd.state = USB_STATE_HALT;
+
+       spin_lock_init(&sl811->lock);
+       INIT_LIST_HEAD(&sl811->async);
+       sl811->board = dev->platform_data;
+       init_timer(&sl811->timer);
+       sl811->timer.function = sl811h_timer;
+       sl811->timer.data = (unsigned long) sl811;
+
+       sl811->addr_reg = ioremap(addr->start, resource_len(addr));
+       if (sl811->addr_reg == NULL) {
+               status = -ENOMEM;
+               goto fail;
+       }
+       sl811->data_reg = ioremap(data->start, resource_len(addr));
+       if (sl811->data_reg == NULL) {
+               status = -ENOMEM;
+               goto fail;
+       }
+
+       spin_lock_irqsave(&sl811->lock, flags);
+       port_power(sl811, 0);
+       spin_unlock_irqrestore(&sl811->lock, flags);
+       msleep(200);
+
+       tmp = sl811_read(sl811, SL11H_HWREVREG);
+       switch (tmp >> 4) {
+       case 1:
+               sl811->hcd.product_desc = "SL811HS v1.2";
+               break;
+       case 2:
+               sl811->hcd.product_desc = "SL811HS v1.5";
+               break;
+       default:
+               /* reject case 0, SL11S is less functional */
+               DBG("chiprev %02x\n", tmp);
+               status = -ENXIO;
+               goto fail;
+       }
+
+       /* sl811s would need a different handler for this irq */
+#ifdef CONFIG_ARM
+       /* Cypress docs say the IRQ is IRQT_HIGH ... */
+       set_irq_type(irq, IRQT_RISING);
+#endif
+       status = request_irq(irq, sl811h_irq, SA_INTERRUPT, hcd_name, sl811);
+       if (status < 0)
+               goto fail;
+       sl811->hcd.irq = irq;
+
+       INFO("%s, irq %d\n", sl811->hcd.product_desc, irq);
+
+       status = usb_register_bus(&sl811->hcd.self);
+       if (status < 0)
+               goto fail;
+       status = sl811h_start(&sl811->hcd);
+       if (status == 0) {
+               create_debug_file(sl811);
+               return 0;
+       }
+fail:
+       sl811h_remove(dev);
+       DBG("init error, %d\n", status);
+       return status;
+}
+
+#ifdef CONFIG_PM
+
+/* for this device there's no useful distinction between the controller
+ * and its root hub, except that the root hub only gets direct PM calls 
+ * when CONFIG_USB_SUSPEND is enabled.
+ */
+
+static int
+sl811h_suspend(struct device *dev, u32 state, u32 phase)
+{
+       struct sl811    *sl811 = dev_get_drvdata(dev);
+       int             retval = 0;
+
+       if (phase != SUSPEND_POWER_DOWN)
+               return retval;
+
+       if (state <= PM_SUSPEND_MEM)
+               retval = sl811h_hub_suspend(&sl811->hcd);
+       else
+               port_power(sl811, 0);
+       if (retval == 0)
+               dev->power.power_state = state;
+       return retval;
+}
+
+static int
+sl811h_resume(struct device *dev, u32 phase)
+{
+       struct sl811    *sl811 = dev_get_drvdata(dev);
+
+       if (phase != RESUME_POWER_ON)
+               return 0;
+
+       /* with no "check to see if VBUS is still powered" board hook,
+        * let's assume it'd only be powered to enable remote wakeup.
+        */
+       if (dev->power.power_state > PM_SUSPEND_MEM
+                       || !sl811->hcd.can_wakeup) {
+               sl811->port1 = 0;
+               port_power(sl811, 1);
+               return 0;
+       }
+
+       dev->power.power_state = PM_SUSPEND_ON;
+       return sl811h_hub_resume(&sl811->hcd);
+}
+
+#else
+
+#define        sl811h_suspend  NULL
+#define        sl811h_resume   NULL
+
+#endif
+
+
+static struct device_driver sl811h_driver = {
+       .name =         (char *) hcd_name,
+       .bus =          &platform_bus_type,
+
+       .probe =        sl811h_probe,
+       .remove =       sl811h_remove,
+
+       .suspend =      sl811h_suspend,
+       .resume =       sl811h_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+static int __init sl811h_init(void) 
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
+       return driver_register(&sl811h_driver);
+}
+module_init(sl811h_init);
+
+static void __exit sl811h_cleanup(void) 
+{      
+       driver_unregister(&sl811h_driver);
+}
+module_exit(sl811h_cleanup);
diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h
new file mode 100644 (file)
index 0000000..1f5f0d4
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * SL811HS register declarations and HCD data structures
+ *
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ * Copyright (C) 2001 Cypress Semiconductor Inc. 
+ */
+
+/*
+ * SL811HS has transfer registers, and control registers.  In host/master
+ * mode one set of registers is used; in peripheral/slave mode, another.
+ *  - SL11H only has some "A" transfer registers from 0x00-0x04
+ *  - SL811HS also has "B" registers from 0x08-0x0c
+ *  - SL811S (or HS in slave mode) has four A+B sets, at 00, 10, 20, 30
+ */
+
+#define SL811_EP_A(base)       ((base) + 0)
+#define SL811_EP_B(base)       ((base) + 8)
+
+#define SL811_HOST_BUF         0x00
+#define SL811_PERIPH_EP0       0x00
+#define SL811_PERIPH_EP1       0x10
+#define SL811_PERIPH_EP2       0x20
+#define SL811_PERIPH_EP3       0x30
+
+
+/* TRANSFER REGISTERS:  host and peripheral sides are similar
+ * except for the control models (master vs slave).
+ */
+#define SL11H_HOSTCTLREG       0
+#      define SL11H_HCTLMASK_ARM       0x01
+#      define SL11H_HCTLMASK_ENABLE    0x02
+#      define SL11H_HCTLMASK_IN        0x00
+#      define SL11H_HCTLMASK_OUT       0x04
+#      define SL11H_HCTLMASK_ISOCH     0x10
+#      define SL11H_HCTLMASK_AFTERSOF  0x20
+#      define SL11H_HCTLMASK_TOGGLE    0x40
+#      define SL11H_HCTLMASK_PREAMBLE  0x80
+#define SL11H_BUFADDRREG       1
+#define SL11H_BUFLNTHREG       2
+#define SL11H_PKTSTATREG       3       /* read */
+#      define SL11H_STATMASK_ACK       0x01
+#      define SL11H_STATMASK_ERROR     0x02
+#      define SL11H_STATMASK_TMOUT     0x04
+#      define SL11H_STATMASK_SEQ       0x08
+#      define SL11H_STATMASK_SETUP     0x10
+#      define SL11H_STATMASK_OVF       0x20
+#      define SL11H_STATMASK_NAK       0x40
+#      define SL11H_STATMASK_STALL     0x80
+#define SL11H_PIDEPREG         3       /* write */
+#      define  SL_SETUP        0xd0
+#      define  SL_IN           0x90
+#      define  SL_OUT          0x10
+#      define  SL_SOF          0x50
+#      define  SL_PREAMBLE     0xc0
+#      define  SL_NAK          0xa0
+#      define  SL_STALL        0xe0
+#      define  SL_DATA0        0x30
+#      define  SL_DATA1        0xb0
+#define SL11H_XFERCNTREG       4       /* read */
+#define SL11H_DEVADDRREG       4       /* write */
+
+
+/* CONTROL REGISTERS:  host and peripheral are very different.
+ */
+#define SL11H_CTLREG1          5
+#      define SL11H_CTL1MASK_SOF_ENA   0x01
+#      define SL11H_CTL1MASK_FORCE     0x18
+#              define SL11H_CTL1MASK_NORMAL    0x00
+#              define SL11H_CTL1MASK_SE0       0x08    /* reset */
+#              define SL11H_CTL1MASK_J         0x10
+#              define SL11H_CTL1MASK_K         0x18    /* resume */
+#      define SL11H_CTL1MASK_LSPD      0x20
+#      define SL11H_CTL1MASK_SUSPEND   0x40
+#define SL11H_IRQ_ENABLE       6
+#      define SL11H_INTMASK_DONE_A     0x01
+#      define SL11H_INTMASK_DONE_B     0x02
+#      define SL11H_INTMASK_SOFINTR    0x10
+#      define SL11H_INTMASK_INSRMV     0x20    /* to/from SE0 */
+#      define SL11H_INTMASK_RD         0x40
+#      define SL11H_INTMASK_DP         0x80    /* only in INTSTATREG */
+#define SL11S_ADDRESS          7
+
+/* 0x08-0x0c are for the B buffer (not in SL11) */
+
+#define SL11H_IRQ_STATUS       0x0D    /* write to ack */
+#define SL11H_HWREVREG         0x0E    /* read */
+#      define SL11H_HWRMASK_HWREV      0xF0
+#define SL11H_SOFLOWREG                0x0E    /* write */
+#define SL11H_SOFTMRREG                0x0F    /* read */
+
+/* a write to this register enables SL811HS features.
+ * HOST flag presumably overrides the chip input signal?
+ */
+#define SL811HS_CTLREG2                0x0F
+#      define SL811HS_CTL2MASK_SOF_MASK        0x3F
+#      define SL811HS_CTL2MASK_DSWAP           0x40
+#      define SL811HS_CTL2MASK_HOST            0x80
+
+#define SL811HS_CTL2_INIT      (SL811HS_CTL2MASK_HOST | 0x2e)
+
+
+/* DATA BUFFERS: registers from 0x10..0xff are for data buffers;
+ * that's 240 bytes, which we'll split evenly between A and B sides.
+ * Only ISO can use more than 64 bytes per packet.
+ * (The SL11S has 0x40..0xff for buffers.)
+ */
+#define H_MAXPACKET    120             /* bytes in A or B fifos */
+
+#define SL11H_DATA_START       0x10
+#define        SL811HS_PACKET_BUF(is_a)        ((is_a) \
+               ? SL11H_DATA_START \
+               : (SL11H_DATA_START + H_MAXPACKET))
+
+/*-------------------------------------------------------------------------*/
+
+#define        LOG2_PERIODIC_SIZE      5       /* arbitrary; this matches OHCI */
+#define        PERIODIC_SIZE           (1 << LOG2_PERIODIC_SIZE)
+
+struct sl811 {
+       struct usb_hcd          hcd;
+       spinlock_t              lock;
+       void __iomem            *addr_reg;
+       void __iomem            *data_reg;
+       struct sl811_platform_data      *board;
+       struct proc_dir_entry   *pde;
+
+       unsigned long           stat_insrmv;
+       unsigned long           stat_wake;
+       unsigned long           stat_sof;
+       unsigned long           stat_a;
+       unsigned long           stat_b;
+       unsigned long           stat_lost;
+       unsigned long           stat_overrun;
+
+       /* sw model */
+       struct timer_list       timer;
+       struct sl811h_ep        *next_periodic;
+       struct sl811h_ep        *next_async;
+
+       struct sl811h_ep        *active_a;
+       unsigned long           jiffies_a;
+       struct sl811h_ep        *active_b;
+       unsigned long           jiffies_b;
+
+       u32                     port1;
+       u8                      ctrl1, ctrl2, irq_enable;
+       u16                     frame;
+
+       /* async schedule: control, bulk */
+       struct list_head        async;
+
+       /* periodic schedule: interrupt, iso */
+       u16                     load[PERIODIC_SIZE];
+       struct sl811h_ep        *periodic[PERIODIC_SIZE];
+       unsigned                periodic_count;
+};
+
+static inline struct sl811 *hcd_to_sl811(struct usb_hcd *hcd)
+{
+       return container_of(hcd, struct sl811, hcd);
+}
+
+struct sl811h_ep {
+       struct list_head        queue;
+       struct usb_device       *udev;
+
+       u8                      defctrl;
+       u8                      maxpacket;
+       u8                      epnum;
+       u8                      nextpid;
+
+       u16                     error_count;
+       u16                     nak_count;
+       u16                     length;         /* of current packet */
+
+       /* periodic schedule */
+       u16                     period;
+       u16                     branch;
+       u16                     load;
+       struct sl811h_ep        *next;
+
+       /* async schedule */
+       struct list_head        schedule;
+};
+
+struct sl811h_req {
+       /* FIXME usbcore should maintain endpoints' urb queues
+        * directly in 'struct usb_host_endpoint'
+        */
+       struct urb              *urb;
+       struct list_head        queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* These register utilities should work for the SL811S register API too
+ * NOTE:  caller must hold sl811->lock.
+ */
+
+static inline u8 sl811_read(struct sl811 *sl811, int reg)
+{
+       writeb(reg, sl811->addr_reg);
+       return readb(sl811->data_reg);
+}
+
+static inline void sl811_write(struct sl811 *sl811, int reg, u8 val)
+{
+       writeb(reg, sl811->addr_reg);
+       writeb(val, sl811->data_reg);
+}
+
+static inline void
+sl811_write_buf(struct sl811 *sl811, int addr, const void *buf, size_t count)
+{
+       const u8        *data;
+       void __iomem    *data_reg;
+
+       if (!count)
+               return;
+       writeb(addr, sl811->addr_reg);
+
+       data = buf;
+       data_reg = sl811->data_reg;
+       do {
+               writeb(*data++, data_reg);
+       } while (--count);
+}
+
+static inline void
+sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count)
+{
+       u8              *data;
+       void __iomem    *data_reg;
+
+       if (!count)
+               return;
+       writeb(addr, sl811->addr_reg);
+
+       data = buf;
+       data_reg = sl811->data_reg;
+       do {
+               *data++ = readb(data_reg);
+       } while (--count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)          printk(KERN_DEBUG "sl811: " stuff)
+#else
+#define DBG(stuff...)          do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG               DBG
+#else
+#    define VDBG(stuff...)     do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET             VDBG
+#else
+#    define PACKET(stuff...)   do{}while(0)
+#endif
+
+#define ERR(stuff...)          printk(KERN_ERR "sl811: " stuff)
+#define WARN(stuff...)         printk(KERN_WARNING "sl811: " stuff)
+#define INFO(stuff...)         printk(KERN_INFO "sl811: " stuff)
+
diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c
new file mode 100644 (file)
index 0000000..26944ea
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
+ *                       <medaglia@undl.org.br>                            *
+ *                       http://cadu.homelinux.com:8080/                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x20, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x0c);
+       err += sn9c102_i2c_write(cam, 0x03, 0x40);
+       err += sn9c102_i2c_write(cam, 0x04, 0x07);
+       err += sn9c102_i2c_write(cam, 0x05, 0x25);
+       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x08, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0b, 0x01);
+       err += sn9c102_i2c_write(cam, 0x13, 0x63);
+       err += sn9c102_i2c_write(cam, 0x15, 0x70);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct sn9c102_device* cam, 
+                              struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_BRIGHTNESS:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas202bcb_set_ctrl(struct sn9c102_device* cam, 
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f);
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f));
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       return err;
+}
+
+
+static int pas202bcb_set_crop(struct sn9c102_device* cam, 
+                              const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas202bcb;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas202bcb = {
+       .name = "PAS202BCB",
+       .maintainer = "Carlos Eduardo Medaglia Dyonisio "
+                     "<medaglia@undl.org.br>",
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .slave_read_id = 0x40,
+       .slave_write_id = 0x40,
+       .init = &pas202bcb_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BRIGHTNESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "brightness",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x0f,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &pas202bcb_get_ctrl,
+       .set_ctrl = &pas202bcb_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &pas202bcb_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       }
+};
+
+
+int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
+{       
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       /*
+        *  Minimal initialization to enable the I2C communication
+        *  NOTE: do NOT change the values!
+        */
+       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
+       err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
+       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
+       
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x017)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas202bcb);
+
+       return 0;
+}
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
new file mode 100644 (file)
index 0000000..ace44a7
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * USB PhidgetInterfaceKit driver 1.0
+ *
+ * Copyright (C) 2004 Sean Young <sean@mess.org>
+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is a driver for the USB PhidgetInterfaceKit.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
+#define DRIVER_DESC "USB PhidgetInterfaceKit Driver"
+
+#define USB_VENDOR_ID_GLAB             0x06c2
+#define USB_DEVICE_ID_INTERFACEKIT004  0x0040
+#define USB_DEVICE_ID_INTERFACEKIT888  0x0045
+#define USB_DEVICE_ID_INTERFACEKIT047  0x0051
+#define USB_DEVICE_ID_INTERFACEKIT088  0x0053
+
+#define USB_VENDOR_ID_WISEGROUP                0x0925
+#define USB_DEVICE_ID_INTERFACEKIT884  0x8201
+
+#define MAX_INTERFACES                 8
+
+struct driver_interfacekit {
+       int sensors;
+       int inputs;
+       int outputs;
+       int has_lcd;
+};
+#define ifkit(_sensors, _inputs, _outputs, _lcd)                       \
+static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \
+       .sensors        = _sensors,                                     \
+       .inputs         = _inputs,                                      \
+       .outputs        = _outputs,                                     \
+       .has_lcd        = _lcd,                                         \
+};
+ifkit(0, 0, 4, 0);
+ifkit(8, 8, 8, 0);
+ifkit(0, 4, 7, 1);
+ifkit(8, 8, 4, 0);
+ifkit(0, 8, 8, 1);
+
+struct phidget_interfacekit {
+       struct usb_device *udev;
+       struct usb_interface *intf;
+       struct driver_interfacekit *ifkit;
+       int outputs[MAX_INTERFACES];
+       int inputs[MAX_INTERFACES];
+       int sensors[MAX_INTERFACES];
+       u8 lcd_files_on;
+
+       struct urb *irq;
+       unsigned char *data;
+       dma_addr_t data_dma;
+};
+
+static struct usb_device_id id_table[] = {
+       {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004),
+               .driver_info = (kernel_ulong_t)&ph_004},
+       {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888),
+               .driver_info = (kernel_ulong_t)&ph_888},
+       {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047),
+               .driver_info = (kernel_ulong_t)&ph_047},
+       {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
+               .driver_info = (kernel_ulong_t)&ph_088},
+       {USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884),
+               .driver_info = (kernel_ulong_t)&ph_884},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int change_outputs(struct phidget_interfacekit *kit, int output_num, int enable)
+{
+       unsigned char *buffer;
+       int retval;
+       int n;
+
+       buffer = kmalloc(4, GFP_KERNEL);
+       if (!buffer) {
+               dev_err(&kit->udev->dev, "%s - out of memory\n",
+                       __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       kit->outputs[output_num] = enable;
+       memset(buffer, 0, 4);
+       for (n=0; n<8; n++) {
+               if (kit->outputs[n]) {
+                       buffer[0] |= 1 << n;
+               }
+       }
+
+       dev_dbg(&kit->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]);
+
+       retval = usb_control_msg(kit->udev,
+                        usb_sndctrlpipe(kit->udev, 0),
+                        0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2 * HZ);
+
+       if (retval != 4)
+               dev_err(&kit->udev->dev, "retval = %d\n", retval);
+       kfree(buffer);
+
+       return retval < 0 ? retval : 0;
+}
+
+static int change_string(struct phidget_interfacekit *kit, const char *display, unsigned char row)
+{
+       unsigned char *buffer;
+        unsigned char *form_buffer;
+       int retval = -ENOMEM;
+       int i,j, len, buf_ptr;
+       
+       buffer = kmalloc(8, GFP_KERNEL);
+       form_buffer = kmalloc(30, GFP_KERNEL);
+       if ((!buffer) || (!form_buffer)) {
+               dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+               goto exit;
+       }
+
+       len = strlen(display);
+       if (len > 20)
+               len = 20;
+
+       dev_dbg(&kit->udev->dev, "Setting LCD line %d to %s\n", row, display);
+
+       form_buffer[0] = row * 0x40 + 0x80;
+       form_buffer[1] = 0x02;
+       buf_ptr = 2;
+       for (i = 0; i<len; i++)
+               form_buffer[buf_ptr++] = display[i];
+
+       for (i = 0; i < (20 - len); i++)
+               form_buffer[buf_ptr++] = 0x20;
+       form_buffer[buf_ptr++] = 0x01;
+       form_buffer[buf_ptr++] = row * 0x40 + 0x80 + strlen(display);
+
+       for (i = 0; i < buf_ptr; i += 7) {
+               if ((buf_ptr - i) > 7)
+                       len = 7;
+               else
+                       len = (buf_ptr - i);
+               for (j = 0; j < len; j++)
+                       buffer[j] = form_buffer[i + j];
+               buffer[7] = len;
+
+               retval = usb_control_msg(kit->udev,
+                                usb_sndctrlpipe(kit->udev, 0),
+                                0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2 * HZ);
+               if (retval < 0)
+                       goto exit;
+       }
+
+       retval = 0;
+exit:
+       kfree(buffer);
+       kfree(form_buffer);
+
+       return retval;
+}
+
+#define set_lcd_line(number)   \
+static ssize_t lcd_line_##number(struct device *dev, const char *buf, size_t count)    \
+{                                                                                      \
+       struct usb_interface *intf = to_usb_interface(dev);                             \
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);                      \
+       change_string(kit, buf, number - 1);                                            \
+       return count;                                                                   \
+}                                                                                      \
+static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number);
+set_lcd_line(1);
+set_lcd_line(2);
+
+static ssize_t set_backlight(struct device *dev, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);
+       int enabled;
+       unsigned char *buffer;
+       int retval = -ENOMEM;
+       
+       buffer = kmalloc(8, GFP_KERNEL);
+       if (!buffer) {
+               dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+               goto exit;
+       }
+
+       if (sscanf(buf, "%d", &enabled) < 1) {
+               retval = -EINVAL;
+               goto exit;
+       }
+       memset(buffer, 0x00, 8);
+       if (enabled)
+               buffer[0] = 0x01;
+       buffer[7] = 0x11;
+
+       dev_dbg(&kit->udev->dev, "Setting backlight to %s\n", enabled ? "on" : "off");
+       
+       retval = usb_control_msg(kit->udev,
+                        usb_sndctrlpipe(kit->udev, 0),
+                        0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2 * HZ);
+       if (retval < 0)
+               goto exit;
+
+       retval = count;
+exit:
+       kfree(buffer);
+       return retval;
+}
+static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight);
+
+static void remove_lcd_files(struct phidget_interfacekit *kit)
+{
+       if (kit->lcd_files_on) {
+               dev_dbg(&kit->udev->dev, "Removing lcd files\n");
+               device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1);
+               device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2);
+               device_remove_file(&kit->intf->dev, &dev_attr_backlight);
+       }
+}
+
+static ssize_t enable_lcd_files(struct device *dev, const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);
+       int enable;
+       
+       if (kit->ifkit->has_lcd == 0)
+               return -ENODEV;
+
+       if (sscanf(buf, "%d", &enable) < 1)
+               return -EINVAL;
+
+       if (enable) {
+               if (!kit->lcd_files_on) {
+                       dev_dbg(&kit->udev->dev, "Adding lcd files\n");
+                       device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1);
+                       device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2);
+                       device_create_file(&kit->intf->dev, &dev_attr_backlight);
+                       kit->lcd_files_on = 1;
+               }
+       } else {
+               if (kit->lcd_files_on) {
+                       remove_lcd_files(kit);
+                       kit->lcd_files_on = 0;
+               }
+       }
+       
+       return count;
+}
+static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
+
+static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct phidget_interfacekit *kit = urb->context;
+       unsigned char *buffer = kit->data;
+       int status;
+       int n;
+
+       switch (urb->status) {
+       case 0:                 /* success */
+               break;
+       case -ECONNRESET:       /* unlink */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       /* -EPIPE:  should clear the halt */
+       default:                /* error */
+               goto resubmit;
+       }
+
+       for (n=0; n<8; n++) {
+               kit->inputs[n] = buffer[1] & (1 << n) ? 1 : 0;
+       }
+
+       if (buffer[0] & 1) {
+               kit->sensors[4] = buffer[2] + (buffer[3] & 0x0f) * 256;
+               kit->sensors[5] = buffer[4] + (buffer[3] & 0xf0) * 16;
+               kit->sensors[6] = buffer[5] + (buffer[6] & 0x0f) * 256;
+               kit->sensors[7] = buffer[7] + (buffer[6] & 0xf0) * 16;
+       } else {
+               kit->sensors[0] = buffer[2] + (buffer[3] & 0x0f) * 256;
+               kit->sensors[1] = buffer[4] + (buffer[3] & 0xf0) * 16;
+               kit->sensors[2] = buffer[5] + (buffer[6] & 0x0f) * 256;
+               kit->sensors[3] = buffer[7] + (buffer[6] & 0xf0) * 16;
+       }
+
+resubmit:
+       status = usb_submit_urb(urb, SLAB_ATOMIC);
+       if (status)
+               err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+                       kit->udev->bus->bus_name,
+                       kit->udev->devpath, status);
+}
+
+#define show_set_output(value)         \
+static ssize_t set_output##value(struct device *dev, const char *buf,  \
+                                                       size_t count)   \
+{                                                                      \
+       struct usb_interface *intf = to_usb_interface(dev);             \
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+       int enabled;                                                    \
+       int retval;                                                     \
+                                                                       \
+       if (sscanf(buf, "%d", &enabled) < 1) {                          \
+               return -EINVAL;                                         \
+       }                                                               \
+                                                                       \
+       retval = change_outputs(kit, value - 1, enabled ? 1 : 0);       \
+                                                                       \
+       return retval ? retval : count;                                 \
+}                                                                      \
+                                                                       \
+static ssize_t show_output##value(struct device *dev, char *buf)       \
+{                                                                      \
+       struct usb_interface *intf = to_usb_interface(dev);             \
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+                                                                       \
+       return sprintf(buf, "%d\n", kit->outputs[value - 1 ]);          \
+}                                                                      \
+static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO,                   \
+               show_output##value, set_output##value);
+show_set_output(1);
+show_set_output(2);
+show_set_output(3);
+show_set_output(4);
+show_set_output(5);
+show_set_output(6);
+show_set_output(7);
+show_set_output(8);    /* should be MAX_INTERFACES - 1 */
+
+#define show_input(value)      \
+static ssize_t show_input##value(struct device *dev, char *buf)        \
+{                                                                      \
+       struct usb_interface *intf = to_usb_interface(dev);             \
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+                                                                       \
+       return sprintf(buf, "%d\n", kit->inputs[value - 1]);            \
+}                                                                      \
+static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL);
+
+show_input(1);
+show_input(2);
+show_input(3);
+show_input(4);
+show_input(5);
+show_input(6);
+show_input(7);
+show_input(8);         /* should be MAX_INTERFACES - 1 */
+
+#define show_sensor(value)     \
+static ssize_t show_sensor##value(struct device *dev, char *buf)       \
+{                                                                      \
+       struct usb_interface *intf = to_usb_interface(dev);             \
+       struct phidget_interfacekit *kit = usb_get_intfdata(intf);      \
+                                                                       \
+       return sprintf(buf, "%d\n", kit->sensors[value - 1]);           \
+}                                                                      \
+static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL);
+
+show_sensor(1);
+show_sensor(2);
+show_sensor(3);
+show_sensor(4);
+show_sensor(5);
+show_sensor(6);
+show_sensor(7);
+show_sensor(8);                /* should be MAX_INTERFACES - 1 */
+
+static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct phidget_interfacekit *kit;
+       struct driver_interfacekit *ifkit;
+       int pipe, maxp;
+
+       ifkit = (struct driver_interfacekit *)id->driver_info;
+       if (!ifkit)
+               return -ENODEV;
+
+       interface = intf->cur_altsetting;
+       if (interface->desc.bNumEndpoints != 1)
+               return -ENODEV;
+
+       endpoint = &interface->endpoint[0].desc;
+       if (!(endpoint->bEndpointAddress & 0x80)) 
+               return -ENODEV;
+       /*
+        * bmAttributes
+        */
+       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+       
+       kit = kmalloc(sizeof(*kit), GFP_KERNEL);
+       if (kit  == NULL) {
+               dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+       memset(kit, 0, sizeof(*kit));
+       kit->ifkit = ifkit;
+
+       kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma);
+       if (!kit->data) {
+               kfree(kit);
+               return -ENOMEM;
+       }
+
+       kit->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!kit->irq) {
+               usb_buffer_free(dev, 8, kit->data, kit->data_dma);
+               kfree(kit);
+               return -ENOMEM;
+       }
+
+       kit->udev = usb_get_dev(dev);
+       kit->intf = intf;
+       usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
+                       (maxp > 8 ? 8 : maxp),
+                       interfacekit_irq, kit, endpoint->bInterval);
+       kit->irq->transfer_dma = kit->data_dma;
+       kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       usb_set_intfdata(intf, kit);
+
+       if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
+               return -EIO;
+       }
+
+       if (ifkit->outputs == 8) {
+               device_create_file(&intf->dev, &dev_attr_output1);
+               device_create_file(&intf->dev, &dev_attr_output2);
+               device_create_file(&intf->dev, &dev_attr_output3);
+               device_create_file(&intf->dev, &dev_attr_output4);
+               device_create_file(&intf->dev, &dev_attr_output5);
+               device_create_file(&intf->dev, &dev_attr_output6);
+               device_create_file(&intf->dev, &dev_attr_output7);
+               device_create_file(&intf->dev, &dev_attr_output8);
+       } 
+
+       if (ifkit->inputs >= 4) {
+               device_create_file(&intf->dev, &dev_attr_input1);
+               device_create_file(&intf->dev, &dev_attr_input2);
+               device_create_file(&intf->dev, &dev_attr_input3);
+               device_create_file(&intf->dev, &dev_attr_input4);
+       }
+       if (ifkit->inputs == 8) {
+               device_create_file(&intf->dev, &dev_attr_input5);
+               device_create_file(&intf->dev, &dev_attr_input6);
+               device_create_file(&intf->dev, &dev_attr_input7);
+               device_create_file(&intf->dev, &dev_attr_input8);
+       }
+
+       if (ifkit->sensors >= 4) {
+               device_create_file(&intf->dev, &dev_attr_sensor1);
+               device_create_file(&intf->dev, &dev_attr_sensor2);
+               device_create_file(&intf->dev, &dev_attr_sensor3);
+               device_create_file(&intf->dev, &dev_attr_sensor4);
+       }
+       if (ifkit->sensors >= 7) {
+               device_create_file(&intf->dev, &dev_attr_sensor5);
+               device_create_file(&intf->dev, &dev_attr_sensor6);
+               device_create_file(&intf->dev, &dev_attr_sensor7);
+       }
+       if (ifkit->sensors == 8) {
+               device_create_file(&intf->dev, &dev_attr_sensor8);
+       }
+
+       if (ifkit->has_lcd)
+               device_create_file(&intf->dev, &dev_attr_lcd);
+
+       dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
+                       ifkit->inputs, ifkit->outputs, ifkit->sensors);
+
+       return 0;
+}
+
+static void interfacekit_disconnect(struct usb_interface *interface)
+{
+       struct phidget_interfacekit *kit;
+
+       kit = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+       if (!kit)
+               return;
+
+       if (kit->ifkit->outputs == MAX_INTERFACES) {
+               device_remove_file(&interface->dev, &dev_attr_output1);
+               device_remove_file(&interface->dev, &dev_attr_output2);
+               device_remove_file(&interface->dev, &dev_attr_output3);
+               device_remove_file(&interface->dev, &dev_attr_output4);
+               device_remove_file(&interface->dev, &dev_attr_output5);
+               device_remove_file(&interface->dev, &dev_attr_output6);
+               device_remove_file(&interface->dev, &dev_attr_output7);
+               device_remove_file(&interface->dev, &dev_attr_output7);
+       }
+
+       if (kit->ifkit->inputs >= 4) {
+               device_remove_file(&interface->dev, &dev_attr_input1);
+               device_remove_file(&interface->dev, &dev_attr_input2);
+               device_remove_file(&interface->dev, &dev_attr_input3);
+               device_remove_file(&interface->dev, &dev_attr_input4);
+       }
+       if (kit->ifkit->inputs == 8) {
+               device_remove_file(&interface->dev, &dev_attr_input5);
+               device_remove_file(&interface->dev, &dev_attr_input6);
+               device_remove_file(&interface->dev, &dev_attr_input7);
+               device_remove_file(&interface->dev, &dev_attr_input8);
+       }
+
+       if (kit->ifkit->sensors >= 4) {
+               device_remove_file(&interface->dev, &dev_attr_sensor1);
+               device_remove_file(&interface->dev, &dev_attr_sensor2);
+               device_remove_file(&interface->dev, &dev_attr_sensor3);
+               device_remove_file(&interface->dev, &dev_attr_sensor4);
+       }
+       if (kit->ifkit->sensors >= 7) {
+               device_remove_file(&interface->dev, &dev_attr_sensor5);
+               device_remove_file(&interface->dev, &dev_attr_sensor6);
+               device_remove_file(&interface->dev, &dev_attr_sensor7);
+       }
+       if (kit->ifkit->sensors == 8) {
+               device_remove_file(&interface->dev, &dev_attr_sensor8);
+       }
+       if (kit->ifkit->has_lcd)
+               device_create_file(&interface->dev, &dev_attr_lcd);
+
+       dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
+               kit->ifkit->inputs, kit->ifkit->outputs, kit->ifkit->sensors);
+
+       usb_kill_urb(kit->irq);
+       usb_free_urb(kit->irq);
+       usb_buffer_free(kit->udev, 8, kit->data, kit->data_dma);
+
+       usb_put_dev(kit->udev);
+       kfree(kit);
+}
+
+static struct usb_driver interfacekit_driver = {
+       .owner = THIS_MODULE,
+       .name = "phidgetkit",
+       .probe = interfacekit_probe,
+       .disconnect = interfacekit_disconnect,
+       .id_table = id_table
+};
+
+static int __init interfacekit_init(void)
+{
+       int retval = 0;
+
+       retval = usb_register(&interfacekit_driver);
+       if (retval)
+               err("usb_register failed. Error number %d", retval);
+
+       return retval;
+}
+
+static void __exit interfacekit_exit(void)
+{
+       usb_deregister(&interfacekit_driver);
+}
+
+module_init(interfacekit_init);
+module_exit(interfacekit_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
new file mode 100644 (file)
index 0000000..0a51a11
--- /dev/null
@@ -0,0 +1,1222 @@
+/*
+ * USB Cypress M8 driver
+ *
+ *     Copyright (C) 2004
+ *         Lonnie Mendez (dignome@gmail.com) 
+ *     Copyright (C) 2003,2004
+ *         Neil Whelchel (koyama@firstlight.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * See http://geocities.com/i0xox0i for information on this driver and the
+ * earthmate usb device.
+ *
+ *
+ *  Lonnie Mendez <dignome@gmail.com>
+ *  04-10-2004
+ *     Driver modified to support dynamic line settings.  Various improvments
+ *      and features.
+ *
+ *  Neil Whelchel
+ *  10-2003
+ *     Driver first released.
+ *
+ *
+ * Long Term TODO:
+ *     Improve transfer speeds - both read/write are somewhat slow
+ *   at this point.
+ */
+
+/* Neil Whelchel wrote the cypress m8 implementation */
+/* Thanks to cypress for providing references for the hid reports. */
+/* Thanks to Jiang Zhang for providing links and for general help. */
+/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others. */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+#include <linux/serial.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       static int debug = 1;
+#else
+       static int debug;
+#endif
+
+static int stats;
+
+#include "usb-serial.h"
+#include "cypress_m8.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.06"
+#define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"
+#define DRIVER_DESC "Cypress USB to Serial Driver"
+
+static struct usb_device_id id_table_earthmate [] = {
+       { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
+       { }                                             /* Terminating entry */
+};
+
+static struct usb_device_id id_table_cyphidcomrs232 [] = {
+       { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+       { }                                             /* Terminating entry */
+};
+
+static struct usb_device_id id_table_combined [] = {
+       { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
+       { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
+static struct usb_driver cypress_driver = {
+       .name =         "cypress",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table_combined,
+};
+
+struct cypress_private {
+       spinlock_t lock;                   /* private lock */
+       int chiptype;                      /* identifier of device, for quirks/etc */
+       int bytes_in;                      /* used for statistics */
+       int bytes_out;                     /* used for statistics */
+       int cmd_count;                     /* used for statistics */
+       int cmd_ctrl;                      /* always set this to 1 before issuing a command */
+       int termios_initialized;
+       __u8 line_control;                 /* holds dtr / rts value */
+       __u8 current_status;               /* received from last read - info on dsr,cts,cd,ri,etc */
+       __u8 current_config;               /* stores the current configuration byte */
+       __u8 rx_flags;                     /* throttling - used from whiteheat/ftdi_sio */
+       int baud_rate;                     /* stores current baud rate in integer form */
+       int cbr_mask;                      /* stores current baud rate in masked form */
+       int isthrottled;                   /* if throttled, discard reads */
+       wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */
+       char prev_status, diff_status;     /* used for TIOCMIWAIT */
+       /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
+       struct termios tmp_termios;        /* stores the old termios settings */
+       int write_interval;                /* interrupt out write interval, as obtained from interrupt_out_urb */
+       int writepipe;                     /* used for clear halt, if necessary */
+};
+
+/* function prototypes for the Cypress USB to serial device */
+static int  cypress_earthmate_startup  (struct usb_serial *serial);
+static int  cypress_hidcom_startup     (struct usb_serial *serial);
+static void cypress_shutdown           (struct usb_serial *serial);
+static int  cypress_open               (struct usb_serial_port *port, struct file *filp);
+static void cypress_close              (struct usb_serial_port *port, struct file *filp);
+static int  cypress_write              (struct usb_serial_port *port, const unsigned char *buf, int count);
+static int  cypress_write_room         (struct usb_serial_port *port);
+static int  cypress_ioctl              (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void cypress_set_termios                (struct usb_serial_port *port, struct termios * old);
+static int  cypress_tiocmget           (struct usb_serial_port *port, struct file *file);
+static int  cypress_tiocmset           (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
+static int  cypress_chars_in_buffer    (struct usb_serial_port *port);
+static void cypress_throttle           (struct usb_serial_port *port);
+static void cypress_unthrottle         (struct usb_serial_port *port);
+static void cypress_read_int_callback  (struct urb *urb, struct pt_regs *regs);
+static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs);
+static int  mask_to_rate               (unsigned mask);
+static unsigned rate_to_mask           (int rate);
+
+static struct usb_serial_device_type cypress_earthmate_device = {
+       .owner =                        THIS_MODULE,
+       .name =                         "DeLorme Earthmate USB",
+       .short_name =                   "earthmate",
+       .id_table =                     id_table_earthmate,
+       .num_interrupt_in =             1,
+       .num_interrupt_out =            1,
+       .num_bulk_in =                  NUM_DONT_CARE,
+       .num_bulk_out =                 NUM_DONT_CARE,
+       .num_ports =                    1,
+       .attach =                       cypress_earthmate_startup,
+       .shutdown =                     cypress_shutdown,
+       .open =                         cypress_open,
+       .close =                        cypress_close,
+       .write =                        cypress_write,
+       .write_room =                   cypress_write_room,
+       .ioctl =                        cypress_ioctl,
+       .set_termios =                  cypress_set_termios,
+       .tiocmget =                     cypress_tiocmget,
+       .tiocmset =                     cypress_tiocmset,
+       .chars_in_buffer =              cypress_chars_in_buffer,
+       .throttle =                     cypress_throttle,
+       .unthrottle =                   cypress_unthrottle,
+       .read_int_callback =            cypress_read_int_callback,
+       .write_int_callback =           cypress_write_int_callback,
+};
+
+static struct usb_serial_device_type cypress_hidcom_device = {
+       .owner =                        THIS_MODULE,
+       .name =                         "HID->COM RS232 Adapter",
+       .short_name =                   "cyphidcom",
+       .id_table =                     id_table_cyphidcomrs232,
+       .num_interrupt_in =             1,
+       .num_interrupt_out =            1,
+       .num_bulk_in =                  NUM_DONT_CARE,
+       .num_bulk_out =                 NUM_DONT_CARE,
+       .num_ports =                    1,
+       .attach =                       cypress_hidcom_startup,
+       .shutdown =                     cypress_shutdown,
+       .open =                         cypress_open,
+       .close =                        cypress_close,
+       .write =                        cypress_write,
+       .write_room =                   cypress_write_room,
+       .ioctl =                        cypress_ioctl,
+       .set_termios =                  cypress_set_termios,
+       .tiocmget =                     cypress_tiocmget,
+       .tiocmset =                     cypress_tiocmset,
+       .chars_in_buffer =              cypress_chars_in_buffer,
+       .throttle =                     cypress_throttle,
+       .unthrottle =                   cypress_unthrottle,
+       .read_int_callback =            cypress_read_int_callback,
+       .write_int_callback =           cypress_write_int_callback,
+};
+
+
+/*****************************************************************************
+ * Cypress serial helper functions
+ *****************************************************************************/
+
+
+/* This function can either set or retreive the current serial line settings */
+static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits,
+                                  int parity_enable, int parity_type, int reset, int cypress_request_type)
+{
+       int i, n_baud_rate = 0, retval = 0;
+       struct cypress_private *priv;
+       __u8 feature_buffer[5];
+       __u8 config;
+       unsigned long flags;
+
+       dbg("%s", __FUNCTION__);
+       
+       priv = usb_get_serial_port_data(port);
+
+       switch(cypress_request_type) {
+               case CYPRESS_SET_CONFIG:
+
+                       /*
+                        * The general purpose firmware for the Cypress M8 allows for a maximum speed
+                        * of 57600bps (I have no idea whether DeLorme chose to use the general purpose
+                        * firmware or not), if you need to modify this speed setting for your own
+                        * project please add your own chiptype and modify the code likewise.  The
+                        * Cypress HID->COM device will work successfully up to 115200bps.
+                        */
+                       if (baud_mask != priv->cbr_mask) {
+                               dbg("%s - baud rate is changing", __FUNCTION__);
+                               if ( priv->chiptype == CT_EARTHMATE ) {
+                                       /* 300 and 600 baud rates are supported under the generic firmware,
+                                        * but are not used with NMEA and SiRF protocols */
+                                       
+                                       if ( (baud_mask == B300) || (baud_mask == B600) ) {
+                                               err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+                                                   __FUNCTION__);
+                                               n_baud_rate = 4800;
+                                       } else if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
+                                               err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+                                                   __FUNCTION__);
+                                               n_baud_rate = 4800;
+                                       }
+                               } else if (priv->chiptype == CT_CYPHIDCOM) {
+                                       if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
+                                               err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+                                                   __FUNCTION__);
+                                               n_baud_rate = 4800;
+                                       }
+                               } else if (priv->chiptype == CT_GENERIC) {
+                                       if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) {
+                                               err("%s - failed setting baud rate, unsupported speed (default to 4800)",
+                                                   __FUNCTION__);
+                                               n_baud_rate = 4800;
+                                       }
+                               } else {
+                                       info("%s - please define your chiptype, using 4800bps default", __FUNCTION__);
+                                       n_baud_rate = 4800;
+                               }
+                       } else {  /* baud rate not changing, keep the old */
+                               n_baud_rate = priv->baud_rate;
+                       }
+                       dbg("%s - baud rate is being sent as %d", __FUNCTION__, n_baud_rate);
+
+                       
+                       /*
+                        * This algorithm accredited to Jiang Jay Zhang... thanks for all the help!
+                        */
+                       for (i = 0; i < 4; ++i) {
+                               feature_buffer[i] = ( n_baud_rate >> (i*8) & 0xFF );
+                       }
+
+                       config = 0;                      // reset config byte
+                       config |= data_bits;             // assign data bits in 2 bit space ( max 3 )
+                       /* 1 bit gap */
+                       config |= (stop_bits << 3);      // assign stop bits in 1 bit space
+                       config |= (parity_enable << 4);  // assign parity flag in 1 bit space
+                       config |= (parity_type << 5);    // assign parity type in 1 bit space
+                       /* 1 bit gap */
+                       config |= (reset << 7);          // assign reset at end of byte, 1 bit space
+
+                       feature_buffer[4] = config;
+                               
+                       dbg("%s - device is being sent this feature report:", __FUNCTION__);
+                       dbg("%s - %02X - %02X - %02X - %02X - %02X", __FUNCTION__, feature_buffer[0], feature_buffer[1],
+                           feature_buffer[2], feature_buffer[3], feature_buffer[4]);
+                       
+                       retval = usb_control_msg (port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
+                                                 HID_REQ_SET_REPORT, USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+                                                 0x0300, 0, feature_buffer, 5, 500);
+
+                       if (retval != 5)
+                               err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
+                       else {
+                               spin_lock_irqsave(&priv->lock, flags);
+                               priv->baud_rate = n_baud_rate;
+                               priv->cbr_mask = baud_mask;
+                               priv->current_config = config;
+                               ++priv->cmd_count;
+                               spin_unlock_irqrestore(&priv->lock, flags);
+                       }
+               break;
+               case CYPRESS_GET_CONFIG:
+                       dbg("%s - retreiving serial line settings", __FUNCTION__);
+                       /* reset values in feature buffer */
+                       memset(feature_buffer, 0, 5);
+
+                       retval = usb_control_msg (port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0),
+                                                 HID_REQ_GET_REPORT, USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+                                                 0x0300, 0, feature_buffer, 5, 500);
+                       if (retval != 5) {
+                               err("%s - failed to retreive serial line settings - %d", __FUNCTION__, retval);
+                               return retval;
+                       } else {
+                               spin_lock_irqsave(&priv->lock, flags);
+                               /* store the config in one byte, and later use bit masks to check values */
+                               priv->current_config = feature_buffer[4];
+                               /* reverse the process above to get the baud_mask value */
+                               n_baud_rate = 0; // reset bits
+                               for (i = 0; i < 4; ++i) {
+                                       n_baud_rate |= ( feature_buffer[i] << (i*8) );
+                               }
+                               
+                               priv->baud_rate = n_baud_rate;
+                               if ( (priv->cbr_mask = rate_to_mask(n_baud_rate)) == 0x40)
+                                       dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__);
+                               ++priv->cmd_count;
+                               spin_unlock_irqrestore(&priv->lock, flags);
+                       }
+                       break;
+               default:
+                       err("%s - unsupported serial control command issued", __FUNCTION__);
+       }
+       return retval;
+} /* cypress_serial_control */
+
+
+/* given a baud mask, it will return speed on success */
+static int mask_to_rate (unsigned mask)
+{
+       int rate;
+
+       switch (mask) {
+               case B0: rate = 0; break;
+               case B300: rate = 300; break;
+               case B600: rate = 600; break;
+               case B1200: rate = 1200; break;
+               case B2400: rate = 2400; break;
+               case B4800: rate = 4800; break;
+               case B9600: rate = 9600; break;
+               case B19200: rate = 19200; break;
+               case B38400: rate = 38400; break;
+               case B57600: rate = 57600; break;
+               case B115200: rate = 115200; break;
+               default: rate = -1;
+       }
+
+       return rate;
+}
+
+
+static unsigned rate_to_mask (int rate)
+{
+       unsigned mask;
+
+       switch (rate) {
+               case 0: mask = B0; break;
+               case 300: mask = B300; break;
+               case 600: mask = B600; break;
+               case 1200: mask = B1200; break;
+               case 2400: mask = B2400; break;
+               case 4800: mask = B4800; break;
+               case 9600: mask = B9600; break;
+               case 19200: mask = B19200; break;
+               case 38400: mask = B38400; break;
+               case 57600: mask = B57600; break;
+               case 115200: mask = B115200; break;
+               default: mask = 0x40;
+       }
+
+       return mask;
+}
+/*****************************************************************************
+ * Cypress serial driver functions
+ *****************************************************************************/
+
+
+static int generic_startup (struct usb_serial *serial)
+{
+       struct cypress_private *priv;
+
+       dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
+
+       priv = kmalloc(sizeof (struct cypress_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       memset(priv, 0x00, sizeof (struct cypress_private));
+       spin_lock_init(&priv->lock);
+       init_waitqueue_head(&priv->delta_msr_wait);
+       priv->writepipe = serial->port[0]->interrupt_out_urb->pipe;
+       
+       /* free up interrupt_out buffer / urb allocated by usbserial
+        * for this port as we use our own urbs for writing */
+       if (serial->port[0]->interrupt_out_buffer) {
+               kfree(serial->port[0]->interrupt_out_buffer);
+               serial->port[0]->interrupt_out_buffer = NULL;
+       }
+       if (serial->port[0]->interrupt_out_urb) {
+               priv->write_interval = serial->port[0]->interrupt_out_urb->interval;
+               usb_free_urb(serial->port[0]->interrupt_out_urb);
+               serial->port[0]->interrupt_out_urb = NULL;
+       } else /* still need a write interval */
+               priv->write_interval = 10;
+
+       priv->cmd_ctrl = 0;
+       priv->line_control = 0;
+       priv->termios_initialized = 0;
+       priv->rx_flags = 0;
+       usb_set_serial_port_data(serial->port[0], priv);
+       
+       return (0);     
+}      
+
+
+static int cypress_earthmate_startup (struct usb_serial *serial)
+{
+       struct cypress_private *priv;
+
+       dbg("%s", __FUNCTION__);
+
+       if (generic_startup(serial)) {
+               dbg("%s - Failed setting up port %d", __FUNCTION__, serial->port[0]->number);
+               return 1;
+       }
+
+       priv = usb_get_serial_port_data(serial->port[0]);
+       priv->chiptype = CT_EARTHMATE;
+       
+       return (0);     
+} /* cypress_earthmate_startup */
+
+
+static int cypress_hidcom_startup (struct usb_serial *serial)
+{
+       struct cypress_private *priv;
+
+       dbg("%s", __FUNCTION__);
+
+       if (generic_startup(serial)) {
+               dbg("%s - Failed setting up port %d", __FUNCTION__, serial->port[0]->number);
+               return 1;
+       }
+
+       priv = usb_get_serial_port_data(serial->port[0]);
+       priv->chiptype = CT_CYPHIDCOM;
+       
+       return (0);     
+} /* cypress_hidcom_startup */
+
+
+static void cypress_shutdown (struct usb_serial *serial)
+{
+       struct cypress_private *priv;
+
+       dbg ("%s - port %d", __FUNCTION__, serial->port[0]->number);
+
+       /* all open ports are closed at this point */
+
+       priv = usb_get_serial_port_data(serial->port[0]);
+
+       if (priv) {
+               kfree(priv);
+               usb_set_serial_port_data(serial->port[0], NULL);
+       }
+}
+
+
+static int cypress_open (struct usb_serial_port *port, struct file *filp)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       struct usb_serial *serial = port->serial;
+       unsigned long flags;
+       int result = 0;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       /* reset read/write statistics */
+       priv->bytes_in = 0;
+       priv->bytes_out = 0;
+       priv->cmd_count = 0;
+
+       /* turn on dtr / rts since we are not flow controlling by default */
+       priv->line_control = CONTROL_DTR | CONTROL_RTS; /* sent in status byte */
+       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->cmd_ctrl = 1;
+       result = cypress_write(port, NULL, 0);
+       
+       port->tty->low_latency = 1;
+
+       /* termios defaults are set by usb_serial_init */
+       
+       cypress_set_termios(port, &priv->tmp_termios);
+
+       if (result) {
+               dev_err(&port->dev, "%s - failed setting the control lines - error %d\n", __FUNCTION__, result);
+               return result;
+       } else
+               dbg("%s - success setting the control lines", __FUNCTION__);
+
+       /* throttling off */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->rx_flags = 0;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* setup the port and
+        * start reading from the device */
+       if(!port->interrupt_in_urb){
+               err("%s - interrupt_in_urb is empty!", __FUNCTION__);
+               return(-1);
+       }
+
+       usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
+               usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
+               port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
+               cypress_read_int_callback, port, port->interrupt_in_urb->interval);
+       result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+
+       if (result){
+               dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+       }
+
+       return result;
+} /* cypress_open */
+
+
+static void cypress_close(struct usb_serial_port *port, struct file * filp)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       unsigned int c_cflag;
+       unsigned long flags;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (port->tty) {
+               c_cflag = port->tty->termios->c_cflag;
+               if (c_cflag & HUPCL) {
+                       /* drop dtr and rts */
+                       priv = usb_get_serial_port_data(port);
+                       spin_lock_irqsave(&priv->lock, flags);
+                       priv->line_control = 0;
+                       priv->cmd_ctrl = 1;
+                       spin_unlock_irqrestore(&priv->lock, flags);
+                       cypress_write(port, NULL, 0);
+               }
+       }
+
+       if (port->interrupt_in_urb) {
+               dbg("%s - stopping read urb", __FUNCTION__);
+               usb_kill_urb (port->interrupt_in_urb);
+       }
+
+       if (stats)
+               dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
+                         priv->bytes_in, priv->bytes_out, priv->cmd_count);
+} /* cypress_close */
+
+
+static int cypress_write(struct usb_serial_port *port, const unsigned char *buf, int count)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       struct urb *urb;
+       int status, s_pos = 0;
+       __u8 transfer_size = 0;
+       __u8 *buffer;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (count == 0 && !priv->cmd_ctrl) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               dbg("%s - write request of 0 bytes", __FUNCTION__);
+               return 0;
+       }
+
+       if (priv->cmd_ctrl)
+               ++priv->cmd_count;
+       priv->cmd_ctrl = 0;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
+       dbg("%s - count is %d", __FUNCTION__, count);
+
+       /* Allocate buffer and urb */
+       buffer = kmalloc (port->interrupt_out_size, GFP_ATOMIC);
+       if (!buffer) {
+               dev_err(&port->dev, "ran out of memory for buffer\n");
+               return -ENOMEM;
+       }
+
+       urb = usb_alloc_urb (0, GFP_ATOMIC);
+       if (!urb) {
+               dev_err(&port->dev, "failed allocating write urb\n");
+               kfree (buffer);
+               return -ENOMEM;
+       }
+
+       memset(buffer, 0, port->interrupt_out_size); // test if this is needed... probably not since loop removed
+
+       spin_lock_irqsave(&priv->lock, flags);
+       switch (port->interrupt_out_size) {
+               case 32:
+                       // this is for the CY7C64013...
+                       transfer_size = min (count, 30);
+                       buffer[0] = priv->line_control;
+                       buffer[1] = transfer_size;
+                       s_pos = 2;
+                       break;
+               case 8:
+                       // this is for the CY7C63743...
+                       transfer_size = min (count, 7);
+                       buffer[0] = priv->line_control | transfer_size;
+                       s_pos = 1;
+                       break;
+               default:
+                       dbg("%s - wrong packet size", __FUNCTION__);
+                       spin_unlock_irqrestore(&priv->lock, flags);
+                       kfree (buffer);
+                       usb_free_urb (urb);
+                       return -1;
+       }
+
+       if (priv->line_control & CONTROL_RESET)
+               priv->line_control &= ~CONTROL_RESET;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* copy data to offset position in urb transfer buffer */
+       memcpy (&buffer[s_pos], buf, transfer_size);
+
+       usb_serial_debug_data (debug, &port->dev, __FUNCTION__, port->interrupt_out_size, buffer);
+
+       /* build up the urb */
+       usb_fill_int_urb (urb, port->serial->dev,
+                         usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
+                         buffer, port->interrupt_out_size,
+                         cypress_write_int_callback, port, priv->write_interval);
+
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (status) {
+               dev_err(&port->dev, "%s - usb_submit_urb (write interrupt) failed with status %d\n",
+                       __FUNCTION__, status);
+               transfer_size = status;
+               kfree (buffer);
+               goto exit;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->bytes_out += transfer_size;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+exit:
+       /* buffer free'd in callback */
+       usb_free_urb (urb);
+
+       return transfer_size;
+
+} /* cypress_write */
+
+
+static int cypress_write_room(struct usb_serial_port *port)
+{
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       /*
+        * We really can take anything the user throw at us
+        * but let's pick a nice big number to tell the tty
+        * layer that we have lots of free space
+        */     
+
+       return 2048;
+}
+
+
+static int cypress_tiocmget (struct usb_serial_port *port, struct file *file)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       __u8 status, control;
+       unsigned int result = 0;
+       unsigned long flags;
+       
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       control = priv->line_control;
+       status = priv->current_status;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       result = ((control & CONTROL_DTR)        ? TIOCM_DTR : 0)
+               | ((control & CONTROL_RTS)       ? TIOCM_RTS : 0)
+               | ((status & UART_CTS)        ? TIOCM_CTS : 0)
+               | ((status & UART_DSR)        ? TIOCM_DSR : 0)
+               | ((status & UART_RI)         ? TIOCM_RI  : 0)
+               | ((status & UART_CD)         ? TIOCM_CD  : 0);
+
+       dbg("%s - result = %x", __FUNCTION__, result);
+
+       return result;
+}
+
+
+static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
+                              unsigned int set, unsigned int clear)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (set & TIOCM_RTS)
+               priv->line_control |= CONTROL_RTS;
+       if (set & TIOCM_DTR)
+               priv->line_control |= CONTROL_DTR;
+       if (clear & TIOCM_RTS)
+               priv->line_control &= ~CONTROL_RTS;
+       if (clear & TIOCM_DTR)
+               priv->line_control &= ~CONTROL_DTR;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       priv->cmd_ctrl = 1;
+       return cypress_write(port, NULL, 0);
+}
+
+
+static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+
+       dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
+
+       switch (cmd) {
+               case TIOCGSERIAL:
+                       if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) {
+                               return -EFAULT;
+                       }
+                       return (0);
+                       break;
+               case TIOCSSERIAL:
+                       if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) {
+                               return -EFAULT;
+                       }
+                       /* here we need to call cypress_set_termios to invoke the new settings */
+                       cypress_set_termios(port, &priv->tmp_termios);
+                       return (0);
+                       break;
+               /* these are called when setting baud rate from gpsd */
+               case TCGETS:
+                       if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) {
+                               return -EFAULT;
+                       }
+                       return (0);
+                       break;
+               case TCSETS:
+                       if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) {
+                               return -EFAULT;
+                       }
+                       /* here we need to call cypress_set_termios to invoke the new settings */
+                       cypress_set_termios(port, &priv->tmp_termios);
+                       return (0);
+                       break;
+               /* This code comes from drivers/char/serial.c and ftdi_sio.c */
+               case TIOCMIWAIT:
+                       while (priv != NULL) {
+                               interruptible_sleep_on(&priv->delta_msr_wait);
+                               /* see if a signal did it */
+                               if (signal_pending(current))
+                                       return -ERESTARTSYS;
+                               else {
+                                       char diff = priv->diff_status;
+
+                                       if (diff == 0) {
+                                               return -EIO; /* no change => error */
+                                       }
+                                       
+                                       /* consume all events */
+                                       priv->diff_status = 0;
+
+                                       /* return 0 if caller wanted to know about these bits */
+                                       if ( ((arg & TIOCM_RNG) && (diff & UART_RI)) ||
+                                            ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
+                                            ((arg & TIOCM_CD) && (diff & UART_CD)) ||
+                                            ((arg & TIOCM_CTS) && (diff & UART_CTS)) ) {
+                                               return 0;
+                                       }
+                                       /* otherwise caller can't care less about what happened,
+                                        * and so we continue to wait for more events.
+                                        */
+                               }
+                       }
+                       return 0;
+                       break;
+               default:
+                       break;
+       }
+
+       dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __FUNCTION__, cmd);
+
+       return -ENOIOCTLCMD;
+} /* cypress_ioctl */
+
+
+static void cypress_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
+       int data_bits, stop_bits, parity_type, parity_enable;
+       unsigned cflag, iflag, baud_mask;
+       unsigned long flags;
+       
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       tty = port->tty;
+       if ((!tty) || (!tty->termios)) {
+               dbg("%s - no tty structures", __FUNCTION__);
+               return;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (!priv->termios_initialized) {
+               if (priv->chiptype == CT_EARTHMATE) {
+                       *(tty->termios) = tty_std_termios;
+                       tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+               } else if (priv->chiptype == CT_CYPHIDCOM) {
+                       *(tty->termios) = tty_std_termios;
+                       tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+               }
+               priv->termios_initialized = 1;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       cflag = tty->termios->c_cflag;
+       iflag = tty->termios->c_iflag;
+
+       /* check if there are new settings */
+       if (old_termios) {
+               if ((cflag != old_termios->c_cflag) ||
+                   (RELEVANT_IFLAG(iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+                       dbg("%s - attempting to set new termios settings", __FUNCTION__);
+                       /* should make a copy of this in case something goes wrong in the function, we can restore it */
+                       spin_lock_irqsave(&priv->lock, flags);
+                       priv->tmp_termios = *(tty->termios);
+                       spin_unlock_irqrestore(&priv->lock, flags); 
+               } else {
+                       dbg("%s - nothing to do, exiting", __FUNCTION__);
+                       return;
+               }
+       } else
+               return;
+
+       /* set number of data bits, parity, stop bits */
+       /* when parity is disabled the parity type bit is ignored */
+
+       stop_bits = cflag & CSTOPB ? 1 : 0; /* 1 means 2 stop bits, 0 means 1 stop bit */
+       
+       if (cflag & PARENB) {
+               parity_enable = 1;
+               parity_type = cflag & PARODD ? 1 : 0; /* 1 means odd parity, 0 means even parity */
+       } else
+               parity_enable = parity_type = 0;
+
+       if (cflag & CSIZE) {
+               switch (cflag & CSIZE) {
+                       case CS5: data_bits = 0; break;
+                       case CS6: data_bits = 1; break;
+                       case CS7: data_bits = 2; break;
+                       case CS8: data_bits = 3; break;
+                       default: err("%s - CSIZE was set, but not CS5-CS8", __FUNCTION__); data_bits = 3;
+               }
+       } else
+               data_bits = 3;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if ((cflag & CBAUD) == B0) {
+               /* drop dtr and rts */
+               dbg("%s - dropping the lines, baud rate 0bps", __FUNCTION__);
+               baud_mask = B0;
+               priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+       } else {
+               baud_mask = (cflag & CBAUD);
+               switch(baud_mask) {
+                       case B300: dbg("%s - setting baud 300bps", __FUNCTION__); break;
+                       case B600: dbg("%s - setting baud 600bps", __FUNCTION__); break;
+                       case B1200: dbg("%s - setting baud 1200bps", __FUNCTION__); break;
+                       case B2400: dbg("%s - setting baud 2400bps", __FUNCTION__); break;
+                       case B4800: dbg("%s - setting baud 4800bps", __FUNCTION__); break;
+                       case B9600: dbg("%s - setting baud 9600bps", __FUNCTION__); break;
+                       case B19200: dbg("%s - setting baud 19200bps", __FUNCTION__); break;
+                       case B38400: dbg("%s - setting baud 38400bps", __FUNCTION__); break;
+                       case B57600: dbg("%s - setting baud 57600bps", __FUNCTION__); break;
+                       case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break;
+                       default: dbg("%s - unknown masked baud rate", __FUNCTION__);
+               }
+               priv->line_control |= CONTROL_DTR;
+               
+               /* this is probably not what I think it is... check into it */
+               if (cflag & CRTSCTS)
+                       priv->line_control |= CONTROL_RTS;
+               else
+                       priv->line_control &= ~CONTROL_RTS;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+       
+       dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)", __FUNCTION__,
+           stop_bits, parity_enable, parity_type, data_bits);
+
+       cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
+                              parity_type, 0, CYPRESS_SET_CONFIG);
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       schedule_timeout(50*HZ/1000); /* give some time between change and read (50ms) */ 
+
+       /* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure
+         * this should confirm that all is working if it returns what we just set */
+       cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
+
+       /* Here we can define custom tty settings for devices
+         *
+         * the main tty base comes from empeg.c
+         */
+
+       spin_lock_irqsave(&priv->lock, flags);  
+       if ( (priv->chiptype == CT_EARTHMATE) && (priv->baud_rate == 4800) ) {
+
+               dbg("Using custom termios settings for a baud rate of 4800bps.");
+               /* define custom termios settings for NMEA protocol */
+
+               
+               tty->termios->c_iflag /* input modes - */
+                       &= ~(IGNBRK             /* disable ignore break */
+                       | BRKINT                /* disable break causes interrupt */
+                       | PARMRK                /* disable mark parity errors */
+                       | ISTRIP                /* disable clear high bit of input characters */
+                       | INLCR                 /* disable translate NL to CR */
+                       | IGNCR                 /* disable ignore CR */
+                       | ICRNL                 /* disable translate CR to NL */
+                       | IXON);                /* disable enable XON/XOFF flow control */
+               
+               tty->termios->c_oflag /* output modes */
+                       &= ~OPOST;              /* disable postprocess output characters */
+               
+               tty->termios->c_lflag /* line discipline modes */
+                       &= ~(ECHO               /* disable echo input characters */
+                       | ECHONL                /* disable echo new line */
+                       | ICANON                /* disable erase, kill, werase, and rprnt special characters */
+                       | ISIG                  /* disable interrupt, quit, and suspend special characters */
+                       | IEXTEN);              /* disable non-POSIX special characters */
+
+       } else if (priv->chiptype == CT_CYPHIDCOM) {
+
+               // Software app handling it for device...       
+
+       } else {
+               
+               /* do something here */
+
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* set lines */
+       priv->cmd_ctrl = 1;
+       cypress_write(port, NULL, 0);
+       
+       return;
+} /* cypress_set_termios */
+
+
+static int cypress_chars_in_buffer(struct usb_serial_port *port)
+{
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       /*
+        * We can't really account for how much data we
+        * have sent out, but hasn't made it through to the
+        * device, so just tell the tty layer that everything
+        * is flushed.
+        */
+
+       return 0;
+}
+
+
+static void cypress_throttle (struct usb_serial_port *port)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->rx_flags = THROTTLED;
+       spin_unlock_irqrestore(&priv->lock, flags);        
+}
+
+
+static void cypress_unthrottle (struct usb_serial_port *port)
+{
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       int actually_throttled, result;
+       unsigned long flags;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
+       priv->rx_flags = 0;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (actually_throttled) {
+               port->interrupt_in_urb->dev = port->serial->dev;
+
+               result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+               if (result)
+                       dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+       }
+}
+
+
+static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct cypress_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+       unsigned long flags;
+       char tty_flag = TTY_NORMAL;
+       int bytes=0;
+       int result;
+       int i=0;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (urb->status) {
+               dbg("%s - nonzero read status received: %d", __FUNCTION__, urb->status);
+               return;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->rx_flags & THROTTLED) {
+               priv->rx_flags |= ACTUALLY_THROTTLED;
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       tty = port->tty;
+       if (!tty) {
+               dbg("%s - bad tty pointer - exiting", __FUNCTION__);
+               return;
+       }
+
+       usb_serial_debug_data (debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+       
+       spin_lock_irqsave(&priv->lock, flags);
+       switch(urb->actual_length) {
+               case 32:
+                       // This is for the CY7C64013...
+                       priv->current_status = data[0] & 0xF8;
+                       bytes = data[1]+2;
+                       i=2;
+                       break;
+               case 8:
+                       // This is for the CY7C63743...
+                       priv->current_status = data[0] & 0xF8;
+                       bytes = (data[0] & 0x07)+1;
+                       i=1;
+                       break;
+               default:
+                       dbg("%s - wrong packet size - received %d bytes", __FUNCTION__, urb->actual_length);
+                       spin_unlock_irqrestore(&priv->lock, flags);
+                       goto continue_read;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       /* check to see if status has changed */
+       if (priv != NULL) {
+               if (priv->current_status != priv->prev_status) {
+                       priv->diff_status |= priv->current_status ^ priv->prev_status;
+                       wake_up_interruptible(&priv->delta_msr_wait);
+                       priv->prev_status = priv->current_status;
+               }
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);     
+
+       /* hangup, as defined in acm.c... this might be a bad place for it though */
+       if (tty && !(tty->termios->c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) {
+               dbg("%s - calling hangup", __FUNCTION__);
+               tty_hangup(tty);
+               goto continue_read;
+       }
+
+       /* There is one error bit... I'm assuming it is a parity error indicator
+        * as the generic firmware will set this bit to 1 if a parity error occurs.
+        * I can not find reference to any other error events.
+        *
+        */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->current_status & CYP_ERROR) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               tty_flag = TTY_PARITY;
+               dbg("%s - Parity Error detected", __FUNCTION__);
+       } else
+               spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* process read if there is data other than line status */
+       if (tty && (bytes > i)) {
+               for (; i < bytes ; ++i) {
+                       dbg("pushing byte number %d - %d",i,data[i]);
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       tty_insert_flip_char(tty, data[i], tty_flag);
+               }
+               tty_flip_buffer_push(port->tty);
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->bytes_in += bytes;  /* control and status byte(s) are also counted */
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+continue_read:
+       
+       /* Continue trying to always read... unless the port has closed.  */
+
+       if (port->open_count > 0) {
+       usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
+               usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
+               port->interrupt_in_urb->transfer_buffer,
+               port->interrupt_in_urb->transfer_buffer_length,
+               cypress_read_int_callback, port,
+               port->interrupt_in_urb->interval);
+       result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+       if (result)
+               dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+       }
+       
+       return;
+} /* cypress_read_int_callback */
+
+
+static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+       /* free up the transfer buffer, as usb_free_urb() does not do this */
+       kfree (urb->transfer_buffer);
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+       
+       if (urb->status) {
+               dbg("%s - nonzero write status received: %d", __FUNCTION__, urb->status);
+               return;
+       }
+
+       schedule_work(&port->work);
+}
+
+
+/*****************************************************************************
+ * Module functions
+ *****************************************************************************/
+
+static int __init cypress_init(void)
+{
+       int retval;
+       
+       dbg("%s", __FUNCTION__);
+       
+       retval = usb_serial_register(&cypress_earthmate_device);
+       if (retval)
+               goto failed_em_register;
+       retval = usb_serial_register(&cypress_hidcom_device);
+       if (retval)
+               goto failed_hidcom_register;
+       retval = usb_register(&cypress_driver);
+       if (retval)
+               goto failed_usb_register;
+
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+failed_usb_register:
+       usb_deregister(&cypress_driver);
+failed_hidcom_register:
+       usb_serial_deregister(&cypress_hidcom_device);
+failed_em_register:
+       usb_serial_deregister(&cypress_earthmate_device);
+
+       return retval;
+}
+
+
+static void __exit cypress_exit (void)
+{
+       dbg("%s", __FUNCTION__);
+
+       usb_deregister (&cypress_driver);
+       usb_serial_deregister (&cypress_earthmate_device);
+       usb_serial_deregister (&cypress_hidcom_device);
+}
+
+
+module_init(cypress_init);
+module_exit(cypress_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(stats, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(stats, "Enable statistics or not");
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
new file mode 100644 (file)
index 0000000..1012ee6
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef CYPRESS_M8_H
+#define CYPRESS_M8_H
+
+/* definitions and function prototypes used for the cypress USB to Serial controller */
+
+/* For sending our feature buffer - controlling serial communication states */
+/* Linux HID has no support for serial devices so we do this through the driver */
+#define HID_REQ_GET_REPORT 0x01
+#define HID_REQ_SET_REPORT 0x09
+
+/* List other cypress USB to Serial devices here, and add them to the id_table */
+
+/* DeLorme Earthmate USB - a GPS device */
+#define        VENDOR_ID_DELORME                0x1163
+#define PRODUCT_ID_EARTHMATEUSB                 0x0100
+
+/* Cypress HID->COM RS232 Adapter */
+#define VENDOR_ID_CYPRESS               0x04b4
+#define PRODUCT_ID_CYPHIDCOM            0x5500
+/* End of device listing */
+
+/* Used for setting / requesting serial line settings */
+#define CYPRESS_SET_CONFIG 0x01
+#define CYPRESS_GET_CONFIG 0x02
+
+/* Used for throttle control */
+#define THROTTLED 0x1
+#define ACTUALLY_THROTTLED 0x2
+
+/* chiptypes - used in case firmware differs from the generic form ... offering
+ *     different baud speeds/etc.
+ */
+
+#define CT_EARTHMATE   0x01
+#define CT_CYPHIDCOM   0x02
+#define CT_GENERIC     0x0F
+/* End of chiptype definitions */
+
+/* RS-232 serial data communication protocol definitions */
+/* these are sent / read at byte 0 of the input/output hid reports */
+/* You can find these values defined in the CY4601 USB to Serial design notes */
+
+#define CONTROL_DTR    0x20    /* data terminal ready - flow control - host to device */
+#define UART_DSR       0x20    /* data set ready - flow control - device to host */
+#define CONTROL_RTS    0x10    /* request to send - flow control - host to device */
+#define UART_CTS       0x10    /* clear to send - flow control - device to host */
+#define        UART_RI         0x10    /* ring indicator - modem - device to host */ 
+#define UART_CD                0x40    /* carrier detect - modem - device to host */
+#define CYP_ERROR      0x08    /* received from input report - device to host */
+/* Note - the below has nothing to to with the "feature report" reset */
+#define CONTROL_RESET  0x08    /* sent with output report - host to device */
+
+/* End of RS-232 protocol definitions */
+
+#endif /* CYPRESS_M8_H */
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
new file mode 100644 (file)
index 0000000..2097793
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * IPWireless 3G UMTS TDD Modem driver (USB connected)
+ *
+ *   Copyright (C) 2004 Roelf Diedericks <roelfd@inet.co.za>
+ *   Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.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.
+ *
+ * All information about the device was acquired using SnoopyPro
+ * on MSFT's O/S, and examing the MSFT drivers' debug output 
+ * (insanely left _on_ in the enduser version)
+ *
+ * It was written out of frustration with the IPWireless USB modem
+ * supplied by Axity3G/Sentech South Africa not supporting
+ * Linux whatsoever.
+ *
+ * Nobody provided any proprietary information that was not already 
+ * available for this device.
+ * 
+ * The modem adheres to the "3GPP TS  27.007 AT command set for 3G 
+ * User Equipment (UE)" standard, available from 
+ * http://www.3gpp.org/ftp/Specs/html-info/27007.htm
+ *
+ * The code was only tested the IPWireless handheld modem distributed
+ * in South Africa by Sentech.
+ * 
+ * It may work for Woosh Inc in .nz too, as it appears they use the
+ * same kit.
+ *
+ * There is still some work to be done in terms of handling 
+ * DCD, DTR, RTS, CTS which are currently faked.
+ * It's good enough for PPP at this point. It's based off all kinds of
+ * code found in usb/serial and usb/class
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include "usb-serial.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.3"
+#define DRIVER_AUTHOR  "Roelf Diedericks"
+#define DRIVER_DESC    "IPWireless tty driver"
+
+#define IPW_TTY_MAJOR  240     /* real device node major id, experimental range */
+#define IPW_TTY_MINORS 256     /* we support 256 devices, dunno why, it'd be insane :) */
+
+#define USB_IPW_MAGIC  0x6d02  /* magic number for ipw struct */
+
+
+/* Message sizes */
+#define EVENT_BUFFER_SIZE      0xFF
+#define CHAR2INT16(c1,c0)      (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
+#define NUM_BULK_URBS          24
+#define NUM_CONTROL_URBS       16
+
+/* vendor/product pairs that are known work with this driver*/
+#define IPW_VID                0x0bc3
+#define IPW_PID                0x0001
+
+
+/* Vendor commands: */
+
+/* baud rates */
+enum {
+       ipw_sio_b256000 = 0x000e,
+       ipw_sio_b128000 = 0x001d,
+       ipw_sio_b115200 = 0x0020,
+       ipw_sio_b57600  = 0x0040,
+       ipw_sio_b56000  = 0x0042,
+       ipw_sio_b38400  = 0x0060,
+       ipw_sio_b19200  = 0x00c0,
+       ipw_sio_b14400  = 0x0100,
+       ipw_sio_b9600   = 0x0180,
+       ipw_sio_b4800   = 0x0300,
+       ipw_sio_b2400   = 0x0600,
+       ipw_sio_b1200   = 0x0c00,
+       ipw_sio_b600    = 0x1800
+};
+
+/* data bits */
+#define ipw_dtb_7              0x700
+#define ipw_dtb_8              0x810   // ok so the define is misleading, I know, but forces 8,n,1
+                                       // I mean, is there a point to any other setting these days? :) 
+
+/* usb control request types : */
+#define IPW_SIO_RXCTL          0x00    // control bulk rx channel transmissions, value=1/0 (on/off)
+#define IPW_SIO_SET_BAUD       0x01    // set baud, value=requested ipw_sio_bxxxx
+#define IPW_SIO_SET_LINE       0x03    // set databits, parity. value=ipw_dtb_x
+#define IPW_SIO_SET_PIN                0x03    // set/clear dtr/rts value=ipw_pin_xxx
+#define IPW_SIO_POLL           0x08    // get serial port status byte, call with value=0
+#define IPW_SIO_INIT           0x11    // initializes ? value=0 (appears as first thing todo on open)
+#define IPW_SIO_PURGE          0x12    // purge all transmissions?, call with value=numchar_to_purge
+#define IPW_SIO_HANDFLOW       0x13    // set xon/xoff limits value=0, and a buffer of 0x10 bytes
+#define IPW_SIO_SETCHARS       0x13    // set the flowcontrol special chars, value=0, buf=6 bytes, 
+                                       // last 2 bytes contain flowcontrol chars e.g. 00 00 00 00 11 13
+
+/* values used for request IPW_SIO_SET_PIN */
+#define IPW_PIN_SETDTR         0x101
+#define IPW_PIN_SETRTS         0x202
+#define IPW_PIN_CLRDTR         0x100
+#define IPW_PIN_CLRRTS         0x200 // unconfirmed
+
+/* values used for request IPW_SIO_RXCTL */
+#define IPW_RXBULK_ON          1
+#define IPW_RXBULK_OFF         0
+
+/* various 16 byte hardcoded transferbuffers used by flow control */
+#define IPW_BYTES_FLOWINIT     { 0x01, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* Interpretation of modem status lines */
+/* These need sorting out by individually connecting pins and checking
+ * results. FIXME!
+ * When data is being sent we see 0x30 in the lower byte; this must
+ * contain DSR and CTS ...
+ */
+#define IPW_DSR                        ((1<<4) | (1<<5))
+#define IPW_CTS                        ((1<<5) | (1<<4))
+
+#define IPW_WANTS_TO_SEND      0x30
+//#define IPW_DTR                      /* Data Terminal Ready */
+//#define IPW_CTS                      /* Clear To Send */
+//#define IPW_CD                       /* Carrier Detect */
+//#define IPW_DSR                      /* Data Set Ready */
+//#define IPW_RxD                      /* Receive pin */
+
+//#define IPW_LE
+//#define IPW_RTS              
+//#define IPW_ST               
+//#define IPW_SR               
+//#define IPW_RI                       /* Ring Indicator */
+
+static struct usb_device_id usb_ipw_ids[] = {
+       { USB_DEVICE(IPW_VID, IPW_PID) },
+       { },
+};
+
+MODULE_DEVICE_TABLE(usb, usb_ipw_ids);
+
+static struct usb_driver usb_ipw_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "ipwtty",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     usb_ipw_ids,
+};
+
+static int debug;
+
+static void ipw_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_serial_port *port = urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       struct tty_struct *tty;
+       int i;
+       int result;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (urb->status) {
+               dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+               return;
+       }
+
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+
+       tty = port->tty;
+       if (tty && urb->actual_length) {
+               for (i = 0; i < urb->actual_length ; ++i) {
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       /* this doesn't actually push the data through unless tty->low_latency is set */
+                       tty_insert_flip_char(tty, data[i], 0);
+               }
+               tty_flip_buffer_push(tty);
+       }
+
+       /* Continue trying to always read  */
+       usb_fill_bulk_urb (port->read_urb, port->serial->dev,
+                          usb_rcvbulkpipe(port->serial->dev,
+                                          port->bulk_in_endpointAddress),
+                          port->read_urb->transfer_buffer,
+                          port->read_urb->transfer_buffer_length,
+                          ipw_read_bulk_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       if (result)
+               dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+       return;
+}
+
+static int ipw_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_device *dev = port->serial->dev;
+       u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT;
+       u8 *buf_flow_init;
+       int result;
+
+       dbg("%s", __FUNCTION__);
+
+       buf_flow_init = kmalloc(16, GFP_KERNEL);
+       if (!buf_flow_init)
+               return -ENOMEM;
+       memcpy(buf_flow_init, buf_flow_static, 16);
+
+       if (port->tty)
+               port->tty->low_latency = 1;
+
+       /* --1: Tell the modem to initialize (we think) From sniffs this is always the
+        * first thing that gets sent to the modem during opening of the device */
+       dbg("%s: Sending SIO_INIT (we guess)",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+                                IPW_SIO_INIT,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                0,
+                                0, /* index */
+                                NULL,
+                                0,
+                                100*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "Init of modem failed (error = %d)", result);
+
+       /* reset the bulk pipes */
+       usb_clear_halt(dev, usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress));
+       usb_clear_halt(dev, usb_sndbulkpipe(dev, port->bulk_out_endpointAddress));
+
+       /*--2: Start reading from the device */ 
+       dbg("%s: setting up bulk read callback",__FUNCTION__);
+       usb_fill_bulk_urb(port->read_urb, dev,
+                         usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
+                         port->bulk_in_buffer,
+                         port->bulk_in_size,
+                         ipw_read_bulk_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+       if (result < 0)
+               dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result);
+
+       /*--3: Tell the modem to open the floodgates on the rx bulk channel */
+       dbg("%s:asking modem for RxRead (RXBULK_ON)",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_RXCTL,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                IPW_RXBULK_ON,
+                                0, /* index */
+                                NULL,
+                                0,
+                                100*HZ);
+       if (result < 0) 
+               dev_err(&port->dev, "Enabling bulk RxRead failed (error = %d)", result);
+
+       /*--4: setup the initial flowcontrol */
+       dbg("%s:setting init flowcontrol (%s)",__FUNCTION__,buf_flow_init);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_HANDFLOW,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                0,
+                                0,
+                                buf_flow_init,
+                                0x10,
+                                200*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "initial flowcontrol failed (error = %d)", result);
+
+
+       /*--5: raise the dtr */
+       dbg("%s:raising dtr",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_SET_PIN,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                IPW_PIN_SETDTR,
+                                0,
+                                NULL,
+                                0,
+                                200*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "setting dtr failed (error = %d)", result);
+
+       /*--6: raise the rts */
+       dbg("%s:raising rts",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_SET_PIN,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                IPW_PIN_SETRTS,
+                                0,
+                                NULL,
+                                0,
+                                200*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "setting dtr failed (error = %d)", result);
+       
+       kfree(buf_flow_init);
+       return 0;
+}
+
+static void ipw_close(struct usb_serial_port *port, struct file * filp)
+{
+       struct usb_device *dev = port->serial->dev;
+       int result;
+
+       if (tty_hung_up_p(filp)) {
+               dbg("%s: tty_hung_up_p ...", __FUNCTION__);
+               return;
+       }
+
+       /*--1: drop the dtr */
+       dbg("%s:dropping dtr",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_SET_PIN,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                IPW_PIN_CLRDTR,
+                                0,
+                                NULL,
+                                0,
+                                200*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "dropping dtr failed (error = %d)", result);
+
+       /*--2: drop the rts */
+       dbg("%s:dropping rts",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_SET_PIN, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                IPW_PIN_CLRRTS,
+                                0,
+                                NULL,
+                                0,
+                                200*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "dropping rts failed (error = %d)", result);
+
+
+       /*--3: purge */
+       dbg("%s:sending purge",__FUNCTION__);
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_PURGE, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                0x03,
+                                0,
+                                NULL,
+                                0,
+                                200*HZ);
+       if (result < 0)
+               dev_err(&port->dev, "purge failed (error = %d)", result);
+
+
+       /* send RXBULK_off (tell modem to stop transmitting bulk data on rx chan) */
+       result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                                IPW_SIO_RXCTL,
+                                USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                                IPW_RXBULK_OFF,
+                                0, /* index */
+                                NULL,
+                                0,
+                                100*HZ);
+
+       if (result < 0)
+               dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)", result);
+
+       /* shutdown any in-flight urbs that we know about */
+       usb_kill_urb(port->read_urb);
+       usb_kill_urb(port->write_urb);
+}
+
+static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_serial_port *port = urb->context;
+
+       dbg("%s", __FUNCTION__);
+
+       if (urb->status)
+               dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+
+       schedule_work(&port->work);
+}
+
+static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int count)
+{
+       struct usb_device *dev = port->serial->dev;
+       int ret;
+
+       dbg("%s: TOP: count=%d, in_interrupt=%ld", __FUNCTION__,
+               count, in_interrupt() );
+
+       if (count == 0) {
+               dbg("%s - write request of 0 bytes", __FUNCTION__);
+               return 0;
+       }
+       
+       /* Racy and broken, FIXME properly! */
+       if (port->write_urb->status == -EINPROGRESS)
+               return 0;
+
+       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,
+                         count,
+                         ipw_write_bulk_callback,
+                         port);
+
+       ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       if (ret != 0) {
+               dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
+               return ret;
+       }
+
+       dbg("%s returning %d", __FUNCTION__, count);
+       return count;
+} 
+
+static int ipw_probe(struct usb_serial_port *port)
+{
+       return 0;
+}
+
+static int ipw_disconnect(struct usb_serial_port *port)
+{
+       usb_set_serial_port_data(port, NULL);
+       return 0;
+}
+
+static struct usb_serial_device_type ipw_device = {
+       .owner =                THIS_MODULE,
+       .name =                 "IPWireless converter",
+       .short_name =           "ipw",
+       .id_table =             usb_ipw_ids,
+       .num_interrupt_in =     NUM_DONT_CARE,
+       .num_bulk_in =          1,
+       .num_bulk_out =         1,
+       .num_ports =            1,
+       .open =                 ipw_open,
+       .close =                ipw_close,
+       .port_probe =           ipw_probe,
+       .port_remove =          ipw_disconnect,
+       .write =                ipw_write,
+       .write_bulk_callback =  ipw_write_bulk_callback,
+       .read_bulk_callback =   ipw_read_bulk_callback,
+};
+
+
+
+int usb_ipw_init(void)
+{
+       int retval;
+
+       retval = usb_serial_register(&ipw_device);
+       if (retval)
+               return retval;
+       retval = usb_register(&usb_ipw_driver);
+       if (retval) {
+               usb_serial_deregister(&ipw_device);
+               return retval;
+       }
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+}
+
+void usb_ipw_exit(void)
+{
+       usb_deregister(&usb_ipw_driver);
+       usb_serial_deregister(&ipw_device);
+}
+
+module_init(usb_ipw_init);
+module_exit(usb_ipw_exit);
+
+/* Module information */
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
new file mode 100644 (file)
index 0000000..d6af37b
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ *  linux/drivers/video/amba-clcd.c
+ *
+ * Copyright (C) 2001 ARM Limited, by David A Rusling
+ * Updated to 2.5, Deep Blue Solutions Ltd.
+ *
+ * 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.
+ *
+ *  ARM PrimeCell PL110 Color LCD Controller
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+
+#include <asm/hardware/amba.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/hardware/amba_clcd.h>
+
+#define to_clcd(info)  container_of(info, struct clcd_fb, fb)
+
+/* This is limited to 16 characters when displayed by X startup */
+static const char *clcd_name = "CLCD FB";
+
+/*
+ * Unfortunately, the enable/disable functions may be called either from
+ * process or IRQ context, and we _need_ to delay.  This is _not_ good.
+ */
+static inline void clcdfb_sleep(unsigned int ms)
+{
+       if (in_atomic()) {
+               mdelay(ms);
+       } else {
+               msleep(ms);
+       }
+}
+
+static inline void clcdfb_set_start(struct clcd_fb *fb)
+{
+       unsigned long ustart = fb->fb.fix.smem_start;
+       unsigned long lstart;
+
+       ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
+       lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
+
+       writel(ustart, fb->regs + CLCD_UBAS);
+       writel(lstart, fb->regs + CLCD_LBAS);
+}
+
+static void clcdfb_disable(struct clcd_fb *fb)
+{
+       u32 val;
+
+       if (fb->board->disable)
+               fb->board->disable(fb);
+
+       val = readl(fb->regs + CLCD_CNTL);
+       if (val & CNTL_LCDPWR) {
+               val &= ~CNTL_LCDPWR;
+               writel(val, fb->regs + CLCD_CNTL);
+
+               clcdfb_sleep(20);
+       }
+       if (val & CNTL_LCDEN) {
+               val &= ~CNTL_LCDEN;
+               writel(val, fb->regs + CLCD_CNTL);
+       }
+
+       /*
+        * Disable CLCD clock source.
+        */
+       clk_disable(fb->clk);
+}
+
+static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
+{
+       /*
+        * Enable the CLCD clock source.
+        */
+       clk_enable(fb->clk);
+
+       /*
+        * Bring up by first enabling..
+        */
+       cntl |= CNTL_LCDEN;
+       writel(cntl, fb->regs + CLCD_CNTL);
+
+       clcdfb_sleep(20);
+
+       /*
+        * and now apply power.
+        */
+       cntl |= CNTL_LCDPWR;
+       writel(cntl, fb->regs + CLCD_CNTL);
+
+       /*
+        * finally, enable the interface.
+        */
+       if (fb->board->enable)
+               fb->board->enable(fb);
+}
+
+static int
+clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
+{
+       int ret = 0;
+
+       memset(&var->transp, 0, sizeof(var->transp));
+       memset(&var->red, 0, sizeof(var->red));
+       memset(&var->green, 0, sizeof(var->green));
+       memset(&var->blue, 0, sizeof(var->blue));
+
+       switch (var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               var->red.length         = 8;
+               var->red.offset         = 0;
+               var->green.length       = 8;
+               var->green.offset       = 0;
+               var->blue.length        = 8;
+               var->blue.offset        = 0;
+               break;
+       case 16:
+               var->red.length         = 5;
+               var->green.length       = 5;
+               var->blue.length        = 5;
+               if (fb->panel->cntl & CNTL_BGR) {
+                       var->red.offset         = 10;
+                       var->green.offset       = 5;
+                       var->blue.offset        = 0;
+               } else {
+                       var->red.offset         = 0;
+                       var->green.offset       = 5;
+                       var->blue.offset        = 10;
+               }
+               break;
+       case 24:
+               if (fb->panel->cntl & CNTL_LCDTFT) {
+                       var->red.length         = 8;
+                       var->green.length       = 8;
+                       var->blue.length        = 8;
+
+                       if (fb->panel->cntl & CNTL_BGR) {
+                               var->red.offset         = 16;
+                               var->green.offset       = 8;
+                               var->blue.offset        = 0;
+                       } else {
+                               var->red.offset         = 0;
+                               var->green.offset       = 8;
+                               var->blue.offset        = 16;
+                       }
+                       break;
+               }
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+       int ret = -EINVAL;
+
+       if (fb->board->check)
+               ret = fb->board->check(fb, var);
+       if (ret == 0)
+               ret = clcdfb_set_bitfields(fb, var);
+
+       return ret;
+}
+
+static int clcdfb_set_par(struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+       struct clcd_regs regs;
+
+       fb->fb.fix.line_length = fb->fb.var.xres_virtual *
+                                fb->fb.var.bits_per_pixel / 8;
+
+       if (fb->fb.var.bits_per_pixel <= 8)
+               fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       else
+               fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+
+       fb->board->decode(fb, &regs);
+
+       clcdfb_disable(fb);
+
+       writel(regs.tim0, fb->regs + CLCD_TIM0);
+       writel(regs.tim1, fb->regs + CLCD_TIM1);
+       writel(regs.tim2, fb->regs + CLCD_TIM2);
+       writel(regs.tim3, fb->regs + CLCD_TIM3);
+
+       clcdfb_set_start(fb);
+
+       clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
+
+       fb->clcd_cntl = regs.cntl;
+
+       clcdfb_enable(fb, regs.cntl);
+
+#ifdef DEBUG
+       printk(KERN_INFO "CLCD: Registers set to\n"
+              KERN_INFO "  %08x %08x %08x %08x\n"
+              KERN_INFO "  %08x %08x %08x %08x\n",
+               readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
+               readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
+               readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
+               readl(fb->regs + CLCD_IENB), readl(fb->regs + CLCD_CNTL));
+#endif
+
+       return 0;
+}
+
+static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
+{
+       unsigned int mask = (1 << bf->length) - 1;
+
+       return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
+/*
+ *  Set a single color register. The values supplied have a 16 bit
+ *  magnitude.  Return != 0 for invalid regno.
+ */
+static int
+clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+                unsigned int blue, unsigned int transp, struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+
+       if (regno < 16)
+               fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
+                                 convert_bitfield(blue, &fb->fb.var.blue) |
+                                 convert_bitfield(green, &fb->fb.var.green) |
+                                 convert_bitfield(red, &fb->fb.var.red);
+
+       if (fb->fb.var.bits_per_pixel == 8 && regno < 256) {
+               int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
+               u32 val, mask, newval;
+
+               newval  = (red >> 11)  & 0x001f;
+               newval |= (green >> 6) & 0x03e0;
+               newval |= (blue >> 1)  & 0x7c00;
+
+               /*
+                * 3.2.11: if we're configured for big endian
+                * byte order, the palette entries are swapped.
+                */
+               if (fb->clcd_cntl & CNTL_BEBO)
+                       regno ^= 1;
+
+               if (regno & 1) {
+                       newval <<= 16;
+                       mask = 0x0000ffff;
+               } else {
+                       mask = 0xffff0000;
+               }
+
+               val = readl(fb->regs + hw_reg) & mask;
+               writel(val | newval, fb->regs + hw_reg);
+       }
+
+       return regno > 255;
+}
+
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+static int clcdfb_blank(int blank_mode, struct fb_info *info)
+{
+       struct clcd_fb *fb = to_clcd(info);
+
+       if (blank_mode != 0) {
+               clcdfb_disable(fb);
+       } else {
+               clcdfb_enable(fb, fb->clcd_cntl);
+       }
+       return 0;
+}
+
+static struct fb_ops clcdfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = clcdfb_check_var,
+       .fb_set_par     = clcdfb_set_par,
+       .fb_setcolreg   = clcdfb_setcolreg,
+       .fb_blank       = clcdfb_blank,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_cursor      = soft_cursor,
+};
+
+static int clcdfb_register(struct clcd_fb *fb)
+{
+       int ret;
+
+       fb->clk = clk_get(&fb->dev->dev, "CLCDCLK");
+       if (IS_ERR(fb->clk)) {
+               ret = PTR_ERR(fb->clk);
+               goto out;
+       }
+
+       ret = clk_use(fb->clk);
+       if (ret)
+               goto free_clk;
+
+       fb->fb.fix.mmio_start   = fb->dev->res.start;
+       fb->fb.fix.mmio_len     = SZ_4K;
+
+       fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
+       if (!fb->regs) {
+               printk(KERN_ERR "CLCD: unable to remap registers\n");
+               ret = -ENOMEM;
+               goto unuse_clk;
+       }
+
+       fb->fb.fbops            = &clcdfb_ops;
+       fb->fb.flags            = FBINFO_FLAG_DEFAULT;
+       fb->fb.pseudo_palette   = fb->cmap;
+
+       strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
+       fb->fb.fix.type         = FB_TYPE_PACKED_PIXELS;
+       fb->fb.fix.type_aux     = 0;
+       fb->fb.fix.xpanstep     = 0;
+       fb->fb.fix.ypanstep     = 0;
+       fb->fb.fix.ywrapstep    = 0;
+       fb->fb.fix.accel        = FB_ACCEL_NONE;
+
+       fb->fb.var.xres         = fb->panel->mode.xres;
+       fb->fb.var.yres         = fb->panel->mode.yres;
+       fb->fb.var.xres_virtual = fb->panel->mode.xres;
+       fb->fb.var.yres_virtual = fb->panel->mode.yres;
+       fb->fb.var.bits_per_pixel = fb->panel->bpp;
+       fb->fb.var.grayscale    = fb->panel->grayscale;
+       fb->fb.var.pixclock     = fb->panel->mode.pixclock;
+       fb->fb.var.left_margin  = fb->panel->mode.left_margin;
+       fb->fb.var.right_margin = fb->panel->mode.right_margin;
+       fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
+       fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
+       fb->fb.var.hsync_len    = fb->panel->mode.hsync_len;
+       fb->fb.var.vsync_len    = fb->panel->mode.vsync_len;
+       fb->fb.var.sync         = fb->panel->mode.sync;
+       fb->fb.var.vmode        = fb->panel->mode.vmode;
+       fb->fb.var.activate     = FB_ACTIVATE_NOW;
+       fb->fb.var.nonstd       = 0;
+       fb->fb.var.height       = fb->panel->height;
+       fb->fb.var.width        = fb->panel->width;
+       fb->fb.var.accel_flags  = 0;
+
+       fb->fb.monspecs.hfmin   = 0;
+       fb->fb.monspecs.hfmax   = 100000;
+       fb->fb.monspecs.vfmin   = 0;
+       fb->fb.monspecs.vfmax   = 400;
+       fb->fb.monspecs.dclkmin = 1000000;
+       fb->fb.monspecs.dclkmax = 100000000;
+
+       /*
+        * Make sure that the bitfields are set appropriately.
+        */
+       clcdfb_set_bitfields(fb, &fb->fb.var);
+
+       /*
+        * Allocate colourmap.
+        */
+       fb_alloc_cmap(&fb->fb.cmap, 256, 0);
+
+       /*
+        * Ensure interrupts are disabled.
+        */
+       writel(0, fb->regs + CLCD_IENB);
+
+       fb_set_var(&fb->fb, &fb->fb.var);
+
+        printk(KERN_INFO "CLCD: %s hardware, %s display\n",
+               fb->board->name, fb->panel->mode.name);
+
+       ret = register_framebuffer(&fb->fb);
+       if (ret == 0)
+               goto out;
+
+       printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
+
+       iounmap(fb->regs);
+ unuse_clk:
+       clk_unuse(fb->clk);
+ free_clk:
+       clk_put(fb->clk);
+ out:
+       return ret;
+}
+
+static int clcdfb_probe(struct amba_device *dev, void *id)
+{
+       struct clcd_board *board = dev->dev.platform_data;
+       struct clcd_fb *fb;
+       int ret;
+
+       if (!board)
+               return -EINVAL;
+
+       ret = amba_request_regions(dev, NULL);
+       if (ret) {
+               printk(KERN_ERR "CLCD: unable to reserve regs region\n");
+               goto out;
+       }
+
+       fb = (struct clcd_fb *) kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+       if (!fb) {
+               printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
+               ret = -ENOMEM;
+               goto free_region;
+       }
+       memset(fb, 0, sizeof(struct clcd_fb));
+
+       fb->dev = dev;
+       fb->board = board;
+
+       ret = fb->board->setup(fb);
+       if (ret)
+               goto free_fb;
+
+       ret = clcdfb_register(fb); 
+       if (ret == 0) {
+               amba_set_drvdata(dev, fb);
+               goto out;
+       }
+
+       fb->board->remove(fb);
+ free_fb:
+       kfree(fb);
+ free_region:
+       amba_release_regions(dev);
+ out:
+       return ret;
+}
+
+static int clcdfb_remove(struct amba_device *dev)
+{
+       struct clcd_fb *fb = amba_get_drvdata(dev);
+
+       amba_set_drvdata(dev, NULL);
+
+       clcdfb_disable(fb);
+       unregister_framebuffer(&fb->fb);
+       iounmap(fb->regs);
+       clk_unuse(fb->clk);
+       clk_put(fb->clk);
+
+       fb->board->remove(fb);
+
+       kfree(fb);
+
+       amba_release_regions(dev);
+
+       return 0;
+}
+
+static struct amba_id clcdfb_id_table[] = {
+       {
+               .id     = 0x00041110,
+               .mask   = 0x000fffff,
+       },
+       { 0, 0 },
+};
+
+static struct amba_driver clcd_driver = {
+       .drv            = {
+               .name   = "clcd-pl110",
+       },
+       .probe          = clcdfb_probe,
+       .remove         = clcdfb_remove,
+       .id_table       = clcdfb_id_table,
+};
+
+int __init amba_clcdfb_init(void)
+{
+       if (fb_get_options("ambafb", NULL))
+               return -ENODEV;
+
+       return amba_driver_register(&clcd_driver);
+}
+
+module_init(amba_clcdfb_init);
+
+static void __exit amba_clcdfb_exit(void)
+{
+       amba_driver_unregister(&clcd_driver);
+}
+
+module_exit(amba_clcdfb_exit);
+
+MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
new file mode 100644 (file)
index 0000000..2ab37d6
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ *  linux/drivers/video/console/bitblit.c -- BitBlitting Operation
+ *
+ *  Originally from the 'accel_*' routines in drivers/video/console/fbcon.c
+ *
+ *      Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+
+/*
+ * Accelerated handlers.
+ */
+#define FBCON_ATTRIBUTE_UNDERLINE 1
+#define FBCON_ATTRIBUTE_REVERSE   2
+#define FBCON_ATTRIBUTE_BOLD      4
+
+static inline int real_y(struct display *p, int ypos)
+{
+       int rows = p->vrows;
+
+       ypos += p->yscroll;
+       return ypos < rows ? ypos : ypos - rows;
+}
+
+
+static inline int get_attribute(struct fb_info *info, u16 c)
+{
+       int attribute = 0;
+
+       if (fb_get_color_depth(info) == 1) {
+               if (attr_underline(c))
+                       attribute |= FBCON_ATTRIBUTE_UNDERLINE;
+               if (attr_reverse(c))
+                       attribute |= FBCON_ATTRIBUTE_REVERSE;
+               if (attr_bold(c))
+                       attribute |= FBCON_ATTRIBUTE_BOLD;
+       }
+
+       return attribute;
+}
+
+static inline void update_attr(u8 *dst, u8 *src, int attribute,
+                              struct vc_data *vc)
+{
+       int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
+       int width = (vc->vc_font.width + 7) >> 3;
+       unsigned int cellsize = vc->vc_font.height * width;
+       u8 c;
+
+       offset = cellsize - (offset * width);
+       for (i = 0; i < cellsize; i++) {
+               c = src[i];
+               if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
+                       c = 0xff;
+               if (attribute & FBCON_ATTRIBUTE_BOLD)
+                       c |= c >> 1;
+               if (attribute & FBCON_ATTRIBUTE_REVERSE)
+                       c = ~c;
+               dst[i] = c;
+       }
+}
+
+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width)
+{
+       struct fb_copyarea area;
+
+       area.sx = sx * vc->vc_font.width;
+       area.sy = sy * vc->vc_font.height;
+       area.dx = dx * vc->vc_font.width;
+       area.dy = dy * vc->vc_font.height;
+       area.height = height * vc->vc_font.height;
+       area.width = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
+static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int height, int width)
+{
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       struct fb_fillrect region;
+
+       region.color = attr_bgcol_ec(bgshift, vc);
+       region.dx = sx * vc->vc_font.width;
+       region.dy = sy * vc->vc_font.height;
+       region.width = width * vc->vc_font.width;
+       region.height = height * vc->vc_font.height;
+       region.rop = ROP_COPY;
+
+       info->fbops->fb_fillrect(info, &region);
+}
+
+static void bit_putcs(struct vc_data *vc, struct fb_info *info,
+                     const unsigned short *s, int count, int yy, int xx,
+                     int fg, int bg)
+{
+       void (*move_unaligned)(struct fb_info *info, struct fb_pixmap *buf,
+                              u8 *dst, u32 d_pitch, u8 *src, u32 idx,
+                              u32 height, u32 shift_high, u32 shift_low,
+                              u32 mod);
+       void (*move_aligned)(struct fb_info *info, struct fb_pixmap *buf,
+                            u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch,
+                            u32 height);
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       unsigned int width = (vc->vc_font.width + 7) >> 3;
+       unsigned int cellsize = vc->vc_font.height * width;
+       unsigned int maxcnt = info->pixmap.size/cellsize;
+       unsigned int scan_align = info->pixmap.scan_align - 1;
+       unsigned int buf_align = info->pixmap.buf_align - 1;
+       unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
+       unsigned int shift_high = 8, pitch, cnt, size, k;
+       unsigned int idx = vc->vc_font.width >> 3;
+       unsigned int attribute = get_attribute(info, scr_readw(s));
+       struct fb_image image;
+       u8 *src, *dst, *buf = NULL;
+
+       if (attribute) {
+               buf = kmalloc(cellsize, GFP_KERNEL);
+               if (!buf)
+                       return;
+       }
+
+       image.fg_color = fg;
+       image.bg_color = bg;
+
+       image.dx = xx * vc->vc_font.width;
+       image.dy = yy * vc->vc_font.height;
+       image.height = vc->vc_font.height;
+       image.depth = 1;
+
+       if (info->pixmap.outbuf && info->pixmap.inbuf) {
+               move_aligned = fb_iomove_buf_aligned;
+               move_unaligned = fb_iomove_buf_unaligned;
+       } else {
+               move_aligned = fb_sysmove_buf_aligned;
+               move_unaligned = fb_sysmove_buf_unaligned;
+       }
+       while (count) {
+               if (count > maxcnt)
+                       cnt = k = maxcnt;
+               else
+                       cnt = k = count;
+
+               image.width = vc->vc_font.width * cnt;
+               pitch = ((image.width + 7) >> 3) + scan_align;
+               pitch &= ~scan_align;
+               size = pitch * image.height + buf_align;
+               size &= ~buf_align;
+               dst = fb_get_buffer_offset(info, &info->pixmap, size);
+               image.data = dst;
+               if (mod) {
+                       while (k--) {
+                               src = vc->vc_font.data + (scr_readw(s++)&
+                                                         charmask)*cellsize;
+
+                               if (attribute) {
+                                       update_attr(buf, src, attribute, vc);
+                                       src = buf;
+                               }
+
+                               move_unaligned(info, &info->pixmap, dst, pitch,
+                                              src, idx, image.height,
+                                              shift_high, shift_low, mod);
+                               shift_low += mod;
+                               dst += (shift_low >= 8) ? width : width - 1;
+                               shift_low &= 7;
+                               shift_high = 8 - shift_low;
+                       }
+               } else {
+                       while (k--) {
+                               src = vc->vc_font.data + (scr_readw(s++)&
+                                                         charmask)*cellsize;
+
+                               if (attribute) {
+                                       update_attr(buf, src, attribute, vc);
+                                       src = buf;
+                               }
+
+                               move_aligned(info, &info->pixmap, dst, pitch,
+                                            src, idx, image.height);
+                               dst += width;
+                       }
+               }
+               info->fbops->fb_imageblit(info, &image);
+               image.dx += cnt * vc->vc_font.width;
+               count -= cnt;
+       }
+
+       if (buf)
+               kfree(buf);
+}
+
+static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
+                             int bottom_only)
+{
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       unsigned int cw = vc->vc_font.width;
+       unsigned int ch = vc->vc_font.height;
+       unsigned int rw = info->var.xres - (vc->vc_cols*cw);
+       unsigned int bh = info->var.yres - (vc->vc_rows*ch);
+       unsigned int rs = info->var.xres - rw;
+       unsigned int bs = info->var.yres - bh;
+       struct fb_fillrect region;
+
+       region.color = attr_bgcol_ec(bgshift, vc);
+       region.rop = ROP_COPY;
+
+       if (rw && !bottom_only) {
+               region.dx = info->var.xoffset + rs;
+               region.dy = 0;
+               region.width = rw;
+               region.height = info->var.yres_virtual;
+               info->fbops->fb_fillrect(info, &region);
+       }
+
+       if (bh) {
+               region.dx = info->var.xoffset;
+               region.dy = info->var.yoffset + bs;
+               region.width = rs;
+               region.height = bh;
+               info->fbops->fb_fillrect(info, &region);
+       }
+}
+
+static void bit_cursor(struct vc_data *vc, struct fb_info *info,
+                      struct display *p, int mode, int fg, int bg)
+{
+       struct fb_cursor cursor;
+       struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       int w = (vc->vc_font.width + 7) >> 3, c;
+       int y = real_y(p, vc->vc_y);
+       int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+       char *src;
+
+       cursor.set = 0;
+
+       c = scr_readw((u16 *) vc->vc_pos);
+       attribute = get_attribute(info, c);
+       src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
+
+       if (ops->cursor_state.image.data != src ||
+           ops->cursor_reset) {
+           ops->cursor_state.image.data = src;
+           cursor.set |= FB_CUR_SETIMAGE;
+       }
+
+       if (attribute) {
+               u8 *dst;
+
+               dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
+               if (!dst)
+                       return;
+               if (ops->cursor_data)
+                       kfree(ops->cursor_data);
+               ops->cursor_data = dst;
+               update_attr(dst, src, attribute, vc);
+               src = dst;
+       }
+
+       if (ops->cursor_state.image.fg_color != fg ||
+           ops->cursor_state.image.bg_color != bg ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.fg_color = fg;
+               ops->cursor_state.image.bg_color = bg;
+               cursor.set |= FB_CUR_SETCMAP;
+       }
+
+       if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) ||
+           (ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x;
+               ops->cursor_state.image.dy = vc->vc_font.height * y;
+               cursor.set |= FB_CUR_SETPOS;
+       }
+
+       if (ops->cursor_state.image.height != vc->vc_font.height ||
+           ops->cursor_state.image.width != vc->vc_font.width ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.height = vc->vc_font.height;
+               ops->cursor_state.image.width = vc->vc_font.width;
+               cursor.set |= FB_CUR_SETSIZE;
+       }
+
+       if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+           ops->cursor_reset) {
+               ops->cursor_state.hot.x = cursor.hot.y = 0;
+               cursor.set |= FB_CUR_SETHOT;
+       }
+
+       if (cursor.set & FB_CUR_SETSIZE ||
+           vc->vc_cursor_type != p->cursor_shape ||
+           ops->cursor_state.mask == NULL ||
+           ops->cursor_reset) {
+               char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
+               int cur_height, size, i = 0;
+               u8 msk = 0xff;
+
+               if (!mask)
+                       return;
+
+               if (ops->cursor_state.mask)
+                       kfree(ops->cursor_state.mask);
+               ops->cursor_state.mask = mask;
+
+               p->cursor_shape = vc->vc_cursor_type;
+               cursor.set |= FB_CUR_SETSHAPE;
+
+               switch (p->cursor_shape & CUR_HWMASK) {
+               case CUR_NONE:
+                       cur_height = 0;
+                       break;
+               case CUR_UNDERLINE:
+                       cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+                       break;
+               case CUR_LOWER_THIRD:
+                       cur_height = vc->vc_font.height/3;
+                       break;
+               case CUR_LOWER_HALF:
+                       cur_height = vc->vc_font.height >> 1;
+                       break;
+               case CUR_TWO_THIRDS:
+                       cur_height = (vc->vc_font.height << 1)/3;
+                       break;
+               case CUR_BLOCK:
+               default:
+                       cur_height = vc->vc_font.height;
+                       break;
+               }
+               size = (vc->vc_font.height - cur_height) * w;
+               while (size--)
+                       mask[i++] = ~msk;
+               size = cur_height * w;
+               while (size--)
+                       mask[i++] = msk;
+       }
+
+       switch (mode) {
+       case CM_ERASE:
+               ops->cursor_state.enable = 0;
+               break;
+       case CM_DRAW:
+       case CM_MOVE:
+       default:
+               ops->cursor_state.enable = (use_sw) ? 0 : 1;
+               break;
+       }
+
+       cursor.image.data = src;
+       cursor.image.fg_color = ops->cursor_state.image.fg_color;
+       cursor.image.bg_color = ops->cursor_state.image.bg_color;
+       cursor.image.dx = ops->cursor_state.image.dx;
+       cursor.image.dy = ops->cursor_state.image.dy;
+       cursor.image.height = ops->cursor_state.image.height;
+       cursor.image.width = ops->cursor_state.image.width;
+       cursor.hot.x = ops->cursor_state.hot.x;
+       cursor.hot.y = ops->cursor_state.hot.y;
+       cursor.mask = ops->cursor_state.mask;
+       cursor.enable = ops->cursor_state.enable;
+       cursor.image.depth = 1;
+       cursor.rop = ROP_XOR;
+
+       info->fbops->fb_cursor(info, &cursor);
+
+       ops->cursor_reset = 0;
+}
+
+void fbcon_set_bitops(struct fbcon_ops *ops)
+{
+       ops->bmove = bit_bmove;
+       ops->clear = bit_clear;
+       ops->putcs = bit_putcs;
+       ops->clear_margins = bit_clear_margins;
+       ops->cursor = bit_cursor;
+}
+
+EXPORT_SYMBOL(fbcon_set_bitops);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Bit Blitting Operation");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
new file mode 100644 (file)
index 0000000..0984adc
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  linux/drivers/video/console/tileblit.c -- Tile Blitting Operation
+ *
+ *      Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
+ *
+ *  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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+
+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                      int sx, int dy, int dx, int height, int width)
+{
+       struct fb_tilearea area;
+
+       area.sx = sx;
+       area.sy = sy;
+       area.dx = dx;
+       area.dy = dy;
+       area.height = height;
+       area.width = width;
+
+       info->tileops->fb_tilecopy(info, &area);
+}
+
+static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
+                      int sx, int height, int width)
+{
+       struct fb_tilerect rect;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
+
+       rect.index = vc->vc_video_erase_char &
+               ((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
+       rect.fg = attr_fgcol_ec(fgshift, vc);
+       rect.bg = attr_bgcol_ec(bgshift, vc);
+       rect.sx = sx;
+       rect.sy = sy;
+       rect.width = width;
+       rect.height = height;
+       rect.rop = ROP_COPY;
+
+       info->tileops->fb_tilefill(info, &rect);
+}
+
+static void tile_putcs(struct vc_data *vc, struct fb_info *info,
+                      const unsigned short *s, int count, int yy, int xx,
+                      int fg, int bg)
+{
+       struct fb_tileblit blit;
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       int size = sizeof(u32) * count, i;
+
+       blit.sx = xx;
+       blit.sy = yy;
+       blit.width = count;
+       blit.height = 1;
+       blit.fg = fg;
+       blit.bg = bg;
+       blit.length = count;
+       blit.indices = (u32 *) fb_get_buffer_offset(info, &info->pixmap, size);
+       for (i = 0; i < count; i++)
+               blit.indices[i] = (u32)(scr_readw(s++) & charmask);
+
+       info->tileops->fb_tileblit(info, &blit);
+}
+
+static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
+                              int bottom_only)
+{
+       return;
+}
+
+static void tile_cursor(struct vc_data *vc, struct fb_info *info,
+                       struct display *p, int mode, int fg, int bg)
+{
+       struct fb_tilecursor cursor;
+       int use_sw = (vc->vc_cursor_type & 0x01);
+
+       cursor.sx = vc->vc_x;
+       cursor.sy = vc->vc_y;
+       cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1;
+       cursor.fg = fg;
+       cursor.bg = bg;
+
+       switch (vc->vc_cursor_type & 0x0f) {
+       case CUR_NONE:
+               cursor.shape = FB_TILE_CURSOR_NONE;
+               break;
+       case CUR_UNDERLINE:
+               cursor.shape = FB_TILE_CURSOR_UNDERLINE;
+               break;
+       case CUR_LOWER_THIRD:
+               cursor.shape = FB_TILE_CURSOR_LOWER_THIRD;
+               break;
+       case CUR_LOWER_HALF:
+               cursor.shape = FB_TILE_CURSOR_LOWER_HALF;
+               break;
+       case CUR_TWO_THIRDS:
+               cursor.shape = FB_TILE_CURSOR_TWO_THIRDS;
+               break;
+       case CUR_BLOCK:
+       default:
+               cursor.shape = FB_TILE_CURSOR_BLOCK;
+               break;
+       }
+
+       info->tileops->fb_tilecursor(info, &cursor);
+}
+
+void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
+                      struct display *p, struct fbcon_ops *ops)
+{
+       struct fb_tilemap map;
+
+       ops->bmove = tile_bmove;
+       ops->clear = tile_clear;
+       ops->putcs = tile_putcs;
+       ops->clear_margins = tile_clear_margins;
+       ops->cursor = tile_cursor;
+
+       if (p) {
+               map.width = vc->vc_font.width;
+               map.height = vc->vc_font.height;
+               map.depth = 1;
+               map.length = (p->userfont) ?
+                       FNTCHARCNT(p->fontdata) : 256;
+               map.data = p->fontdata;
+               info->tileops->fb_settile(info, &map);
+       }
+}
+
+EXPORT_SYMBOL(fbcon_set_tileops);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Tile Blitting Operation");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile
new file mode 100644 (file)
index 0000000..722d21d
--- /dev/null
@@ -0,0 +1,8 @@
+obj-$(CONFIG_FB_INTEL) += intelfb.o
+
+intelfb-objs := intelfbdrv.o intelfbhw.o
+
+ifdef CONFIG_FB_INTEL_DEBUG
+#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
+EXTRA_CFLAGS += -DDEBUG -DREGDUMP
+endif
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
new file mode 100644 (file)
index 0000000..1c5b472
--- /dev/null
@@ -0,0 +1,278 @@
+#ifndef _INTELFB_H
+#define _INTELFB_H
+
+/* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */
+
+#include <linux/agp_backend.h>
+#include <linux/fb.h>
+
+
+/*** Version/name ***/
+#define INTELFB_VERSION                        "0.9.2"
+#define INTELFB_MODULE_NAME            "intelfb"
+#define SUPPORTED_CHIPSETS             "830M/845G/852GM/855GM/865G"
+
+
+/*** Debug/feature defines ***/
+
+#ifndef DEBUG
+#define DEBUG                          0
+#endif
+
+#ifndef VERBOSE
+#define VERBOSE                                0
+#endif
+
+#ifndef REGDUMP
+#define REGDUMP                                0
+#endif
+
+#ifndef DETECT_VGA_CLASS_ONLY
+#define DETECT_VGA_CLASS_ONLY          1
+#endif
+
+#ifndef ALLOCATE_FOR_PANNING
+#define ALLOCATE_FOR_PANNING           1
+#endif
+
+#ifndef PREFERRED_MODE
+#define PREFERRED_MODE                 "1024x768-16@60"
+#endif
+
+/*** hw-related values ***/
+
+/* PCI ids for supported devices */
+#define PCI_DEVICE_ID_INTEL_830M       0x3577
+#define PCI_DEVICE_ID_INTEL_845G       0x2562
+#define PCI_DEVICE_ID_INTEL_85XGM      0x3582
+#define PCI_DEVICE_ID_INTEL_865G       0x2572
+
+/* Size of MMIO region */
+#define INTEL_REG_SIZE                 0x80000
+
+#define STRIDE_ALIGNMENT               16
+
+#define PALETTE_8_ENTRIES              256
+
+
+/*** Macros ***/
+
+/* basic arithmetic */
+#define KB(x)                  ((x) * 1024)
+#define MB(x)                  ((x) * 1024 * 1024)
+#define BtoKB(x)               ((x) / 1024)
+#define BtoMB(x)               ((x) / 1024 / 1024)
+
+#define GTT_PAGE_SIZE           KB(4)
+
+#define ROUND_UP_TO(x, y)      (((x) + (y) - 1) / (y) * (y))
+#define ROUND_DOWN_TO(x, y)    ((x) / (y) * (y))
+#define ROUND_UP_TO_PAGE(x)    ROUND_UP_TO((x), GTT_PAGE_SIZE)
+#define ROUND_DOWN_TO_PAGE(x)  ROUND_DOWN_TO((x), GTT_PAGE_SIZE)
+
+/* messages */
+#define PFX                    INTELFB_MODULE_NAME ": "
+
+#define ERR_MSG(fmt, args...)  printk(KERN_ERR PFX fmt, ## args)
+#define WRN_MSG(fmt, args...)  printk(KERN_WARNING PFX fmt, ## args)
+#define NOT_MSG(fmt, args...)  printk(KERN_NOTICE PFX fmt, ## args)
+#define INF_MSG(fmt, args...)  printk(KERN_INFO PFX fmt, ## args)
+#if DEBUG
+#define DBG_MSG(fmt, args...)  printk(KERN_DEBUG PFX fmt, ## args)
+#else
+#define DBG_MSG(fmt, args...)  while (0) printk(fmt, ## args)
+#endif
+
+/* get commonly used pointers */
+#define GET_DINFO(info)                (info)->par
+
+/* misc macros */
+#define ACCEL(d, i)                                                     \
+       ((d)->accel && !(d)->ring_lockup &&                             \
+        ((i)->var.accel_flags & FB_ACCELF_TEXT))
+
+/*#define NOACCEL_CHIPSET(d)                                           \
+       ((d)->chipset != INTEL_865G)*/
+#define NOACCEL_CHIPSET(d)                                             \
+       (0)
+
+#define FIXED_MODE(d) ((d)->fixed_mode)
+
+/*** Driver paramters ***/
+
+#define RINGBUFFER_SIZE                KB(64)
+#define HW_CURSOR_SIZE         KB(4)
+
+/* Intel agpgart driver */
+#define AGP_PHYSICAL_MEMORY     2
+
+/*** Data Types ***/
+
+/* supported chipsets */
+enum intel_chips {
+       INTEL_830M,
+       INTEL_845G,
+       INTEL_85XGM,
+       INTEL_852GM,
+       INTEL_852GME,
+       INTEL_855GM,
+       INTEL_855GME,
+       INTEL_865G
+};
+
+struct intelfb_hwstate {
+       u32 vga0_divisor;
+       u32 vga1_divisor;
+       u32 vga_pd;
+       u32 dpll_a;
+       u32 dpll_b;
+       u32 fpa0;
+       u32 fpa1;
+       u32 fpb0;
+       u32 fpb1;
+       u32 palette_a[PALETTE_8_ENTRIES];
+       u32 palette_b[PALETTE_8_ENTRIES];
+       u32 htotal_a;
+       u32 hblank_a;
+       u32 hsync_a;
+       u32 vtotal_a;
+       u32 vblank_a;
+       u32 vsync_a;
+       u32 src_size_a;
+       u32 bclrpat_a;
+       u32 htotal_b;
+       u32 hblank_b;
+       u32 hsync_b;
+       u32 vtotal_b;
+       u32 vblank_b;
+       u32 vsync_b;
+       u32 src_size_b;
+       u32 bclrpat_b;
+       u32 adpa;
+       u32 dvoa;
+       u32 dvob;
+       u32 dvoc;
+       u32 dvoa_srcdim;
+       u32 dvob_srcdim;
+       u32 dvoc_srcdim;
+       u32 lvds;
+       u32 pipe_a_conf;
+       u32 pipe_b_conf;
+       u32 disp_arb;
+       u32 cursor_a_control;
+       u32 cursor_b_control;
+       u32 cursor_a_base;
+       u32 cursor_b_base;
+       u32 cursor_size;
+       u32 disp_a_ctrl;
+       u32 disp_b_ctrl;
+       u32 disp_a_base;
+       u32 disp_b_base;
+       u32 cursor_a_palette[4];
+       u32 cursor_b_palette[4];
+       u32 disp_a_stride;
+       u32 disp_b_stride;
+       u32 vgacntrl;
+       u32 add_id;
+       u32 swf0x[7];
+       u32 swf1x[7];
+       u32 swf3x[3];
+       u32 fence[8];
+       u32 instpm;
+       u32 mem_mode;
+       u32 fw_blc_0;
+       u32 fw_blc_1;
+};
+
+struct intelfb_heap_data {
+       u32 physical;
+       u8 __iomem *virtual;
+       u32 offset;  // in GATT pages
+       u32 size;    // in bytes
+};
+
+struct intelfb_info {
+       struct fb_info *info;
+       struct fb_ops  *fbops;
+       struct pci_dev *pdev;
+
+       struct intelfb_hwstate save_state;
+
+       /* agpgart structs */
+       struct agp_memory *gtt_fb_mem;     // use all stolen memory or vram
+       struct agp_memory *gtt_ring_mem;   // ring buffer
+       struct agp_memory *gtt_cursor_mem; // hw cursor
+
+       /* use a gart reserved fb mem */
+       u8 fbmem_gart;
+
+       /* mtrr support */
+       u32 mtrr_reg;
+       u32 has_mtrr;
+
+       /* heap data */
+       struct intelfb_heap_data aperture;
+       struct intelfb_heap_data fb;
+       struct intelfb_heap_data ring;
+       struct intelfb_heap_data cursor;
+
+       /* mmio regs */
+       u32 mmio_base_phys;
+       u8 __iomem *mmio_base;
+
+       /* fb start offset (in bytes) */
+       u32 fb_start;
+
+       /* ring buffer */
+       u8 __iomem *ring_head;
+       u32 ring_tail;
+       u32 ring_tail_mask;
+       u32 ring_space;
+       u32 ring_lockup;
+
+       /* palette */
+       u32 pseudo_palette[17];
+       struct { u8 red, green, blue, pad; } palette[256];
+
+       /* chip info */
+       int pci_chipset;
+       int chipset;
+       const char *name;
+       int mobile;
+
+       /* current mode */
+       int bpp, depth;
+       u32 visual;
+       int xres, yres, pitch;
+       int pixclock;
+
+       /* current pipe */
+       int pipe;
+
+       /* some flags */
+       int accel;
+       int hwcursor;
+       int fixed_mode;
+       int ring_active;
+
+       /* hw cursor */
+       int cursor_on;
+       int cursor_blanked;
+       u8  cursor_src[64];
+
+       /* initial parameters */
+       int initial_vga;
+       struct fb_var_screeninfo initial_var;
+       u32 initial_fb_base;
+       u32 initial_video_ram;
+       u32 initial_pitch;
+
+       /* driver registered */
+       int registered;
+};
+
+/*** function prototypes ***/
+
+extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
+
+#endif /* _INTELFB_H */
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
new file mode 100644 (file)
index 0000000..a506cb4
--- /dev/null
@@ -0,0 +1,1557 @@
+/*
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G
+ * integrated graphics chips.
+ *
+ * Copyright Â© 2002, 2003 David Dawes <dawes@xfree86.org>
+ *                   2004 Sylvain Meyer
+ *
+ * This driver consists of two parts.  The first part (intelfbdrv.c) provides
+ * the basic fbdev interfaces, is derived in part from the radeonfb and
+ * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
+ * provides the code to program the hardware.  Most of it is derived from
+ * the i810/i830 XFree86 driver.  The HW-specific code is covered here
+ * under a dual license (GPL and MIT/XFree86 license).
+ *
+ * Author: David Dawes
+ *
+ */
+
+/* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */
+
+/*
+ * Changes:
+ *    01/2003 - Initial driver (0.1.0), no mode switching, no acceleration.
+ *             This initial version is a basic core that works a lot like
+ *             the vesafb driver.  It must be built-in to the kernel,
+ *             and the initial video mode must be set with vga=XXX at
+ *             boot time.  (David Dawes)
+ *
+ *    01/2003 - Version 0.2.0: Mode switching added, colormap support
+ *             implemented, Y panning, and soft screen blanking implemented.
+ *             No acceleration yet.  (David Dawes)
+ *
+ *    01/2003 - Version 0.3.0: fbcon acceleration support added.  Module
+ *             option handling added.  (David Dawes)
+ *
+ *    01/2003 - Version 0.4.0: fbcon HW cursor support added.  (David Dawes)
+ *
+ *    01/2003 - Version 0.4.1: Add auto-generation of built-in modes.
+ *             (David Dawes)
+ *
+ *    02/2003 - Version 0.4.2: Add check for active non-CRT devices, and
+ *             mode validation checks.  (David Dawes)
+ *
+ *    02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that
+ *             acceleration is disabled while an XFree86 server is running.
+ *             (David Dawes)
+ *
+ *    02/2003 - Version 0.4.4: Monitor DPMS support.  (David Dawes)
+ *
+ *    02/2003 - Version 0.4.5: Basic XFree86 + fbdev working.  (David Dawes)
+ *
+ *    02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well
+ *             as 2.4.x kernels.  (David Dawes)
+ *
+ *    02/2003 - Version 0.6.0: Split out HW-specifics into a separate file.
+ *             (David Dawes)
+ *
+ *    02/2003 - Version 0.7.0: Test on 852GM/855GM.  Acceleration and HW
+ *             cursor are disabled on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.1: Test on 845G.  Acceleration is disabled
+ *             on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.2: Test on 830M.  Acceleration and HW
+ *             cursor are disabled on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms
+ *             (David Dawes)
+ *
+ *    02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured
+ *             in the kernel, and add mode bpp verification and default
+ *             bpp selection based on which FBCON_HAS_CFB* are configured.
+ *             (David Dawes)
+ *
+ *    02/2003 - Version 0.7.5: Add basic package/install scripts based on the
+ *             DRI packaging scripts.  (David Dawes)
+ *
+ *    04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled
+ *             kernels.  (David Dawes, reported by Anupam).
+ *
+ *    06/2003 - Version 0.7.7:
+ *              Fix Makefile.kernel build problem (Tsutomu Yasuda).
+ *             Fix mis-placed #endif (2.4.21 kernel).
+ *
+ *    09/2004 - Version 0.9.0 - by Sylvain Meyer
+ *              Port to linux 2.6 kernel fbdev
+ *              Fix HW accel and HW cursor on i845G
+ *              Use of agpgart for fb memory reservation
+ *              Add mtrr support
+ *
+ *    10/2004 - Version 0.9.1
+ *              Use module_param instead of old MODULE_PARM
+ *              Some cleanup
+ *
+ *    11/2004 - Version 0.9.2
+ *              Add vram option to reserve more memory than stolen by BIOS
+ *              Fix intelfbhw_pan_display typo
+ *              Add __initdata annotations
+ *
+ * TODO:
+ *
+ *
+ * Wish List:
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "intelfb.h"
+#include "intelfbdrv.h"
+#include "intelfbhw.h"
+
+/*
+ * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the
+ * mobile chipsets from being registered.
+ */
+#if DETECT_VGA_CLASS_ONLY
+#define INTELFB_CLASS_MASK ~0 << 8
+#else
+#define INTELFB_CLASS_MASK 0
+#endif
+
+static struct pci_device_id intelfb_pci_table[] __devinitdata = {
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
+       { 0, }
+};
+
+/* Global data */
+static int num_registered = 0;
+
+/* fb ops */
+static struct fb_ops intel_fb_ops = {
+       .owner =                THIS_MODULE,
+       .fb_check_var =         intelfb_check_var,
+       .fb_set_par =           intelfb_set_par,
+       .fb_setcolreg =         intelfb_setcolreg,
+       .fb_blank =             intelfb_blank,
+       .fb_pan_display =       intelfb_pan_display,
+       .fb_fillrect  =         intelfb_fillrect,
+       .fb_copyarea  =         intelfb_copyarea,
+       .fb_imageblit =         intelfb_imageblit,
+       .fb_cursor =            intelfb_cursor,
+       .fb_sync =              intelfb_sync,
+       .fb_ioctl =             intelfb_ioctl
+};
+
+/* PCI driver module table */
+static struct pci_driver intelfb_driver = {
+       .name =         "Intel(R) " SUPPORTED_CHIPSETS " Framebuffer Driver",
+       .id_table =     intelfb_pci_table,
+       .probe =        intelfb_pci_register,
+       .remove =       __devexit_p(intelfb_pci_unregister)
+};
+
+/* Module description/parameters */
+MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, "
+             "Sylvain Meyer <sylvain.meyer@worldonline.fr>");
+MODULE_DESCRIPTION(
+       "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
+
+static int accel        __initdata = 1;
+static int vram         __initdata = 4;
+static int hwcursor     __initdata = 1;
+static int mtrr         __initdata = 1;
+static int fixed        __initdata = 0;
+static int noinit       __initdata = 0;
+static int noregister   __initdata = 0;
+static int probeonly    __initdata = 0;
+static int idonly       __initdata = 0;
+static int bailearly    __initdata = 0;
+static char *mode       __initdata = NULL;
+
+module_param(accel, bool, S_IRUGO);
+MODULE_PARM_DESC(accel, "Enable console acceleration");
+module_param(vram, int, S_IRUGO);
+MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB");
+module_param(hwcursor, bool, S_IRUGO);
+MODULE_PARM_DESC(hwcursor, "Enable HW cursor");
+module_param(mtrr, bool, S_IRUGO);
+MODULE_PARM_DESC(mtrr, "Enable MTRR support");
+module_param(fixed, bool, S_IRUGO);
+MODULE_PARM_DESC(fixed, "Disable mode switching");
+module_param(noinit, bool, 0);
+MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading");
+module_param(noregister, bool, 0);
+MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)");
+module_param(probeonly, bool, 0);
+MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)");
+module_param(idonly, bool, 0);
+MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)");
+module_param(bailearly, bool, 0);
+MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)");
+module_param(mode, charp, S_IRUGO);
+MODULE_PARM_DESC(mode,
+                "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");
+/***************************************************************
+ *                     modules entry points                    *
+ ***************************************************************/
+
+/* module load/unload entry points */
+int __init
+intelfb_init(void)
+{
+#ifndef MODULE
+       char *option = NULL;
+#endif
+
+       DBG_MSG("intelfb_init\n");
+
+       INF_MSG("Framebuffer driver for "
+               "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n");
+       INF_MSG("Version " INTELFB_VERSION "\n");
+
+       if (idonly)
+               return -ENODEV;
+
+#ifndef MODULE
+       if (fb_get_options("intelfb", &option))
+               return -ENODEV;
+       intelfb_setup(option);
+#endif
+
+       return pci_module_init(&intelfb_driver);
+}
+
+static void __exit
+intelfb_exit(void)
+{
+       DBG_MSG("intelfb_exit\n");
+       pci_unregister_driver(&intelfb_driver);
+}
+
+#ifndef MODULE
+#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
+#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0)
+#define OPT_STRVAL(opt, name) (opt + strlen(name))
+
+static __inline__ char *
+get_opt_string(const char *this_opt, const char *name)
+{
+       const char *p;
+       int i;
+       char *ret;
+
+       p = OPT_STRVAL(this_opt, name);
+       i = 0;
+       while (p[i] && p[i] != ' ' && p[i] != ',')
+               i++;
+       ret = kmalloc(i + 1, GFP_KERNEL);
+       if (ret) {
+               strncpy(ret, p, i);
+               ret[i] = '\0';
+       }
+       return ret;
+}
+
+static __inline__ int
+get_opt_int(const char *this_opt, const char *name, int *ret)
+{
+       if (!ret)
+               return 0;
+
+       if (!OPT_EQUAL(this_opt, name))
+               return 0;
+
+       *ret = OPT_INTVAL(this_opt, name);
+       return 1;
+}
+
+static __inline__ int
+get_opt_bool(const char *this_opt, const char *name, int *ret)
+{
+       if (!ret)
+               return 0;
+
+       if (OPT_EQUAL(this_opt, name)) {
+               if (this_opt[strlen(name)] == '=')
+                       *ret = simple_strtoul(this_opt + strlen(name) + 1,
+                                             NULL, 0);
+               else
+                       *ret = 1;
+       } else {
+               if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name))
+                       *ret = 0;
+               else
+                       return 0;
+       }
+       return 1;
+}
+
+int __init
+intelfb_setup(char *options)
+{
+       char *this_opt;
+
+       DBG_MSG("intelfb_setup\n");
+
+       if (!options || !*options) {
+               DBG_MSG("no options\n");
+               return 0;
+       } else
+               DBG_MSG("options: %s\n", options);
+
+       /*
+        * These are the built-in options analogous to the module parameters
+        * defined above.
+        *
+        * The syntax is:
+        *
+        *    video=intelfb:[mode][,<param>=<val>] ...
+        *
+        * e.g.,
+        *
+        *    video=intelfb:1024x768-16@75,accel=0
+        */
+
+       while ((this_opt = strsep(&options, ","))) {
+               if (!*this_opt)
+                       continue;
+               if (get_opt_bool(this_opt, "accel", &accel))
+                       ;
+               else if (get_opt_int(this_opt, "vram", &vram))
+                       ;
+               else if (get_opt_bool(this_opt, "hwcursor", &hwcursor))
+                       ;
+               else if (get_opt_bool(this_opt, "mtrr", &mtrr))
+                       ;
+               else if (get_opt_bool(this_opt, "fixed", &fixed))
+                       ;
+               else if (get_opt_bool(this_opt, "init", &noinit))
+                       noinit = !noinit;
+               else if (OPT_EQUAL(this_opt, "mode="))
+                       mode = get_opt_string(this_opt, "mode=");
+               else
+                       mode = this_opt;
+       }
+
+       return 0;
+}
+
+#endif
+
+module_init(intelfb_init);
+
+#ifdef MODULE
+module_exit(intelfb_exit);
+#endif
+
+/***************************************************************
+ *                     mtrr support functions                  *
+ ***************************************************************/
+
+#ifdef CONFIG_MTRR
+static inline void __devinit set_mtrr(struct intelfb_info *dinfo)
+{
+       dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical,
+                                  dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1);
+       if (dinfo->mtrr_reg < 0) {
+               ERR_MSG("unable to set MTRR\n");
+               return;
+       }
+       dinfo->has_mtrr = 1;
+}
+static inline void unset_mtrr(struct intelfb_info *dinfo)
+{
+       if (dinfo->has_mtrr)
+               mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical,
+                        dinfo->aperture.size);
+}
+#else
+#define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n")
+
+#define unset_mtrr(x) do { } while (0)
+#endif /* CONFIG_MTRR */
+
+/***************************************************************
+ *                        driver init / cleanup                *
+ ***************************************************************/
+
+static void
+cleanup(struct intelfb_info *dinfo)
+{
+       DBG_MSG("cleanup\n");
+
+       if (!dinfo)
+               return;
+
+       fb_dealloc_cmap(&dinfo->info->cmap);
+       kfree(dinfo->info->pixmap.addr);
+
+       if (dinfo->registered)
+               unregister_framebuffer(dinfo->info);
+
+       unset_mtrr(dinfo);
+
+       if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) {
+               agp_unbind_memory(dinfo->gtt_fb_mem);
+               agp_free_memory(dinfo->gtt_fb_mem);
+       }
+       if (dinfo->gtt_cursor_mem) {
+               agp_unbind_memory(dinfo->gtt_cursor_mem);
+               agp_free_memory(dinfo->gtt_cursor_mem);
+       }
+       if (dinfo->gtt_ring_mem) {
+               agp_unbind_memory(dinfo->gtt_ring_mem);
+               agp_free_memory(dinfo->gtt_ring_mem);
+       }
+
+       if (dinfo->mmio_base)
+               iounmap((void __iomem *)dinfo->mmio_base);
+       if (dinfo->aperture.virtual)
+               iounmap((void __iomem *)dinfo->aperture.virtual);
+
+       if (dinfo->mmio_base_phys)
+               release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE);
+       if (dinfo->aperture.physical)
+               release_mem_region(dinfo->aperture.physical,
+                                  dinfo->aperture.size);
+       framebuffer_release(dinfo->info);
+}
+
+#define bailout(dinfo) do {                                            \
+       DBG_MSG("bailout\n");                                           \
+       cleanup(dinfo);                                                 \
+       INF_MSG("Not going to register framebuffer, exiting...\n");     \
+       return -ENODEV;                                                 \
+} while (0)
+
+
+static int __devinit
+intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct fb_info *info;
+       struct intelfb_info *dinfo;
+       int i, j, err, dvo;
+       int aperture_size, stolen_size;
+       struct agp_kern_info gtt_info;
+       int agp_memtype;
+       const char *s;
+
+       DBG_MSG("intelfb_pci_register\n");
+
+       num_registered++;
+       if (num_registered != 1) {
+               ERR_MSG("Attempted to register %d devices "
+                       "(should be only 1).\n", num_registered);
+               return -ENODEV;
+       }
+
+       info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev);
+       if (!info) {
+               ERR_MSG("Could not allocate memory for intelfb_info.\n");
+               return -ENODEV;
+       }
+       if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
+               ERR_MSG("Could not allocate cmap for intelfb_info.\n");
+               goto err_out_cmap;
+               return -ENODEV;
+       }
+
+       dinfo = info->par;
+       dinfo->info  = info;
+       dinfo->fbops = &intel_fb_ops;
+       dinfo->pdev  = pdev;
+
+       /* Reserve pixmap space. */
+       info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL);
+       if (info->pixmap.addr == NULL) {
+               ERR_MSG("Cannot reserve pixmap memory.\n");
+               goto err_out_pixmap;
+       }
+       memset(info->pixmap.addr, 0, 64 * 1024);
+
+       /* set early this option because it could be changed by tv encoder
+          driver */
+       dinfo->fixed_mode = fixed;
+
+       /* Enable device. */
+       if ((err = pci_enable_device(pdev))) {
+               ERR_MSG("Cannot enable device.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       /* Set base addresses. */
+       dinfo->aperture.physical = pci_resource_start(pdev, 0);
+       dinfo->aperture.size     = pci_resource_len(pdev, 0);
+       dinfo->mmio_base_phys    = pci_resource_start(pdev, 1);
+
+       DBG_MSG("fb aperture: 0x%lx/0x%lx, MMIO region: 0x%lx/0x%lx\n",
+               pci_resource_start(pdev, 0), pci_resource_len(pdev, 0),
+               pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+
+       /* Reserve the fb and MMIO regions */
+       if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size,
+                               INTELFB_MODULE_NAME)) {
+               ERR_MSG("Cannot reserve FB region.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+       if (!request_mem_region(dinfo->mmio_base_phys,
+                               INTEL_REG_SIZE,
+                               INTELFB_MODULE_NAME)) {
+               ERR_MSG("Cannot reserve MMIO region.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       /* Map the fb and MMIO regions */
+       dinfo->aperture.virtual = (u8 __iomem *)ioremap_nocache
+               (dinfo->aperture.physical, dinfo->aperture.size);
+       if (!dinfo->aperture.virtual) {
+               ERR_MSG("Cannot remap FB region.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+       dinfo->mmio_base =
+               (u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys,
+                                              INTEL_REG_SIZE);
+       if (!dinfo->mmio_base) {
+               ERR_MSG("Cannot remap MMIO region.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       /* Get the chipset info. */
+       dinfo->pci_chipset = pdev->device;
+
+       if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
+                                 &dinfo->mobile)) {
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) {
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, "
+               "stolen memory %dkB\n",
+               pdev->bus->number, PCI_SLOT(pdev->devfn),
+               PCI_FUNC(pdev->devfn), dinfo->name,
+               BtoMB(aperture_size), BtoKB(stolen_size));
+
+       /* Set these from the options. */
+       dinfo->accel    = accel;
+       dinfo->hwcursor = hwcursor;
+
+       if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) {
+               INF_MSG("Acceleration is not supported for the %s chipset.\n",
+                       dinfo->name);
+               dinfo->accel = 0;
+       }
+
+       /* Framebuffer parameters - Use all the stolen memory if >= vram */
+       if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) {
+               dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size);
+               dinfo->fbmem_gart = 0;
+       } else {
+               dinfo->fb.size =  MB(vram);
+               dinfo->fbmem_gart = 1;
+       }
+
+       /* Allocate space for the ring buffer and HW cursor if enabled. */
+       if (dinfo->accel) {
+               dinfo->ring.size = RINGBUFFER_SIZE;
+               dinfo->ring_tail_mask = dinfo->ring.size - 1;
+       }
+       if (dinfo->hwcursor) {
+               dinfo->cursor.size = HW_CURSOR_SIZE;
+       }
+
+       /* Use agpgart to manage the GATT */
+       if (agp_backend_acquire()) {
+               ERR_MSG("cannot acquire agp\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       /* get the current gatt info */
+       if (agp_copy_info(&gtt_info)) {
+               ERR_MSG("cannot get agp info\n");
+               agp_backend_release();
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       /* set the mem offsets - set them after the already used pages */
+       if (dinfo->accel) {
+               dinfo->ring.offset = (stolen_size >> 12)
+                       + gtt_info.current_memory;
+       }
+       if (dinfo->hwcursor) {
+               dinfo->cursor.offset = (stolen_size >> 12) +
+                       + gtt_info.current_memory + (dinfo->ring.size >> 12);
+       }
+       if (dinfo->fbmem_gart) {
+               dinfo->fb.offset = (stolen_size >> 12) +
+                       + gtt_info.current_memory + (dinfo->ring.size >> 12)
+                       + (dinfo->cursor.size >> 12);
+       }
+
+       /* Allocate memories (which aren't stolen) */
+       if (dinfo->accel) {
+               if (!(dinfo->gtt_ring_mem =
+                     agp_allocate_memory(dinfo->ring.size >> 12,
+                                         AGP_NORMAL_MEMORY))) {
+                       ERR_MSG("cannot allocate ring buffer memory\n");
+                       agp_backend_release();
+                       cleanup(dinfo);
+                       return -ENOMEM;
+               }
+               if (agp_bind_memory(dinfo->gtt_ring_mem,
+                                   dinfo->ring.offset)) {
+                       ERR_MSG("cannot bind ring buffer memory\n");
+                       agp_backend_release();
+                       cleanup(dinfo);
+                       return -EBUSY;
+               }
+               dinfo->ring.physical = dinfo->aperture.physical
+                       + (dinfo->ring.offset << 12);
+               dinfo->ring.virtual  = dinfo->aperture.virtual
+                       + (dinfo->ring.offset << 12);
+               dinfo->ring_head = dinfo->ring.virtual;
+       }
+       if (dinfo->hwcursor) {
+               agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
+                       : AGP_NORMAL_MEMORY;
+               if (!(dinfo->gtt_cursor_mem =
+                     agp_allocate_memory(dinfo->cursor.size >> 12,
+                                         agp_memtype))) {
+                       ERR_MSG("cannot allocate cursor memory\n");
+                       agp_backend_release();
+                       cleanup(dinfo);
+                       return -ENOMEM;
+               }
+               if (agp_bind_memory(dinfo->gtt_cursor_mem,
+                                   dinfo->cursor.offset)) {
+                       ERR_MSG("cannot bind cursor memory\n");
+                       agp_backend_release();
+                       cleanup(dinfo);
+                       return -EBUSY;
+               }
+               if (dinfo->mobile)
+                       dinfo->cursor.physical
+                               = dinfo->gtt_cursor_mem->physical;
+               else
+                       dinfo->cursor.physical = dinfo->aperture.physical
+                               + (dinfo->cursor.offset << 12);
+               dinfo->cursor.virtual = dinfo->aperture.virtual
+                       + (dinfo->cursor.offset << 12);
+       }
+       if (dinfo->fbmem_gart) {
+               if (!(dinfo->gtt_fb_mem =
+                     agp_allocate_memory(dinfo->fb.size >> 12,
+                                         AGP_NORMAL_MEMORY))) {
+                       WRN_MSG("cannot allocate framebuffer memory - use "
+                               "the stolen one\n");
+                       dinfo->fbmem_gart = 0;
+               }
+               if (agp_bind_memory(dinfo->gtt_fb_mem,
+                                   dinfo->fb.offset)) {
+                       WRN_MSG("cannot bind framebuffer memory - use "
+                               "the stolen one\n");
+                       dinfo->fbmem_gart = 0;
+               }
+       }
+
+       /* update framebuffer memory parameters */
+       if (!dinfo->fbmem_gart)
+               dinfo->fb.offset = 0;   /* starts at offset 0 */
+       dinfo->fb.physical = dinfo->aperture.physical
+               + (dinfo->fb.offset << 12);
+       dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12);
+       dinfo->fb_start = dinfo->fb.offset << 12;
+
+       /* release agpgart */
+       agp_backend_release();
+
+       if (mtrr)
+               set_mtrr(dinfo);
+
+       DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n",
+               dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size,
+               (u32 __iomem ) dinfo->fb.virtual);
+       DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n",
+               dinfo->mmio_base_phys, INTEL_REG_SIZE,
+               (u32 __iomem) dinfo->mmio_base);
+       DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n",
+               dinfo->ring.physical, dinfo->ring.size,
+               (u32 __iomem ) dinfo->ring.virtual);
+       DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n",
+               dinfo->cursor.physical, dinfo->cursor.size,
+               (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset,
+               dinfo->cursor.physical);
+
+       DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, "
+               "noinit = %d\n", vram, accel, hwcursor, fixed, noinit);
+       DBG_MSG("options: mode = \"%s\"\n", mode ? mode : "");
+
+       if (probeonly)
+               bailout(dinfo);
+
+       /*
+        * Check if the LVDS port or any DVO ports are enabled.  If so,
+        * don't allow mode switching
+        */
+       dvo = intelfbhw_check_non_crt(dinfo);
+       if (dvo) {
+               dinfo->fixed_mode = 1;
+               WRN_MSG("Non-CRT device is enabled ( ");
+               i = 0;
+               while (dvo) {
+                       if (dvo & 1) {
+                               s = intelfbhw_dvo_to_string(1 << i);
+                               if (s)
+                                       printk("%s ", s);
+                       }
+                       dvo >>= 1;
+                       ++i;
+               }
+               printk(").  Disabling mode switching.\n");
+       }
+
+       if (bailearly == 1)
+               bailout(dinfo);
+
+       if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) {
+               ERR_MSG("Video mode must be programmed at boot time.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       if (bailearly == 2)
+               bailout(dinfo);
+
+       /* Initialise dinfo and related data. */
+       /* If an initial mode was programmed at boot time, get its details. */
+       if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB)
+               get_initial_mode(dinfo);
+
+       if (bailearly == 3)
+               bailout(dinfo);
+
+       if (FIXED_MODE(dinfo)) {
+               /* remap fb address */
+               update_dinfo(dinfo, &dinfo->initial_var);
+       }
+
+       if (bailearly == 4)
+               bailout(dinfo);
+
+
+       if (intelfb_set_fbinfo(dinfo)) {
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       if (bailearly == 5)
+               bailout(dinfo);
+
+       for (i = 0; i < 16; i++) {
+               j = color_table[i];
+               dinfo->palette[i].red = default_red[j];
+               dinfo->palette[i].green = default_grn[j];
+               dinfo->palette[i].blue = default_blu[j];
+       }
+
+       if (bailearly == 6)
+               bailout(dinfo);
+
+       pci_set_drvdata(pdev, dinfo);
+
+       /* Save the initial register state. */
+       i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state,
+                                   bailearly > 6 ? bailearly - 6 : 0);
+       if (i != 0) {
+               DBG_MSG("intelfbhw_read_hw_state returned %d\n", i);
+               bailout(dinfo);
+       }
+
+       intelfbhw_print_hw_state(dinfo, &dinfo->save_state);
+
+       if (bailearly == 18)
+               bailout(dinfo);
+
+       /* Cursor initialisation */
+       if (dinfo->hwcursor) {
+               intelfbhw_cursor_init(dinfo);
+               intelfbhw_cursor_reset(dinfo);
+       }
+
+       if (bailearly == 19)
+               bailout(dinfo);
+
+       /* 2d acceleration init */
+       if (dinfo->accel)
+               intelfbhw_2d_start(dinfo);
+
+       if (bailearly == 20)
+               bailout(dinfo);
+
+       if (noregister)
+               bailout(dinfo);
+
+       if (register_framebuffer(dinfo->info) < 0) {
+               ERR_MSG("Cannot register framebuffer.\n");
+               cleanup(dinfo);
+               return -ENODEV;
+       }
+
+       dinfo->registered = 1;
+
+       return 0;
+
+err_out_pixmap:
+       fb_dealloc_cmap(&info->cmap);
+err_out_cmap:
+       framebuffer_release(info);
+       return -ENODEV;
+}
+
+static void __devexit
+intelfb_pci_unregister(struct pci_dev *pdev)
+{
+       struct intelfb_info *dinfo = pci_get_drvdata(pdev);
+
+       DBG_MSG("intelfb_pci_unregister\n");
+
+       if (!dinfo)
+               return;
+
+       cleanup(dinfo);
+
+       pci_set_drvdata(pdev, NULL);
+}
+
+/***************************************************************
+ *                       helper functions                      *
+ ***************************************************************/
+
+int __inline__
+intelfb_var_to_depth(const struct fb_var_screeninfo *var)
+{
+       DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n",
+               var->bits_per_pixel, var->green.length);
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               return (var->green.length == 6) ? 16 : 15;
+       case 32:
+               return 24;
+       default:
+               return var->bits_per_pixel;
+       }
+}
+
+
+static __inline__ int
+var_to_refresh(const struct fb_var_screeninfo *var)
+{
+       int xtot = var->xres + var->left_margin + var->right_margin +
+                  var->hsync_len;
+       int ytot = var->yres + var->upper_margin + var->lower_margin +
+                  var->vsync_len;
+
+       return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
+}
+
+/***************************************************************
+ *                Various intialisation functions              *
+ ***************************************************************/
+
+static void __devinit
+get_initial_mode(struct intelfb_info *dinfo)
+{
+       struct fb_var_screeninfo *var;
+       int xtot, ytot;
+
+       DBG_MSG("get_initial_mode\n");
+
+       dinfo->initial_vga = 1;
+       dinfo->initial_fb_base = screen_info.lfb_base;
+       dinfo->initial_video_ram = screen_info.lfb_size * KB(64);
+       dinfo->initial_pitch = screen_info.lfb_linelength;
+
+       var = &dinfo->initial_var;
+       memset(var, 0, sizeof(*var));
+       var->xres = screen_info.lfb_width;
+       var->yres = screen_info.lfb_height;
+       var->bits_per_pixel = screen_info.lfb_depth;
+       switch (screen_info.lfb_depth) {
+       case 15:
+               var->bits_per_pixel = 16;
+               break;
+       case 24:
+               var->bits_per_pixel = 32;
+               break;
+       }
+
+       DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n",
+               dinfo->initial_fb_base, dinfo->initial_video_ram,
+               BtoKB(dinfo->initial_video_ram));
+
+       DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n",
+               var->xres, var->yres, var->bits_per_pixel,
+               dinfo->initial_pitch);
+
+       /* Dummy timing values (assume 60Hz) */
+       var->left_margin = (var->xres / 8) & 0xf8;
+       var->right_margin = 32;
+       var->upper_margin = 16;
+       var->lower_margin = 4;
+       var->hsync_len = (var->xres / 8) & 0xf8;
+       var->vsync_len = 4;
+
+       xtot = var->xres + var->left_margin +
+               var->right_margin + var->hsync_len;
+       ytot = var->yres + var->upper_margin +
+               var->lower_margin + var->vsync_len;
+       var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60;
+
+       var->height = -1;
+       var->width = -1;
+
+       if (var->bits_per_pixel > 8) {
+               var->red.offset = screen_info.red_pos;
+               var->red.length = screen_info.red_size;
+               var->green.offset = screen_info.green_pos;
+               var->green.length = screen_info.green_size;
+               var->blue.offset = screen_info.blue_pos;
+               var->blue.length = screen_info.blue_size;
+               var->transp.offset = screen_info.rsvd_pos;
+               var->transp.length = screen_info.rsvd_size;
+       } else {
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+       }
+}
+
+static int __devinit
+intelfb_init_var(struct intelfb_info *dinfo)
+{
+       struct fb_var_screeninfo *var;
+       int msrc = 0;
+
+       DBG_MSG("intelfb_init_var\n");
+
+       var = &dinfo->info->var;
+       if (FIXED_MODE(dinfo)) {
+               memcpy(var, &dinfo->initial_var,
+                      sizeof(struct fb_var_screeninfo));
+               msrc = 5;
+       } else {
+               if (mode) {
+                       msrc = fb_find_mode(var, dinfo->info, mode,
+                                           NULL, 0, NULL, 0);
+                       if (msrc)
+                               msrc |= 8;
+               }
+               if (!msrc) {
+                       msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
+                                           NULL, 0, NULL, 0);
+               }
+       }
+
+       if (!msrc) {
+               ERR_MSG("Cannot find a suitable video mode.\n");
+               return 1;
+       }
+
+       INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres,
+               var->bits_per_pixel, var_to_refresh(var));
+
+       DBG_MSG("Initial video mode is from %d.\n", msrc);
+
+#if ALLOCATE_FOR_PANNING
+       /* Allow use of half of the video ram for panning */
+       var->xres_virtual = var->xres;
+       var->yres_virtual =
+               dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres);
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+#else
+       var->yres_virtual = var->yres;
+#endif
+
+       if (dinfo->accel)
+               var->accel_flags |= FB_ACCELF_TEXT;
+       else
+               var->accel_flags &= ~FB_ACCELF_TEXT;
+
+       return 0;
+}
+
+static int __devinit
+intelfb_set_fbinfo(struct intelfb_info *dinfo)
+{
+       struct fb_info *info = dinfo->info;
+
+       DBG_MSG("intelfb_set_fbinfo\n");
+
+       info->flags = FBINFO_FLAG_DEFAULT;
+       info->fbops = &intel_fb_ops;
+       info->pseudo_palette = dinfo->pseudo_palette;
+
+       info->pixmap.size = 64*1024;
+       info->pixmap.buf_align = 8;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+       if (intelfb_init_var(dinfo))
+               return 1;
+
+       info->pixmap.scan_align = 1;
+
+       update_dinfo(dinfo, &info->var);
+
+       return 0;
+}
+
+/* Update dinfo to match the active video mode. */
+static void
+update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
+{
+       DBG_MSG("update_dinfo\n");
+
+       dinfo->bpp = var->bits_per_pixel;
+       dinfo->depth = intelfb_var_to_depth(var);
+       dinfo->xres = var->xres;
+       dinfo->yres = var->xres;
+       dinfo->pixclock = var->pixclock;
+
+       intelfb_get_fix(&dinfo->info->fix, dinfo->info);
+
+       switch (dinfo->bpp) {
+       case 8:
+               dinfo->visual = FB_VISUAL_PSEUDOCOLOR;
+               dinfo->pitch = var->xres_virtual;
+               break;
+       case 16:
+               dinfo->visual = FB_VISUAL_TRUECOLOR;
+               dinfo->pitch = var->xres_virtual * 2;
+               break;
+       case 32:
+               dinfo->visual = FB_VISUAL_TRUECOLOR;
+               dinfo->pitch = var->xres_virtual * 4;
+               break;
+       }
+
+       /* Make sure the line length is a aligned correctly. */
+       dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
+
+       if (FIXED_MODE(dinfo))
+               dinfo->pitch = dinfo->initial_pitch;
+
+       dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual;
+       dinfo->info->fix.line_length = dinfo->pitch;
+       dinfo->info->fix.visual = dinfo->visual;
+}
+
+/* fbops functions */
+
+static int
+intelfb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+
+       DBG_MSG("intelfb_get_fix\n");
+
+       memset(fix, 0, sizeof(*fix));
+       strcpy(fix->id, dinfo->name);
+       fix->smem_start = dinfo->fb.physical;
+       fix->smem_len = dinfo->fb.size;
+       fix->type = FB_TYPE_PACKED_PIXELS;
+       fix->type_aux = 0;
+       fix->visual = dinfo->visual;
+       fix->xpanstep = 8;
+       fix->ypanstep = 1;
+       fix->ywrapstep = 0;
+       fix->line_length = dinfo->pitch;
+       fix->mmio_start = dinfo->mmio_base_phys;
+       fix->mmio_len = INTEL_REG_SIZE;
+       fix->accel = FB_ACCEL_I830;
+       return 0;
+}
+
+/***************************************************************
+ *                       fbdev interface                       *
+ ***************************************************************/
+
+static int
+intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       int change_var = 0;
+       struct fb_var_screeninfo v;
+       struct intelfb_info *dinfo;
+       static int first = 1;
+
+       DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags);
+
+       dinfo = GET_DINFO(info);
+
+       if (intelfbhw_validate_mode(dinfo, var) != 0)
+               return -EINVAL;
+
+       v = *var;
+
+       /* Check for a supported bpp. */
+       if (v.bits_per_pixel <= 8) {
+               v.bits_per_pixel = 8;
+       } else if (v.bits_per_pixel <= 16) {
+               if (v.bits_per_pixel == 16)
+                       v.green.length = 6;
+               v.bits_per_pixel = 16;
+       } else if (v.bits_per_pixel <= 32) {
+               v.bits_per_pixel = 32;
+       } else
+               return -EINVAL;
+
+       change_var = ((info->var.xres != var->xres) ||
+                     (info->var.yres != var->yres) ||
+                     (info->var.xres_virtual != var->xres_virtual) ||
+                     (info->var.yres_virtual != var->yres_virtual) ||
+                     (info->var.bits_per_pixel != var->bits_per_pixel) ||
+                     memcmp(&info->var.red, &var->red, sizeof(var->red)) ||
+                     memcmp(&info->var.green, &var->green,
+                            sizeof(var->green)) ||
+                     memcmp(&info->var.blue, &var->blue, sizeof(var->blue)));
+
+       if (FIXED_MODE(dinfo) &&
+           (change_var ||
+            var->yres_virtual > dinfo->initial_var.yres_virtual ||
+            var->yres_virtual < dinfo->initial_var.yres ||
+            var->xoffset || var->nonstd)) {
+               if (first) {
+                       ERR_MSG("Changing the video mode is not supported.\n");
+                       first = 0;
+               }
+               return -EINVAL;
+       }
+
+       switch (intelfb_var_to_depth(&v)) {
+       case 8:
+               v.red.offset = v.green.offset = v.blue.offset = 0;
+               v.red.length = v.green.length = v.blue.length = 8;
+               v.transp.offset = v.transp.length = 0;
+               break;
+       case 15:
+               v.red.offset = 10;
+               v.green.offset = 5;
+               v.blue.offset = 0;
+               v.red.length = v.green.length = v.blue.length = 5;
+               v.transp.offset = v.transp.length = 0;
+               break;
+       case 16:
+               v.red.offset = 11;
+               v.green.offset = 5;
+               v.blue.offset = 0;
+               v.red.length = 5;
+               v.green.length = 6;
+               v.blue.length = 5;
+               v.transp.offset = v.transp.length = 0;
+               break;
+       case 24:
+               v.red.offset = 16;
+               v.green.offset = 8;
+               v.blue.offset = 0;
+               v.red.length = v.green.length = v.blue.length = 8;
+               v.transp.offset = v.transp.length = 0;
+               break;
+       case 32:
+               v.red.offset = 16;
+               v.green.offset = 8;
+               v.blue.offset = 0;
+               v.red.length = v.green.length = v.blue.length = 8;
+               v.transp.offset = 24;
+               v.transp.length = 8;
+               break;
+       }
+
+       if (v.xoffset < 0)
+               v.xoffset = 0;
+       if (v.yoffset < 0)
+               v.yoffset = 0;
+
+       if (v.xoffset > v.xres_virtual - v.xres)
+               v.xoffset = v.xres_virtual - v.xres;
+       if (v.yoffset > v.yres_virtual - v.yres)
+               v.yoffset = v.yres_virtual - v.yres;
+
+       v.red.msb_right = v.green.msb_right = v.blue.msb_right =
+                         v.transp.msb_right = 0;
+
+        *var = v;
+
+       return 0;
+}
+
+static int
+intelfb_set_par(struct fb_info *info)
+{
+       struct intelfb_hwstate hw;
+
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+       if (FIXED_MODE(dinfo)) {
+               ERR_MSG("Changing the video mode is not supported.\n");
+               return -EINVAL;
+       }
+
+       DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
+               info->var.yres, info->var.bits_per_pixel);
+
+       intelfb_blank(FB_BLANK_POWERDOWN, info);
+
+       if (dinfo->accel)
+               intelfbhw_2d_stop(dinfo);
+
+       hw = dinfo->save_state;
+       if (intelfbhw_mode_to_hw(dinfo, &hw, &info->var))
+               return -EINVAL;
+       if (intelfbhw_program_mode(dinfo, &hw, 0))
+               return -EINVAL;
+
+#if REGDUMP > 0
+       intelfbhw_read_hw_state(dinfo, &hw, 0);
+       intelfbhw_print_hw_state(dinfo, &hw);
+#endif
+
+       update_dinfo(dinfo, &info->var);
+
+       if (dinfo->accel)
+               intelfbhw_2d_start(dinfo);
+
+       intelfb_pan_display(&info->var, info);
+
+       intelfb_blank(FB_BLANK_UNBLANK, info);
+
+       if (ACCEL(dinfo, info)) {
+               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+               FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+               FBINFO_HWACCEL_IMAGEBLIT;
+       } else {
+               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+       }
+       return 0;
+}
+
+static int
+intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                 unsigned blue, unsigned transp, struct fb_info *info)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+       DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth);
+#endif
+
+       if (regno > 255)
+               return 1;
+
+       switch (dinfo->depth) {
+       case 8:
+               {
+                       red >>= 8;
+                       green >>= 8;
+                       blue >>= 8;
+
+                       dinfo->palette[regno].red = red;
+                       dinfo->palette[regno].green = green;
+                       dinfo->palette[regno].blue = blue;
+
+                       intelfbhw_setcolreg(dinfo, regno, red, green, blue,
+                                           transp);
+               }
+               break;
+       case 15:
+               dinfo->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
+                                              ((green & 0xf800) >>  6) |
+                                              ((blue & 0xf800) >> 11);
+               break;
+       case 16:
+               dinfo->pseudo_palette[regno] = (red & 0xf800) |
+                                              ((green & 0xfc00) >>  5) |
+                                              ((blue  & 0xf800) >> 11);
+               break;
+       case 24:
+               dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                                              (green & 0xff00) |
+                                              ((blue  & 0xff00) >> 8);
+               break;
+       }
+       return 0;
+}
+
+static int
+intelfb_blank(int blank, struct fb_info *info)
+{
+       intelfbhw_do_blank(blank, info);
+       return 0;
+}
+
+static int
+intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       intelfbhw_pan_display(var, info);
+       return 0;
+}
+
+/* When/if we have our own ioctls. */
+static int
+intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+             unsigned long arg, struct fb_info *info)
+{
+       int retval = 0;
+
+       return retval;
+}
+
+static void
+intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+       u32 rop, color;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfb_fillrect\n");
+#endif
+
+       if (!ACCEL(dinfo, info) || dinfo->depth == 4)
+               return cfb_fillrect(info, rect);
+
+       if (rect->rop == ROP_COPY)
+               rop = PAT_ROP_GXCOPY;
+       else // ROP_XOR
+               rop = PAT_ROP_GXXOR;
+
+       if (dinfo->depth != 8)
+               color = dinfo->pseudo_palette[rect->color];
+       else
+               color = rect->color;
+
+       intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy,
+                             rect->width, rect->height, color,
+                             dinfo->pitch, info->var.bits_per_pixel,
+                             rop);
+}
+
+static void
+intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+       DBG_MSG("intelfb_copyarea\n");
+#endif
+
+       if (!ACCEL(dinfo, info) || dinfo->depth == 4)
+               return cfb_copyarea(info, region);
+
+       intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx,
+                           region->dy, region->width, region->height,
+                           dinfo->pitch, info->var.bits_per_pixel);
+}
+
+static void
+intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+       u32 fgcolor, bgcolor;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfb_imageblit\n");
+#endif
+
+       if (!ACCEL(dinfo, info) || dinfo->depth == 4
+           || image->depth != 1)
+               return cfb_imageblit(info, image);
+
+       if (dinfo->depth != 8) {
+               fgcolor = dinfo->pseudo_palette[image->fg_color];
+               bgcolor = dinfo->pseudo_palette[image->bg_color];
+       } else {
+               fgcolor = image->fg_color;
+               bgcolor = image->bg_color;
+       }
+
+       if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width,
+                                   image->height, image->data,
+                                   image->dx, image->dy,
+                                   dinfo->pitch, info->var.bits_per_pixel))
+               return cfb_imageblit(info, image);
+}
+
+static int
+intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+       DBG_MSG("intelfb_cursor\n");
+#endif
+
+       if (!dinfo->hwcursor)
+               return soft_cursor(info, cursor);
+
+       intelfbhw_cursor_hide(dinfo);
+
+       /* If XFree killed the cursor - restore it */
+       if (INREG(CURSOR_A_BASEADDR) != dinfo->cursor.offset << 12) {
+               u32 fg, bg;
+
+               DBG_MSG("the cursor was killed - restore it !!\n");
+               DBG_MSG("size %d, %d   pos %d, %d\n",
+                       cursor->image.width, cursor->image.height,
+                       cursor->image.dx, cursor->image.dy);
+
+               intelfbhw_cursor_init(dinfo);
+               intelfbhw_cursor_reset(dinfo);
+               intelfbhw_cursor_setpos(dinfo, cursor->image.dx,
+                                       cursor->image.dy);
+
+               if (dinfo->depth != 8) {
+                       fg =dinfo->pseudo_palette[cursor->image.fg_color];
+                       bg =dinfo->pseudo_palette[cursor->image.bg_color];
+               } else {
+                       fg = cursor->image.fg_color;
+                       bg = cursor->image.bg_color;
+               }
+               intelfbhw_cursor_setcolor(dinfo, bg, fg);
+               intelfbhw_cursor_load(dinfo, cursor->image.width,
+                                     cursor->image.height,
+                                     dinfo->cursor_src);
+
+               if (cursor->enable)
+                       intelfbhw_cursor_show(dinfo);
+               return 0;
+       }
+
+       if (cursor->set & FB_CUR_SETPOS) {
+               u32 dx, dy;
+
+               dx = cursor->image.dx - info->var.xoffset;
+               dy = cursor->image.dy - info->var.yoffset;
+
+               intelfbhw_cursor_setpos(dinfo, dx, dy);
+       }
+
+       if (cursor->set & FB_CUR_SETSIZE) {
+               if (cursor->image.width > 64 || cursor->image.height > 64)
+                       return -ENXIO;
+
+               intelfbhw_cursor_reset(dinfo);
+       }
+
+       if (cursor->set & FB_CUR_SETCMAP) {
+               u32 fg, bg;
+
+               if (dinfo->depth != 8) {
+                       fg = dinfo->pseudo_palette[cursor->image.fg_color];
+                       bg = dinfo->pseudo_palette[cursor->image.bg_color];
+               } else {
+                       fg = cursor->image.fg_color;
+                       bg = cursor->image.bg_color;
+               }
+
+               intelfbhw_cursor_setcolor(dinfo, bg, fg);
+       }
+
+       if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+               u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8);
+               u32 size = s_pitch * cursor->image.height;
+               u8 *dat = (u8 *) cursor->image.data;
+               u8 *msk = (u8 *) cursor->mask;
+               u8 src[64];
+               u32 i;
+
+               if (cursor->image.depth != 1)
+                       return -ENXIO;
+
+               switch (cursor->rop) {
+               case ROP_XOR:
+                       for (i = 0; i < size; i++)
+                               src[i] = dat[i] ^ msk[i];
+                       break;
+               case ROP_COPY:
+               default:
+                       for (i = 0; i < size; i++)
+                               src[i] = dat[i] & msk[i];
+                       break;
+               }
+
+               /* save the bitmap to restore it when XFree will
+                  make the cursor dirty */
+               memcpy(dinfo->cursor_src, src, size);
+
+               intelfbhw_cursor_load(dinfo, cursor->image.width,
+                                     cursor->image.height, src);
+       }
+
+       if (cursor->enable)
+               intelfbhw_cursor_show(dinfo);
+
+       return 0;
+}
+
+static int
+intelfb_sync(struct fb_info *info)
+{
+        struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if VERBOSE > 0
+       DBG_MSG("intelfb_sync\n");
+#endif
+
+       if (dinfo->ring_lockup)
+               return 0;
+
+       intelfbhw_do_sync(dinfo);
+       return 0;
+}
+
diff --git a/drivers/video/intelfb/intelfbdrv.h b/drivers/video/intelfb/intelfbdrv.h
new file mode 100644 (file)
index 0000000..f05dffa
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef _INTELFBDRV_H
+#define _INTELFBDRV_H
+
+/*
+ ******************************************************************************
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G
+ * integrated graphics chips.
+ *
+ * Copyright Â© 2004 Sylvain Meyer
+ *
+ * Author: Sylvain Meyer
+ *
+ ******************************************************************************
+ *    This 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.
+*/
+
+int __init intelfb_setup(char *options);
+static void __devinit get_initial_mode(struct intelfb_info *dinfo);
+static void update_dinfo(struct intelfb_info *dinfo,
+                        struct fb_var_screeninfo *var);
+static int intelfb_get_fix(struct fb_fix_screeninfo *fix,
+                          struct fb_info *info);
+
+static int intelfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info);
+static int intelfb_set_par(struct fb_info *info);
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                            unsigned blue, unsigned transp,
+                            struct fb_info *info);
+
+static int intelfb_blank(int blank, struct fb_info *info);
+static int intelfb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *info);
+
+static void intelfb_fillrect(struct fb_info *info,
+                            const struct fb_fillrect *rect);
+static void intelfb_copyarea(struct fb_info *info,
+                            const struct fb_copyarea *region);
+static void intelfb_imageblit(struct fb_info *info,
+                             const struct fb_image *image);
+static int intelfb_cursor(struct fb_info *info,
+                          struct fb_cursor *cursor);
+
+static int intelfb_sync(struct fb_info *info);
+
+static int intelfb_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg,
+                        struct fb_info *info);
+
+static int __devinit intelfb_pci_register(struct pci_dev *pdev,
+                                         const struct pci_device_id *ent);
+static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);
+static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
+
+#endif
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
new file mode 100644 (file)
index 0000000..5ce1c82
--- /dev/null
@@ -0,0 +1,1753 @@
+/*
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 865G integrated graphics chips.
+ *
+ * Copyright Â© 2002, 2003 David Dawes <dawes@xfree86.org>
+ *                   2004 Sylvain Meyer
+ *
+ * This driver consists of two parts.  The first part (intelfbdrv.c) provides
+ * the basic fbdev interfaces, is derived in part from the radeonfb and
+ * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
+ * provides the code to program the hardware.  Most of it is derived from
+ * the i810/i830 XFree86 driver.  The HW-specific code is covered here
+ * under a dual license (GPL and MIT/XFree86 license).
+ *
+ * Author: David Dawes
+ *
+ */
+
+/* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+
+#include "intelfb.h"
+#include "intelfbhw.h"
+
+int
+intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
+                     int *mobile)
+{
+       u32 tmp;
+
+       if (!pdev || !name || !chipset || !mobile)
+               return 1;
+
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_830M:
+               *name = "Intel(R) 830M";
+               *chipset = INTEL_830M;
+               *mobile = 1;
+               return 0;
+       case PCI_DEVICE_ID_INTEL_845G:
+               *name = "Intel(R) 845G";
+               *chipset = INTEL_845G;
+               *mobile = 0;
+               return 0;
+       case PCI_DEVICE_ID_INTEL_85XGM:
+               tmp = 0;
+               *mobile = 1;
+               pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
+               switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
+                       INTEL_85X_VARIANT_MASK) {
+               case INTEL_VAR_855GME:
+                       *name = "Intel(R) 855GME";
+                       *chipset = INTEL_855GME;
+                       return 0;
+               case INTEL_VAR_855GM:
+                       *name = "Intel(R) 855GM";
+                       *chipset = INTEL_855GM;
+                       return 0;
+               case INTEL_VAR_852GME:
+                       *name = "Intel(R) 852GME";
+                       *chipset = INTEL_852GME;
+                       return 0;
+               case INTEL_VAR_852GM:
+                       *name = "Intel(R) 852GM";
+                       *chipset = INTEL_852GM;
+                       return 0;
+               default:
+                       *name = "Intel(R) 852GM/855GM";
+                       *chipset = INTEL_85XGM;
+                       return 0;
+               }
+               break;
+       case PCI_DEVICE_ID_INTEL_865G:
+               *name = "Intel(R) 865G";
+               *chipset = INTEL_865G;
+               *mobile = 0;
+               return 0;
+       default:
+               return 1;
+       }
+}
+
+int
+intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+                    int *stolen_size)
+{
+       struct pci_dev *bridge_dev;
+       u16 tmp;
+
+       if (!pdev || !aperture_size || !stolen_size)
+               return 1;
+
+       /* Find the bridge device.  It is always 0:0.0 */
+       if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) {
+               ERR_MSG("cannot find bridge device\n");
+               return 1;
+       }
+
+       /* Get the fb aperture size and "stolen" memory amount. */
+       tmp = 0;
+       pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_830M:
+       case PCI_DEVICE_ID_INTEL_845G:
+               if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
+                       *aperture_size = MB(64);
+               else
+                       *aperture_size = MB(128);
+               switch (tmp & INTEL_830_GMCH_GMS_MASK) {
+               case INTEL_830_GMCH_GMS_STOLEN_512:
+                       *stolen_size = KB(512) - KB(132);
+                       return 0;
+               case INTEL_830_GMCH_GMS_STOLEN_1024:
+                       *stolen_size = MB(1) - KB(132);
+                       return 0;
+               case INTEL_830_GMCH_GMS_STOLEN_8192:
+                       *stolen_size = MB(8) - KB(132);
+                       return 0;
+               case INTEL_830_GMCH_GMS_LOCAL:
+                       ERR_MSG("only local memory found\n");
+                       return 1;
+               case INTEL_830_GMCH_GMS_DISABLED:
+                       ERR_MSG("video memory is disabled\n");
+                       return 1;
+               default:
+                       ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
+                               tmp & INTEL_830_GMCH_GMS_MASK);
+                       return 1;
+               }
+               break;
+       default:
+               *aperture_size = MB(128);
+               switch (tmp & INTEL_855_GMCH_GMS_MASK) {
+               case INTEL_855_GMCH_GMS_STOLEN_1M:
+                       *stolen_size = MB(1) - KB(132);
+                       return 0;
+               case INTEL_855_GMCH_GMS_STOLEN_4M:
+                       *stolen_size = MB(4) - KB(132);
+                       return 0;
+               case INTEL_855_GMCH_GMS_STOLEN_8M:
+                       *stolen_size = MB(8) - KB(132);
+                       return 0;
+               case INTEL_855_GMCH_GMS_STOLEN_16M:
+                       *stolen_size = MB(16) - KB(132);
+                       return 0;
+               case INTEL_855_GMCH_GMS_STOLEN_32M:
+                       *stolen_size = MB(32) - KB(132);
+                       return 0;
+               case INTEL_855_GMCH_GMS_DISABLED:
+                       ERR_MSG("video memory is disabled\n");
+                       return 0;
+               default:
+                       ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
+                               tmp & INTEL_855_GMCH_GMS_MASK);
+                       return 1;
+               }
+       }
+}
+
+int
+intelfbhw_check_non_crt(struct intelfb_info *dinfo)
+{
+       int dvo = 0;
+
+       if (INREG(LVDS) & PORT_ENABLE)
+               dvo |= LVDS_PORT;
+       if (INREG(DVOA) & PORT_ENABLE)
+               dvo |= DVOA_PORT;
+       if (INREG(DVOB) & PORT_ENABLE)
+               dvo |= DVOB_PORT;
+       if (INREG(DVOC) & PORT_ENABLE)
+               dvo |= DVOC_PORT;
+
+       return dvo;
+}
+
+const char *
+intelfbhw_dvo_to_string(int dvo)
+{
+       if (dvo & DVOA_PORT)
+               return "DVO port A";
+       else if (dvo & DVOB_PORT)
+               return "DVO port B";
+       else if (dvo & DVOC_PORT)
+               return "DVO port C";
+       else if (dvo & LVDS_PORT)
+               return "LVDS port";
+       else
+               return NULL;
+}
+
+
+int
+intelfbhw_validate_mode(struct intelfb_info *dinfo,
+                       struct fb_var_screeninfo *var)
+{
+       int bytes_per_pixel;
+       int tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_validate_mode\n");
+#endif
+
+       bytes_per_pixel = var->bits_per_pixel / 8;
+       if (bytes_per_pixel == 3)
+               bytes_per_pixel = 4;
+
+       /* Check if enough video memory. */
+       tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel;
+       if (tmp > dinfo->fb.size) {
+               WRN_MSG("Not enough video ram for mode "
+                       "(%d KByte vs %d KByte).\n",
+                       BtoKB(tmp), BtoKB(dinfo->fb.size));
+               return 1;
+       }
+
+       /* Check if x/y limits are OK. */
+       if (var->xres - 1 > HACTIVE_MASK) {
+               WRN_MSG("X resolution too large (%d vs %d).\n",
+                       var->xres, HACTIVE_MASK + 1);
+               return 1;
+       }
+       if (var->yres - 1 > VACTIVE_MASK) {
+               WRN_MSG("Y resolution too large (%d vs %d).\n",
+                       var->yres, VACTIVE_MASK + 1);
+               return 1;
+       }
+
+       /* Check for interlaced/doublescan modes. */
+       if (var->vmode & FB_VMODE_INTERLACED) {
+               WRN_MSG("Mode is interlaced.\n");
+               return 1;
+       }
+       if (var->vmode & FB_VMODE_DOUBLE) {
+               WRN_MSG("Mode is double-scan.\n");
+               return 1;
+       }
+
+       /* Check if clock is OK. */
+       tmp = 1000000000 / var->pixclock;
+       if (tmp < MIN_CLOCK) {
+               WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n",
+                       (tmp + 500) / 1000, MIN_CLOCK / 1000);
+               return 1;
+       }
+       if (tmp > MAX_CLOCK) {
+               WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n",
+                       (tmp + 500) / 1000, MAX_CLOCK / 1000);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+       u32 offset, xoffset, yoffset;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_pan_display\n");
+#endif
+
+       xoffset = ROUND_DOWN_TO(var->xoffset, 8);
+       yoffset = var->yoffset;
+
+       if ((xoffset + var->xres > var->xres_virtual) ||
+           (yoffset + var->yres > var->yres_virtual))
+               return -EINVAL;
+
+       offset = (yoffset * dinfo->pitch) +
+                (xoffset * var->bits_per_pixel) / 8;
+
+       offset += dinfo->fb.offset << 12;
+
+       OUTREG(DSPABASE, offset);
+
+       return 0;
+}
+
+/* Blank the screen. */
+void
+intelfbhw_do_blank(int blank, struct fb_info *info)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+       u32 tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank);
+#endif
+
+       /* Turn plane A on or off */
+       tmp = INREG(DSPACNTR);
+       if (blank)
+               tmp &= ~DISPPLANE_PLANE_ENABLE;
+       else
+               tmp |= DISPPLANE_PLANE_ENABLE;
+       OUTREG(DSPACNTR, tmp);
+       /* Flush */
+       tmp = INREG(DSPABASE);
+       OUTREG(DSPABASE, tmp);
+
+       /* Turn off/on the HW cursor */
+#if VERBOSE > 0
+       DBG_MSG("cursor_on is %d\n", dinfo->cursor_on);
+#endif
+       if (dinfo->cursor_on) {
+               if (blank) {
+                       intelfbhw_cursor_hide(dinfo);
+               } else {
+                       intelfbhw_cursor_show(dinfo);
+               }
+               dinfo->cursor_on = 1;
+       }
+       dinfo->cursor_blanked = blank;
+
+       /* Set DPMS level */
+       tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK;
+       switch (blank) {
+       case FB_BLANK_UNBLANK:
+       case FB_BLANK_NORMAL:
+               tmp |= ADPA_DPMS_D0;
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               tmp |= ADPA_DPMS_D1;
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               tmp |= ADPA_DPMS_D2;
+               break;
+       case FB_BLANK_POWERDOWN:
+               tmp |= ADPA_DPMS_D3;
+               break;
+       }
+       OUTREG(ADPA, tmp);
+
+       return;
+}
+
+
+void
+intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+                   unsigned red, unsigned green, unsigned blue,
+                   unsigned transp)
+{
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
+               regno, red, green, blue);
+#endif
+
+       u32 palette_reg = (dinfo->pipe == PIPE_A) ?
+                         PALETTE_A : PALETTE_B;
+
+       OUTREG(palette_reg + (regno << 2),
+              (red << PALETTE_8_RED_SHIFT) |
+              (green << PALETTE_8_GREEN_SHIFT) |
+              (blue << PALETTE_8_BLUE_SHIFT));
+}
+
+
+int
+intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
+                       int flag)
+{
+       int i;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_read_hw_state\n");
+#endif
+
+       if (!hw || !dinfo)
+               return -1;
+
+       /* Read in as much of the HW state as possible. */
+       hw->vga0_divisor = INREG(VGA0_DIVISOR);
+       hw->vga1_divisor = INREG(VGA1_DIVISOR);
+       hw->vga_pd = INREG(VGAPD);
+       hw->dpll_a = INREG(DPLL_A);
+       hw->dpll_b = INREG(DPLL_B);
+       hw->fpa0 = INREG(FPA0);
+       hw->fpa1 = INREG(FPA1);
+       hw->fpb0 = INREG(FPB0);
+       hw->fpb1 = INREG(FPB1);
+
+       if (flag == 1)
+               return flag;
+
+#if 0
+       /* This seems to be a problem with the 852GM/855GM */
+       for (i = 0; i < PALETTE_8_ENTRIES; i++) {
+               hw->palette_a[i] = INREG(PALETTE_A + (i << 2));
+               hw->palette_b[i] = INREG(PALETTE_B + (i << 2));
+       }
+#endif
+
+       if (flag == 2)
+               return flag;
+
+       hw->htotal_a = INREG(HTOTAL_A);
+       hw->hblank_a = INREG(HBLANK_A);
+       hw->hsync_a = INREG(HSYNC_A);
+       hw->vtotal_a = INREG(VTOTAL_A);
+       hw->vblank_a = INREG(VBLANK_A);
+       hw->vsync_a = INREG(VSYNC_A);
+       hw->src_size_a = INREG(SRC_SIZE_A);
+       hw->bclrpat_a = INREG(BCLRPAT_A);
+       hw->htotal_b = INREG(HTOTAL_B);
+       hw->hblank_b = INREG(HBLANK_B);
+       hw->hsync_b = INREG(HSYNC_B);
+       hw->vtotal_b = INREG(VTOTAL_B);
+       hw->vblank_b = INREG(VBLANK_B);
+       hw->vsync_b = INREG(VSYNC_B);
+       hw->src_size_b = INREG(SRC_SIZE_B);
+       hw->bclrpat_b = INREG(BCLRPAT_B);
+
+       if (flag == 3)
+               return flag;
+
+       hw->adpa = INREG(ADPA);
+       hw->dvoa = INREG(DVOA);
+       hw->dvob = INREG(DVOB);
+       hw->dvoc = INREG(DVOC);
+       hw->dvoa_srcdim = INREG(DVOA_SRCDIM);
+       hw->dvob_srcdim = INREG(DVOB_SRCDIM);
+       hw->dvoc_srcdim = INREG(DVOC_SRCDIM);
+       hw->lvds = INREG(LVDS);
+
+       if (flag == 4)
+               return flag;
+
+       hw->pipe_a_conf = INREG(PIPEACONF);
+       hw->pipe_b_conf = INREG(PIPEBCONF);
+       hw->disp_arb = INREG(DISPARB);
+
+       if (flag == 5)
+               return flag;
+
+       hw->cursor_a_control = INREG(CURSOR_A_CONTROL);
+       hw->cursor_b_control = INREG(CURSOR_B_CONTROL);
+       hw->cursor_a_base = INREG(CURSOR_A_BASEADDR);
+       hw->cursor_b_base = INREG(CURSOR_B_BASEADDR);
+
+       if (flag == 6)
+               return flag;
+
+       for (i = 0; i < 4; i++) {
+               hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2));
+               hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2));
+       }
+
+       if (flag == 7)
+               return flag;
+
+       hw->cursor_size = INREG(CURSOR_SIZE);
+
+       if (flag == 8)
+               return flag;
+
+       hw->disp_a_ctrl = INREG(DSPACNTR);
+       hw->disp_b_ctrl = INREG(DSPBCNTR);
+       hw->disp_a_base = INREG(DSPABASE);
+       hw->disp_b_base = INREG(DSPBBASE);
+       hw->disp_a_stride = INREG(DSPASTRIDE);
+       hw->disp_b_stride = INREG(DSPBSTRIDE);
+
+       if (flag == 9)
+               return flag;
+
+       hw->vgacntrl = INREG(VGACNTRL);
+
+       if (flag == 10)
+               return flag;
+
+       hw->add_id = INREG(ADD_ID);
+
+       if (flag == 11)
+               return flag;
+
+       for (i = 0; i < 7; i++) {
+               hw->swf0x[i] = INREG(SWF00 + (i << 2));
+               hw->swf1x[i] = INREG(SWF10 + (i << 2));
+               if (i < 3)
+                       hw->swf3x[i] = INREG(SWF30 + (i << 2));
+       }
+
+       for (i = 0; i < 8; i++)
+               hw->fence[i] = INREG(FENCE + (i << 2));
+
+       hw->instpm = INREG(INSTPM);
+       hw->mem_mode = INREG(MEM_MODE);
+       hw->fw_blc_0 = INREG(FW_BLC_0);
+       hw->fw_blc_1 = INREG(FW_BLC_1);
+
+       return 0;
+}
+
+
+void
+intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
+{
+#if REGDUMP
+       int i, m1, m2, n, p1, p2;
+
+       DBG_MSG("intelfbhw_print_hw_state\n");
+
+       if (!hw || !dinfo)
+               return;
+       /* Read in as much of the HW state as possible. */
+       printk("hw state dump start\n");
+       printk("        VGA0_DIVISOR:           0x%08x\n", hw->vga0_divisor);
+       printk("        VGA1_DIVISOR:           0x%08x\n", hw->vga1_divisor);
+       printk("        VGAPD:                  0x%08x\n", hw->vga_pd);
+       n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
+               p1 = 0;
+       else
+               p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
+       p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
+       printk("        VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+               m1, m2, n, p1, p2);
+       printk("        VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+       n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
+               p1 = 0;
+       else
+               p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
+       p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
+       printk("        VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+               m1, m2, n, p1, p2);
+       printk("        VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+       printk("        DPLL_A:                 0x%08x\n", hw->dpll_a);
+       printk("        DPLL_B:                 0x%08x\n", hw->dpll_b);
+       printk("        FPA0:                   0x%08x\n", hw->fpa0);
+       printk("        FPA1:                   0x%08x\n", hw->fpa1);
+       printk("        FPB0:                   0x%08x\n", hw->fpb0);
+       printk("        FPB1:                   0x%08x\n", hw->fpb1);
+
+       n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+               p1 = 0;
+       else
+               p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+       p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+       printk("        PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+               m1, m2, n, p1, p2);
+       printk("        PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+       n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+       if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+               p1 = 0;
+       else
+               p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+       p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+       printk("        PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+               m1, m2, n, p1, p2);
+       printk("        PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+#if 0
+       printk("        PALETTE_A:\n");
+       for (i = 0; i < PALETTE_8_ENTRIES)
+               printk("        %3d:    0x%08x\n", i, hw->palette_a[i];
+       printk("        PALETTE_B:\n");
+       for (i = 0; i < PALETTE_8_ENTRIES)
+               printk("        %3d:    0x%08x\n", i, hw->palette_b[i];
+#endif
+
+       printk("        HTOTAL_A:               0x%08x\n", hw->htotal_a);
+       printk("        HBLANK_A:               0x%08x\n", hw->hblank_a);
+       printk("        HSYNC_A:                0x%08x\n", hw->hsync_a);
+       printk("        VTOTAL_A:               0x%08x\n", hw->vtotal_a);
+       printk("        VBLANK_A:               0x%08x\n", hw->vblank_a);
+       printk("        VSYNC_A:                0x%08x\n", hw->vsync_a);
+       printk("        SRC_SIZE_A:             0x%08x\n", hw->src_size_a);
+       printk("        BCLRPAT_A:              0x%08x\n", hw->bclrpat_a);
+       printk("        HTOTAL_B:               0x%08x\n", hw->htotal_b);
+       printk("        HBLANK_B:               0x%08x\n", hw->hblank_b);
+       printk("        HSYNC_B:                0x%08x\n", hw->hsync_b);
+       printk("        VTOTAL_B:               0x%08x\n", hw->vtotal_b);
+       printk("        VBLANK_B:               0x%08x\n", hw->vblank_b);
+       printk("        VSYNC_B:                0x%08x\n", hw->vsync_b);
+       printk("        SRC_SIZE_B:             0x%08x\n", hw->src_size_b);
+       printk("        BCLRPAT_B:              0x%08x\n", hw->bclrpat_b);
+
+       printk("        ADPA:                   0x%08x\n", hw->adpa);
+       printk("        DVOA:                   0x%08x\n", hw->dvoa);
+       printk("        DVOB:                   0x%08x\n", hw->dvob);
+       printk("        DVOC:                   0x%08x\n", hw->dvoc);
+       printk("        DVOA_SRCDIM:            0x%08x\n", hw->dvoa_srcdim);
+       printk("        DVOB_SRCDIM:            0x%08x\n", hw->dvob_srcdim);
+       printk("        DVOC_SRCDIM:            0x%08x\n", hw->dvoc_srcdim);
+       printk("        LVDS:                   0x%08x\n", hw->lvds);
+
+       printk("        PIPEACONF:              0x%08x\n", hw->pipe_a_conf);
+       printk("        PIPEBCONF:              0x%08x\n", hw->pipe_b_conf);
+       printk("        DISPARB:                0x%08x\n", hw->disp_arb);
+
+       printk("        CURSOR_A_CONTROL:       0x%08x\n", hw->cursor_a_control);
+       printk("        CURSOR_B_CONTROL:       0x%08x\n", hw->cursor_b_control);
+       printk("        CURSOR_A_BASEADDR:      0x%08x\n", hw->cursor_a_base);
+       printk("        CURSOR_B_BASEADDR:      0x%08x\n", hw->cursor_b_base);
+
+       printk("        CURSOR_A_PALETTE:       ");
+       for (i = 0; i < 4; i++) {
+               printk("0x%08x", hw->cursor_a_palette[i]);
+               if (i < 3)
+                       printk(", ");
+       }
+       printk("\n");
+       printk("        CURSOR_B_PALETTE:       ");
+       for (i = 0; i < 4; i++) {
+               printk("0x%08x", hw->cursor_b_palette[i]);
+               if (i < 3)
+                       printk(", ");
+       }
+       printk("\n");
+
+       printk("        CURSOR_SIZE:            0x%08x\n", hw->cursor_size);
+
+       printk("        DSPACNTR:               0x%08x\n", hw->disp_a_ctrl);
+       printk("        DSPBCNTR:               0x%08x\n", hw->disp_b_ctrl);
+       printk("        DSPABASE:               0x%08x\n", hw->disp_a_base);
+       printk("        DSPBBASE:               0x%08x\n", hw->disp_b_base);
+       printk("        DSPASTRIDE:             0x%08x\n", hw->disp_a_stride);
+       printk("        DSPBSTRIDE:             0x%08x\n", hw->disp_b_stride);
+
+       printk("        VGACNTRL:               0x%08x\n", hw->vgacntrl);
+       printk("        ADD_ID:                 0x%08x\n", hw->add_id);
+
+       for (i = 0; i < 7; i++) {
+               printk("        SWF0%d                  0x%08x\n", i,
+                       hw->swf0x[i]);
+       }
+       for (i = 0; i < 7; i++) {
+               printk("        SWF1%d                  0x%08x\n", i,
+                       hw->swf1x[i]);
+       }
+       for (i = 0; i < 3; i++) {
+               printk("        SWF3%d                  0x%08x\n", i,
+                       hw->swf3x[i]);
+       }
+       for (i = 0; i < 8; i++)
+               printk("        FENCE%d                 0x%08x\n", i,
+                       hw->fence[i]);
+
+       printk("        INSTPM                  0x%08x\n", hw->instpm);
+       printk("        MEM_MODE                0x%08x\n", hw->mem_mode);
+       printk("        FW_BLC_0                0x%08x\n", hw->fw_blc_0);
+       printk("        FW_BLC_1                0x%08x\n", hw->fw_blc_1);
+
+       printk("hw state dump end\n");
+#endif
+}
+
+/* Split the M parameter into M1 and M2. */
+static int
+splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
+{
+       int m1, m2;
+
+       m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
+       if (m1 < MIN_M1)
+               m1 = MIN_M1;
+       if (m1 > MAX_M1)
+               m1 = MAX_M1;
+       m2 = m - 5 * (m1 + 2) - 2;
+       if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
+               return 1;
+       } else {
+               *retm1 = (unsigned int)m1;
+               *retm2 = (unsigned int)m2;
+               return 0;
+       }
+}
+
+/* Split the P parameter into P1 and P2. */
+static int
+splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
+{
+       int p1, p2;
+
+       if (p % 4 == 0)
+               p2 = 1;
+       else
+               p2 = 0;
+       p1 = (p / (1 << (p2 + 1))) - 2;
+       if (p % 4 == 0 && p1 < MIN_P1) {
+               p2 = 0;
+               p1 = (p / (1 << (p2 + 1))) - 2;
+       }
+       if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
+               return 1;
+       } else {
+               *retp1 = (unsigned int)p1;
+               *retp2 = (unsigned int)p2;
+               return 0;
+       }
+}
+
+static int
+calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
+               u32 *retp2, u32 *retclock)
+{
+       u32 m1, m2, n, p1, p2, n1;
+       u32 f_vco, p, p_best = 0, m, f_out;
+       u32 err_max, err_target, err_best = 10000000;
+       u32 n_best = 0, m_best = 0, f_best, f_err;
+       u32 p_min, p_max, p_inc, div_min, div_max;
+
+       /* Accept 0.5% difference, but aim for 0.1% */
+       err_max = 5 * clock / 1000;
+       err_target = clock / 1000;
+
+       DBG_MSG("Clock is %d\n", clock);
+
+       div_max = MAX_VCO_FREQ / clock;
+       div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
+
+       if (clock <= P_TRANSITION_CLOCK)
+               p_inc = 4;
+       else
+               p_inc = 2;
+       p_min = ROUND_UP_TO(div_min, p_inc);
+       p_max = ROUND_DOWN_TO(div_max, p_inc);
+       if (p_min < MIN_P)
+               p_min = 4;
+       if (p_max > MAX_P)
+               p_max = 128;
+
+       DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
+
+       p = p_min;
+       do {
+               if (splitp(p, &p1, &p2)) {
+                       WRN_MSG("cannot split p = %d\n", p);
+                       p += p_inc;
+                       continue;
+               }
+               n = MIN_N;
+               f_vco = clock * p;
+
+               do {
+                       m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
+                       if (m < MIN_M)
+                               m = MIN_M;
+                       if (m > MAX_M)
+                               m = MAX_M;
+                       f_out = CALC_VCLOCK3(m, n, p);
+                       if (splitm(m, &m1, &m2)) {
+                               WRN_MSG("cannot split m = %d\n", m);
+                               n++;
+                               continue;
+                       }
+                       if (clock > f_out)
+                               f_err = clock - f_out;
+                       else
+                               f_err = f_out - clock;
+
+                       if (f_err < err_best) {
+                               m_best = m;
+                               n_best = n;
+                               p_best = p;
+                               f_best = f_out;
+                               err_best = f_err;
+                       }
+                       n++;
+               } while ((n <= MAX_N) && (f_out >= clock));
+               p += p_inc;
+       } while ((p <= p_max));
+
+       if (!m_best) {
+               WRN_MSG("cannot find parameters for clock %d\n", clock);
+               return 1;
+       }
+       m = m_best;
+       n = n_best;
+       p = p_best;
+       splitm(m, &m1, &m2);
+       splitp(p, &p1, &p2);
+       n1 = n - 2;
+
+       DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
+               "f: %d (%d), VCO: %d\n",
+               m, m1, m2, n, n1, p, p1, p2,
+               CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
+               CALC_VCLOCK3(m, n, p) * p);
+       *retm1 = m1;
+       *retm2 = m2;
+       *retn = n1;
+       *retp1 = p1;
+       *retp2 = p2;
+       *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+
+       return 0;
+}
+
+static __inline__ int
+check_overflow(u32 value, u32 limit, const char *description)
+{
+       if (value > limit) {
+               WRN_MSG("%s value %d exceeds limit %d\n",
+                       description, value, limit);
+               return 1;
+       }
+       return 0;
+}
+
+/* It is assumed that hw is filled in with the initial state information. */
+int
+intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
+                    struct fb_var_screeninfo *var)
+{
+       int pipe = PIPE_A;
+       u32 *dpll, *fp0, *fp1;
+       u32 m1, m2, n, p1, p2, clock_target, clock;
+       u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive;
+       u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
+       u32 vsync_pol, hsync_pol;
+       u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
+
+       DBG_MSG("intelfbhw_mode_to_hw\n");
+
+       /* Disable VGA */
+       hw->vgacntrl |= VGA_DISABLE;
+
+       /* Check whether pipe A or pipe B is enabled. */
+       if (hw->pipe_a_conf & PIPECONF_ENABLE)
+               pipe = PIPE_A;
+       else if (hw->pipe_b_conf & PIPECONF_ENABLE)
+               pipe = PIPE_B;
+
+       /* Set which pipe's registers will be set. */
+       if (pipe == PIPE_B) {
+               dpll = &hw->dpll_b;
+               fp0 = &hw->fpb0;
+               fp1 = &hw->fpb1;
+               hs = &hw->hsync_b;
+               hb = &hw->hblank_b;
+               ht = &hw->htotal_b;
+               vs = &hw->vsync_b;
+               vb = &hw->vblank_b;
+               vt = &hw->vtotal_b;
+               ss = &hw->src_size_b;
+               pipe_conf = &hw->pipe_b_conf;
+       } else {
+               dpll = &hw->dpll_a;
+               fp0 = &hw->fpa0;
+               fp1 = &hw->fpa1;
+               hs = &hw->hsync_a;
+               hb = &hw->hblank_a;
+               ht = &hw->htotal_a;
+               vs = &hw->vsync_a;
+               vb = &hw->vblank_a;
+               vt = &hw->vtotal_a;
+               ss = &hw->src_size_a;
+               pipe_conf = &hw->pipe_a_conf;
+       }
+
+       /* Use ADPA register for sync control. */
+       hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY;
+
+       /* sync polarity */
+       hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ?
+                       ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
+       vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ?
+                       ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
+       hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) |
+                     (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT));
+       hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) |
+                   (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT);
+
+       /* Connect correct pipe to the analog port DAC */
+       hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT);
+       hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT);
+
+       /* Set DPMS state to D0 (on) */
+       hw->adpa &= ~ADPA_DPMS_CONTROL_MASK;
+       hw->adpa |= ADPA_DPMS_D0;
+
+       hw->adpa |= ADPA_DAC_ENABLE;
+
+       *dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE);
+       *dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK);
+       *dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0);
+
+       /* Desired clock in kHz */
+       clock_target = 1000000000 / var->pixclock;
+
+       if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+               WRN_MSG("calc_pll_params failed\n");
+               return 1;
+       }
+
+       /* Check for overflow. */
+       if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter"))
+               return 1;
+       if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter"))
+               return 1;
+       if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter"))
+               return 1;
+       if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter"))
+               return 1;
+       if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter"))
+               return 1;
+
+       *dpll &= ~DPLL_P1_FORCE_DIV2;
+       *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
+                  (DPLL_P1_MASK << DPLL_P1_SHIFT));
+       *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+       *fp0 = (n << FP_N_DIVISOR_SHIFT) |
+              (m1 << FP_M1_DIVISOR_SHIFT) |
+              (m2 << FP_M2_DIVISOR_SHIFT);
+       *fp1 = *fp0;
+
+       hw->dvob &= ~PORT_ENABLE;
+       hw->dvoc &= ~PORT_ENABLE;
+
+       /* Use display plane A. */
+       hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE;
+       hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE;
+       hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK;
+       switch (intelfb_var_to_depth(var)) {
+       case 8:
+               hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
+               break;
+       case 15:
+               hw->disp_a_ctrl |= DISPPLANE_15_16BPP;
+               break;
+       case 16:
+               hw->disp_a_ctrl |= DISPPLANE_16BPP;
+               break;
+       case 24:
+               hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA;
+               break;
+       }
+       hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT);
+       hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT);
+
+       /* Set CRTC registers. */
+       hactive = var->xres;
+       hsync_start = hactive + var->right_margin;
+       hsync_end = hsync_start + var->hsync_len;
+       htotal = hsync_end + var->left_margin;
+       hblank_start = hactive;
+       hblank_end = htotal;
+
+       DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
+               hactive, hsync_start, hsync_end, htotal, hblank_start,
+               hblank_end);
+
+       vactive = var->yres;
+       vsync_start = vactive + var->lower_margin;
+       vsync_end = vsync_start + var->vsync_len;
+       vtotal = vsync_end + var->upper_margin;
+       vblank_start = vactive;
+       vblank_end = vtotal;
+       vblank_end = vsync_end + 1;
+
+       DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
+               vactive, vsync_start, vsync_end, vtotal, vblank_start,
+               vblank_end);
+
+       /* Adjust for register values, and check for overflow. */
+       hactive--;
+       if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive"))
+               return 1;
+       hsync_start--;
+       if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start"))
+               return 1;
+       hsync_end--;
+       if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end"))
+               return 1;
+       htotal--;
+       if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal"))
+               return 1;
+       hblank_start--;
+       if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start"))
+               return 1;
+       hblank_end--;
+       if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end"))
+               return 1;
+
+       vactive--;
+       if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive"))
+               return 1;
+       vsync_start--;
+       if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start"))
+               return 1;
+       vsync_end--;
+       if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end"))
+               return 1;
+       vtotal--;
+       if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal"))
+               return 1;
+       vblank_start--;
+       if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start"))
+               return 1;
+       vblank_end--;
+       if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end"))
+               return 1;
+
+       *ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT);
+       *hb = (hblank_start << HBLANKSTART_SHIFT) |
+             (hblank_end << HSYNCEND_SHIFT);
+       *hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT);
+
+       *vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT);
+       *vb = (vblank_start << VBLANKSTART_SHIFT) |
+             (vblank_end << VSYNCEND_SHIFT);
+       *vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT);
+       *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
+             (vactive << SRC_SIZE_VERT_SHIFT);
+
+       hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8;
+       DBG_MSG("pitch is %d\n", hw->disp_a_stride);
+
+       hw->disp_a_base = hw->disp_a_stride * var->yoffset +
+                         var->xoffset * var->bits_per_pixel / 8;
+
+       hw->disp_a_base += dinfo->fb.offset << 12;
+
+       /* Check stride alignment. */
+       if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) {
+               WRN_MSG("display stride %d has bad alignment %d\n",
+                       hw->disp_a_stride, STRIDE_ALIGNMENT);
+               return 1;
+       }
+
+       /* Set the palette to 8-bit mode. */
+       *pipe_conf &= ~PIPECONF_GAMMA;
+       return 0;
+}
+
+/* Program a (non-VGA) video mode. */
+int
+intelfbhw_program_mode(struct intelfb_info *dinfo,
+                    const struct intelfb_hwstate *hw, int blank)
+{
+       int pipe = PIPE_A;
+       u32 tmp;
+       const u32 *dpll, *fp0, *fp1, *pipe_conf;
+       const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
+       u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg;
+       u32 hsync_reg, htotal_reg, hblank_reg;
+       u32 vsync_reg, vtotal_reg, vblank_reg;
+       u32 src_size_reg;
+
+       /* Assume single pipe, display plane A, analog CRT. */
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_program_mode\n");
+#endif
+
+       /* Disable VGA */
+       tmp = INREG(VGACNTRL);
+       tmp |= VGA_DISABLE;
+       OUTREG(VGACNTRL, tmp);
+
+       /* Check whether pipe A or pipe B is enabled. */
+       if (hw->pipe_a_conf & PIPECONF_ENABLE)
+               pipe = PIPE_A;
+       else if (hw->pipe_b_conf & PIPECONF_ENABLE)
+               pipe = PIPE_B;
+
+       dinfo->pipe = pipe;
+
+       if (pipe == PIPE_B) {
+               dpll = &hw->dpll_b;
+               fp0 = &hw->fpb0;
+               fp1 = &hw->fpb1;
+               pipe_conf = &hw->pipe_b_conf;
+               hs = &hw->hsync_b;
+               hb = &hw->hblank_b;
+               ht = &hw->htotal_b;
+               vs = &hw->vsync_b;
+               vb = &hw->vblank_b;
+               vt = &hw->vtotal_b;
+               ss = &hw->src_size_b;
+               dpll_reg = DPLL_B;
+               fp0_reg = FPB0;
+               fp1_reg = FPB1;
+               pipe_conf_reg = PIPEBCONF;
+               hsync_reg = HSYNC_B;
+               htotal_reg = HTOTAL_B;
+               hblank_reg = HBLANK_B;
+               vsync_reg = VSYNC_B;
+               vtotal_reg = VTOTAL_B;
+               vblank_reg = VBLANK_B;
+               src_size_reg = SRC_SIZE_B;
+       } else {
+               dpll = &hw->dpll_a;
+               fp0 = &hw->fpa0;
+               fp1 = &hw->fpa1;
+               pipe_conf = &hw->pipe_a_conf;
+               hs = &hw->hsync_a;
+               hb = &hw->hblank_a;
+               ht = &hw->htotal_a;
+               vs = &hw->vsync_a;
+               vb = &hw->vblank_a;
+               vt = &hw->vtotal_a;
+               ss = &hw->src_size_a;
+               dpll_reg = DPLL_A;
+               fp0_reg = FPA0;
+               fp1_reg = FPA1;
+               pipe_conf_reg = PIPEACONF;
+               hsync_reg = HSYNC_A;
+               htotal_reg = HTOTAL_A;
+               hblank_reg = HBLANK_A;
+               vsync_reg = VSYNC_A;
+               vtotal_reg = VTOTAL_A;
+               vblank_reg = VBLANK_A;
+               src_size_reg = SRC_SIZE_A;
+       }
+
+       /* Disable planes A and B. */
+       tmp = INREG(DSPACNTR);
+       tmp &= ~DISPPLANE_PLANE_ENABLE;
+       OUTREG(DSPACNTR, tmp);
+       tmp = INREG(DSPBCNTR);
+       tmp &= ~DISPPLANE_PLANE_ENABLE;
+       OUTREG(DSPBCNTR, tmp);
+
+       /* Wait for vblank.  For now, just wait for a 50Hz cycle (20ms)) */
+       mdelay(20);
+
+       /* Disable Sync */
+       tmp = INREG(ADPA);
+       tmp &= ~ADPA_DPMS_CONTROL_MASK;
+       tmp |= ADPA_DPMS_D3;
+       OUTREG(ADPA, tmp);
+
+       /* turn off pipe */
+       tmp = INREG(pipe_conf_reg);
+       tmp &= ~PIPECONF_ENABLE;
+       OUTREG(pipe_conf_reg, tmp);
+
+       /* turn off PLL */
+       tmp = INREG(dpll_reg);
+       dpll_reg &= ~DPLL_VCO_ENABLE;
+       OUTREG(dpll_reg, tmp);
+
+       /* Set PLL parameters */
+       OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
+       OUTREG(fp0_reg, *fp0);
+       OUTREG(fp1_reg, *fp1);
+
+       /* Set pipe parameters */
+       OUTREG(hsync_reg, *hs);
+       OUTREG(hblank_reg, *hb);
+       OUTREG(htotal_reg, *ht);
+       OUTREG(vsync_reg, *vs);
+       OUTREG(vblank_reg, *vb);
+       OUTREG(vtotal_reg, *vt);
+       OUTREG(src_size_reg, *ss);
+
+       /* Set DVOs B/C */
+       OUTREG(DVOB, hw->dvob);
+       OUTREG(DVOC, hw->dvoc);
+
+       /* Set ADPA */
+       OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
+
+       /* Enable PLL */
+       tmp = INREG(dpll_reg);
+       tmp |= DPLL_VCO_ENABLE;
+       OUTREG(dpll_reg, tmp);
+
+       /* Enable pipe */
+       OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
+
+       /* Enable sync */
+       tmp = INREG(ADPA);
+       tmp &= ~ADPA_DPMS_CONTROL_MASK;
+       tmp |= ADPA_DPMS_D0;
+       OUTREG(ADPA, tmp);
+
+       /* setup display plane */
+       OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
+       OUTREG(DSPASTRIDE, hw->disp_a_stride);
+       OUTREG(DSPABASE, hw->disp_a_base);
+
+       /* Enable plane */
+       if (!blank) {
+               tmp = INREG(DSPACNTR);
+               tmp |= DISPPLANE_PLANE_ENABLE;
+               OUTREG(DSPACNTR, tmp);
+               OUTREG(DSPABASE, hw->disp_a_base);
+       }
+
+       return 0;
+}
+
+/* forward declarations */
+static void refresh_ring(struct intelfb_info *dinfo);
+static void reset_state(struct intelfb_info *dinfo);
+static void do_flush(struct intelfb_info *dinfo);
+
+static int
+wait_ring(struct intelfb_info *dinfo, int n)
+{
+       int i = 0;
+       unsigned long end;
+       u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
+
+#if VERBOSE > 0
+       DBG_MSG("wait_ring: %d\n", n);
+#endif
+
+       end = jiffies + (HZ * 3);
+       while (dinfo->ring_space < n) {
+               dinfo->ring_head = (u8 __iomem *)(INREG(PRI_RING_HEAD) &
+                                                  RING_HEAD_MASK);
+               if (dinfo->ring_tail + RING_MIN_FREE <
+                   (u32 __iomem) dinfo->ring_head)
+                       dinfo->ring_space = (u32 __iomem) dinfo->ring_head
+                               - (dinfo->ring_tail + RING_MIN_FREE);
+               else
+                       dinfo->ring_space = (dinfo->ring.size +
+                                            (u32 __iomem) dinfo->ring_head)
+                               - (dinfo->ring_tail + RING_MIN_FREE);
+               if ((u32 __iomem) dinfo->ring_head != last_head) {
+                       end = jiffies + (HZ * 3);
+                       last_head = (u32 __iomem) dinfo->ring_head;
+               }
+               i++;
+               if (time_before(end, jiffies)) {
+                       if (!i) {
+                               /* Try again */
+                               reset_state(dinfo);
+                               refresh_ring(dinfo);
+                               do_flush(dinfo);
+                               end = jiffies + (HZ * 3);
+                               i = 1;
+                       } else {
+                               WRN_MSG("ring buffer : space: %d wanted %d\n",
+                                       dinfo->ring_space, n);
+                               WRN_MSG("lockup - turning off hardware "
+                                       "acceleration\n");
+                               dinfo->ring_lockup = 1;
+                               break;
+                       }
+               }
+               udelay(1);
+       }
+       return i;
+}
+
+static void
+do_flush(struct intelfb_info *dinfo) {
+       START_RING(2);
+       OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
+       OUT_RING(MI_NOOP);
+       ADVANCE_RING();
+}
+
+void
+intelfbhw_do_sync(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_do_sync\n");
+#endif
+
+       if (!dinfo->accel)
+               return;
+
+       /*
+        * Send a flush, then wait until the ring is empty.  This is what
+        * the XFree86 driver does, and actually it doesn't seem a lot worse
+        * than the recommended method (both have problems).
+        */
+       do_flush(dinfo);
+       wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE);
+       dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;
+}
+
+static void
+refresh_ring(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+       DBG_MSG("refresh_ring\n");
+#endif
+
+       dinfo->ring_head = (u8 __iomem *) (INREG(PRI_RING_HEAD) &
+                                          RING_HEAD_MASK);
+       dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
+       if (dinfo->ring_tail + RING_MIN_FREE < (u32 __iomem)dinfo->ring_head)
+               dinfo->ring_space = (u32 __iomem) dinfo->ring_head
+                       - (dinfo->ring_tail + RING_MIN_FREE);
+       else
+               dinfo->ring_space = (dinfo->ring.size +
+                                    (u32 __iomem) dinfo->ring_head)
+                       - (dinfo->ring_tail + RING_MIN_FREE);
+}
+
+static void
+reset_state(struct intelfb_info *dinfo)
+{
+       int i;
+       u32 tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("reset_state\n");
+#endif
+
+       for (i = 0; i < FENCE_NUM; i++)
+               OUTREG(FENCE + (i << 2), 0);
+
+       /* Flush the ring buffer if it's enabled. */
+       tmp = INREG(PRI_RING_LENGTH);
+       if (tmp & RING_ENABLE) {
+#if VERBOSE > 0
+               DBG_MSG("reset_state: ring was enabled\n");
+#endif
+               refresh_ring(dinfo);
+               intelfbhw_do_sync(dinfo);
+               DO_RING_IDLE();
+       }
+
+       OUTREG(PRI_RING_LENGTH, 0);
+       OUTREG(PRI_RING_HEAD, 0);
+       OUTREG(PRI_RING_TAIL, 0);
+       OUTREG(PRI_RING_START, 0);
+}
+
+/* Stop the 2D engine, and turn off the ring buffer. */
+void
+intelfbhw_2d_stop(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel,
+               dinfo->ring_active);
+#endif
+
+       if (!dinfo->accel)
+               return;
+
+       dinfo->ring_active = 0;
+       reset_state(dinfo);
+}
+
+/*
+ * Enable the ring buffer, and initialise the 2D engine.
+ * It is assumed that the graphics engine has been stopped by previously
+ * calling intelfb_2d_stop().
+ */
+void
+intelfbhw_2d_start(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
+               dinfo->accel, dinfo->ring_active);
+#endif
+
+       if (!dinfo->accel)
+               return;
+
+       /* Initialise the primary ring buffer. */
+       OUTREG(PRI_RING_LENGTH, 0);
+       OUTREG(PRI_RING_TAIL, 0);
+       OUTREG(PRI_RING_HEAD, 0);
+
+       OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK);
+       OUTREG(PRI_RING_LENGTH,
+               ((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) |
+               RING_NO_REPORT | RING_ENABLE);
+       refresh_ring(dinfo);
+       dinfo->ring_active = 1;
+}
+
+/* 2D fillrect (solid fill or invert) */
+void
+intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h,
+                     u32 color, u32 pitch, u32 bpp, u32 rop)
+{
+       u32 br00, br09, br13, br14, br16;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, "
+               "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop);
+#endif
+
+       br00 = COLOR_BLT_CMD;
+       br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8));
+       br13 = (rop << ROP_SHIFT) | pitch;
+       br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT);
+       br16 = color;
+
+       switch (bpp) {
+       case 8:
+               br13 |= COLOR_DEPTH_8;
+               break;
+       case 16:
+               br13 |= COLOR_DEPTH_16;
+               break;
+       case 32:
+               br13 |= COLOR_DEPTH_32;
+               br00 |= WRITE_ALPHA | WRITE_RGB;
+               break;
+       }
+
+       START_RING(6);
+       OUT_RING(br00);
+       OUT_RING(br13);
+       OUT_RING(br14);
+       OUT_RING(br09);
+       OUT_RING(br16);
+       OUT_RING(MI_NOOP);
+       ADVANCE_RING();
+
+#if VERBOSE > 0
+       DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head,
+               dinfo->ring_tail, dinfo->ring_space);
+#endif
+}
+
+void
+intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
+                   u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp)
+{
+       u32 br00, br09, br11, br12, br13, br22, br23, br26;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n",
+               curx, cury, dstx, dsty, w, h, pitch, bpp);
+#endif
+
+       br00 = XY_SRC_COPY_BLT_CMD;
+       br09 = dinfo->fb_start;
+       br11 = (pitch << PITCH_SHIFT);
+       br12 = dinfo->fb_start;
+       br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
+       br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT);
+       br23 = ((dstx + w) << WIDTH_SHIFT) |
+              ((dsty + h) << HEIGHT_SHIFT);
+       br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT);
+
+       switch (bpp) {
+       case 8:
+               br13 |= COLOR_DEPTH_8;
+               break;
+       case 16:
+               br13 |= COLOR_DEPTH_16;
+               break;
+       case 32:
+               br13 |= COLOR_DEPTH_32;
+               br00 |= WRITE_ALPHA | WRITE_RGB;
+               break;
+       }
+
+       START_RING(8);
+       OUT_RING(br00);
+       OUT_RING(br13);
+       OUT_RING(br22);
+       OUT_RING(br23);
+       OUT_RING(br09);
+       OUT_RING(br26);
+       OUT_RING(br11);
+       OUT_RING(br12);
+       ADVANCE_RING();
+}
+
+int
+intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
+                      u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp)
+{
+       int nbytes, ndwords, pad, tmp;
+       u32 br00, br09, br13, br18, br19, br22, br23;
+       int dat, ix, iy, iw;
+       int i, j;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);
+#endif
+
+       /* size in bytes of a padded scanline */
+       nbytes = ROUND_UP_TO(w, 16) / 8;
+
+       /* Total bytes of padded scanline data to write out. */
+       nbytes = nbytes * h;
+
+       /*
+        * Check if the glyph data exceeds the immediate mode limit.
+        * It would take a large font (1K pixels) to hit this limit.
+        */
+       if (nbytes > MAX_MONO_IMM_SIZE)
+               return 0;
+
+       /* Src data is packaged a dword (32-bit) at a time. */
+       ndwords = ROUND_UP_TO(nbytes, 4) / 4;
+
+       /*
+        * Ring has to be padded to a quad word. But because the command starts
+          with 7 bytes, pad only if there is an even number of ndwords
+        */
+       pad = !(ndwords % 2);
+
+       tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords;
+       br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp;
+       br09 = dinfo->fb_start;
+       br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
+       br18 = bg;
+       br19 = fg;
+       br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT);
+       br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT);
+
+       switch (bpp) {
+       case 8:
+               br13 |= COLOR_DEPTH_8;
+               break;
+       case 16:
+               br13 |= COLOR_DEPTH_16;
+               break;
+       case 32:
+               br13 |= COLOR_DEPTH_32;
+               br00 |= WRITE_ALPHA | WRITE_RGB;
+               break;
+       }
+
+       START_RING(8 + ndwords);
+       OUT_RING(br00);
+       OUT_RING(br13);
+       OUT_RING(br22);
+       OUT_RING(br23);
+       OUT_RING(br09);
+       OUT_RING(br18);
+       OUT_RING(br19);
+       ix = iy = 0;
+       iw = ROUND_UP_TO(w, 8) / 8;
+       while (ndwords--) {
+               dat = 0;
+               for (j = 0; j < 2; ++j) {
+                       for (i = 0; i < 2; ++i) {
+                               if (ix != iw || i == 0)
+                                       dat |= cdat[iy*iw + ix++] << (i+j*2)*8;
+                       }
+                       if (ix == iw && iy != (h-1)) {
+                               ix = 0;
+                               ++iy;
+                       }
+               }
+               OUT_RING(dat);
+       }
+       if (pad)
+               OUT_RING(MI_NOOP);
+       ADVANCE_RING();
+
+       return 1;
+}
+
+/* HW cursor functions. */
+void
+intelfbhw_cursor_init(struct intelfb_info *dinfo)
+{
+       u32 tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_init\n");
+#endif
+
+       if (dinfo->mobile) {
+               if (!dinfo->cursor.physical)
+                       return;
+               tmp = INREG(CURSOR_A_CONTROL);
+               tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE |
+                        CURSOR_MEM_TYPE_LOCAL |
+                        (1 << CURSOR_PIPE_SELECT_SHIFT));
+               tmp |= CURSOR_MODE_DISABLE;
+               OUTREG(CURSOR_A_CONTROL, tmp);
+               OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+       } else {
+               tmp = INREG(CURSOR_CONTROL);
+               tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE |
+                        CURSOR_ENABLE | CURSOR_STRIDE_MASK);
+               tmp = CURSOR_FORMAT_3C;
+               OUTREG(CURSOR_CONTROL, tmp);
+               OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12);
+               tmp = (64 << CURSOR_SIZE_H_SHIFT) |
+                     (64 << CURSOR_SIZE_V_SHIFT);
+               OUTREG(CURSOR_SIZE, tmp);
+       }
+}
+
+void
+intelfbhw_cursor_hide(struct intelfb_info *dinfo)
+{
+       u32 tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_hide\n");
+#endif
+
+       dinfo->cursor_on = 0;
+       if (dinfo->mobile) {
+               if (!dinfo->cursor.physical)
+                       return;
+               tmp = INREG(CURSOR_A_CONTROL);
+               tmp &= ~CURSOR_MODE_MASK;
+               tmp |= CURSOR_MODE_DISABLE;
+               OUTREG(CURSOR_A_CONTROL, tmp);
+               /* Flush changes */
+               OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+       } else {
+               tmp = INREG(CURSOR_CONTROL);
+               tmp &= ~CURSOR_ENABLE;
+               OUTREG(CURSOR_CONTROL, tmp);
+       }
+}
+
+void
+intelfbhw_cursor_show(struct intelfb_info *dinfo)
+{
+       u32 tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_show\n");
+#endif
+
+       dinfo->cursor_on = 1;
+
+       if (dinfo->cursor_blanked)
+               return;
+
+       if (dinfo->mobile) {
+               if (!dinfo->cursor.physical)
+                       return;
+               tmp = INREG(CURSOR_A_CONTROL);
+               tmp &= ~CURSOR_MODE_MASK;
+               tmp |= CURSOR_MODE_64_4C_AX;
+               OUTREG(CURSOR_A_CONTROL, tmp);
+               /* Flush changes */
+               OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
+       } else {
+               tmp = INREG(CURSOR_CONTROL);
+               tmp |= CURSOR_ENABLE;
+               OUTREG(CURSOR_CONTROL, tmp);
+       }
+}
+
+void
+intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
+{
+       u32 tmp;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y);
+#endif
+
+       /*
+        * Sets the position.  The coordinates are assumed to already
+        * have any offset adjusted.  Assume that the cursor is never
+        * completely off-screen, and that x, y are always >= 0.
+        */
+
+       tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
+             ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+       OUTREG(CURSOR_A_POSITION, tmp);
+}
+
+void
+intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
+{
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_setcolor\n");
+#endif
+
+       OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK);
+       OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK);
+       OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK);
+       OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
+}
+
+void
+intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
+                     u8 *data)
+{
+       u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
+       int i, j, w = width / 8;
+       int mod = width % 8, t_mask, d_mask;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_load\n");
+#endif
+
+       if (!dinfo->cursor.virtual)
+               return;
+
+       t_mask = 0xff >> mod;
+       d_mask = ~(0xff >> mod);
+       for (i = height; i--; ) {
+               for (j = 0; j < w; j++) {
+                       writeb(0x00, addr + j);
+                       writeb(*(data++), addr + j+8);
+               }
+               if (mod) {
+                       writeb(t_mask, addr + j);
+                       writeb(*(data++) & d_mask, addr + j+8);
+               }
+               addr += 16;
+       }
+}
+
+void
+intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
+       u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
+       int i, j;
+
+#if VERBOSE > 0
+       DBG_MSG("intelfbhw_cursor_reset\n");
+#endif
+
+       if (!dinfo->cursor.virtual)
+               return;
+
+       for (i = 64; i--; ) {
+               for (j = 0; j < 8; j++) {
+                       writeb(0xff, addr + j+0);
+                       writeb(0x00, addr + j+8);
+               }
+               addr += 16;
+       }
+}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
new file mode 100644 (file)
index 0000000..d4336cc
--- /dev/null
@@ -0,0 +1,567 @@
+#ifndef _INTELFBHW_H
+#define _INTELFBHW_H
+
+/* $DHD: intelfb/intelfbhw.h,v 1.5 2003/06/27 15:06:25 dawes Exp $ */
+
+
+/*** HW-specific data ***/
+
+/* Information about the 852GM/855GM variants */
+#define INTEL_85X_CAPID                0x44
+#define INTEL_85X_VARIANT_MASK         0x7
+#define INTEL_85X_VARIANT_SHIFT                5
+#define INTEL_VAR_855GME               0x0
+#define INTEL_VAR_855GM                        0x4
+#define INTEL_VAR_852GME               0x2
+#define INTEL_VAR_852GM                        0x5
+
+/* Information about DVO/LVDS Ports */
+#define DVOA_PORT  0x1
+#define DVOB_PORT  0x2
+#define DVOC_PORT  0x4
+#define LVDS_PORT  0x8
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL                0x52
+#define INTEL_GMCH_ENABLED             0x4
+#define INTEL_GMCH_MEM_MASK            0x1
+#define INTEL_GMCH_MEM_64M             0x1
+#define INTEL_GMCH_MEM_128M            0
+
+#define INTEL_830_GMCH_GMS_MASK                (0x7 << 4)
+#define INTEL_830_GMCH_GMS_DISABLED    (0x0 << 4)
+#define INTEL_830_GMCH_GMS_LOCAL       (0x1 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_512  (0x2 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_1024 (0x3 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_8192 (0x4 << 4)
+
+#define INTEL_855_GMCH_GMS_MASK                (0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED    (0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M   (0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M   (0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M   (0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M  (0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M  (0x5 << 4)
+
+/* HW registers */
+
+/* Fence registers */
+#define FENCE                  0x2000
+#define FENCE_NUM                      8
+
+/* Primary ring buffer */
+#define PRI_RING_TAIL          0x2030
+#define RING_TAIL_MASK                 0x001ffff8
+#define RING_INUSE                     0x1
+
+#define PRI_RING_HEAD          0x2034
+#define RING_HEAD_WRAP_MASK            0x7ff
+#define RING_HEAD_WRAP_SHIFT           21
+#define RING_HEAD_MASK                 0x001ffffc
+
+#define PRI_RING_START         0x2038
+#define RING_START_MASK                        0xfffff000
+
+#define PRI_RING_LENGTH                0x203c
+#define RING_LENGTH_MASK               0x001ff000
+#define RING_REPORT_MASK               (0x3 << 1)
+#define RING_NO_REPORT                 (0x0 << 1)
+#define RING_REPORT_64K                        (0x1 << 1)
+#define RING_REPORT_4K                 (0x2 << 1)
+#define RING_REPORT_128K               (0x3 << 1)
+#define RING_ENABLE                    0x1
+
+/*
+ * Tail can't wrap to any closer than RING_MIN_FREE bytes of the head,
+ * and the last RING_MIN_FREE bytes need to be padded with MI_NOOP
+ */
+#define RING_MIN_FREE                  64
+
+#define IPEHR                  0x2088
+
+#define INSTDONE               0x2090
+#define PRI_RING_EMPTY                 1
+
+#define INSTPM                 0x20c0
+#define SYNC_FLUSH_ENABLE              (1 << 5)
+
+#define INSTPS                 0x20c4
+
+#define MEM_MODE               0x20cc
+
+#define MASK_SHIFT                     16
+
+#define FW_BLC_0               0x20d8
+#define FW_DISPA_WM_SHIFT              0
+#define FW_DISPA_WM_MASK               0x3f
+#define FW_DISPA_BL_SHIFT              8
+#define FW_DISPA_BL_MASK               0xf
+#define FW_DISPB_WM_SHIFT              16
+#define FW_DISPB_WM_MASK               0x1f
+#define FW_DISPB_BL_SHIFT              24
+#define FW_DISPB_BL_MASK               0x7
+
+#define FW_BLC_1               0x20dc
+#define FW_DISPC_WM_SHIFT              0
+#define FW_DISPC_WM_MASK               0x1f
+#define FW_DISPC_BL_SHIFT              8
+#define FW_DISPC_BL_MASK               0x7
+
+
+/* PLL registers */
+#define VGA0_DIVISOR           0x06000
+#define VGA1_DIVISOR           0x06004
+#define VGAPD                  0x06010
+#define VGAPD_0_P1_SHIFT               0
+#define VGAPD_0_P1_FORCE_DIV2          (1 << 5)
+#define VGAPD_0_P2_SHIFT               7
+#define VGAPD_1_P1_SHIFT               8
+#define VGAPD_1_P1_FORCE_DIV2          (1 << 13)
+#define VGAPD_1_P2_SHIFT               15
+
+#define DPLL_A                 0x06014
+#define DPLL_B                 0x06018
+#define DPLL_VCO_ENABLE                        (1 << 31)
+#define DPLL_2X_CLOCK_ENABLE           (1 << 30)
+#define DPLL_SYNCLOCK_ENABLE           (1 << 29)
+#define DPLL_VGA_MODE_DISABLE          (1 << 28)
+#define DPLL_P2_MASK                   1
+#define DPLL_P2_SHIFT                  23
+#define DPLL_P1_FORCE_DIV2             (1 << 21)
+#define DPLL_P1_MASK                   0x1f
+#define DPLL_P1_SHIFT                  16
+#define DPLL_REFERENCE_SELECT_MASK     (0x3 << 13)
+#define DPLL_REFERENCE_DEFAULT         (0x0 << 13)
+#define DPLL_REFERENCE_TVCLK           (0x2 << 13)
+#define DPLL_RATE_SELECT_MASK          (1 << 8)
+#define DPLL_RATE_SELECT_FP0           (0 << 8)
+#define DPLL_RATE_SELECT_FP1           (1 << 8)
+
+#define FPA0                   0x06040
+#define FPA1                   0x06044
+#define FPB0                   0x06048
+#define FPB1                   0x0604c
+#define FP_DIVISOR_MASK                        0x3f
+#define FP_N_DIVISOR_SHIFT             16
+#define FP_M1_DIVISOR_SHIFT            8
+#define FP_M2_DIVISOR_SHIFT            0
+
+/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
+/* Clock values are in units of kHz */
+#define PLL_REFCLK             48000
+#define MIN_VCO_FREQ           930000
+#define MAX_VCO_FREQ           1400000
+#define MIN_CLOCK              25000
+#define MAX_CLOCK              350000
+#define P_TRANSITION_CLOCK     165000
+#define MIN_M                  108
+#define MAX_M                  140
+#define MIN_M1                 18
+#define MAX_M1                 26
+#define MIN_M2                 6
+#define MAX_M2                 16
+#define MIN_P                  4
+#define MAX_P                  128
+#define MIN_P1                 0
+#define MAX_P1                 31
+#define MIN_N                  3
+#define MAX_N                  16
+
+#define CALC_VCLOCK(m1, m2, n, p1, p2) \
+        ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
+        (((p1) + 2) * (1 << (p2 + 1))))
+
+#define CALC_VCLOCK3(m, n, p)  ((PLL_REFCLK * (m) / (n)) / (p))
+
+/* Two pipes */
+#define PIPE_A                 0
+#define PIPE_B                 1
+#define PIPE_MASK              1
+
+/* palette registers */
+#define PALETTE_A              0x0a000
+#define PALETTE_B              0x0a800
+#ifndef PALETTE_8_ENTRIES
+#define PALETTE_8_ENTRIES              256
+#endif
+#define PALETTE_8_SIZE                 (PALETTE_8_ENTRIES * 4)
+#define PALETTE_10_ENTRIES             128
+#define PALETTE_10_SIZE                        (PALETTE_10_ENTRIES * 8)
+#define PALETTE_8_MASK                 0xff
+#define PALETTE_8_RED_SHIFT            16
+#define PALETTE_8_GREEN_SHIFT          8
+#define PALETTE_8_BLUE_SHIFT           0
+
+/* CRTC registers */
+#define HTOTAL_A               0x60000
+#define HBLANK_A               0x60004
+#define HSYNC_A                        0x60008
+#define VTOTAL_A               0x6000c
+#define VBLANK_A               0x60010
+#define VSYNC_A                        0x60014
+#define SRC_SIZE_A             0x6001c
+#define BCLRPAT_A              0x60020
+
+#define HTOTAL_B               0x61000
+#define HBLANK_B               0x61004
+#define HSYNC_B                        0x61008
+#define VTOTAL_B               0x6100c
+#define VBLANK_B               0x61010
+#define VSYNC_B                        0x61014
+#define SRC_SIZE_B             0x6101c
+#define BCLRPAT_B              0x61020
+
+#define HTOTAL_MASK                    0xfff
+#define HTOTAL_SHIFT                   16
+#define HACTIVE_MASK                   0x7ff
+#define HACTIVE_SHIFT                  0
+#define HBLANKEND_MASK                 0xfff
+#define HBLANKEND_SHIFT                        16
+#define HBLANKSTART_MASK               0xfff
+#define HBLANKSTART_SHIFT              0
+#define HSYNCEND_MASK                  0xfff
+#define HSYNCEND_SHIFT                 16
+#define HSYNCSTART_MASK                        0xfff
+#define HSYNCSTART_SHIFT               0
+#define VTOTAL_MASK                    0xfff
+#define VTOTAL_SHIFT                   16
+#define VACTIVE_MASK                   0x7ff
+#define VACTIVE_SHIFT                  0
+#define VBLANKEND_MASK                 0xfff
+#define VBLANKEND_SHIFT                        16
+#define VBLANKSTART_MASK               0xfff
+#define VBLANKSTART_SHIFT              0
+#define VSYNCEND_MASK                  0xfff
+#define VSYNCEND_SHIFT                 16
+#define VSYNCSTART_MASK                        0xfff
+#define VSYNCSTART_SHIFT               0
+#define SRC_SIZE_HORIZ_MASK            0x7ff
+#define SRC_SIZE_HORIZ_SHIFT           16
+#define SRC_SIZE_VERT_MASK             0x7ff
+#define SRC_SIZE_VERT_SHIFT            0
+
+#define ADPA                   0x61100
+#define ADPA_DAC_ENABLE                        (1 << 31)
+#define ADPA_DAC_DISABLE               0
+#define ADPA_PIPE_SELECT_SHIFT         30
+#define ADPA_USE_VGA_HVPOLARITY                (1 << 15)
+#define ADPA_SETS_HVPOLARITY           0
+#define ADPA_DPMS_CONTROL_MASK         (0x3 << 10)
+#define ADPA_DPMS_D0                   (0x0 << 10)
+#define ADPA_DPMS_D2                   (0x1 << 10)
+#define ADPA_DPMS_D1                   (0x2 << 10)
+#define ADPA_DPMS_D3                   (0x3 << 10)
+#define ADPA_VSYNC_ACTIVE_SHIFT                4
+#define ADPA_HSYNC_ACTIVE_SHIFT                3
+#define ADPA_SYNC_ACTIVE_MASK          1
+#define ADPA_SYNC_ACTIVE_HIGH          1
+#define ADPA_SYNC_ACTIVE_LOW           0
+
+#define DVOA                   0x61120
+#define DVOB                   0x61140
+#define DVOC                   0x61160
+#define LVDS                   0x61180
+#define PORT_ENABLE                    (1 << 31)
+#define PORT_PIPE_SELECT_SHIFT         30
+#define PORT_TV_FLAGS_MASK              0xFF
+#define PORT_TV_FLAGS                   0xC4  // ripped from my BIOS
+                                              // to understand and correct
+
+#define DVOA_SRCDIM            0x61124
+#define DVOB_SRCDIM            0x61144
+#define DVOC_SRCDIM            0x61164
+
+#define PIPEACONF              0x70008
+#define PIPEBCONF              0x71008
+#define PIPECONF_ENABLE                        (1 << 31)
+#define PIPECONF_DISABLE               0
+#define PIPECONF_DOUBLE_WIDE           (1 << 30)
+#define PIPECONF_SINGLE_WIDE           0
+#define PIPECONF_LOCKED                        (1 << 25)
+#define PIPECONF_UNLOCKED              0
+#define PIPECONF_GAMMA                 (1 << 24)
+#define PIPECONF_PALETTE               0
+
+#define DISPARB                        0x70030
+#define DISPARB_AEND_MASK              0x1ff
+#define DISPARB_AEND_SHIFT             0
+#define DISPARB_BEND_MASK              0x3ff
+#define DISPARB_BEND_SHIFT             9
+
+/* Desktop HW cursor */
+#define CURSOR_CONTROL         0x70080
+#define CURSOR_ENABLE                  (1 << 31)
+#define CURSOR_GAMMA_ENABLE            (1 << 30)
+#define CURSOR_STRIDE_MASK             (0x3 << 28)
+#define CURSOR_STRIDE_256              (0x0 << 28)
+#define CURSOR_STRIDE_512              (0x1 << 28)
+#define CURSOR_STRIDE_1K               (0x2 << 28)
+#define CURSOR_STRIDE_2K               (0x3 << 28)
+#define CURSOR_FORMAT_MASK             (0x7 << 24)
+#define CURSOR_FORMAT_2C               (0x0 << 24)
+#define CURSOR_FORMAT_3C               (0x1 << 24)
+#define CURSOR_FORMAT_4C               (0x2 << 24)
+#define CURSOR_FORMAT_ARGB             (0x4 << 24)
+#define CURSOR_FORMAT_XRGB             (0x5 << 24)
+
+/* Mobile HW cursor (and i810) */
+#define CURSOR_A_CONTROL       CURSOR_CONTROL
+#define CURSOR_B_CONTROL       0x700c0
+#define CURSOR_MODE_MASK               0x27
+#define CURSOR_MODE_DISABLE            0
+#define CURSOR_MODE_64_3C              0x04
+#define CURSOR_MODE_64_4C_AX           0x05
+#define CURSOR_MODE_64_4C              0x06
+#define CURSOR_MODE_64_32B_AX          0x07
+#define CURSOR_MODE_64_ARGB_AX         0x27
+#define CURSOR_PIPE_SELECT_SHIFT       28
+#define CURSOR_MOBILE_GAMMA_ENABLE     (1 << 26)
+#define CURSOR_MEM_TYPE_LOCAL          (1 << 25)
+
+/* All platforms (desktop has no pipe B) */
+#define CURSOR_A_BASEADDR      0x70084
+#define CURSOR_B_BASEADDR      0x700c4
+#define CURSOR_BASE_MASK               0xffffff00
+
+#define CURSOR_A_POSITION      0x70088
+#define CURSOR_B_POSITION      0x700c8
+#define CURSOR_POS_SIGN                        (1 << 15)
+#define CURSOR_POS_MASK                        0x7ff
+#define CURSOR_X_SHIFT                 0
+#define CURSOR_Y_SHIFT                 16
+
+#define CURSOR_A_PALETTE0      0x70090
+#define CURSOR_A_PALETTE1      0x70094
+#define CURSOR_A_PALETTE2      0x70098
+#define CURSOR_A_PALETTE3      0x7009c
+#define CURSOR_B_PALETTE0      0x700d0
+#define CURSOR_B_PALETTE1      0x700d4
+#define CURSOR_B_PALETTE2      0x700d8
+#define CURSOR_B_PALETTE3      0x700dc
+#define CURSOR_COLOR_MASK                      0xff
+#define CURSOR_RED_SHIFT                       16
+#define CURSOR_GREEN_SHIFT                     8
+#define CURSOR_BLUE_SHIFT                      0
+#define CURSOR_PALETTE_MASK                    0xffffff
+
+/* Desktop only */
+#define CURSOR_SIZE            0x700a0
+#define CURSOR_SIZE_MASK               0x3ff
+#define CURSOR_SIZE_H_SHIFT            0
+#define CURSOR_SIZE_V_SHIFT            12
+
+#define DSPACNTR               0x70180
+#define DSPBCNTR               0x71180
+#define DISPPLANE_PLANE_ENABLE         (1 << 31)
+#define DISPPLANE_PLANE_DISABLE                0
+#define DISPPLANE_GAMMA_ENABLE         (1<<30)
+#define DISPPLANE_GAMMA_DISABLE                0
+#define DISPPLANE_PIXFORMAT_MASK       (0xf<<26)
+#define DISPPLANE_8BPP                 (0x2<<26)
+#define DISPPLANE_15_16BPP             (0x4<<26)
+#define DISPPLANE_16BPP                        (0x5<<26)
+#define DISPPLANE_32BPP_NO_ALPHA       (0x6<<26)
+#define DISPPLANE_32BPP                        (0x7<<26)
+#define DISPPLANE_STEREO_ENABLE                (1<<25)
+#define DISPPLANE_STEREO_DISABLE       0
+#define DISPPLANE_SEL_PIPE_SHIFT       24
+#define DISPPLANE_SRC_KEY_ENABLE       (1<<22)
+#define DISPPLANE_SRC_KEY_DISABLE      0
+#define DISPPLANE_LINE_DOUBLE          (1<<20)
+#define DISPPLANE_NO_LINE_DOUBLE       0
+#define DISPPLANE_STEREO_POLARITY_FIRST        0
+#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+/* plane B only */
+#define DISPPLANE_ALPHA_TRANS_ENABLE   (1<<15)
+#define DISPPLANE_ALPHA_TRANS_DISABLE  0
+#define DISPPLANE_SPRITE_ABOVE_DISPLAYA        0
+#define DISPPLANE_SPRITE_ABOVE_OVERLAY 1
+
+#define DSPABASE               0x70184
+#define DSPASTRIDE             0x70188
+
+#define DSPBBASE               0x71184
+#define DSPBSTRIDE             0x71188
+
+#define VGACNTRL               0x71400
+#define VGA_DISABLE                    (1 << 31)
+#define VGA_ENABLE                     0
+#define VGA_PIPE_SELECT_SHIFT          29
+#define VGA_PALETTE_READ_SELECT                23
+#define VGA_PALETTE_A_WRITE_DISABLE    (1 << 22)
+#define VGA_PALETTE_B_WRITE_DISABLE    (1 << 21)
+#define VGA_LEGACY_PALETTE             (1 << 20)
+#define VGA_6BIT_DAC                   0
+#define VGA_8BIT_DAC                   (1 << 20)
+
+#define ADD_ID                 0x71408
+#define ADD_ID_MASK                    0xff
+
+/* BIOS scratch area registers (830M and 845G). */
+#define SWF0                   0x71410
+#define SWF1                   0x71414
+#define SWF2                   0x71418
+#define SWF3                   0x7141c
+#define SWF4                   0x71420
+#define SWF5                   0x71424
+#define SWF6                   0x71428
+
+/* BIOS scratch area registers (852GM, 855GM, 865G). */
+#define SWF00                  0x70410
+#define SWF01                  0x70414
+#define SWF02                  0x70418
+#define SWF03                  0x7041c
+#define SWF04                  0x70420
+#define SWF05                  0x70424
+#define SWF06                  0x70428
+
+#define SWF10                  SWF0
+#define SWF11                  SWF1
+#define SWF12                  SWF2
+#define SWF13                  SWF3
+#define SWF14                  SWF4
+#define SWF15                  SWF5
+#define SWF16                  SWF6
+
+#define SWF30                  0x72414
+#define SWF31                  0x72418
+#define SWF32                  0x7241c
+
+/* Memory Commands */
+#define MI_NOOP                        (0x00 << 23)
+#define MI_NOOP_WRITE_ID               (1 << 22)
+#define MI_NOOP_ID_MASK                        ((1 << 22) - 1)
+
+#define MI_FLUSH               (0x04 << 23)
+#define MI_WRITE_DIRTY_STATE           (1 << 4)
+#define MI_END_SCENE                   (1 << 3)
+#define MI_INHIBIT_RENDER_CACHE_FLUSH  (1 << 2)
+#define MI_INVALIDATE_MAP_CACHE                (1 << 0)
+
+#define MI_STORE_DWORD_IMM     ((0x20 << 23) | 1)
+
+/* 2D Commands */
+#define COLOR_BLT_CMD          ((2 << 29) | (0x40 << 22) | 3)
+#define XY_COLOR_BLT_CMD       ((2 << 29) | (0x50 << 22) | 4)
+#define XY_SETUP_CLIP_BLT_CMD  ((2 << 29) | (0x03 << 22) | 1)
+#define XY_SRC_COPY_BLT_CMD    ((2 << 29) | (0x53 << 22) | 6)
+#define SRC_COPY_BLT_CMD       ((2 << 29) | (0x43 << 22) | 4)
+#define XY_MONO_PAT_BLT_CMD    ((2 << 29) | (0x52 << 22) | 7)
+#define XY_MONO_SRC_BLT_CMD    ((2 << 29) | (0x54 << 22) | 6)
+#define XY_MONO_SRC_IMM_BLT_CMD        ((2 << 29) | (0x71 << 22) | 5)
+#define TXT_IMM_BLT_CMD                ((2 << 29) | (0x30 << 22) | 2)
+#define SETUP_BLT_CMD          ((2 << 29) | (0x00 << 22) | 6)
+
+#define DW_LENGTH_MASK                 0xff
+
+#define WRITE_ALPHA                    (1 << 21)
+#define WRITE_RGB                      (1 << 20)
+#define VERT_SEED                      (3 << 8)
+#define HORIZ_SEED                     (3 << 12)
+
+#define COLOR_DEPTH_8                  (0 << 24)
+#define COLOR_DEPTH_16                 (1 << 24)
+#define COLOR_DEPTH_32                 (3 << 24)
+
+#define SRC_ROP_GXCOPY                 0xcc
+#define SRC_ROP_GXXOR                  0x66
+
+#define PAT_ROP_GXCOPY                  0xf0
+#define PAT_ROP_GXXOR                   0x5a
+
+#define PITCH_SHIFT                    0
+#define ROP_SHIFT                      16
+#define WIDTH_SHIFT                    0
+#define HEIGHT_SHIFT                   16
+
+/* in bytes */
+#define MAX_MONO_IMM_SIZE              128
+
+
+/*** Macros ***/
+
+/* I/O macros */
+#define INREG8(addr)         readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
+#define INREG(addr)          readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
+#define OUTREG8(addr, val)    writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
+                                                          (addr)))
+#define OUTREG(addr, val)     writel((val),(u32 __iomem *)(dinfo->mmio_base + \
+                                     (addr)))
+
+/* Ring buffer macros */
+#define OUT_RING(n)    do {                                            \
+       writel((n), (u32 __iomem *)(dinfo->ring.virtual + dinfo->ring_tail));\
+       dinfo->ring_tail += 4;                                          \
+       dinfo->ring_tail &= dinfo->ring_tail_mask;                      \
+} while (0)
+
+#define START_RING(n)  do {                                            \
+       if (dinfo->ring_space < (n) * 4)                                \
+               wait_ring(dinfo,(n) * 4);                               \
+       dinfo->ring_space -= (n) * 4;                                   \
+} while (0)
+
+#define ADVANCE_RING() do {                                            \
+       OUTREG(PRI_RING_TAIL, dinfo->ring_tail);                        \
+} while (0)
+
+#define DO_RING_IDLE() do {                                            \
+       u32 head, tail;                                                 \
+       do {                                                            \
+               head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;           \
+               tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;           \
+               udelay(10);                                             \
+       } while (head != tail);                                         \
+} while (0)
+
+
+/* function protoypes */
+extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
+                                int *chipset, int *mobile);
+extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+                               int *stolen_size);
+extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);
+extern const char *intelfbhw_dvo_to_string(int dvo);
+extern int intelfbhw_validate_mode(struct intelfb_info *dinfo,
+                                  struct fb_var_screeninfo *var);
+extern int intelfbhw_pan_display(struct fb_var_screeninfo *var,
+                                struct fb_info *info);
+extern void intelfbhw_do_blank(int blank, struct fb_info *info);
+extern void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+                               unsigned red, unsigned green, unsigned blue,
+                               unsigned transp);
+extern int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
+                                  struct intelfb_hwstate *hw, int flag);
+extern void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
+                                    struct intelfb_hwstate *hw);
+extern int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
+                               struct intelfb_hwstate *hw,
+                               struct fb_var_screeninfo *var);
+extern int intelfbhw_program_mode(struct intelfb_info *dinfo,
+                                 const struct intelfb_hwstate *hw, int blank);
+extern void intelfbhw_do_sync(struct intelfb_info *dinfo);
+extern void intelfbhw_2d_stop(struct intelfb_info *dinfo);
+extern void intelfbhw_2d_start(struct intelfb_info *dinfo);
+extern void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y,
+                                 u32 w, u32 h, u32 color, u32 pitch, u32 bpp,
+                                 u32 rop);
+extern void intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
+                               u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch,
+                               u32 bpp);
+extern int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg,
+                                 u32 w, u32 h, const u8* cdat, u32 x, u32 y,
+                                 u32 pitch, u32 bpp);
+extern void intelfbhw_cursor_init(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_hide(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_show(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y);
+extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
+                                     u32 fg);
+extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
+                                 int height, u8 *data);
+extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
+
+#endif /* _INTELFBHW_H */
diff --git a/drivers/video/savage/Makefile b/drivers/video/savage/Makefile
new file mode 100644 (file)
index 0000000..4859115
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the S3 Savage framebuffer driver
+#
+
+obj-$(CONFIG_FB_SAVAGE)                += savagefb.o
+obj-$(CONFIG_FB_SAVAGE_I2C)     += savagefb-i2c.o
+obj-$(CONFIG_FB_SAVAGE_ACCEL)   += savagefb_accel.o
+
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
new file mode 100644 (file)
index 0000000..2037dad
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based partly on rivafb-i2c.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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+#include "savagefb.h"
+
+#define SAVAGE_DDC     0x50
+
+#define VGA_CR_IX      0x3d4
+#define VGA_CR_DATA    0x3d5
+
+#define CR_SERIAL1     0xa0    /* I2C serial communications interface */
+#define MM_SERIAL1     0xff20
+#define CR_SERIAL2     0xb1    /* DDC2 monitor communications interface */
+
+/* based on vt8365 documentation */
+#define PROSAVAGE_I2C_ENAB     0x10
+#define PROSAVAGE_I2C_SCL_OUT  0x01
+#define PROSAVAGE_I2C_SDA_OUT  0x02
+#define PROSAVAGE_I2C_SCL_IN   0x04
+#define PROSAVAGE_I2C_SDA_IN   0x08
+
+#define SAVAGE4_I2C_ENAB       0x00000020
+#define SAVAGE4_I2C_SCL_OUT    0x00000001
+#define SAVAGE4_I2C_SDA_OUT    0x00000002
+#define SAVAGE4_I2C_SCL_IN     0x00000008
+#define SAVAGE4_I2C_SDA_IN     0x00000010
+
+#define SET_CR_IX(base, val)   writeb((val), base + 0x8000 + VGA_CR_IX)
+#define SET_CR_DATA(base, val) writeb((val), base + 0x8000 + VGA_CR_DATA)
+#define GET_CR_DATA(base)      readb(base + 0x8000 + VGA_CR_DATA)
+
+static void savage4_gpio_setscl(void *data, int val)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+       unsigned int r;
+
+       r = readl(chan->ioaddr + chan->reg);
+       if(val)
+               r |= SAVAGE4_I2C_SCL_OUT;
+       else
+               r &= ~SAVAGE4_I2C_SCL_OUT;
+       writel(r, chan->ioaddr + chan->reg);
+       readl(chan->ioaddr + chan->reg);        /* flush posted write */
+}
+
+static void savage4_gpio_setsda(void *data, int val)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+       unsigned int r;
+       r = readl(chan->ioaddr + chan->reg);
+       if(val)
+               r |= SAVAGE4_I2C_SDA_OUT;
+       else
+               r &= ~SAVAGE4_I2C_SDA_OUT;
+       writel(r, chan->ioaddr + chan->reg);
+       readl(chan->ioaddr + chan->reg);        /* flush posted write */
+}
+
+static int savage4_gpio_getscl(void *data)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+       return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN));
+}
+
+static int savage4_gpio_getsda(void *data)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+       return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN));
+}
+
+static void prosavage_gpio_setscl(void* data, int val)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+       u32                       r;
+
+       SET_CR_IX(chan->ioaddr, chan->reg);
+       r = GET_CR_DATA(chan->ioaddr);
+       r |= PROSAVAGE_I2C_ENAB;
+       if (val) {
+               r |= PROSAVAGE_I2C_SCL_OUT;
+       } else {
+               r &= ~PROSAVAGE_I2C_SCL_OUT;
+       }
+       SET_CR_DATA(chan->ioaddr, r);
+}
+
+static void prosavage_gpio_setsda(void* data, int val)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+       unsigned int r;
+
+       SET_CR_IX(chan->ioaddr, chan->reg);
+       r = GET_CR_DATA(chan->ioaddr);
+       r |= PROSAVAGE_I2C_ENAB;
+       if (val) {
+               r |= PROSAVAGE_I2C_SDA_OUT;
+       } else {
+               r &= ~PROSAVAGE_I2C_SDA_OUT;
+       }
+       SET_CR_DATA(chan->ioaddr, r);
+}
+
+static int prosavage_gpio_getscl(void* data)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+       SET_CR_IX(chan->ioaddr, chan->reg);
+       return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SCL_IN));
+}
+
+static int prosavage_gpio_getsda(void* data)
+{
+       struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+       SET_CR_IX(chan->ioaddr, chan->reg);
+       return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
+}
+
+#define I2C_ALGO_SAVAGE   0x0f0000
+static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
+                               const char *name)
+{
+       int (*add_bus)(struct i2c_adapter *) = symbol_get(i2c_bit_add_bus);
+       int rc = 0;
+
+       if (add_bus && chan->par) {
+               strcpy(chan->adapter.name, name);
+               chan->adapter.owner             = THIS_MODULE;
+               chan->adapter.id                = I2C_ALGO_SAVAGE;
+               chan->adapter.algo_data         = &chan->algo;
+               chan->adapter.dev.parent        = &chan->par->pcidev->dev;
+               chan->algo.udelay               = 40;
+               chan->algo.mdelay               = 5;
+               chan->algo.timeout              = 20;
+               chan->algo.data                 = chan;
+
+               i2c_set_adapdata(&chan->adapter, chan);
+
+               /* Raise SCL and SDA */
+               chan->algo.setsda(chan, 1);
+               chan->algo.setscl(chan, 1);
+               udelay(20);
+
+               rc = add_bus(&chan->adapter);
+               if (rc == 0)
+                       dev_dbg(&chan->par->pcidev->dev,
+                               "I2C bus %s registered.\n", name);
+               else
+                       dev_warn(&chan->par->pcidev->dev,
+                                "Failed to register I2C bus %s.\n", name);
+       } else
+               chan->par = NULL;
+
+       return rc;
+}
+
+void savagefb_create_i2c_busses(struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       par->chan.par   = par;
+
+       switch(info->fix.accel) {
+       case FB_ACCEL_PROSAVAGE_DDRK:
+       case FB_ACCEL_PROSAVAGE_PM:
+               par->chan.reg         = CR_SERIAL2;
+               par->chan.ioaddr      = par->mmio.vbase;
+               par->chan.algo.setsda = prosavage_gpio_setsda;
+               par->chan.algo.setscl = prosavage_gpio_setscl;
+               par->chan.algo.getsda = prosavage_gpio_getsda;
+               par->chan.algo.getscl = prosavage_gpio_getscl;
+               break;
+       case FB_ACCEL_SAVAGE4:
+               par->chan.reg         = 0xff20;
+               par->chan.ioaddr      = par->mmio.vbase;
+               par->chan.algo.setsda = savage4_gpio_setsda;
+               par->chan.algo.setscl = savage4_gpio_setscl;
+               par->chan.algo.getsda = savage4_gpio_getsda;
+               par->chan.algo.getscl = savage4_gpio_getscl;
+               break;
+       default:
+               par->chan.par = NULL;
+       }
+
+       savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2");
+}
+EXPORT_SYMBOL(savagefb_create_i2c_busses);
+
+void savagefb_delete_i2c_busses(struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int (*del_bus)(struct i2c_adapter *) =
+               symbol_get(i2c_bit_del_bus);
+
+       if (del_bus && par->chan.par)
+               del_bus(&par->chan.adapter);
+
+       par->chan.par = NULL;
+}
+EXPORT_SYMBOL(savagefb_delete_i2c_busses);
+
+static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
+{
+       u8 start = 0x0;
+       int (*transfer)(struct i2c_adapter *, struct i2c_msg *, int) =
+               symbol_get(i2c_transfer);
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = SAVAGE_DDC,
+                       .len    = 1,
+                       .buf    = &start,
+               }, {
+                       .addr   = SAVAGE_DDC,
+                       .flags  = I2C_M_RD,
+                       .len    = EDID_LENGTH,
+               },
+       };
+       u8 *buf = NULL;
+
+       if (transfer && chan->par) {
+               buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+               if (buf) {
+                       msgs[1].buf = buf;
+
+                       if (transfer(&chan->adapter, msgs, 2) != 2) {
+                               dev_dbg(&chan->par->pcidev->dev,
+                                       "Unable to read EDID block.\n");
+                               kfree(buf);
+                               buf = NULL;
+                       }
+               }
+       }
+
+       return buf;
+}
+
+int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid)
+{
+       u8 *edid = NULL;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               /* Do the real work */
+               edid = savage_do_probe_i2c_edid(&par->chan);
+               if (edid)
+                       break;
+       }
+       if (out_edid)
+               *out_edid = edid;
+       if (!edid)
+               return 1;
+
+       return 0;
+}
+EXPORT_SYMBOL(savagefb_probe_i2c_connector);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb.c b/drivers/video/savage/savagefb.c
new file mode 100644 (file)
index 0000000..4c5edfa
--- /dev/null
@@ -0,0 +1,2276 @@
+/*
+ * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
+ *                          Sven Neumann <neo@directfb.org>
+ *
+ *
+ * Card specific code is based on XFree86's savage driver.
+ * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
+ *
+ * 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.
+ *
+ * 0.4.0 (neo)
+ *  - hardware accelerated clear and move
+ *
+ * 0.3.2 (dok)
+ *  - wait for vertical retrace before writing to cr67
+ *    at the beginning of savagefb_set_par
+ *  - use synchronization registers cr23 and cr26
+ *
+ * 0.3.1 (dok)
+ *  - reset 3D engine
+ *  - don't return alpha bits for 32bit format
+ *
+ * 0.3.0 (dok)
+ *  - added WaitIdle functions for all Savage types
+ *  - do WaitIdle before mode switching
+ *  - code cleanup
+ *
+ * 0.2.0 (dok)
+ *  - first working version
+ *
+ *
+ * TODO
+ * - clock validations in decode_var
+ *
+ * BUGS
+ * - white margin on bootup
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "savagefb.h"
+
+
+#define SAVAGEFB_VERSION "0.4.0_2.6"
+
+/* --------------------------------------------------------------------- */
+
+
+static char *mode_option __initdata = NULL;
+static int   paletteEnabled = 0;
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static void vgaHWSeqReset (struct savagefb_par *par, int start)
+{
+       if (start)
+               VGAwSEQ (0x00, 0x01);           /* Synchronous Reset */
+       else
+               VGAwSEQ (0x00, 0x03);           /* End Reset */
+}
+
+static void vgaHWProtect (struct savagefb_par *par, int on)
+{
+       unsigned char tmp;
+
+       if (on) {
+               /*
+                * Turn off screen and disable sequencer.
+                */
+               tmp = VGArSEQ (0x01);
+
+               vgaHWSeqReset (par, 1);         /* start synchronous reset */
+               VGAwSEQ (0x01, tmp | 0x20);     /* disable the display */
+
+               VGAenablePalette();
+       } else {
+               /*
+                * Reenable sequencer, then turn on screen.
+                */
+
+               tmp = VGArSEQ (0x01);
+
+               VGAwSEQ (0x01, tmp & ~0x20);    /* reenable display */
+               vgaHWSeqReset (par, 0);         /* clear synchronous reset */
+
+               VGAdisablePalette();
+       }
+}
+
+static void vgaHWRestore (struct savagefb_par  *par)
+{
+       int i;
+
+       VGAwMISC (par->MiscOutReg);
+
+       for (i = 1; i < 5; i++)
+               VGAwSEQ (i, par->Sequencer[i]);
+
+       /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
+          CRTC[17] */
+       VGAwCR (17, par->CRTC[17] & ~0x80);
+
+       for (i = 0; i < 25; i++)
+               VGAwCR (i, par->CRTC[i]);
+
+       for (i = 0; i < 9; i++)
+               VGAwGR (i, par->Graphics[i]);
+
+       VGAenablePalette();
+
+       for (i = 0; i < 21; i++)
+               VGAwATTR (i, par->Attribute[i]);
+
+       VGAdisablePalette();
+}
+
+static void vgaHWInit (struct fb_var_screeninfo *var,
+                      struct savagefb_par            *par,
+                      struct xtimings                *timings)
+{
+       par->MiscOutReg = 0x23;
+
+       if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+               par->MiscOutReg |= 0x40;
+
+       if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+               par->MiscOutReg |= 0x80;
+
+       /*
+        * Time Sequencer
+        */
+       par->Sequencer[0x00] = 0x00;
+       par->Sequencer[0x01] = 0x01;
+       par->Sequencer[0x02] = 0x0F;
+       par->Sequencer[0x03] = 0x00;          /* Font select */
+       par->Sequencer[0x04] = 0x0E;          /* Misc */
+
+       /*
+        * CRTC Controller
+        */
+       par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
+       par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
+       par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
+       par->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
+       par->CRTC[0x04] = (timings->HSyncStart >> 3);
+       par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
+               (((timings->HSyncEnd >> 3)) & 0x1f);
+       par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
+       par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
+               (((timings->VDisplay - 1) & 0x100) >> 7) |
+               ((timings->VSyncStart & 0x100) >> 6) |
+               (((timings->VSyncStart - 1) & 0x100) >> 5) |
+               0x10 |
+               (((timings->VTotal - 2) & 0x200) >> 4) |
+               (((timings->VDisplay - 1) & 0x200) >> 3) |
+               ((timings->VSyncStart & 0x200) >> 2);
+       par->CRTC[0x08] = 0x00;
+       par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
+
+       if (timings->dblscan)
+               par->CRTC[0x09] |= 0x80;
+
+       par->CRTC[0x0a] = 0x00;
+       par->CRTC[0x0b] = 0x00;
+       par->CRTC[0x0c] = 0x00;
+       par->CRTC[0x0d] = 0x00;
+       par->CRTC[0x0e] = 0x00;
+       par->CRTC[0x0f] = 0x00;
+       par->CRTC[0x10] = timings->VSyncStart & 0xff;
+       par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
+       par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
+       par->CRTC[0x13] = var->xres_virtual >> 4;
+       par->CRTC[0x14] = 0x00;
+       par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
+       par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
+       par->CRTC[0x17] = 0xc3;
+       par->CRTC[0x18] = 0xff;
+
+       /*
+        * are these unnecessary?
+        * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+        * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+        */
+
+       /*
+        * Graphics Display Controller
+        */
+       par->Graphics[0x00] = 0x00;
+       par->Graphics[0x01] = 0x00;
+       par->Graphics[0x02] = 0x00;
+       par->Graphics[0x03] = 0x00;
+       par->Graphics[0x04] = 0x00;
+       par->Graphics[0x05] = 0x40;
+       par->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
+       par->Graphics[0x07] = 0x0F;
+       par->Graphics[0x08] = 0xFF;
+
+
+       par->Attribute[0x00]  = 0x00; /* standard colormap translation */
+       par->Attribute[0x01]  = 0x01;
+       par->Attribute[0x02]  = 0x02;
+       par->Attribute[0x03]  = 0x03;
+       par->Attribute[0x04]  = 0x04;
+       par->Attribute[0x05]  = 0x05;
+       par->Attribute[0x06]  = 0x06;
+       par->Attribute[0x07]  = 0x07;
+       par->Attribute[0x08]  = 0x08;
+       par->Attribute[0x09]  = 0x09;
+       par->Attribute[0x0a] = 0x0A;
+       par->Attribute[0x0b] = 0x0B;
+       par->Attribute[0x0c] = 0x0C;
+       par->Attribute[0x0d] = 0x0D;
+       par->Attribute[0x0e] = 0x0E;
+       par->Attribute[0x0f] = 0x0F;
+       par->Attribute[0x10] = 0x41;
+       par->Attribute[0x11] = 0xFF;
+       par->Attribute[0x12] = 0x0F;
+       par->Attribute[0x13] = 0x00;
+       par->Attribute[0x14] = 0x00;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for SavageFB
+ */
+
+/* Wait for fifo space */
+static void
+savage3D_waitfifo(struct savagefb_par *par, int space)
+{
+       int slots = MAXFIFO - space;
+
+       while ((savage_in32(0x48C00) & 0x0000ffff) > slots);
+}
+
+static void
+savage4_waitfifo(struct savagefb_par *par, int space)
+{
+       int slots = MAXFIFO - space;
+
+       while ((savage_in32(0x48C60) & 0x001fffff) > slots);
+}
+
+static void
+savage2000_waitfifo(struct savagefb_par *par, int space)
+{
+       int slots = MAXFIFO - space;
+
+       while ((savage_in32(0x48C60) & 0x0000ffff) > slots);
+}
+
+/* Wait for idle accelerator */
+static void
+savage3D_waitidle(struct savagefb_par *par)
+{
+       while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000);
+}
+
+static void
+savage4_waitidle(struct savagefb_par *par)
+{
+       while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000);
+}
+
+static void
+savage2000_waitidle(struct savagefb_par *par)
+{
+       while ((savage_in32(0x48C60) & 0x009fffff));
+}
+
+
+static void
+SavageSetup2DEngine (struct savagefb_par  *par)
+{
+       unsigned long GlobalBitmapDescriptor;
+
+       GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
+       BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
+       BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
+
+       switch(par->chip) {
+       case S3_SAVAGE3D:
+       case S3_SAVAGE_MX:
+               /* Disable BCI */
+               savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+               /* Setup BCI command overflow buffer */
+               savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29));
+               /* Program shadow status update. */
+               savage_out32(0x48C10, 0x78207220);
+               savage_out32(0x48C0C, 0);
+               /* Enable BCI and command overflow buffer */
+               savage_out32(0x48C18, savage_in32(0x48C18) | 0x0C);
+               break;
+       case S3_SAVAGE4:
+       case S3_PROSAVAGE:
+       case S3_SUPERSAVAGE:
+               /* Disable BCI */
+               savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+               /* Program shadow status update */
+               savage_out32(0x48C10, 0x00700040);
+               savage_out32(0x48C0C, 0);
+               /* Enable BCI without the COB */
+               savage_out32(0x48C18, savage_in32(0x48C18) | 0x08);
+               break;
+       case S3_SAVAGE2000:
+               /* Disable BCI */
+               savage_out32(0x48C18, 0);
+               /* Setup BCI command overflow buffer */
+               savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index));
+               /* Disable shadow status update */
+               savage_out32(0x48A30, 0);
+               /* Enable BCI and command overflow buffer */
+               savage_out32(0x48C18, savage_in32(0x48C18) | 0x00280000 );
+               break;
+           default:
+               break;
+       }
+       /* Turn on 16-bit register access. */
+       vga_out8(0x3d4, 0x31);
+       vga_out8(0x3d5, 0x0c);
+
+       /* Set stride to use GBD. */
+       vga_out8 (0x3d4, 0x50);
+       vga_out8 (0x3d5, vga_in8 (0x3d5 ) | 0xC1);
+
+       /* Enable 2D engine. */
+       vga_out8 (0x3d4, 0x40 );
+       vga_out8 (0x3d5, 0x01 );
+
+       savage_out32 (MONO_PAT_0, ~0);
+       savage_out32 (MONO_PAT_1, ~0);
+
+       /* Setup plane masks */
+       savage_out32 (0x8128, ~0 ); /* enable all write planes */
+       savage_out32 (0x812C, ~0 ); /* enable all read planes */
+       savage_out16 (0x8134, 0x27 );
+       savage_out16 (0x8136, 0x07 );
+
+       /* Now set the GBD */
+       par->bci_ptr = 0;
+       par->SavageWaitFifo (par, 4);
+
+       BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
+       BCI_SEND( 0 );
+       BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
+       BCI_SEND( GlobalBitmapDescriptor );
+}
+
+
+static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
+                           int min_n2, int max_n2, long freq_min,
+                           long freq_max, unsigned int *mdiv,
+                           unsigned int *ndiv, unsigned int *r)
+{
+       long diff, best_diff;
+       unsigned int m;
+       unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
+
+       if (freq < freq_min / (1 << max_n2)) {
+               printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+               freq = freq_min / (1 << max_n2);
+       }
+       if (freq > freq_max / (1 << min_n2)) {
+               printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+               freq = freq_max / (1 << min_n2);
+       }
+
+       /* work out suitable timings */
+       best_diff = freq;
+
+       for (n2=min_n2; n2<=max_n2; n2++) {
+               for (n1=min_n1+2; n1<=max_n1+2; n1++) {
+                       m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
+                               BASE_FREQ;
+                       if (m < min_m+2 || m > 127+2)
+                               continue;
+                       if ((m * BASE_FREQ >= freq_min * n1) &&
+                           (m * BASE_FREQ <= freq_max * n1)) {
+                               diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
+                               if (diff < 0)
+                                       diff = -diff;
+                               if (diff < best_diff) {
+                                       best_diff = diff;
+                                       best_m = m;
+                                       best_n1 = n1;
+                                       best_n2 = n2;
+                               }
+                       }
+               }
+       }
+
+       *ndiv = best_n1 - 2;
+       *r = best_n2;
+       *mdiv = best_m - 2;
+}
+
+static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
+                            int min_n2, int max_n2, long freq_min,
+                            long freq_max, unsigned char *mdiv,
+                            unsigned char *ndiv)
+{
+       long diff, best_diff;
+       unsigned int m;
+       unsigned char n1, n2;
+       unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2;
+
+       best_diff = freq;
+
+       for (n2 = min_n2; n2 <= max_n2; n2++) {
+               for (n1 = min_n1+2; n1 <= max_n1+2; n1++) {
+                       m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
+                               BASE_FREQ;
+                       if (m < min_m + 2 || m > 127+2)
+                               continue;
+                       if((m * BASE_FREQ >= freq_min * n1) &&
+                          (m * BASE_FREQ <= freq_max * n1)) {
+                               diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
+                               if(diff < 0)
+                                       diff = -diff;
+                               if(diff < best_diff) {
+                                       best_diff = diff;
+                                       best_m = m;
+                                       best_n1 = n1;
+                                       best_n2 = n2;
+                               }
+                       }
+               }
+       }
+
+       if(max_n1 == 63)
+               *ndiv = (best_n1 - 2) | (best_n2 << 6);
+       else
+               *ndiv = (best_n1 - 2) | (best_n2 << 5);
+
+       *mdiv = best_m - 2;
+
+       return 0;
+}
+
+#ifdef SAVAGEFB_DEBUG
+/* This function is used to debug, it prints out the contents of s3 regs */
+
+static void SavagePrintRegs(void)
+{
+       unsigned char i;
+       int vgaCRIndex = 0x3d4;
+       int vgaCRReg = 0x3d5;
+
+       printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
+              "xF" );
+
+       for( i = 0; i < 0x70; i++ ) {
+               if( !(i % 16) )
+                       printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
+               vga_out8( 0x3c4, i );
+               printk(KERN_DEBUG " %02x", vga_in8(0x3c5) );
+       }
+
+       printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
+              "xD xE xF" );
+
+       for( i = 0; i < 0xB7; i++ ) {
+               if( !(i % 16) )
+                       printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
+               vga_out8( vgaCRIndex, i );
+               printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg) );
+       }
+
+       printk(KERN_DEBUG "\n\n");
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static void savage_get_default_par(struct savagefb_par *par)
+{
+       unsigned char cr3a, cr53, cr66;
+
+       vga_out16 (0x3d4, 0x4838);
+       vga_out16 (0x3d4, 0xa039);
+       vga_out16 (0x3c4, 0x0608);
+
+       vga_out8 (0x3d4, 0x66);
+       cr66 = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr66 | 0x80);
+       vga_out8 (0x3d4, 0x3a);
+       cr3a = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr3a | 0x80);
+       vga_out8 (0x3d4, 0x53);
+       cr53 = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr53 & 0x7f);
+
+       vga_out8 (0x3d4, 0x66);
+       vga_out8 (0x3d5, cr66);
+       vga_out8 (0x3d4, 0x3a);
+       vga_out8 (0x3d5, cr3a);
+
+       vga_out8 (0x3d4, 0x66);
+       vga_out8 (0x3d5, cr66);
+       vga_out8 (0x3d4, 0x3a);
+       vga_out8 (0x3d5, cr3a);
+
+       /* unlock extended seq regs */
+       vga_out8 (0x3c4, 0x08);
+       par->SR08 = vga_in8 (0x3c5);
+       vga_out8 (0x3c5, 0x06);
+
+       /* now save all the extended regs we need */
+       vga_out8 (0x3d4, 0x31);
+       par->CR31 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x32);
+       par->CR32 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x34);
+       par->CR34 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x36);
+       par->CR36 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x3a);
+       par->CR3A = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x40);
+       par->CR40 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x42);
+       par->CR42 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x45);
+       par->CR45 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x50);
+       par->CR50 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x51);
+       par->CR51 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x53);
+       par->CR53 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x58);
+       par->CR58 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x60);
+       par->CR60 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x66);
+       par->CR66 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x67);
+       par->CR67 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x68);
+       par->CR68 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x69);
+       par->CR69 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x6f);
+       par->CR6F = vga_in8 (0x3d5);
+
+       vga_out8 (0x3d4, 0x33);
+       par->CR33 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x86);
+       par->CR86 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x88);
+       par->CR88 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x90);
+       par->CR90 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x91);
+       par->CR91 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0xb0);
+       par->CRB0 = vga_in8 (0x3d5) | 0x80;
+
+       /* extended mode timing regs */
+       vga_out8 (0x3d4, 0x3b);
+       par->CR3B = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x3c);
+       par->CR3C = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x43);
+       par->CR43 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x5d);
+       par->CR5D = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x5e);
+       par->CR5E = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x65);
+       par->CR65 = vga_in8 (0x3d5);
+
+       /* save seq extended regs for DCLK PLL programming */
+       vga_out8 (0x3c4, 0x0e);
+       par->SR0E = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x0f);
+       par->SR0F = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x10);
+       par->SR10 = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x11);
+       par->SR11 = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x12);
+       par->SR12 = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x13);
+       par->SR13 = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x29);
+       par->SR29 = vga_in8 (0x3c5);
+
+       vga_out8 (0x3c4, 0x15);
+       par->SR15 = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x30);
+       par->SR30 = vga_in8 (0x3c5);
+       vga_out8 (0x3c4, 0x18);
+       par->SR18 = vga_in8 (0x3c5);
+
+       /* Save flat panel expansion regsters. */
+       if (par->chip == S3_SAVAGE_MX) {
+               int i;
+
+               for (i = 0; i < 8; i++) {
+                       vga_out8 (0x3c4, 0x54+i);
+                       par->SR54[i] = vga_in8 (0x3c5);
+               }
+       }
+
+       vga_out8 (0x3d4, 0x66);
+       cr66 = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr66 | 0x80);
+       vga_out8 (0x3d4, 0x3a);
+       cr3a = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr3a | 0x80);
+
+       /* now save MIU regs */
+       if (par->chip != S3_SAVAGE_MX) {
+               par->MMPR0 = savage_in32(FIFO_CONTROL_REG);
+               par->MMPR1 = savage_in32(MIU_CONTROL_REG);
+               par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG);
+               par->MMPR3 = savage_in32(MISC_TIMEOUT_REG);
+       }
+
+       vga_out8 (0x3d4, 0x3a);
+       vga_out8 (0x3d5, cr3a);
+       vga_out8 (0x3d4, 0x66);
+       vga_out8 (0x3d5, cr66);
+}
+
+static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
+{
+       var->xres = var->xres_virtual = modedb->xres;
+       var->yres = modedb->yres;
+        if (var->yres_virtual < var->yres)
+           var->yres_virtual = var->yres;
+        var->xoffset = var->yoffset = 0;
+        var->pixclock = modedb->pixclock;
+        var->left_margin = modedb->left_margin;
+        var->right_margin = modedb->right_margin;
+        var->upper_margin = modedb->upper_margin;
+        var->lower_margin = modedb->lower_margin;
+        var->hsync_len = modedb->hsync_len;
+        var->vsync_len = modedb->vsync_len;
+        var->sync = modedb->sync;
+        var->vmode = modedb->vmode;
+}
+
+static int savagefb_check_var (struct fb_var_screeninfo   *var,
+                              struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int memlen, vramlen, mode_valid = 0;
+
+       DBG("savagefb_check_var");
+
+       var->transp.offset = 0;
+       var->transp.length = 0;
+       switch (var->bits_per_pixel) {
+       case 8:
+               var->red.offset = var->green.offset =
+                       var->blue.offset = 0;
+               var->red.length = var->green.length =
+                       var->blue.length = var->bits_per_pixel;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->red.length = 5;
+               var->green.offset = 5;
+               var->green.length = 6;
+               var->blue.offset = 0;
+               var->blue.length = 5;
+               break;
+       case 32:
+               var->transp.offset = 24;
+               var->transp.length = 8;
+               var->red.offset = 16;
+               var->red.length = 8;
+               var->green.offset = 8;
+               var->green.length = 8;
+               var->blue.offset = 0;
+               var->blue.length = 8;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
+           !info->monspecs.dclkmax || !fb_validate_mode(var, info))
+               mode_valid = 1;
+
+       /* calculate modeline if supported by monitor */
+       if (!mode_valid && info->monspecs.gtf) {
+               if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+                       mode_valid = 1;
+       }
+
+       if (!mode_valid) {
+               struct fb_videomode *mode;
+
+               mode = fb_find_best_mode(var, &info->modelist);
+               if (mode) {
+                       savage_update_var(var, mode);
+                       mode_valid = 1;
+               }
+       }
+
+       if (!mode_valid && info->monspecs.modedb_len)
+               return -EINVAL;
+
+       /* Is the mode larger than the LCD panel? */
+       if (par->SavagePanelWidth &&
+           (var->xres > par->SavagePanelWidth ||
+            var->yres > par->SavagePanelHeight)) {
+               printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
+                       "(%dx%d)\n", var->xres,  var->yres,
+                       par->SavagePanelWidth,
+                       par->SavagePanelHeight);
+               return -1;
+       }
+
+       if (var->yres_virtual < var->yres)
+               var->yres_virtual = var->yres;
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
+
+       vramlen = info->fix.smem_len;
+
+       memlen = var->xres_virtual * var->bits_per_pixel *
+               var->yres_virtual / 8;
+       if (memlen > vramlen) {
+               var->yres_virtual = vramlen * 8 /
+                       (var->xres_virtual * var->bits_per_pixel);
+               memlen = var->xres_virtual * var->bits_per_pixel *
+                       var->yres_virtual / 8;
+       }
+
+       /* we must round yres/xres down, we already rounded y/xres_virtual up
+          if it was possible. We should return -EINVAL, but I disagree */
+       if (var->yres_virtual < var->yres)
+               var->yres = var->yres_virtual;
+       if (var->xres_virtual < var->xres)
+               var->xres = var->xres_virtual;
+       if (var->xoffset + var->xres > var->xres_virtual)
+               var->xoffset = var->xres_virtual - var->xres;
+       if (var->yoffset + var->yres > var->yres_virtual)
+               var->yoffset = var->yres_virtual - var->yres;
+
+       return 0;
+}
+
+
+static int savagefb_decode_var (struct fb_var_screeninfo   *var,
+                               struct savagefb_par        *par)
+{
+       struct xtimings timings;
+       int width, dclk, i, j; /*, refresh; */
+       unsigned int m, n, r;
+       unsigned char tmp = 0;
+       unsigned int pixclock = var->pixclock;
+
+       DBG("savagefb_decode_var");
+
+       memset (&timings, 0, sizeof(timings));
+
+       if (!pixclock) pixclock = 10000;        /* 10ns = 100MHz */
+       timings.Clock = 1000000000 / pixclock;
+       if (timings.Clock < 1) timings.Clock = 1;
+       timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+       timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+       timings.HDisplay = var->xres;
+       timings.HSyncStart = timings.HDisplay + var->right_margin;
+       timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+       timings.HTotal = timings.HSyncEnd + var->left_margin;
+       timings.VDisplay = var->yres;
+       timings.VSyncStart = timings.VDisplay + var->lower_margin;
+       timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+       timings.VTotal = timings.VSyncEnd + var->upper_margin;
+       timings.sync = var->sync;
+
+
+       par->depth  = var->bits_per_pixel;
+       par->vwidth = var->xres_virtual;
+
+       if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {
+               timings.HDisplay *= 2;
+               timings.HSyncStart *= 2;
+               timings.HSyncEnd *= 2;
+               timings.HTotal *= 2;
+       }
+
+       /*
+        * This will allocate the datastructure and initialize all of the
+        * generic VGA registers.
+        */
+       vgaHWInit (var, par, &timings);
+
+       /* We need to set CR67 whether or not we use the BIOS. */
+
+       dclk = timings.Clock;
+       par->CR67 = 0x00;
+
+       switch( var->bits_per_pixel ) {
+       case 8:
+               if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
+                       par->CR67 = 0x10;       /* 8bpp, 2 pixels/clock */
+               else
+                       par->CR67 = 0x00;       /* 8bpp, 1 pixel/clock */
+               break;
+       case 15:
+               if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+                    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
+                       par->CR67 = 0x30;       /* 15bpp, 2 pixel/clock */
+               else
+                       par->CR67 = 0x20;       /* 15bpp, 1 pixels/clock */
+               break;
+       case 16:
+               if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+                   ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
+                       par->CR67 = 0x50;       /* 16bpp, 2 pixel/clock */
+               else
+                       par->CR67 = 0x40;       /* 16bpp, 1 pixels/clock */
+               break;
+       case 24:
+               par->CR67 = 0x70;
+               break;
+       case 32:
+               par->CR67 = 0xd0;
+               break;
+       }
+
+       /*
+        * Either BIOS use is disabled, or we failed to find a suitable
+        * match.  Fall back to traditional register-crunching.
+        */
+
+       vga_out8 (0x3d4, 0x3a);
+       tmp = vga_in8 (0x3d5);
+       if (1 /*FIXME:psav->pci_burst*/)
+               par->CR3A = (tmp & 0x7f) | 0x15;
+       else
+               par->CR3A = tmp | 0x95;
+
+       par->CR53 = 0x00;
+       par->CR31 = 0x8c;
+       par->CR66 = 0x89;
+
+       vga_out8 (0x3d4, 0x58);
+       par->CR58 = vga_in8 (0x3d5) & 0x80;
+       par->CR58 |= 0x13;
+
+       par->SR15 = 0x03 | 0x80;
+       par->SR18 = 0x00;
+       par->CR43 = par->CR45 = par->CR65 = 0x00;
+
+       vga_out8 (0x3d4, 0x40);
+       par->CR40 = vga_in8 (0x3d5) & ~0x01;
+
+       par->MMPR0 = 0x010400;
+       par->MMPR1 = 0x00;
+       par->MMPR2 = 0x0808;
+       par->MMPR3 = 0x08080810;
+
+       SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
+       /* m = 107; n = 4; r = 2; */
+
+       if (par->MCLK <= 0) {
+               par->SR10 = 255;
+               par->SR11 = 255;
+       } else {
+               common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
+                                  &par->SR11, &par->SR10);
+               /*      par->SR10 = 80; // MCLK == 286000 */
+               /*      par->SR11 = 125; */
+       }
+
+       par->SR12 = (r << 6) | (n & 0x3f);
+       par->SR13 = m & 0xff;
+       par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
+
+       if (var->bits_per_pixel < 24)
+               par->MMPR0 -= 0x8000;
+       else
+               par->MMPR0 -= 0x4000;
+
+       if (timings.interlaced)
+               par->CR42 = 0x20;
+       else
+               par->CR42 = 0x00;
+
+       par->CR34 = 0x10; /* display fifo */
+
+       i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
+               ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
+               ((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
+               ((timings.HSyncStart & 0x800) >> 7);
+
+       if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
+               i |= 0x08;
+       if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
+               i |= 0x20;
+
+       j = (par->CRTC[0] + ((i & 0x01) << 8) +
+            par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
+
+       if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
+               if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
+                   par->CRTC[0] + ((i & 0x01) << 8))
+                       j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
+               else
+                       j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
+       }
+
+       par->CR3B = j & 0xff;
+       i |= (j & 0x100) >> 2;
+       par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
+       par->CR5D = i;
+       par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
+               (((timings.VDisplay - 1) & 0x400) >> 9) |
+               (((timings.VSyncStart) & 0x400) >> 8) |
+               (((timings.VSyncStart) & 0x400) >> 6) | 0x40;
+       width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
+       par->CR91 = par->CRTC[19] = 0xff & width;
+       par->CR51 = (0x300 & width) >> 4;
+       par->CR90 = 0x80 | (width >> 8);
+       par->MiscOutReg |= 0x0c;
+
+       /* Set frame buffer description. */
+
+       if (var->bits_per_pixel <= 8)
+               par->CR50 = 0;
+       else if (var->bits_per_pixel <= 16)
+               par->CR50 = 0x10;
+       else
+               par->CR50 = 0x30;
+
+       if (var->xres_virtual <= 640)
+               par->CR50 |= 0x40;
+       else if (var->xres_virtual == 800)
+               par->CR50 |= 0x80;
+       else if (var->xres_virtual == 1024)
+               par->CR50 |= 0x00;
+       else if (var->xres_virtual == 1152)
+               par->CR50 |= 0x01;
+       else if (var->xres_virtual == 1280)
+               par->CR50 |= 0xc0;
+       else if (var->xres_virtual == 1600)
+               par->CR50 |= 0x81;
+       else
+               par->CR50 |= 0xc1;      /* Use GBD */
+
+       if( par->chip == S3_SAVAGE2000 )
+               par->CR33 = 0x08;
+       else
+               par->CR33 = 0x20;
+
+       par->CRTC[0x17] = 0xeb;
+
+       par->CR67 |= 1;
+
+       vga_out8(0x3d4, 0x36);
+       par->CR36 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x68);
+       par->CR68 = vga_in8 (0x3d5);
+       par->CR69 = 0;
+       vga_out8 (0x3d4, 0x6f);
+       par->CR6F = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x86);
+       par->CR86 = vga_in8 (0x3d5);
+       vga_out8 (0x3d4, 0x88);
+       par->CR88 = vga_in8 (0x3d5) | 0x08;
+       vga_out8 (0x3d4, 0xb0);
+       par->CRB0 = vga_in8 (0x3d5) | 0x80;
+
+       return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int savagefb_setcolreg(unsigned        regno,
+                             unsigned        red,
+                             unsigned        green,
+                             unsigned        blue,
+                             unsigned        transp,
+                             struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+       if (regno >= NR_PALETTE)
+               return -EINVAL;
+
+       par->palette[regno].red    = red;
+       par->palette[regno].green  = green;
+       par->palette[regno].blue   = blue;
+       par->palette[regno].transp = transp;
+
+       switch (info->var.bits_per_pixel) {
+       case 8:
+               vga_out8 (0x3c8, regno);
+
+               vga_out8 (0x3c9, red   >> 10);
+               vga_out8 (0x3c9, green >> 10);
+               vga_out8 (0x3c9, blue  >> 10);
+               break;
+
+       case 16:
+               if (regno < 16)
+                       ((u32 *)info->pseudo_palette)[regno] =
+                               ((red   & 0xf800)      ) |
+                               ((green & 0xfc00) >>  5) |
+                               ((blue  & 0xf800) >> 11);
+               break;
+
+       case 24:
+               if (regno < 16)
+                       ((u32 *)info->pseudo_palette)[regno] =
+                               ((red    & 0xff00) <<  8) |
+                               ((green  & 0xff00)      ) |
+                               ((blue   & 0xff00) >>  8);
+               break;
+       case 32:
+               if (regno < 16)
+                       ((u32 *)info->pseudo_palette)[regno] =
+                               ((transp & 0xff00) << 16) |
+                               ((red    & 0xff00) <<  8) |
+                               ((green  & 0xff00)      ) |
+                               ((blue   & 0xff00) >>  8);
+               break;
+
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+static void savagefb_set_par_int (struct savagefb_par  *par)
+{
+       unsigned char tmp, cr3a, cr66, cr67;
+
+       DBG ("savagefb_set_par_int");
+
+       par->SavageWaitIdle (par);
+
+       vga_out8 (0x3c2, 0x23);
+
+       vga_out16 (0x3d4, 0x4838);
+       vga_out16 (0x3d4, 0xa539);
+       vga_out16 (0x3c4, 0x0608);
+
+       vgaHWProtect (par, 1);
+
+       /*
+        * Some Savage/MX and /IX systems go nuts when trying to exit the
+        * server after WindowMaker has displayed a gradient background.  I
+        * haven't been able to find what causes it, but a non-destructive
+        * switch to mode 3 here seems to eliminate the issue.
+        */
+
+       VerticalRetraceWait();
+       vga_out8 (0x3d4, 0x67);
+       cr67 = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c); /* no STREAMS yet */
+
+       vga_out8 (0x3d4, 0x23);
+       vga_out8 (0x3d5, 0x00);
+       vga_out8 (0x3d4, 0x26);
+       vga_out8 (0x3d5, 0x00);
+
+       /* restore extended regs */
+       vga_out8 (0x3d4, 0x66);
+       vga_out8 (0x3d5, par->CR66);
+       vga_out8 (0x3d4, 0x3a);
+       vga_out8 (0x3d5, par->CR3A);
+       vga_out8 (0x3d4, 0x31);
+       vga_out8 (0x3d5, par->CR31);
+       vga_out8 (0x3d4, 0x32);
+       vga_out8 (0x3d5, par->CR32);
+       vga_out8 (0x3d4, 0x58);
+       vga_out8 (0x3d5, par->CR58);
+       vga_out8 (0x3d4, 0x53);
+       vga_out8 (0x3d5, par->CR53 & 0x7f);
+
+       vga_out16 (0x3c4, 0x0608);
+
+       /* Restore DCLK registers. */
+
+       vga_out8 (0x3c4, 0x0e);
+       vga_out8 (0x3c5, par->SR0E);
+       vga_out8 (0x3c4, 0x0f);
+       vga_out8 (0x3c5, par->SR0F);
+       vga_out8 (0x3c4, 0x29);
+       vga_out8 (0x3c5, par->SR29);
+       vga_out8 (0x3c4, 0x15);
+       vga_out8 (0x3c5, par->SR15);
+
+       /* Restore flat panel expansion regsters. */
+       if( par->chip == S3_SAVAGE_MX ) {
+               int i;
+
+               for( i = 0; i < 8; i++ ) {
+                       vga_out8 (0x3c4, 0x54+i);
+                       vga_out8 (0x3c5, par->SR54[i]);
+               }
+       }
+
+       vgaHWRestore (par);
+
+       /* extended mode timing registers */
+       vga_out8 (0x3d4, 0x53);
+       vga_out8 (0x3d5, par->CR53);
+       vga_out8 (0x3d4, 0x5d);
+       vga_out8 (0x3d5, par->CR5D);
+       vga_out8 (0x3d4, 0x5e);
+       vga_out8 (0x3d5, par->CR5E);
+       vga_out8 (0x3d4, 0x3b);
+       vga_out8 (0x3d5, par->CR3B);
+       vga_out8 (0x3d4, 0x3c);
+       vga_out8 (0x3d5, par->CR3C);
+       vga_out8 (0x3d4, 0x43);
+       vga_out8 (0x3d5, par->CR43);
+       vga_out8 (0x3d4, 0x65);
+       vga_out8 (0x3d5, par->CR65);
+
+       /* restore the desired video mode with cr67 */
+       vga_out8 (0x3d4, 0x67);
+       /* following part not present in X11 driver */
+       cr67 = vga_in8 (0x3d5) & 0xf;
+       vga_out8 (0x3d5, 0x50 | cr67);
+       udelay (10000);
+       vga_out8 (0x3d4, 0x67);
+       /* end of part */
+       vga_out8 (0x3d5, par->CR67 & ~0x0c);
+
+       /* other mode timing and extended regs */
+       vga_out8 (0x3d4, 0x34);
+       vga_out8 (0x3d5, par->CR34);
+       vga_out8 (0x3d4, 0x40);
+       vga_out8 (0x3d5, par->CR40);
+       vga_out8 (0x3d4, 0x42);
+       vga_out8 (0x3d5, par->CR42);
+       vga_out8 (0x3d4, 0x45);
+       vga_out8 (0x3d5, par->CR45);
+       vga_out8 (0x3d4, 0x50);
+       vga_out8 (0x3d5, par->CR50);
+       vga_out8 (0x3d4, 0x51);
+       vga_out8 (0x3d5, par->CR51);
+
+       /* memory timings */
+       vga_out8 (0x3d4, 0x36);
+       vga_out8 (0x3d5, par->CR36);
+       vga_out8 (0x3d4, 0x60);
+       vga_out8 (0x3d5, par->CR60);
+       vga_out8 (0x3d4, 0x68);
+       vga_out8 (0x3d5, par->CR68);
+       vga_out8 (0x3d4, 0x69);
+       vga_out8 (0x3d5, par->CR69);
+       vga_out8 (0x3d4, 0x6f);
+       vga_out8 (0x3d5, par->CR6F);
+
+       vga_out8 (0x3d4, 0x33);
+       vga_out8 (0x3d5, par->CR33);
+       vga_out8 (0x3d4, 0x86);
+       vga_out8 (0x3d5, par->CR86);
+       vga_out8 (0x3d4, 0x88);
+       vga_out8 (0x3d5, par->CR88);
+       vga_out8 (0x3d4, 0x90);
+       vga_out8 (0x3d5, par->CR90);
+       vga_out8 (0x3d4, 0x91);
+       vga_out8 (0x3d5, par->CR91);
+
+       if (par->chip == S3_SAVAGE4) {
+               vga_out8 (0x3d4, 0xb0);
+               vga_out8 (0x3d5, par->CRB0);
+       }
+
+       vga_out8 (0x3d4, 0x32);
+       vga_out8 (0x3d5, par->CR32);
+
+       /* unlock extended seq regs */
+       vga_out8 (0x3c4, 0x08);
+       vga_out8 (0x3c5, 0x06);
+
+       /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
+        * that we should leave the default SR10 and SR11 values there.
+        */
+       if (par->SR10 != 255) {
+               vga_out8 (0x3c4, 0x10);
+               vga_out8 (0x3c5, par->SR10);
+               vga_out8 (0x3c4, 0x11);
+               vga_out8 (0x3c5, par->SR11);
+       }
+
+       /* restore extended seq regs for dclk */
+       vga_out8 (0x3c4, 0x0e);
+       vga_out8 (0x3c5, par->SR0E);
+       vga_out8 (0x3c4, 0x0f);
+       vga_out8 (0x3c5, par->SR0F);
+       vga_out8 (0x3c4, 0x12);
+       vga_out8 (0x3c5, par->SR12);
+       vga_out8 (0x3c4, 0x13);
+       vga_out8 (0x3c5, par->SR13);
+       vga_out8 (0x3c4, 0x29);
+       vga_out8 (0x3c5, par->SR29);
+
+       vga_out8 (0x3c4, 0x18);
+       vga_out8 (0x3c5, par->SR18);
+
+       /* load new m, n pll values for dclk & mclk */
+       vga_out8 (0x3c4, 0x15);
+       tmp = vga_in8 (0x3c5) & ~0x21;
+
+       vga_out8 (0x3c5, tmp | 0x03);
+       vga_out8 (0x3c5, tmp | 0x23);
+       vga_out8 (0x3c5, tmp | 0x03);
+       vga_out8 (0x3c5, par->SR15);
+       udelay (100);
+
+       vga_out8 (0x3c4, 0x30);
+       vga_out8 (0x3c5, par->SR30);
+       vga_out8 (0x3c4, 0x08);
+       vga_out8 (0x3c5, par->SR08);
+
+       /* now write out cr67 in full, possibly starting STREAMS */
+       VerticalRetraceWait();
+       vga_out8 (0x3d4, 0x67);
+       vga_out8 (0x3d5, par->CR67);
+
+       vga_out8 (0x3d4, 0x66);
+       cr66 = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr66 | 0x80);
+       vga_out8 (0x3d4, 0x3a);
+       cr3a = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr3a | 0x80);
+
+       if (par->chip != S3_SAVAGE_MX) {
+               VerticalRetraceWait();
+               savage_out32 (FIFO_CONTROL_REG, par->MMPR0);
+               par->SavageWaitIdle (par);
+               savage_out32 (MIU_CONTROL_REG, par->MMPR1);
+               par->SavageWaitIdle (par);
+               savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2);
+               par->SavageWaitIdle (par);
+               savage_out32 (MISC_TIMEOUT_REG, par->MMPR3);
+       }
+
+       vga_out8 (0x3d4, 0x66);
+       vga_out8 (0x3d5, cr66);
+       vga_out8 (0x3d4, 0x3a);
+       vga_out8 (0x3d5, cr3a);
+
+       SavageSetup2DEngine (par);
+       vgaHWProtect (par, 0);
+}
+
+static void savagefb_update_start (struct savagefb_par      *par,
+                                  struct fb_var_screeninfo *var)
+{
+       int base;
+
+       base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
+               * ((var->bits_per_pixel+7) / 8)) >> 2;
+
+       /* now program the start address registers */
+       vga_out16(0x3d4, (base & 0x00ff00) | 0x0c);
+       vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d);
+       vga_out8 (0x3d4, 0x69);
+       vga_out8 (0x3d5, (base & 0x7f0000) >> 16);
+}
+
+
+static void savagefb_set_fix(struct fb_info *info)
+{
+       info->fix.line_length = info->var.xres_virtual *
+               info->var.bits_per_pixel / 8;
+
+       if (info->var.bits_per_pixel == 8)
+               info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
+       else
+               info->fix.visual      = FB_VISUAL_TRUECOLOR;
+}
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+static void savagefb_set_clip(struct fb_info *info)
+{
+    struct savagefb_par *par = (struct savagefb_par *)info->par;
+    int cmd;
+
+    cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
+    par->bci_ptr = 0;
+    par->SavageWaitFifo(par,3);
+    BCI_SEND(cmd);
+    BCI_SEND(BCI_CLIP_TL(0, 0));
+    BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
+}
+#endif
+
+static int savagefb_set_par (struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       int err;
+
+       DBG("savagefb_set_par");
+       err = savagefb_decode_var (var, par);
+       if (err)
+               return err;
+
+       if (par->dacSpeedBpp <= 0) {
+               if (var->bits_per_pixel > 24)
+                       par->dacSpeedBpp = par->clock[3];
+               else if (var->bits_per_pixel >= 24)
+                       par->dacSpeedBpp = par->clock[2];
+               else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24))
+                       par->dacSpeedBpp = par->clock[1];
+               else if (var->bits_per_pixel <= 8)
+                       par->dacSpeedBpp = par->clock[0];
+       }
+
+       /* Set ramdac limits */
+       par->maxClock = par->dacSpeedBpp;
+       par->minClock = 10000;
+
+       savagefb_set_par_int (par);
+       savagefb_update_start (par, var);
+       fb_set_cmap (&info->cmap, info);
+       savagefb_set_fix(info);
+       savagefb_set_clip(info);
+
+       SavagePrintRegs();
+       return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int savagefb_pan_display (struct fb_var_screeninfo *var,
+                                struct fb_info           *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       u_int y_bottom;
+
+       y_bottom = var->yoffset;
+
+       if (!(var->vmode & FB_VMODE_YWRAP))
+               y_bottom += var->yres;
+
+       if (var->xoffset > (var->xres_virtual - var->xres))
+               return -EINVAL;
+       if (y_bottom > info->var.yres_virtual)
+               return -EINVAL;
+
+       savagefb_update_start (par, var);
+
+       info->var.xoffset = var->xoffset;
+       info->var.yoffset = var->yoffset;
+
+       if (var->vmode & FB_VMODE_YWRAP)
+               info->var.vmode |= FB_VMODE_YWRAP;
+       else
+               info->var.vmode &= ~FB_VMODE_YWRAP;
+
+       return 0;
+}
+
+
+static struct fb_ops savagefb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = savagefb_check_var,
+       .fb_set_par     = savagefb_set_par,
+       .fb_setcolreg   = savagefb_setcolreg,
+       .fb_pan_display = savagefb_pan_display,
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+       .fb_fillrect    = savagefb_fillrect,
+       .fb_copyarea    = savagefb_copyarea,
+       .fb_imageblit   = savagefb_imageblit,
+       .fb_sync        = savagefb_sync,
+#else
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+#endif
+       .fb_cursor      = soft_cursor,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
+       .accel_flags =  FB_ACCELF_TEXT,
+       .xres =         800,
+       .yres =         600,
+       .xres_virtual =  800,
+       .yres_virtual =  600,
+       .bits_per_pixel = 8,
+       .pixclock =     25000,
+       .left_margin =  88,
+       .right_margin = 40,
+       .upper_margin = 23,
+       .lower_margin = 1,
+       .hsync_len =    128,
+       .vsync_len =    4,
+       .sync =         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .vmode =        FB_VMODE_NONINTERLACED
+};
+
+static void savage_enable_mmio (struct savagefb_par *par)
+{
+       unsigned char val;
+
+       DBG ("savage_enable_mmio\n");
+
+       val = vga_in8 (0x3c3);
+       vga_out8 (0x3c3, val | 0x01);
+       val = vga_in8 (0x3cc);
+       vga_out8 (0x3c2, val | 0x01);
+
+       if (par->chip >= S3_SAVAGE4) {
+               vga_out8 (0x3d4, 0x40);
+               val = vga_in8 (0x3d5);
+               vga_out8 (0x3d5, val | 1);
+       }
+}
+
+
+void savage_disable_mmio (struct savagefb_par *par)
+{
+       unsigned char val;
+
+       DBG ("savage_disable_mmio\n");
+
+       if(par->chip >= S3_SAVAGE4 ) {
+               vga_out8 (0x3d4, 0x40);
+               val = vga_in8 (0x3d5);
+               vga_out8 (0x3d5, val | 1);
+       }
+}
+
+
+static int __devinit savage_map_mmio (struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       DBG ("savage_map_mmio");
+
+       if (S3_SAVAGE3D_SERIES (par->chip))
+               par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+                       SAVAGE_NEWMMIO_REGBASE_S3;
+       else
+               par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+                       SAVAGE_NEWMMIO_REGBASE_S4;
+
+       par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
+
+       par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
+       if (!par->mmio.vbase) {
+               printk ("savagefb: unable to map memory mapped IO\n");
+               return -ENOMEM;
+       } else
+               printk (KERN_INFO "savagefb: mapped io at %p\n",
+                       par->mmio.vbase);
+
+       info->fix.mmio_start = par->mmio.pbase;
+       info->fix.mmio_len   = par->mmio.len;
+
+       par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
+       par->bci_ptr  = 0;
+
+       savage_enable_mmio (par);
+
+       return 0;
+}
+
+static void __devinit savage_unmap_mmio (struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       DBG ("savage_unmap_mmio");
+
+       savage_disable_mmio(par);
+
+       if (par->mmio.vbase) {
+               iounmap ((void __iomem *)par->mmio.vbase);
+               par->mmio.vbase = NULL;
+       }
+}
+
+static int __devinit savage_map_video (struct fb_info *info,
+                                      int video_len)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int resource;
+
+       DBG("savage_map_video");
+
+       if (S3_SAVAGE3D_SERIES (par->chip))
+               resource = 0;
+       else
+               resource = 1;
+
+       par->video.pbase = pci_resource_start (par->pcidev, resource);
+       par->video.len   = video_len;
+       par->video.vbase = ioremap (par->video.pbase, par->video.len);
+
+       if (!par->video.vbase) {
+               printk ("savagefb: unable to map screen memory\n");
+               return -ENOMEM;
+       } else
+               printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
+                       "pbase == %x\n", par->video.vbase, par->video.pbase);
+
+       info->fix.smem_start = par->video.pbase;
+       info->fix.smem_len   = par->video.len - par->cob_size;
+       info->screen_base    = par->video.vbase;
+
+#ifdef CONFIG_MTRR
+       par->video.mtrr = mtrr_add (par->video.pbase, video_len,
+                                    MTRR_TYPE_WRCOMB, 1);
+#endif
+       return 0;
+}
+
+static void __devinit savage_unmap_video (struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+       DBG("savage_unmap_video");
+
+       if (par->video.vbase) {
+#ifdef CONFIG_MTRR
+               mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
+#endif
+
+               iounmap (par->video.vbase);
+               par->video.vbase = NULL;
+               info->screen_base = NULL;
+       }
+}
+
+static int __devinit savage_init_hw (struct savagefb_par *par)
+{
+       unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
+
+       static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
+       static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
+       static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+       static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
+
+       int videoRam, videoRambytes;
+
+       DBG("savage_init_hw");
+
+       /* unprotect CRTC[0-7] */
+       vga_out8(0x3d4, 0x11);
+       tmp = vga_in8(0x3d5);
+       vga_out8(0x3d5, tmp & 0x7f);
+
+       /* unlock extended regs */
+       vga_out16(0x3d4, 0x4838);
+       vga_out16(0x3d4, 0xa039);
+       vga_out16(0x3c4, 0x0608);
+
+       vga_out8(0x3d4, 0x40);
+       tmp = vga_in8(0x3d5);
+       vga_out8(0x3d5, tmp & ~0x01);
+
+       /* unlock sys regs */
+       vga_out8(0x3d4, 0x38);
+       vga_out8(0x3d5, 0x48);
+
+       /* Unlock system registers. */
+       vga_out16(0x3d4, 0x4838);
+
+       /* Next go on to detect amount of installed ram */
+
+       vga_out8(0x3d4, 0x36);            /* for register CR36 (CONFG_REG1), */
+       config1 = vga_in8(0x3d5);           /* get amount of vram installed */
+
+       /* Compute the amount of video memory and offscreen memory. */
+
+       switch  (par->chip) {
+       case S3_SAVAGE3D:
+               videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
+               break;
+
+       case S3_SAVAGE4:
+               /*
+                * The Savage4 has one ugly special case to consider.  On
+                * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
+                * when it really means 8MB.  Why do it the same when you
+                * can do it different...
+                */
+               vga_out8(0x3d4, 0x68);  /* memory control 1 */
+               if( (vga_in8(0x3d5) & 0xC0) == (0x01 << 6) )
+                       RamSavage4[1] = 8;
+
+               /*FALLTHROUGH*/
+
+       case S3_SAVAGE2000:
+               videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
+               break;
+
+       case S3_SAVAGE_MX:
+       case S3_SUPERSAVAGE:
+               videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
+               break;
+
+       case S3_PROSAVAGE:
+               videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
+               break;
+
+       default:
+               /* How did we get here? */
+               videoRam = 0;
+               break;
+       }
+
+       videoRambytes = videoRam * 1024;
+
+       printk (KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
+
+       /* reset graphics engine to avoid memory corruption */
+       vga_out8 (0x3d4, 0x66);
+       cr66 = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr66 | 0x02);
+       udelay (10000);
+
+       vga_out8 (0x3d4, 0x66);
+       vga_out8 (0x3d5, cr66 & ~0x02); /* clear reset flag */
+       udelay (10000);
+
+
+       /*
+        * reset memory interface, 3D engine, AGP master, PCI master,
+        * master engine unit, motion compensation/LPB
+        */
+       vga_out8 (0x3d4, 0x3f);
+       cr3f = vga_in8 (0x3d5);
+       vga_out8 (0x3d5, cr3f | 0x08);
+       udelay (10000);
+
+       vga_out8 (0x3d4, 0x3f);
+       vga_out8 (0x3d5, cr3f & ~0x08); /* clear reset flags */
+       udelay (10000);
+
+       /* Savage ramdac speeds */
+       par->numClocks = 4;
+       par->clock[0] = 250000;
+       par->clock[1] = 250000;
+       par->clock[2] = 220000;
+       par->clock[3] = 220000;
+
+       /* detect current mclk */
+       vga_out8(0x3c4, 0x08);
+       sr8 = vga_in8(0x3c5);
+       vga_out8(0x3c5, 0x06);
+       vga_out8(0x3c4, 0x10);
+       n = vga_in8(0x3c5);
+       vga_out8(0x3c4, 0x11);
+       m = vga_in8(0x3c5);
+       vga_out8(0x3c4, 0x08);
+       vga_out8(0x3c5, sr8);
+       m &= 0x7f;
+       n1 = n & 0x1f;
+       n2 = (n >> 5) & 0x03;
+       par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
+       printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
+               par->MCLK);
+
+       /* Check LCD panel parrmation */
+
+       if (par->chip == S3_SAVAGE_MX) {
+               unsigned char cr6b = VGArCR( 0x6b );
+
+               int panelX = (VGArSEQ (0x61) +
+                             ((VGArSEQ (0x66) & 0x02) << 7) + 1) * 8;
+               int panelY = (VGArSEQ (0x69) +
+                             ((VGArSEQ (0x6e) & 0x70) << 4) + 1);
+
+               char * sTechnology = "Unknown";
+
+               /* OK, I admit it.  I don't know how to limit the max dot clock
+                * for LCD panels of various sizes.  I thought I copied the
+                * formula from the BIOS, but many users have parrmed me of
+                * my folly.
+                *
+                * Instead, I'll abandon any attempt to automatically limit the
+                * clock, and add an LCDClock option to XF86Config.  Some day,
+                * I should come back to this.
+                */
+
+               enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
+                       ActiveCRT = 0x01,
+                       ActiveLCD = 0x02,
+                       ActiveTV = 0x04,
+                       ActiveCRT2 = 0x20,
+                       ActiveDUO = 0x80
+               };
+
+               if ((VGArSEQ (0x39) & 0x03) == 0) {
+                       sTechnology = "TFT";
+               } else if ((VGArSEQ (0x30) & 0x01) == 0) {
+                       sTechnology = "DSTN";
+               } else  {
+                       sTechnology = "STN";
+               }
+
+               printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
+                       panelX, panelY, sTechnology,
+                       cr6b & ActiveLCD ? "and active" : "but not active");
+
+               if( cr6b & ActiveLCD )  {
+                       /*
+                        * If the LCD is active and panel expansion is enabled,
+                        * we probably want to kill the HW cursor.
+                        */
+
+                       printk (KERN_INFO "savagefb: Limiting video mode to "
+                               "%dx%d\n", panelX, panelY );
+
+                       par->SavagePanelWidth = panelX;
+                       par->SavagePanelHeight = panelY;
+
+               }
+       }
+
+       savage_get_default_par (par);
+
+       if( S3_SAVAGE4_SERIES(par->chip) ) {
+               /*
+                * The Savage4 and ProSavage have COB coherency bugs which
+                * render the buffer useless.  We disable it.
+                */
+               par->cob_index = 2;
+               par->cob_size = 0x8000 << par->cob_index;
+               par->cob_offset = videoRambytes;
+       } else {
+               /* We use 128kB for the COB on all chips. */
+
+               par->cob_index  = 7;
+               par->cob_size   = 0x400 << par->cob_index;
+               par->cob_offset = videoRambytes - par->cob_size;
+       }
+
+       return videoRambytes;
+}
+
+static int __devinit savage_init_fb_info (struct fb_info *info,
+                                         struct pci_dev *dev,
+                                         const struct pci_device_id *id)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int err = 0;
+
+       par->pcidev  = dev;
+
+       info->fix.type     = FB_TYPE_PACKED_PIXELS;
+       info->fix.type_aux         = 0;
+       info->fix.xpanstep         = 2;
+       info->fix.ypanstep         = 1;
+       info->fix.ywrapstep   = 0;
+       info->fix.accel       = id->driver_data;
+
+       switch (info->fix.accel) {
+       case FB_ACCEL_SUPERSAVAGE:
+               par->chip = S3_SUPERSAVAGE;
+               snprintf (info->fix.id, 16, "SuperSavage");
+               break;
+       case FB_ACCEL_SAVAGE4:
+               par->chip = S3_SAVAGE4;
+               snprintf (info->fix.id, 16, "Savage4");
+               break;
+       case FB_ACCEL_SAVAGE3D:
+               par->chip = S3_SAVAGE3D;
+               snprintf (info->fix.id, 16, "Savage3D");
+               break;
+       case FB_ACCEL_SAVAGE3D_MV:
+               par->chip = S3_SAVAGE3D;
+               snprintf (info->fix.id, 16, "Savage3D-MV");
+               break;
+       case FB_ACCEL_SAVAGE2000:
+               par->chip = S3_SAVAGE2000;
+               snprintf (info->fix.id, 16, "Savage2000");
+               break;
+       case FB_ACCEL_SAVAGE_MX_MV:
+               par->chip = S3_SAVAGE_MX;
+               snprintf (info->fix.id, 16, "Savage/MX-MV");
+               break;
+       case FB_ACCEL_SAVAGE_MX:
+               par->chip = S3_SAVAGE_MX;
+               snprintf (info->fix.id, 16, "Savage/MX");
+               break;
+       case FB_ACCEL_SAVAGE_IX_MV:
+               par->chip = S3_SAVAGE_MX;
+               snprintf (info->fix.id, 16, "Savage/IX-MV");
+               break;
+       case FB_ACCEL_SAVAGE_IX:
+               par->chip = S3_SAVAGE_MX;
+               snprintf (info->fix.id, 16, "Savage/IX");
+               break;
+       case FB_ACCEL_PROSAVAGE_PM:
+               par->chip = S3_PROSAVAGE;
+               snprintf (info->fix.id, 16, "ProSavagePM");
+               break;
+       case FB_ACCEL_PROSAVAGE_KM:
+               par->chip = S3_PROSAVAGE;
+               snprintf (info->fix.id, 16, "ProSavageKM");
+               break;
+       case FB_ACCEL_S3TWISTER_P:
+               par->chip = S3_PROSAVAGE;
+               snprintf (info->fix.id, 16, "TwisterP");
+               break;
+       case FB_ACCEL_S3TWISTER_K:
+               par->chip = S3_PROSAVAGE;
+               snprintf (info->fix.id, 16, "TwisterK");
+               break;
+       case FB_ACCEL_PROSAVAGE_DDR:
+               par->chip = S3_PROSAVAGE;
+               snprintf (info->fix.id, 16, "ProSavageDDR");
+               break;
+       case FB_ACCEL_PROSAVAGE_DDRK:
+               par->chip = S3_PROSAVAGE;
+               snprintf (info->fix.id, 16, "ProSavage8");
+               break;
+       }
+
+       if (S3_SAVAGE3D_SERIES(par->chip)) {
+               par->SavageWaitIdle = savage3D_waitidle;
+               par->SavageWaitFifo = savage3D_waitfifo;
+       } else if (S3_SAVAGE4_SERIES(par->chip) ||
+                  S3_SUPERSAVAGE == par->chip) {
+               par->SavageWaitIdle = savage4_waitidle;
+               par->SavageWaitFifo = savage4_waitfifo;
+       } else {
+               par->SavageWaitIdle = savage2000_waitidle;
+               par->SavageWaitFifo = savage2000_waitfifo;
+       }
+
+       info->var.nonstd      = 0;
+       info->var.activate    = FB_ACTIVATE_NOW;
+       info->var.width       = -1;
+       info->var.height      = -1;
+       info->var.accel_flags = 0;
+
+       info->fbops          = &savagefb_ops;
+       info->flags          = FBINFO_DEFAULT |
+                              FBINFO_HWACCEL_YPAN |
+                              FBINFO_HWACCEL_XPAN |
+                              FBINFO_MISC_MODESWITCHLATE;
+
+       info->pseudo_palette = par->pseudo_palette;
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+       /* FIFO size + padding for commands */
+       info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+
+       err = -ENOMEM;
+       if (info->pixmap.addr) {
+               memset(info->pixmap.addr, 0, 8*1024);
+               info->pixmap.size = 8*1024;
+               info->pixmap.scan_align = 4;
+               info->pixmap.buf_align = 4;
+               info->pixmap.access_align = 4;
+
+               fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
+               info->flags |= FBINFO_HWACCEL_COPYAREA |
+                              FBINFO_HWACCEL_FILLRECT |
+                              FBINFO_HWACCEL_IMAGEBLIT;
+
+               err = 0;
+       }
+#endif
+       return err;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit savagefb_probe (struct pci_dev* dev,
+                                    const struct pci_device_id* id)
+{
+       struct fb_info *info;
+       struct savagefb_par *par;
+       u_int h_sync, v_sync;
+       int err, lpitch;
+       int video_len;
+
+       DBG("savagefb_probe");
+       SavagePrintRegs();
+
+       info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
+       if (!info)
+               return -ENOMEM;
+       par = info->par;
+       err = pci_enable_device(dev);
+       if (err)
+               goto failed_enable;
+
+       if (pci_request_regions(dev, "savagefb")) {
+               printk(KERN_ERR "cannot request PCI regions\n");
+               goto failed_enable;
+       }
+
+       err = -ENOMEM;
+
+       if (savage_init_fb_info(info, dev, id))
+               goto failed_init;
+
+       err = savage_map_mmio(info);
+       if (err)
+               goto failed_mmio;
+
+       video_len = savage_init_hw(par);
+       if (video_len < 0) {
+               err = video_len;
+               goto failed_mmio;
+       }
+
+       err = savage_map_video(info, video_len);
+       if (err)
+               goto failed_video;
+
+       INIT_LIST_HEAD(&info->modelist);
+#if defined(CONFIG_FB_SAVAGE_I2C)
+       savagefb_create_i2c_busses(info);
+       savagefb_probe_i2c_connector(par, &par->edid);
+       fb_edid_to_monspecs(par->edid, &info->monspecs);
+       fb_videomode_to_modelist(info->monspecs.modedb,
+                                info->monspecs.modedb_len,
+                                &info->modelist);
+#endif
+       info->var = savagefb_var800x600x8;
+
+       if (mode_option) {
+               fb_find_mode(&info->var, info, mode_option,
+                            info->monspecs.modedb, info->monspecs.modedb_len,
+                            NULL, 8);
+       } else if (info->monspecs.modedb != NULL) {
+               struct fb_monspecs *specs = &info->monspecs;
+               struct fb_videomode modedb;
+
+               if (info->monspecs.misc & FB_MISC_1ST_DETAIL) {
+                       int i;
+
+                       for (i = 0; i < specs->modedb_len; i++) {
+                               if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+                                       modedb = specs->modedb[i];
+                                       break;
+                               }
+                       }
+               } else {
+                       /* otherwise, get first mode in database */
+                       modedb = specs->modedb[0];
+               }
+
+               savage_update_var(&info->var, &modedb);
+       }
+
+       /* maximize virtual vertical length */
+       lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
+       info->var.yres_virtual = info->fix.smem_len/lpitch;
+
+       if (info->var.yres_virtual < info->var.yres)
+               goto failed;
+
+#if defined(CONFIG_FB_SAVAGE_ACCEL)
+       /*
+        * The clipping coordinates are masked with 0xFFF, so limit our
+        * virtual resolutions to these sizes.
+        */
+       if (info->var.yres_virtual > 0x1000)
+               info->var.yres_virtual = 0x1000;
+
+       if (info->var.xres_virtual > 0x1000)
+               info->var.xres_virtual = 0x1000;
+#endif
+       savagefb_check_var(&info->var, info);
+       savagefb_set_fix(info);
+
+       /*
+        * Calculate the hsync and vsync frequencies.  Note that
+        * we split the 1e12 constant up so that we can preserve
+        * the precision and fit the results into 32-bit registers.
+        *  (1953125000 * 512 = 1e12)
+        */
+       h_sync = 1953125000 / info->var.pixclock;
+       h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin +
+                                info->var.right_margin +
+                                info->var.hsync_len);
+       v_sync = h_sync / (info->var.yres + info->var.upper_margin +
+                          info->var.lower_margin + info->var.vsync_len);
+
+       printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": "
+              "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+              info->fix.smem_len >> 10,
+              info->var.xres, info->var.yres,
+              h_sync / 1000, h_sync % 1000, v_sync);
+
+
+       fb_destroy_modedb(info->monspecs.modedb);
+       info->monspecs.modedb = NULL;
+
+       err = register_framebuffer (info);
+       if (err < 0)
+               goto failed;
+
+       printk (KERN_INFO "fb: S3 %s frame buffer device\n",
+               info->fix.id);
+
+       /*
+        * Our driver data
+        */
+       pci_set_drvdata(dev, info);
+
+       return 0;
+
+ failed:
+#ifdef CONFIG_FB_SAVAGE_I2C
+       savagefb_delete_i2c_busses(info);
+#endif
+       fb_alloc_cmap (&info->cmap, 0, 0);
+       savage_unmap_video(info);
+ failed_video:
+       savage_unmap_mmio (info);
+ failed_mmio:
+       kfree(info->pixmap.addr);
+ failed_init:
+       pci_release_regions(dev);
+ failed_enable:
+       framebuffer_release(info);
+
+       return err;
+}
+
+static void __devexit savagefb_remove (struct pci_dev *dev)
+{
+       struct fb_info *info =
+               (struct fb_info *)pci_get_drvdata(dev);
+
+       DBG("savagefb_remove");
+
+       if (info) {
+               /*
+                * If unregister_framebuffer fails, then
+                * we will be leaving hooks that could cause
+                * oopsen laying around.
+                */
+               if (unregister_framebuffer (info))
+                       printk (KERN_WARNING "savagefb: danger danger! "
+                               "Oopsen imminent!\n");
+
+#ifdef CONFIG_FB_SAVAGE_I2C
+               savagefb_delete_i2c_busses(info);
+#endif
+               fb_alloc_cmap (&info->cmap, 0, 0);
+               savage_unmap_video (info);
+               savage_unmap_mmio (info);
+               kfree(info->pixmap.addr);
+               pci_release_regions(dev);
+               framebuffer_release(info);
+
+               /*
+                * Ensure that the driver data is no longer
+                * valid.
+                */
+               pci_set_drvdata(dev, NULL);
+       }
+}
+
+static int savagefb_suspend (struct pci_dev* dev, u32 state)
+{
+       struct fb_info *info =
+               (struct fb_info *)pci_get_drvdata(dev);
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+       DBG("savagefb_suspend");
+       printk(KERN_DEBUG "state: %u\n", state);
+
+       acquire_console_sem();
+       fb_set_suspend(info, state);
+       savage_disable_mmio(par);
+       release_console_sem();
+
+       pci_disable_device(dev);
+       pci_set_power_state(dev, state);
+
+       return 0;
+}
+
+static int savagefb_resume (struct pci_dev* dev)
+{
+       struct fb_info *info =
+               (struct fb_info *)pci_get_drvdata(dev);
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+       DBG("savage_resume");
+
+       pci_set_power_state(dev, 0);
+       pci_restore_state(dev);
+       if(pci_enable_device(dev))
+               DBG("err");
+
+       SavagePrintRegs();
+
+       acquire_console_sem();
+
+       savage_enable_mmio(par);
+       savage_init_hw(par);
+       savagefb_set_par (info);
+
+       fb_set_suspend (info, 0);
+       release_console_sem();
+
+       return 0;
+}
+
+
+static struct pci_device_id savagefb_devices[] __devinitdata = {
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR},
+
+       {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK},
+
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, savagefb_devices);
+
+static struct pci_driver savagefb_driver = {
+       .name =     "savagefb",
+       .id_table = savagefb_devices,
+       .probe =    savagefb_probe,
+       .suspend =  savagefb_suspend,
+       .resume =   savagefb_resume,
+       .remove =   __devexit_p(savagefb_remove)
+};
+
+/* **************************** exit-time only **************************** */
+
+static void __exit savage_done (void)
+{
+       DBG("savage_done");
+       pci_unregister_driver (&savagefb_driver);
+}
+
+
+/* ************************* init in-kernel code ************************** */
+
+int __init savagefb_setup(char *options)
+{
+#ifndef MODULE
+       char *this_opt;
+
+       if (!options || !*options)
+               return 0;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               mode_option = this_opt;
+       }
+#endif /* !MODULE */
+       return 0;
+}
+
+int __init savagefb_init(void)
+{
+       char *option;
+
+       DBG("savagefb_init");
+
+       if (fb_get_options("savagefb", &option))
+               return -ENODEV;
+
+       savagefb_setup(option);
+       return pci_register_driver (&savagefb_driver);
+
+}
+
+module_init(savagefb_init);
+module_exit(savage_done);
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
new file mode 100644 (file)
index 0000000..8594b1e
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * linux/drivers/video/savagefb.h -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * 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 __SAVAGEFB_H__
+#define __SAVAGEFB_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "../edid.h"
+
+#ifdef SAVAGEFB_DEBUG
+# define DBG(x)                printk (KERN_DEBUG "savagefb: %s\n", (x));
+#else
+# define DBG(x)
+# define SavagePrintRegs(...)
+#endif
+
+
+#define PCI_CHIP_SAVAGE4      0x8a22
+#define PCI_CHIP_SAVAGE3D     0x8a20
+#define PCI_CHIP_SAVAGE3D_MV  0x8a21
+#define PCI_CHIP_SAVAGE2000   0x9102
+#define PCI_CHIP_SAVAGE_MX_MV 0x8c10
+#define PCI_CHIP_SAVAGE_MX    0x8c11
+#define PCI_CHIP_SAVAGE_IX_MV 0x8c12
+#define PCI_CHIP_SAVAGE_IX    0x8c13
+#define PCI_CHIP_PROSAVAGE_PM 0x8a25
+#define PCI_CHIP_PROSAVAGE_KM 0x8a26
+ /* Twister is a code name; hope I get the real name soon. */
+#define PCI_CHIP_S3TWISTER_P  0x8d01
+#define PCI_CHIP_S3TWISTER_K  0x8d02
+#define PCI_CHIP_PROSAVAGE_DDR          0x8d03
+#define PCI_CHIP_PROSAVAGE_DDRK         0x8d04
+#define PCI_CHIP_SUPSAV_MX128          0x8c22
+#define PCI_CHIP_SUPSAV_MX64           0x8c24
+#define PCI_CHIP_SUPSAV_MX64C          0x8c26
+#define PCI_CHIP_SUPSAV_IX128SDR       0x8c2a
+#define PCI_CHIP_SUPSAV_IX128DDR       0x8c2b
+#define PCI_CHIP_SUPSAV_IX64SDR                0x8c2c
+#define PCI_CHIP_SUPSAV_IX64DDR                0x8c2d
+#define PCI_CHIP_SUPSAV_IXCSDR         0x8c2e
+#define PCI_CHIP_SUPSAV_IXCDDR         0x8c2f
+
+
+
+#define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip)   ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+
+#define S3_SAVAGE_MOBILE_SERIES(chip)  ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+
+/* Chip tags.  These are used to group the adapters into
+ * related families.
+ */
+
+typedef enum {
+  S3_UNKNOWN = 0,
+  S3_SAVAGE3D,
+  S3_SAVAGE_MX,
+  S3_SAVAGE4,
+  S3_PROSAVAGE,
+  S3_SUPERSAVAGE,
+  S3_SAVAGE2000,
+  S3_LAST
+} savage_chipset;
+
+#define BIOS_BSIZE                  1024
+#define BIOS_BASE                   0xc0000
+
+#define SAVAGE_NEWMMIO_REGBASE_S3    0x1000000  /* 16MB */
+#define SAVAGE_NEWMMIO_REGBASE_S4    0x0000000
+#define SAVAGE_NEWMMIO_REGSIZE      0x0080000  /* 512kb */
+#define SAVAGE_NEWMMIO_VGABASE      0x8000
+
+#define BASE_FREQ                   14318
+#define HALF_BASE_FREQ               7159
+
+#define FIFO_CONTROL_REG            0x8200
+#define MIU_CONTROL_REG                     0x8204
+#define STREAMS_TIMEOUT_REG         0x8208
+#define MISC_TIMEOUT_REG            0x820c
+
+#define MONO_PAT_0                   0xa4e8
+#define MONO_PAT_1                   0xa4ec
+
+#define MAXFIFO                      0x7f00
+
+#define BCI_CMD_NOP                  0x40000000
+#define BCI_CMD_SETREG               0x96000000
+#define BCI_CMD_RECT                 0x48000000
+#define BCI_CMD_RECT_XP              0x01000000
+#define BCI_CMD_RECT_YP              0x02000000
+#define BCI_CMD_SEND_COLOR           0x00008000
+#define BCI_CMD_DEST_GBD             0x00000000
+#define BCI_CMD_SRC_GBD              0x00000020
+#define BCI_CMD_SRC_SOLID            0x00000000
+#define BCI_CMD_SRC_MONO             0x00000060
+#define BCI_CMD_CLIP_NEW             0x00006000
+#define BCI_CMD_CLIP_LR              0x00004000
+
+#define BCI_CLIP_LR(l, r)            ((((r) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_TL(t, l)            ((((t) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_BR(b, r)            ((((b) << 16) | (r)) & 0x0FFF0FFF)
+#define BCI_W_H(w, h)                (((h) << 16) | ((w) & 0xFFF))
+#define BCI_X_Y(x, y)                (((y) << 16) | ((x) & 0xFFF))
+
+#define BCI_GBD1                     0xE0
+#define BCI_GBD2                     0xE1
+
+#define BCI_BUFFER_OFFSET            0x10000
+#define BCI_SIZE                     0x4000
+
+#define BCI_SEND(dw)                 writel(dw, par->bci_base + par->bci_ptr++)
+
+#define BCI_CMD_GET_ROP(cmd)         (((cmd) >> 16) & 0xFF)
+#define BCI_CMD_SET_ROP(cmd, rop)    ((cmd) |= ((rop & 0xFF) << 16))
+#define BCI_CMD_SEND_COLOR           0x00008000
+
+struct xtimings {
+       unsigned int Clock;
+       unsigned int HDisplay;
+       unsigned int HSyncStart;
+       unsigned int HSyncEnd;
+       unsigned int HTotal;
+       unsigned int HAdjusted;
+       unsigned int VDisplay;
+       unsigned int VSyncStart;
+       unsigned int VSyncEnd;
+       unsigned int VTotal;
+       unsigned int sync;
+       int            dblscan;
+       int            interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+#define NR_PALETTE     256
+
+
+struct savagefb_par;
+
+struct savagefb_i2c_chan {
+       struct savagefb_par *par;
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+       volatile u8 __iomem *ioaddr;
+       u32   reg;
+};
+
+struct savagefb_par {
+       struct pci_dev *pcidev;
+       savage_chipset  chip;
+       struct savagefb_i2c_chan chan;
+       unsigned char   *edid;
+       u32 pseudo_palette[16];
+       int dacSpeedBpp;
+       int maxClock;
+       int minClock;
+       int numClocks;
+       int clock[4];
+       struct {
+               u8   __iomem *vbase;
+               u32    pbase;
+               u32    len;
+#ifdef CONFIG_MTRR
+               int    mtrr;
+#endif
+       } video;
+
+       struct {
+               volatile u8  __iomem *vbase;
+               u32           pbase;
+               u32           len;
+       } mmio;
+
+       volatile u32  __iomem *bci_base;
+       unsigned int  bci_ptr;
+
+       u32           cob_offset;
+       u32           cob_size;
+       int           cob_index;
+
+       void (*SavageWaitIdle) (struct savagefb_par *par);
+       void (*SavageWaitFifo) (struct savagefb_par *par, int space);
+
+       int MCLK, REFCLK, LCDclk;
+       int HorizScaleFactor;
+
+       /* Panels size */
+       int SavagePanelWidth;
+       int SavagePanelHeight;
+
+       struct {
+               u16 red, green, blue, transp;
+       } palette[NR_PALETTE];
+
+       int depth;
+       int vwidth;
+
+       unsigned char MiscOutReg;     /* Misc */
+       unsigned char CRTC[25];       /* Crtc Controller */
+       unsigned char Sequencer[5];   /* Video Sequencer */
+       unsigned char Graphics[9];    /* Video Graphics */
+       unsigned char Attribute[21];  /* Video Atribute */
+
+       unsigned int mode, refresh;
+       unsigned char SR08, SR0E, SR0F;
+       unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30;
+       unsigned char SR54[8];
+       unsigned char Clock;
+       unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
+       unsigned char CR40, CR41, CR42, CR43, CR45;
+       unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E;
+       unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F;
+       unsigned char CR86, CR88;
+       unsigned char CR90, CR91, CRB0;
+       unsigned int  STREAMS[22];      /* yuck, streams regs */
+       unsigned int  MMPR0, MMPR1, MMPR2, MMPR3;
+};
+
+#define BCI_BD_BW_DISABLE            0x10000000
+#define BCI_BD_SET_BPP(bd, bpp)      ((bd) |= (((bpp) & 0xFF) << 16))
+#define BCI_BD_SET_STRIDE(bd, st)    ((bd) |= ((st) & 0xFFFF))
+
+
+/* IO functions */
+
+#define  vga_in8(addr)         (inb (addr))
+#define vga_in16(addr)         (inw (addr))
+#define vga_in32(addr)         (inl (addr))
+
+#define  vga_out8(addr,val)    (outb ((val), (addr)))
+#define vga_out16(addr,val)    (outw ((val), (addr)))
+#define vga_out32(addr,val)    (outl ((val), (addr)))
+
+#define savage_in16(addr)      readw(par->mmio.vbase + (addr))
+#define savage_in32(addr)      readl(par->mmio.vbase + (addr))
+
+#define savage_out16(addr,val) writew((val), par->mmio.vbase + (addr))
+#define savage_out32(addr,val) writel((val), par->mmio.vbase + (addr))
+
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+#define VGAwCR(index, val) \
+do {                       \
+  vga_out8 (0x3d4, index); \
+  vga_out8 (0x3d5, val);   \
+} while (0)
+
+#define VGAwGR(index, val) \
+do {                       \
+  vga_out8 (0x3ce, index); \
+  vga_out8 (0x3cf, val);   \
+} while (0)
+
+#define VGAwSEQ(index, val) \
+do {                        \
+  vga_out8 (0x3c4, index);  \
+  vga_out8 (0x3c5, val);    \
+} while (0)
+
+#define VGAenablePalette() \
+do {                       \
+  u8 tmp;                  \
+                           \
+  tmp = vga_in8 (0x3da);   \
+  vga_out8 (0x3c0, 0x00);  \
+  paletteEnabled = 1;      \
+} while (0)
+
+#define VGAdisablePalette() \
+do {                        \
+  u8 tmp;                   \
+                            \
+  tmp = vga_in8 (0x3da);    \
+  vga_out8 (0x3c0, 0x20);   \
+  paletteEnabled = 0;       \
+} while (0)
+
+#define VGAwATTR(index, value) \
+do {                           \
+  u8 tmp;                      \
+                               \
+  if (paletteEnabled)          \
+    index &= ~0x20;            \
+  else                         \
+    index |= 0x20;             \
+                               \
+  tmp = vga_in8 (0x3da);       \
+  vga_out8 (0x3c0, index);     \
+  vga_out8 (0x3c0, value);     \
+} while (0)
+
+#define VGAwMISC(value)    \
+do {                       \
+  vga_out8 (0x3c2, value); \
+} while (0)
+
+#ifndef CONFIG_FB_SAVAGE_ACCEL
+#define savagefb_set_clip(x)
+#endif
+
+#define VerticalRetraceWait() \
+{ \
+       vga_out8 (0x3d4, 0x17); \
+       if (vga_in8 (0x3d5) & 0x80) { \
+               while ((vga_in8(0x3da) & 0x08) == 0x08) ; \
+               while ((vga_in8(0x3da) & 0x08) == 0x00) ; \
+       } \
+}
+
+extern int savagefb_probe_i2c_connector(struct savagefb_par *par,
+                                       u8 **out_edid);
+extern void savagefb_create_i2c_busses(struct fb_info *info);
+extern void savagefb_delete_i2c_busses(struct fb_info *info);
+extern int  savagefb_sync(struct fb_info *info);
+extern void savagefb_copyarea(struct fb_info *info,
+                             const struct fb_copyarea *region);
+extern void savagefb_fillrect(struct fb_info *info,
+                             const struct fb_fillrect *rect);
+extern void savagefb_imageblit(struct fb_info *info,
+                              const struct fb_image *image);
+
+
+#endif /* __SAVAGEFB_H__ */
diff --git a/drivers/video/savage/savagefb_accel.c b/drivers/video/savage/savagefb_accel.c
new file mode 100644 (file)
index 0000000..da5fb8f
--- /dev/null
@@ -0,0 +1,140 @@
+/*-*- linux-c -*-
+ *  linux/drivers/video/savage/savage_accel.c -- Hardware Acceleration
+ *
+ *      Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
+ *      All Rights Reserved
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include "savagefb.h"
+
+static u32 savagefb_rop[] = {
+       0xCC, /* ROP_COPY */
+       0x5A  /* ROP_XOR  */
+};
+
+int savagefb_sync(struct fb_info *info)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+       par->SavageWaitIdle(par);
+       return 0;
+}
+EXPORT_SYMBOL(savagefb_sync);
+
+void savagefb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int sx = region->sx, dx = region->dx;
+       int sy = region->sy, dy = region->dy;
+       int cmd;
+
+       if (!region->width || !region->height)
+               return;
+       par->bci_ptr = 0;
+       cmd = BCI_CMD_RECT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_GBD;
+       BCI_CMD_SET_ROP(cmd, savagefb_rop[0]);
+
+       if (dx <= sx) {
+               cmd |= BCI_CMD_RECT_XP;
+       } else {
+               sx += region->width - 1;
+               dx += region->width - 1;
+       }
+
+       if (dy <= sy) {
+               cmd |= BCI_CMD_RECT_YP;
+       } else {
+               sy += region->height - 1;
+               dy += region->height - 1;
+       }
+
+       par->SavageWaitFifo(par,4);
+       BCI_SEND(cmd);
+       BCI_SEND(BCI_X_Y(sx, sy));
+       BCI_SEND(BCI_X_Y(dx, dy));
+       BCI_SEND(BCI_W_H(region->width, region->height));
+}
+EXPORT_SYMBOL(savagefb_copyarea);
+
+void savagefb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int cmd, color;
+
+       if (!rect->width || !rect->height)
+               return;
+
+       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+               color = rect->color;
+       else
+               color = ((u32 *)info->pseudo_palette)[rect->color];
+
+       cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+             BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID |
+             BCI_CMD_SEND_COLOR;
+
+       par->bci_ptr = 0;
+       BCI_CMD_SET_ROP(cmd, savagefb_rop[rect->rop]);
+
+       par->SavageWaitFifo(par,4);
+       BCI_SEND(cmd);
+       BCI_SEND(color);
+       BCI_SEND( BCI_X_Y(rect->dx, rect->dy) );
+       BCI_SEND( BCI_W_H(rect->width, rect->height) );
+}
+EXPORT_SYMBOL(savagefb_fillrect);
+
+void savagefb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       struct savagefb_par *par = (struct savagefb_par *)info->par;
+       int fg, bg, size, i, width;
+       int cmd;
+       u32 *src = (u32 *) image->data;
+
+       if (!image->width || !image->height)
+               return;
+
+       if (image->depth != 1) {
+               cfb_imageblit(info, image);
+               return;
+       }
+
+       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+               fg = image->fg_color;
+               bg = image->bg_color;
+       } else {
+               fg = ((u32 *)info->pseudo_palette)[image->fg_color];
+               bg = ((u32 *)info->pseudo_palette)[image->bg_color];
+       }
+
+       cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+             BCI_CMD_CLIP_LR | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO |
+             BCI_CMD_SEND_COLOR;
+
+       par->bci_ptr = 0;
+       BCI_CMD_SET_ROP(cmd, savagefb_rop[0]);
+
+       width = (image->width + 31) & ~31;
+       size = (width * image->height)/8;
+       size >>= 2;
+
+       par->SavageWaitFifo(par, size + 5);
+       BCI_SEND(cmd);
+       BCI_SEND(BCI_CLIP_LR(image->dx, image->dx + image->width - 1));
+       BCI_SEND(fg);
+       BCI_SEND(bg);
+       BCI_SEND(BCI_X_Y(image->dx, image->dy));
+       BCI_SEND(BCI_W_H(width, image->height));
+       for (i = 0; i < size; i++)
+               BCI_SEND(src[i]);
+}
+EXPORT_SYMBOL(savagefb_imageblit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/ds_w1_bridge.c b/drivers/w1/ds_w1_bridge.c
new file mode 100644 (file)
index 0000000..0baaeb5
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *     ds_w1_bridge.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.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/types.h>
+
+#include "../w1/w1.h"
+#include "../w1/w1_int.h"
+#include "dscore.h"
+       
+static struct ds_device *ds_dev;
+static struct w1_bus_master *ds_bus_master;
+
+static u8 ds9490r_touch_bit(unsigned long data, u8 bit)
+{
+       u8 ret;
+       struct ds_device *dev = (struct ds_device *)data;
+
+       if (ds_touch_bit(dev, bit, &ret))
+               return 0;
+
+       return ret;
+}
+
+static void ds9490r_write_bit(unsigned long data, u8 bit)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+
+       ds_write_bit(dev, bit);
+}
+
+static void ds9490r_write_byte(unsigned long data, u8 byte)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+
+       ds_write_byte(dev, byte);
+}
+
+static u8 ds9490r_read_bit(unsigned long data)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+       int err;
+       u8 bit = 0;
+
+       err = ds_touch_bit(dev, 1, &bit);
+       if (err)
+               return 0;
+       //err = ds_read_bit(dev, &bit);
+       //if (err)
+       //      return 0;
+
+       return bit & 1;
+}
+
+static u8 ds9490r_read_byte(unsigned long data)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+       int err;
+       u8 byte = 0;
+
+       err = ds_read_byte(dev, &byte);
+       if (err)
+               return 0;
+
+       return byte;
+}
+
+static void ds9490r_write_block(unsigned long data, u8 *buf, int len)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+
+       ds_write_block(dev, buf, len);
+}
+
+static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+       int err;
+
+       err = ds_read_block(dev, buf, len);
+       if (err < 0)
+               return 0;
+
+       return len;
+}
+
+static u8 ds9490r_reset(unsigned long data)
+{
+       struct ds_device *dev = (struct ds_device *)data;
+       struct ds_status st;
+       int err;
+
+       memset(&st, 0, sizeof(st));
+
+       err = ds_reset(dev, &st);
+       if (err)
+               return 1;
+
+       return 0;
+}
+
+static int __devinit ds_w1_init(void)
+{
+       int err;
+       
+       ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL);
+       if (!ds_bus_master) {
+               printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n");
+               return -ENOMEM;
+       }
+
+       ds_dev = ds_get_device();
+       if (!ds_dev) {
+               printk(KERN_ERR "DS9490R is not registered.\n");
+               err =  -ENODEV;
+               goto err_out_free_bus_master;
+       }
+
+       memset(ds_bus_master, 0, sizeof(*ds_bus_master));
+
+       ds_bus_master->data             = (unsigned long)ds_dev;
+       ds_bus_master->touch_bit        = &ds9490r_touch_bit;
+       ds_bus_master->read_bit         = &ds9490r_read_bit;
+       ds_bus_master->write_bit        = &ds9490r_write_bit;
+       ds_bus_master->read_byte        = &ds9490r_read_byte;
+       ds_bus_master->write_byte       = &ds9490r_write_byte;
+       ds_bus_master->read_block       = &ds9490r_read_block;
+       ds_bus_master->write_block      = &ds9490r_write_block;
+       ds_bus_master->reset_bus        = &ds9490r_reset;
+
+       err = w1_add_master_device(ds_bus_master);
+       if (err)
+               goto err_out_put_device;
+
+       return 0;
+
+err_out_put_device:
+       ds_put_device(ds_dev);
+err_out_free_bus_master:
+       kfree(ds_bus_master);
+
+       return err;
+}
+
+static void __devexit ds_w1_fini(void)
+{
+       w1_remove_master_device(ds_bus_master);
+       ds_put_device(ds_dev);
+       kfree(ds_bus_master);
+}
+
+module_init(ds_w1_init);
+module_exit(ds_w1_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
diff --git a/drivers/w1/dscore.c b/drivers/w1/dscore.c
new file mode 100644 (file)
index 0000000..f0f26a4
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ *     dscore.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.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/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/usb.h>
+
+#include "dscore.h"
+
+static struct usb_device_id ds_id_table [] = {
+       { USB_DEVICE(0x04fa, 0x2490) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, ds_id_table);
+
+int ds_probe(struct usb_interface *, const struct usb_device_id *);
+void ds_disconnect(struct usb_interface *);
+
+inline int ds_touch_bit(struct ds_device *, u8, u8 *);
+inline int ds_read_byte(struct ds_device *, u8 *);
+inline int ds_read_bit(struct ds_device *, u8 *);
+inline int ds_write_byte(struct ds_device *, u8);
+inline int ds_write_bit(struct ds_device *, u8);
+inline int ds_start_pulse(struct ds_device *, int);
+inline int ds_set_speed(struct ds_device *, int);
+inline int ds_reset(struct ds_device *, struct ds_status *);
+inline int ds_detect(struct ds_device *, struct ds_status *);
+inline int ds_stop_pulse(struct ds_device *, int);
+inline int ds_send_data(struct ds_device *, unsigned char *, int);
+inline int ds_recv_data(struct ds_device *, unsigned char *, int);
+inline int ds_recv_status(struct ds_device *, struct ds_status *);
+inline struct ds_device * ds_get_device(void);
+inline void ds_put_device(struct ds_device *);
+
+static inline void ds_dump_status(unsigned char *, unsigned char *, int);
+static inline int ds_send_control(struct ds_device *, u16, u16);
+static inline int ds_send_control_mode(struct ds_device *, u16, u16);
+static inline int ds_send_control_cmd(struct ds_device *, u16, u16);
+
+
+static struct usb_driver ds_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "DS9490R",
+       .probe =        ds_probe,
+       .disconnect =   ds_disconnect,
+       .id_table =     ds_id_table,
+};
+
+static struct ds_device *ds_dev;
+
+struct ds_device * ds_get_device(void)
+{
+       if (ds_dev)
+               atomic_inc(&ds_dev->refcnt);
+       return ds_dev;
+}
+
+void ds_put_device(struct ds_device *dev)
+{
+       atomic_dec(&dev->refcnt);
+}
+
+static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index)
+{
+       int err;
+       
+       err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
+                       CONTROL_CMD, 0x40, value, index, NULL, 0, HZ);
+       if (err < 0) {
+               printk(KERN_ERR "Failed to send command control message %x.%x: err=%d.\n", 
+                               value, index, err);
+               return err;
+       }
+
+       return err;
+}
+
+static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index)
+{
+       int err;
+       
+       err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
+                       MODE_CMD, 0x40, value, index, NULL, 0, HZ);
+       if (err < 0) {
+               printk(KERN_ERR "Failed to send mode control message %x.%x: err=%d.\n", 
+                               value, index, err);
+               return err;
+       }
+
+       return err;
+}
+
+static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
+{
+       int err;
+       
+       err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, dev->ep[EP_CONTROL]), 
+                       COMM_CMD, 0x40, value, index, NULL, 0, HZ);
+       if (err < 0) {
+               printk(KERN_ERR "Failed to send control message %x.%x: err=%d.\n", 
+                               value, index, err);
+               return err;
+       }
+
+       return err;
+}
+
+static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off)
+{
+       printk("%45s: %8x\n", str, buf[off]);
+}
+
+int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st, unsigned char *buf, int size)
+{
+       int count, err;
+               
+       memset(st, 0, sizeof(st));
+       
+       count = 0;
+       err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
+       if (err < 0) {
+               printk(KERN_ERR "Failed to read 1-wire data from 0x%x: err=%d.\n", dev->ep[EP_STATUS], err);
+               return err;
+       }
+       
+       if (count >= sizeof(*st))
+               memcpy(st, buf, sizeof(*st));
+
+       return count;
+}
+
+int ds_recv_status(struct ds_device *dev, struct ds_status *st)
+{
+       unsigned char buf[64];
+       int count, err = 0, i;
+       
+       memcpy(st, buf, sizeof(*st));
+               
+       count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+       if (count < 0)
+               return err;
+       
+       printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
+       for (i=0; i<count; ++i)
+               printk("%02x ", buf[i]);
+       printk("\n");
+
+       if (count >= 16) {
+               ds_dump_status(buf, "enable flag", 0);
+               ds_dump_status(buf, "1-wire speed", 1);
+               ds_dump_status(buf, "strong pullup duration", 2);
+               ds_dump_status(buf, "programming pulse duration", 3);
+               ds_dump_status(buf, "pulldown slew rate control", 4);
+               ds_dump_status(buf, "write-1 low time", 5);
+               ds_dump_status(buf, "data sample offset/write-0 recovery time", 6);
+               ds_dump_status(buf, "reserved (test register)", 7);
+               ds_dump_status(buf, "device status flags", 8);
+               ds_dump_status(buf, "communication command byte 1", 9);
+               ds_dump_status(buf, "communication command byte 2", 10);
+               ds_dump_status(buf, "communication command buffer status", 11);
+               ds_dump_status(buf, "1-wire data output buffer status", 12);
+               ds_dump_status(buf, "1-wire data input buffer status", 13);
+               ds_dump_status(buf, "reserved", 14);
+               ds_dump_status(buf, "reserved", 15);
+       }
+
+       memcpy(st, buf, sizeof(*st));
+
+       if (st->status & ST_EPOF) {
+               printk(KERN_INFO "Resetting device after ST_EPOF.\n");
+               err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+               if (err)
+                       return err;
+               count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+               if (count < 0)
+                       return err;
+       }
+#if 0
+       if (st->status & ST_IDLE) {
+               printk(KERN_INFO "Resetting pulse after ST_IDLE.\n");
+               err = ds_start_pulse(dev, PULLUP_PULSE_DURATION);
+               if (err)
+                       return err;
+       }
+#endif
+       
+       return err;
+}
+
+int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
+{
+       int count, err;
+       struct ds_status st;
+       
+       count = 0;
+       err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]), 
+                               buf, size, &count, HZ);
+       if (err < 0) {
+               printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
+               usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
+               ds_recv_status(dev, &st);
+               return err;
+       }
+
+#if 0
+       {
+               int i;
+
+               printk("%s: count=%d: ", __func__, count);
+               for (i=0; i<count; ++i)
+                       printk("%02x ", buf[i]);
+               printk("\n");
+       }
+#endif
+       return count;
+}
+
+int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
+{
+       int count, err;
+       
+       count = 0;
+       err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, HZ);
+       if (err < 0) {
+               printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
+               return err;
+       }
+
+       return err;
+}
+
+int ds_stop_pulse(struct ds_device *dev, int limit)
+{
+       struct ds_status st;
+       int count = 0, err = 0;
+       u8 buf[0x20];
+       
+       do {
+               err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
+               if (err)
+                       break;
+               err = ds_send_control(dev, CTL_RESUME_EXE, 0);
+               if (err)
+                       break;
+               err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+               if (err)
+                       break;
+
+               if ((st.status & ST_SPUA) == 0) {
+                       err = ds_send_control_mode(dev, MOD_PULSE_EN, 0);
+                       if (err)
+                               break;
+               }
+       } while(++count < limit);
+
+       return err;
+}
+
+int ds_detect(struct ds_device *dev, struct ds_status *st)
+{
+       int err;
+       
+       err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+       if (err)
+               return err;
+
+       err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, 0);
+       if (err)
+               return err;
+       
+       err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM | COMM_TYPE, 0x40);
+       if (err)
+               return err;
+       
+       err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_PROG);
+       if (err)
+               return err;
+
+       err = ds_recv_status(dev, st);
+
+       return err;
+}
+
+int ds_wait_status(struct ds_device *dev, struct ds_status *st)
+{
+       u8 buf[0x20];
+       int err, count = 0;
+
+       do {
+               err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+#if 0
+               if (err >= 0) { 
+                       int i;
+                       printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
+                       for (i=0; i<err; ++i)
+                               printk("%02x ", buf[i]);
+                       printk("\n");
+               }
+#endif
+       } while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
+
+
+       if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
+               ds_recv_status(dev, st);
+               return -1;
+       }
+       else {
+               return 0;
+       }
+}
+
+int ds_reset(struct ds_device *dev, struct ds_status *st)
+{
+       int err;
+
+       //err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
+       err = ds_send_control(dev, 0x43, SPEED_NORMAL);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, st);
+#if 0
+       if (st->command_buffer_status) {
+               printk(KERN_INFO "Short circuit.\n");
+               return -EIO;
+       }
+#endif
+       
+       return 0;
+}
+
+int ds_set_speed(struct ds_device *dev, int speed)
+{
+       int err;
+       
+       if (speed != SPEED_NORMAL && speed != SPEED_FLEXIBLE && speed != SPEED_OVERDRIVE)
+               return -EINVAL;
+
+       if (speed != SPEED_OVERDRIVE)
+               speed = SPEED_FLEXIBLE;
+
+       speed &= 0xff;
+       
+       err = ds_send_control_mode(dev, MOD_1WIRE_SPEED, speed);
+       if (err)
+               return err;
+
+       return err;
+}
+
+int ds_start_pulse(struct ds_device *dev, int delay)
+{
+       int err;
+       u8 del = 1 + (u8)(delay >> 4);
+       struct ds_status st;
+       
+#if 0
+       err = ds_stop_pulse(dev, 10);
+       if (err)
+               return err;
+
+       err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
+       if (err)
+               return err;
+#endif
+       err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
+       if (err)
+               return err;
+
+       err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0);
+       if (err)
+               return err;
+
+       mdelay(delay);
+
+       ds_wait_status(dev, &st);
+       
+       return err;
+}
+
+int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
+{
+       int err, count;
+       struct ds_status st;
+       u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
+       u16 cmd;
+       
+       err = ds_send_control(dev, value, 0);
+       if (err)
+               return err;
+
+       count = 0;
+       do {
+               err = ds_wait_status(dev, &st);
+               if (err)
+                       return err;
+
+               cmd = st.command0 | (st.command1 << 8);
+       } while (cmd != value && ++count < 10);
+
+       if (err < 0 || count >= 10) {
+               printk(KERN_ERR "Failed to obtain status.\n");
+               return -EINVAL;
+       }
+
+       err = ds_recv_data(dev, tbit, sizeof(*tbit));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+int ds_write_bit(struct ds_device *dev, u8 bit)
+{
+       int err;
+       struct ds_status st;
+       
+       err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, &st);
+
+       return 0;
+}
+
+int ds_write_byte(struct ds_device *dev, u8 byte)
+{
+       int err;
+       struct ds_status st;
+       u8 rbyte;
+       
+       err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
+       if (err)
+               return err;
+
+       err = ds_wait_status(dev, &st);
+       if (err)
+               return err;
+               
+       err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
+       if (err < 0)
+               return err;
+       
+       ds_start_pulse(dev, PULLUP_PULSE_DURATION);
+
+       return !(byte == rbyte);
+}
+
+int ds_read_bit(struct ds_device *dev, u8 *bit)
+{
+       int err;
+
+       err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
+       if (err)
+               return err;
+       
+       err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0);
+       if (err)
+               return err;
+       
+       err = ds_recv_data(dev, bit, sizeof(*bit));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+int ds_read_byte(struct ds_device *dev, u8 *byte)
+{
+       int err;
+       struct ds_status st;
+
+       err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM , 0xff);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, &st);
+       
+       err = ds_recv_data(dev, byte, sizeof(*byte));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+inline int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+{
+       struct ds_status st;
+       int err;
+
+       if (len > 64*1024)
+               return -E2BIG;
+
+       memset(buf, 0xFF, len);
+       
+       err = ds_send_data(dev, buf, len);
+       if (err < 0)
+               return err;
+       
+       err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, &st);
+       
+       memset(buf, 0x00, len);
+       err = ds_recv_data(dev, buf, len);
+
+       return err;
+}
+
+inline int ds_write_block(struct ds_device *dev, u8 *buf, int len)
+{
+       int err;
+       struct ds_status st;
+       
+       err = ds_send_data(dev, buf, len);
+       if (err < 0)
+               return err;
+       
+       ds_wait_status(dev, &st);
+
+       err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, &st);
+
+       err = ds_recv_data(dev, buf, len);
+       if (err < 0)
+               return err;
+
+       ds_start_pulse(dev, PULLUP_PULSE_DURATION);
+       
+       return !(err == len);
+}
+
+int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search)
+{
+       int err;
+       u16 value, index;
+       struct ds_status st;
+
+       memset(buf, 0, sizeof(buf));
+       
+       err = ds_send_data(ds_dev, (unsigned char *)&init, 8);
+       if (err)
+               return err;
+       
+       ds_wait_status(ds_dev, &st);
+
+       value = COMM_SEARCH_ACCESS | COMM_IM | COMM_SM | COMM_F | COMM_RTS;
+       index = (conditional_search ? 0xEC : 0xF0) | (id_number << 8);
+       err = ds_send_control(ds_dev, value, index);
+       if (err)
+               return err;
+
+       ds_wait_status(ds_dev, &st);
+
+       err = ds_recv_data(ds_dev, (unsigned char *)buf, 8*id_number);
+       if (err < 0)
+               return err;
+
+       return err/8;
+}
+
+int ds_match_access(struct ds_device *dev, u64 init)
+{
+       int err;
+       struct ds_status st;
+
+       err = ds_send_data(dev, (unsigned char *)&init, sizeof(init));
+       if (err)
+               return err;
+       
+       ds_wait_status(dev, &st);
+
+       err = ds_send_control(dev, COMM_MATCH_ACCESS | COMM_IM | COMM_RST, 0x0055);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, &st);
+
+       return 0;
+}
+
+int ds_set_path(struct ds_device *dev, u64 init)
+{
+       int err;
+       struct ds_status st;
+       u8 buf[9];
+
+       memcpy(buf, &init, 8);
+       buf[8] = BRANCH_MAIN;
+       
+       err = ds_send_data(dev, buf, sizeof(buf));
+       if (err)
+               return err;
+       
+       ds_wait_status(dev, &st);
+
+       err = ds_send_control(dev, COMM_SET_PATH | COMM_IM | COMM_RST, 0);
+       if (err)
+               return err;
+
+       ds_wait_status(dev, &st);
+
+       return 0;
+}
+
+int ds_probe(struct usb_interface *intf, const struct usb_device_id *udev_id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_host_interface *iface_desc;
+       int i, err;
+
+       ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL);
+       if (!ds_dev) {
+               printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
+               return -ENOMEM;
+       }
+
+       ds_dev->udev = usb_get_dev(udev);
+       usb_set_intfdata(intf, ds_dev);
+
+       err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3);
+       if (err) {
+               printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n",
+                               intf->altsetting[0].desc.bInterfaceNumber, err);
+               return err;
+       }
+
+       err = usb_reset_configuration(ds_dev->udev);
+       if (err) {
+               printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err);
+               return err;
+       }
+       
+       iface_desc = &intf->altsetting[0];
+       if (iface_desc->desc.bNumEndpoints != NUM_EP-1) {
+               printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints);
+               return -ENODEV;
+       }
+
+       atomic_set(&ds_dev->refcnt, 0);
+       memset(ds_dev->ep, 0, sizeof(ds_dev->ep));
+       
+       /*
+        * This loop doesn'd show control 0 endpoint, 
+        * so we will fill only 1-3 endpoints entry.
+        */
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               ds_dev->ep[i+1] = endpoint->bEndpointAddress;
+               
+               printk("%d: addr=%x, size=%d, dir=%s, type=%x\n",
+                       i, endpoint->bEndpointAddress, endpoint->wMaxPacketSize,
+                       (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT",
+                       endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+       }
+       
+#if 0
+       {
+               int err, i;
+               u64 buf[3];
+               u64 init=0xb30000002078ee81ull;
+               struct ds_status st;
+               
+               ds_reset(ds_dev, &st);
+               err = ds_search(ds_dev, init, buf, 3, 0);
+               if (err < 0)
+                       return err;
+               for (i=0; i<err; ++i)
+                       printk("%d: %llx\n", i, buf[i]);
+               
+               printk("Resetting...\n");       
+               ds_reset(ds_dev, &st);
+               printk("Setting path for %llx.\n", init);
+               err = ds_set_path(ds_dev, init);
+               if (err)
+                       return err;
+               printk("Calling MATCH_ACCESS.\n");
+               err = ds_match_access(ds_dev, init);
+               if (err)
+                       return err;
+
+               printk("Searching the bus...\n");
+               err = ds_search(ds_dev, init, buf, 3, 0);
+
+               printk("ds_search() returned %d\n", err);
+               
+               if (err < 0)
+                       return err;
+               for (i=0; i<err; ++i)
+                       printk("%d: %llx\n", i, buf[i]);
+               
+               return 0;
+       }
+#endif
+
+       return 0;
+}
+
+void ds_disconnect(struct usb_interface *intf)
+{
+       struct ds_device *dev;
+       
+       dev = usb_get_intfdata (intf);
+       usb_set_intfdata (intf, NULL);
+
+       while(atomic_read(&dev->refcnt))
+               schedule_timeout(HZ);
+
+       usb_put_dev(dev->udev);
+       kfree(dev);
+       ds_dev = NULL;
+}
+
+int ds_init(void)
+{
+       int err;
+
+       err = usb_register(&ds_driver);
+       if (err) {
+               printk(KERN_INFO "Failed to register DS9490R USB device: err=%d.\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+void ds_fini(void)
+{
+       usb_deregister(&ds_driver);
+}
+
+module_init(ds_init);
+module_exit(ds_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+
+EXPORT_SYMBOL(ds_touch_bit);
+EXPORT_SYMBOL(ds_read_byte);
+EXPORT_SYMBOL(ds_read_bit);
+EXPORT_SYMBOL(ds_read_block);
+EXPORT_SYMBOL(ds_write_byte);
+EXPORT_SYMBOL(ds_write_bit);
+EXPORT_SYMBOL(ds_write_block);
+EXPORT_SYMBOL(ds_start_pulse);
+EXPORT_SYMBOL(ds_set_speed);
+EXPORT_SYMBOL(ds_reset);
+EXPORT_SYMBOL(ds_detect);
+EXPORT_SYMBOL(ds_stop_pulse);
+EXPORT_SYMBOL(ds_send_data);
+EXPORT_SYMBOL(ds_recv_data);
+EXPORT_SYMBOL(ds_recv_status);
+EXPORT_SYMBOL(ds_search);
+EXPORT_SYMBOL(ds_get_device);
+EXPORT_SYMBOL(ds_put_device);
+
diff --git a/drivers/w1/dscore.h b/drivers/w1/dscore.h
new file mode 100644 (file)
index 0000000..77c37c6
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *     dscore.h
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.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
+ */
+
+#ifndef __DSCORE_H
+#define __DSCORE_H
+
+#include <linux/usb.h>
+#include <asm/atomic.h>
+
+/* COMMAND TYPE CODES */
+#define CONTROL_CMD                    0x00
+#define COMM_CMD                       0x01
+#define MODE_CMD                       0x02
+
+/* CONTROL COMMAND CODES */
+#define CTL_RESET_DEVICE               0x0000
+#define CTL_START_EXE                  0x0001
+#define CTL_RESUME_EXE                 0x0002
+#define CTL_HALT_EXE_IDLE              0x0003
+#define CTL_HALT_EXE_DONE              0x0004
+#define CTL_FLUSH_COMM_CMDS            0x0007
+#define CTL_FLUSH_RCV_BUFFER           0x0008
+#define CTL_FLUSH_XMT_BUFFER           0x0009
+#define CTL_GET_COMM_CMDS              0x000A
+
+/* MODE COMMAND CODES */
+#define MOD_PULSE_EN                   0x0000
+#define MOD_SPEED_CHANGE_EN            0x0001
+#define MOD_1WIRE_SPEED                        0x0002
+#define MOD_STRONG_PU_DURATION         0x0003
+#define MOD_PULLDOWN_SLEWRATE          0x0004
+#define MOD_PROG_PULSE_DURATION                0x0005
+#define MOD_WRITE1_LOWTIME             0x0006
+#define MOD_DSOW0_TREC                 0x0007
+
+/* COMMUNICATION COMMAND CODES */
+#define COMM_ERROR_ESCAPE              0x0601
+#define COMM_SET_DURATION              0x0012
+#define COMM_BIT_IO                    0x0020
+#define COMM_PULSE                     0x0030
+#define COMM_1_WIRE_RESET              0x0042
+#define COMM_BYTE_IO                   0x0052
+#define COMM_MATCH_ACCESS              0x0064
+#define COMM_BLOCK_IO                  0x0074
+#define COMM_READ_STRAIGHT             0x0080
+#define COMM_DO_RELEASE                        0x6092
+#define COMM_SET_PATH                  0x00A2
+#define COMM_WRITE_SRAM_PAGE           0x00B2
+#define COMM_WRITE_EPROM               0x00C4
+#define COMM_READ_CRC_PROT_PAGE                0x00D4
+#define COMM_READ_REDIRECT_PAGE_CRC    0x21E4
+#define COMM_SEARCH_ACCESS             0x00F4
+
+/* Communication command bits */
+#define COMM_TYPE                      0x0008
+#define COMM_SE                                0x0008
+#define COMM_D                         0x0008
+#define COMM_Z                         0x0008
+#define COMM_CH                                0x0008
+#define COMM_SM                                0x0008
+#define COMM_R                         0x0008
+#define COMM_IM                                0x0001
+
+#define COMM_PS                                0x4000
+#define COMM_PST                       0x4000
+#define COMM_CIB                       0x4000
+#define COMM_RTS                       0x4000
+#define COMM_DT                                0x2000
+#define COMM_SPU                       0x1000
+#define COMM_F                         0x0800
+#define COMM_NTP                       0x0400
+#define COMM_ICP                       0x0200
+#define COMM_RST                       0x0100
+
+#define PULSE_PROG                     0x01
+#define PULSE_SPUE                     0x02
+
+#define BRANCH_MAIN                    0xCC
+#define BRANCH_AUX                     0x33
+
+/*
+ * Duration of the strong pull-up pulse in milliseconds.
+ */
+#define PULLUP_PULSE_DURATION          750
+
+/* Status flags */
+#define ST_SPUA                                0x01  /* Strong Pull-up is active */
+#define ST_PRGA                                0x02  /* 12V programming pulse is being generated */
+#define ST_12VP                                0x04  /* external 12V programming voltage is present */
+#define ST_PMOD                                0x08  /* DS2490 powered from USB and external sources */
+#define ST_HALT                                0x10  /* DS2490 is currently halted */
+#define ST_IDLE                                0x20  /* DS2490 is currently idle */
+#define ST_EPOF                                0x80
+
+#define SPEED_NORMAL                   0x00
+#define SPEED_FLEXIBLE                 0x01
+#define SPEED_OVERDRIVE                        0x02
+
+#define NUM_EP                         4
+#define EP_CONTROL                     0
+#define EP_STATUS                      1
+#define EP_DATA_OUT                    2
+#define EP_DATA_IN                     3
+
+struct ds_device
+{
+       struct usb_device       *udev;
+       struct usb_interface    *intf;
+
+       int                     ep[NUM_EP];
+
+       atomic_t                refcnt;
+};
+
+struct ds_status
+{
+       u8                      enable;
+       u8                      speed;
+       u8                      pullup_dur;
+       u8                      ppuls_dur;
+       u8                      pulldown_slew;
+       u8                      write1_time;
+       u8                      write0_time;
+       u8                      reserved0;
+       u8                      status;
+       u8                      command0;
+       u8                      command1;
+       u8                      command_buffer_status;
+       u8                      data_out_buffer_status;
+       u8                      data_in_buffer_status;
+       u8                      reserved1;
+       u8                      reserved2;
+
+};
+
+inline int ds_touch_bit(struct ds_device *, u8, u8 *);
+inline int ds_read_byte(struct ds_device *, u8 *);
+inline int ds_read_bit(struct ds_device *, u8 *);
+inline int ds_write_byte(struct ds_device *, u8);
+inline int ds_write_bit(struct ds_device *, u8);
+inline int ds_start_pulse(struct ds_device *, int);
+inline int ds_set_speed(struct ds_device *, int);
+inline int ds_reset(struct ds_device *, struct ds_status *);
+inline int ds_detect(struct ds_device *, struct ds_status *);
+inline int ds_stop_pulse(struct ds_device *, int);
+inline int ds_send_data(struct ds_device *, unsigned char *, int);
+inline int ds_recv_data(struct ds_device *, unsigned char *, int);
+inline int ds_recv_status(struct ds_device *, struct ds_status *);
+inline struct ds_device * ds_get_device(void);
+inline void ds_put_device(struct ds_device *);
+inline int ds_write_block(struct ds_device *, u8 *, int);
+inline int ds_read_block(struct ds_device *, u8 *, int);
+
+#endif /* __DSCORE_H */
+
diff --git a/drivers/w1/w1_smem.c b/drivers/w1/w1_smem.c
new file mode 100644 (file)
index 0000000..ab82eb7
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *     w1_smem.c
+ *
+ * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/types.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "w1.h"
+#include "w1_io.h"
+#include "w1_int.h"
+#include "w1_family.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
+
+static ssize_t w1_smem_read_name(struct device *, char *);
+static ssize_t w1_smem_read_val(struct device *, char *);
+static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t);
+
+static struct w1_family_ops w1_smem_fops = {
+       .rname = &w1_smem_read_name,
+       .rbin = &w1_smem_read_bin,
+       .rval = &w1_smem_read_val,
+       .rvalname = "id",
+};
+
+static ssize_t w1_smem_read_name(struct device *dev, char *buf)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+
+       return sprintf(buf, "%s\n", sl->name);
+}
+
+static ssize_t w1_smem_read_val(struct device *dev, char *buf)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int i;
+       ssize_t count = 0;
+       
+       for (i = 0; i < 9; ++i)
+               count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
+       count += sprintf(buf + count, "\n");
+
+       return count;
+}
+
+static ssize_t w1_smem_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       struct w1_slave *sl = container_of(container_of(kobj, struct device, kobj),
+                                               struct w1_slave, dev);
+       int i;
+
+       atomic_inc(&sl->refcnt);
+       if (down_interruptible(&sl->master->mutex)) {
+               count = 0;
+               goto out_dec;
+       }
+
+       if (off > W1_SLAVE_DATA_SIZE) {
+               count = 0;
+               goto out;
+       }
+       if (off + count > W1_SLAVE_DATA_SIZE) {
+               count = 0;
+               goto out;
+       }
+       for (i = 0; i < 9; ++i)
+               count += sprintf(buf + count, "%02x ", ((u8 *)&sl->reg_num)[i]);
+       count += sprintf(buf + count, "\n");
+       
+out:
+       up(&sl->master->mutex);
+out_dec:
+       atomic_dec(&sl->refcnt);
+
+       return count;
+}
+
+static struct w1_family w1_smem_family = {
+       .fid = W1_FAMILY_SMEM,
+       .fops = &w1_smem_fops,
+};
+
+static int __init w1_smem_init(void)
+{
+       return w1_register_family(&w1_smem_family);
+}
+
+static void __exit w1_smem_fini(void)
+{
+       w1_unregister_family(&w1_smem_family);
+}
+
+module_init(w1_smem_init);
+module_exit(w1_smem_fini);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
new file mode 100644 (file)
index 0000000..0fe23d2
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ *   fs/cifs/readdir.c
+ *
+ *   Directory search handling
+ * 
+ *   Copyright (C) International Business Machines  Corp., 2004
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/smp_lock.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+extern int CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon,
+            const char *searchName, const struct nls_table *nls_codepage,
+            __u16 *searchHandle, struct cifs_search_info * psrch_inf);
+
+extern int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
+            __u16 searchHandle, struct cifs_search_info * psrch_inf);
+
+extern int construct_dentry(struct qstr *qstring, struct file *file,
+                struct inode **ptmp_inode, struct dentry **pnew_dentry);
+
+extern void fill_in_inode(struct inode *tmp_inode,
+             FILE_DIRECTORY_INFO * pfindData, int *pobject_type);
+
+extern void unix_fill_in_inode(struct inode *tmp_inode,
+             FILE_UNIX_INFO * pfindData, int *pobject_type);
+
+
+/* BB fixme - add debug wrappers around this function to disable it fixme BB */
+/* static void dump_cifs_file_struct(struct file * file, char * label)
+{
+       struct cifsFileInfo * cf;
+
+       if(file) {
+               cf = (struct cifsFileInfo *)file->private_data;
+               if(cf == NULL) {
+                       cFYI(1,("empty cifs private file data"));
+                       return;
+               }
+               if(cf->invalidHandle) {
+                       cFYI(1,("invalid handle"));
+               }
+               if(cf->srch_inf.endOfSearch) {
+                       cFYI(1,("end of search"));
+               }
+               if(cf->srch_inf.emptyDir) {
+                       cFYI(1,("empty dir"));
+               }
+               
+       }
+} */
+
+static int initiate_cifs_search(const int xid, struct file * file)
+{
+       int rc = 0;
+       char * full_path;
+       struct cifsFileInfo * cifsFile;
+       struct cifs_sb_info *cifs_sb;
+       struct cifsTconInfo *pTcon;
+
+       if(file->private_data == NULL) {
+               file->private_data = 
+                       kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
+       }
+
+       if(file->private_data == NULL) {
+               return -ENOMEM;
+       } else {
+               memset(file->private_data,0,sizeof(struct cifsFileInfo));
+       }
+       cifsFile = (struct cifsFileInfo *)file->private_data;
+       cifsFile->invalidHandle = TRUE;
+       cifsFile->srch_inf.endOfSearch = FALSE;
+
+       cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+       if(cifs_sb == NULL)
+               return -EINVAL;
+
+       pTcon = cifs_sb->tcon;
+       if(pTcon == NULL)
+               return -EINVAL;
+
+       if(file->f_dentry == NULL)
+               return -ENOENT;
+
+       down(&file->f_dentry->d_sb->s_vfs_rename_sem);
+       full_path = build_wildcard_path_from_dentry(file->f_dentry);
+       up(&file->f_dentry->d_sb->s_vfs_rename_sem);
+
+       if(full_path == NULL) {
+               return -ENOMEM;
+       }
+
+       cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
+
+       /* test for Unix extensions */
+       if (pTcon->ses->capabilities & CAP_UNIX) {
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
+       } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+       } else /* not srvinos - BB fixme add check for backlevel? */ {
+               cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
+       }
+
+       rc = CIFSFindFirst2(xid, pTcon,full_path,cifs_sb->local_nls, 
+               &cifsFile->netfid, &cifsFile->srch_inf); 
+       if(rc == 0)
+               cifsFile->invalidHandle = FALSE;
+       if(full_path)
+               kfree(full_path);
+       return rc;
+}
+
+/* return length of unicode string in bytes */
+static int cifs_unicode_bytelen(char * str)
+{
+       int len;
+       __le16 * ustr = (__le16 *)str;
+
+       for(len=0;len <= PATH_MAX;len++) {
+               if(ustr[len] == 0)
+                       return len << 1;
+       }
+       cFYI(1,("Unicode string longer than PATH_MAX found"));
+       return len << 1;
+}
+
+static char * nxt_dir_entry(char * old_entry, char * end_of_smb)
+{
+       char * new_entry;
+       FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
+
+       new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
+       cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
+       /* validate that new_entry is not past end of SMB */
+       if(new_entry >= end_of_smb) {
+               cFYI(1,("search entry %p began after end of SMB %p old entry %p",
+                       new_entry,end_of_smb,old_entry)); 
+               return NULL;
+       } else
+               return new_entry;
+
+}
+
+#define UNICODE_DOT cpu_to_le16(0x2e)
+
+/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
+static int cifs_entry_is_dot(char * current_entry, struct cifsFileInfo * cfile)
+{
+       int rc = 0;
+       char * filename = NULL;
+       int len = 0; 
+
+       if(cfile->srch_inf.info_level == 0x202) {
+               FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               if(cfile->srch_inf.unicode) {
+                       len = cifs_unicode_bytelen(filename);
+               } else {
+                       /* BB should we make this strnlen of PATH_MAX? */
+                       len = strnlen(filename, 5);
+               }
+       } else if(cfile->srch_inf.info_level == 0x101) {
+               FILE_DIRECTORY_INFO * pFindData = 
+                       (FILE_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(cfile->srch_inf.info_level == 0x102) {
+               FILE_FULL_DIRECTORY_INFO * pFindData = 
+                       (FILE_FULL_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(cfile->srch_inf.info_level == 0x105) {
+               SEARCH_ID_FULL_DIR_INFO * pFindData = 
+                       (SEARCH_ID_FULL_DIR_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(cfile->srch_inf.info_level == 0x104) {
+               FILE_BOTH_DIRECTORY_INFO * pFindData = 
+                       (FILE_BOTH_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else {
+               cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
+       }
+
+       if(filename) {
+               if(cfile->srch_inf.unicode) {
+                       __le16 *ufilename = (__le16 *)filename;
+                       if(len == 2) {
+                               /* check for . */
+                               if(ufilename[0] == UNICODE_DOT)
+                                       rc = 1;
+                       } else if(len == 4) {
+                               /* check for .. */
+                               if((ufilename[0] == UNICODE_DOT)
+                                  &&(ufilename[1] == UNICODE_DOT))
+                                       rc = 2;
+                       }
+               } else /* ASCII */ {
+                       if(len == 1) {
+                               if(filename[0] == '.') 
+                                       rc = 1;
+                       } else if(len == 2) {
+                               if((filename[0] == '.') && (filename[1] == '.')) 
+                                       rc = 2;
+                       }
+               }
+       }
+
+       return rc;
+}
+
+/* find the corresponding entry in the search */
+/* Note that the SMB server returns search entries for . and .. which
+   complicates logic here if we choose to parse for them and we do not
+   assume that they are located in the findfirst return buffer.*/
+/* We start counting in the buffer with entry 2 and increment for every
+   entry (do not increment for . or .. entry) */
+static int find_cifs_entry(const int xid, struct cifsTconInfo * pTcon, 
+               struct file * file, char ** ppCurrentEntry,int * num_to_ret) 
+{
+       int rc = 0;
+       int pos_in_buf = 0;
+       loff_t first_entry_in_buffer;
+       loff_t index_to_find = file->f_pos;
+       struct cifsFileInfo * cifsFile = (struct cifsFileInfo *)file->private_data;
+       /* check if index in the buffer */
+       
+       if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL))
+               return -ENOENT;
+       
+       *ppCurrentEntry = NULL;
+       first_entry_in_buffer = 
+               cifsFile->srch_inf.index_of_last_entry - 
+                       cifsFile->srch_inf.entries_in_buffer;
+/*     dump_cifs_file_struct(file, "In fce ");*/
+       if(index_to_find < first_entry_in_buffer) {
+               /* close and restart search */
+               cFYI(1,("search backing up - close and restart search"));
+               cifsFile->invalidHandle = TRUE;
+               CIFSFindClose(xid, pTcon, cifsFile->netfid);
+               if(cifsFile->search_resume_name) {
+                       kfree(cifsFile->search_resume_name);
+                       cifsFile->search_resume_name = NULL;
+               }
+               if(cifsFile->srch_inf.ntwrk_buf_start) {
+                       cFYI(1,("freeing SMB ff cache buf on search rewind")); 
+                       cifs_buf_release(cifsFile->srch_inf.ntwrk_buf_start);
+               }
+               rc = initiate_cifs_search(xid,file);
+               if(rc) {
+                       cFYI(1,("error %d reinitiating a search on rewind",rc));
+                       return rc;
+               }
+       }
+
+       while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 
+             (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
+               cFYI(1,("calling findnext2"));
+               rc = CIFSFindNext2(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
+               if(rc)
+                       return -ENOENT;
+       }
+       if(index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+               /* we found the buffer that contains the entry */
+               /* scan and find it */
+               int i;
+               char * current_entry;
+               char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
+                       smbCalcSize((struct smb_hdr *)cifsFile->srch_inf.ntwrk_buf_start);
+/*     dump_cifs_file_struct(file,"found entry in fce "); */
+               first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry -
+                       cifsFile->srch_inf.entries_in_buffer;
+               pos_in_buf = index_to_find - first_entry_in_buffer;
+               cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
+               current_entry = cifsFile->srch_inf.srch_entries_start;
+               for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
+                       /* go entry to next entry figuring out which we need to start with */
+                       /* if( . or ..)
+                               skip */
+                       rc = cifs_entry_is_dot(current_entry,cifsFile);
+                       if(rc == 1) /* is . or .. so skip */ {
+                               cFYI(1,("Entry is .")); /* BB removeme BB */
+                               /* continue; */
+                       } else if (rc == 2 ) {
+                               cFYI(1,("Entry is ..")); /* BB removeme BB */
+                               /* continue; */
+                       }
+                       current_entry = nxt_dir_entry(current_entry,end_of_smb);
+               }
+               if((current_entry == NULL) && (i < pos_in_buf)) {
+                       cERROR(1,("reached end of buf searching for pos in buf %d index to find %lld rc %d",pos_in_buf,index_to_find,rc)); /* BB removeme BB */
+               }
+               rc = 0;
+               *ppCurrentEntry = current_entry;
+       } else {
+               cFYI(1,("index not in buffer - could not findnext into it"));
+               return 0;
+       }
+
+       if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+               cFYI(1,("can not return entries when pos_in_buf beyond last entry"));
+               *num_to_ret = 0;
+       } else
+               *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
+/*     dump_cifs_file_struct(file, "end fce ");*/
+
+       return rc;
+}
+
+/* inode num, inode type and filename returned */
+static int cifs_get_name_from_search_buf(struct qstr * pqst,char * current_entry,
+                       __u16 level,unsigned int unicode,struct nls_table * nlt,
+                       ino_t * pinum)
+{
+       int rc = 0;
+       unsigned int len = 0;
+       char * filename;
+
+       *pinum = 0;
+
+       if(level == SMB_FIND_FILE_UNIX) {
+               FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
+
+               filename = &pFindData->FileName[0];
+               if(unicode) {
+                       len = cifs_unicode_bytelen(filename);
+               } else {
+                       /* BB should we make this strnlen of PATH_MAX? */
+                       len = strnlen(filename, PATH_MAX);
+               }
+
+               /* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */
+               *pinum = pFindData->UniqueId;
+       } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
+               FILE_DIRECTORY_INFO * pFindData = 
+                       (FILE_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+               FILE_FULL_DIRECTORY_INFO * pFindData = 
+                       (FILE_FULL_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+               SEARCH_ID_FULL_DIR_INFO * pFindData = 
+                       (SEARCH_ID_FULL_DIR_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               *pinum = pFindData->UniqueId;
+       } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+               FILE_BOTH_DIRECTORY_INFO * pFindData = 
+                       (FILE_BOTH_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+       } else {
+               cFYI(1,("Unknown findfirst level %d",level));
+               return -EINVAL;
+       }
+       if(unicode) {
+               /* BB fixme - test with long names */
+               /* Note converted filename can be longer than in unicode */
+               pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt);
+       } else {
+               pqst->name = filename;
+               pqst->len = len;
+       }
+       pqst->hash = full_name_hash(pqst->name,pqst->len);
+/*     cFYI(1,("filldir on %s",pqst->name));  */
+       return rc;
+}
+
+
+static int
+cifs_filldir2(char * pfindEntry, struct file *file, 
+                         filldir_t filldir, void *direntry,char * scratch_buf)
+{
+       int rc = 0;
+       struct qstr qstring;
+       struct cifsFileInfo * pCifsF;
+       unsigned obj_type;
+       ino_t  inum;
+       struct cifs_sb_info * cifs_sb;
+       struct inode *tmp_inode;
+       struct dentry *tmp_dentry;
+
+       /* get filename and len into qstring */
+       /* get dentry */
+       /* decide whether to create and populate ionde */
+       if((direntry == NULL) || (file == NULL))
+               return -EINVAL;
+
+       pCifsF = file->private_data;
+       
+       if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
+               return -ENOENT;
+
+       if(file->f_dentry == NULL)
+               return -ENOENT;
+
+       cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+
+       qstring.name = scratch_buf;
+       rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
+                       pCifsF->srch_inf.info_level,
+                       pCifsF->srch_inf.unicode,cifs_sb->local_nls,
+                       &inum /* returned */);
+
+       if(rc)
+               return rc;
+
+       rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry);
+       if((tmp_inode == NULL) || (tmp_dentry == NULL))
+               return -ENOMEM;
+
+       if(rc) {
+               /* inode created, we need to hash it with right inode number */
+               if(inum != 0) {
+                       /* BB fixme - hash the 2 32 quantities bits together if necessary BB */
+                       tmp_inode->i_ino = inum;
+               }
+               insert_inode_hash(tmp_inode);
+       }
+
+       if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+               unix_fill_in_inode(tmp_inode,(FILE_UNIX_INFO *)pfindEntry,&obj_type);
+       } else {
+               fill_in_inode(tmp_inode,(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type);
+       }
+       
+       rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
+       if(rc) {
+               cFYI(1,("filldir rc = %d",rc));
+       }
+
+       dput(tmp_dentry);
+       return rc;
+}
+
+int cifs_save_resume_key(const char * current_entry,struct cifsFileInfo * cifsFile)
+{
+       int rc = 0;
+       unsigned int len = 0;
+       __u16 level;
+       char * filename;
+
+       if((cifsFile == NULL) || (current_entry == NULL))
+               return -EINVAL;
+
+       level = cifsFile->srch_inf.info_level;
+
+       if(level == SMB_FIND_FILE_UNIX) {
+               FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
+
+               filename = &pFindData->FileName[0];
+               if(cifsFile->srch_inf.unicode) {
+                       len = cifs_unicode_bytelen(filename);
+               } else {
+                       /* BB should we make this strnlen of PATH_MAX? */
+                       len = strnlen(filename, PATH_MAX);
+               }
+               cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+       } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
+               FILE_DIRECTORY_INFO * pFindData = 
+                       (FILE_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+               FILE_FULL_DIRECTORY_INFO * pFindData = 
+                       (FILE_FULL_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+               SEARCH_ID_FULL_DIR_INFO * pFindData = 
+                       (SEARCH_ID_FULL_DIR_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+               FILE_BOTH_DIRECTORY_INFO * pFindData = 
+                       (FILE_BOTH_DIRECTORY_INFO *)current_entry;
+               filename = &pFindData->FileName[0];
+               len = le32_to_cpu(pFindData->FileNameLength);
+               cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+       } else {
+               cFYI(1,("Unknown findfirst level %d",level));
+               return -EINVAL;
+       }
+       cifsFile->srch_inf.resume_name_len = len;
+       cifsFile->srch_inf.presume_name = filename;
+       return rc;
+}
+
+int cifs_readdir2(struct file *file, void *direntry, filldir_t filldir)
+{
+       int rc = 0;
+       int xid,i;
+       struct cifs_sb_info *cifs_sb;
+       struct cifsTconInfo *pTcon;
+       struct cifsFileInfo *cifsFile = NULL;
+       char * current_entry;
+       int num_to_fill = 0;
+       char * tmp_buf = NULL;
+       char * end_of_smb;
+
+       xid = GetXid();
+
+       if(file->f_dentry == NULL) {
+               FreeXid(xid);
+               return -EIO;
+       }
+/*     dump_cifs_file_struct(file, "Begin rdir "); */
+
+       cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+       pTcon = cifs_sb->tcon;
+       if(pTcon == NULL)
+               return -EINVAL;
+
+/*     cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
+
+       switch ((int) file->f_pos) {
+       case 0:
+               /*if (filldir(direntry, ".", 1, file->f_pos,
+                    file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
+                       cERROR(1, ("Filldir for current dir failed "));
+                       rc = -ENOMEM;
+                       break;
+               }
+               file->f_pos++; */
+       case 1:
+               /* if (filldir(direntry, "..", 2, file->f_pos,
+                    file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+                       cERROR(1, ("Filldir for parent dir failed "));
+                       rc = -ENOMEM;
+                       break;
+               }
+               file->f_pos++; */
+       case 2:
+               /* 1) If search is active, 
+                       is in current search buffer? 
+                       if it before then restart search
+                       if after then keep searching till find it */
+
+               if(file->private_data == NULL) {
+                       rc = initiate_cifs_search(xid,file);
+                       cFYI(1,("initiate cifs search rc %d",rc));
+                       if(rc) {
+                               FreeXid(xid);
+                               return rc;
+                       }
+               }
+       default:
+               if(file->private_data == NULL) {
+                       rc = -EINVAL;
+                       FreeXid(xid);
+                       return rc;
+               }
+               cifsFile = (struct cifsFileInfo *) file->private_data;
+               if (cifsFile->srch_inf.endOfSearch) {
+                       if(cifsFile->srch_inf.emptyDir) {
+                               cFYI(1, ("End of search, empty dir"));
+                               rc = 0;
+                               break;
+                       }
+               } /* else {
+                       cifsFile->invalidHandle = TRUE;
+                       CIFSFindClose(xid, pTcon, cifsFile->netfid);
+               } 
+               if(cifsFile->search_resume_name) {
+                       kfree(cifsFile->search_resume_name);
+                       cifsFile->search_resume_name = NULL;
+               } */
+/* BB account for . and .. in f_pos */
+               /* dump_cifs_file_struct(file, "rdir after default ");*/
+
+               rc = find_cifs_entry(xid,pTcon, file,
+                               &current_entry,&num_to_fill);
+               if(rc) {
+                       cFYI(1,("fce error %d",rc)); 
+                       goto rddir2_exit;
+               } else if (current_entry != NULL) {
+                       cFYI(1,("entry %lld found",file->f_pos));
+               } else {
+                       cFYI(1,("could not find entry"));
+                       goto rddir2_exit;
+               }
+               cFYI(1,("loop through %d times filling dir for net buf %p",
+                       num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); 
+               end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
+                       smbCalcSize((struct smb_hdr *)cifsFile->srch_inf.ntwrk_buf_start);
+               tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL);
+               for(i=0;(i<num_to_fill) && (rc == 0);i++) {
+                       if(current_entry == NULL) {
+                               cERROR(1,("beyond end of smb with num to fill %d i %d",num_to_fill,i)); /* BB removeme BB */
+                               break;
+                       }
+/*                     if((!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) || 
+                          (cifsFile->srch_inf.info_level != something that supports server inodes)) {
+                               create dentry
+                               create inode
+                               fill in inode new_inode (which makes number locally)
+                       }
+                       also create local inode for per reasons unless new mount parm says otherwise */
+                       rc = cifs_filldir2(current_entry, file, 
+                                       filldir, direntry,tmp_buf);
+                       file->f_pos++;
+                       if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
+                               cFYI(1,("last entry in buf at pos %lld %s",file->f_pos,tmp_buf)); /* BB removeme BB */
+                               cifs_save_resume_key(current_entry,cifsFile);
+                               break;
+                       } else 
+                               current_entry = nxt_dir_entry(current_entry,end_of_smb);
+               }
+               if(tmp_buf != NULL)
+                       kfree(tmp_buf);
+               break;
+       } /* end switch */
+
+rddir2_exit:
+       /* dump_cifs_file_struct(file, "end rdir ");  */
+       FreeXid(xid);
+       return rc;
+}
+
diff --git a/fs/hfs/attr.c b/fs/hfs/attr.c
new file mode 100644 (file)
index 0000000..e057ec5
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  linux/fs/hfs/attr.c
+ *
+ * (C) 2003 Ardis Technologies <roman@ardistech.com>
+ *
+ * Export hfs data via xattr
+ */
+
+
+#include <linux/fs.h>
+#include <linux/xattr.h>
+
+#include "hfs_fs.h"
+#include "btree.h"
+
+int hfs_setxattr(struct dentry *dentry, const char *name,
+                const void *value, size_t size, int flags)
+{
+       struct inode *inode = dentry->d_inode;
+       struct hfs_find_data fd;
+       hfs_cat_rec rec;
+       struct hfs_cat_file *file;
+       int res;
+
+       if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
+               return -EOPNOTSUPP;
+
+       res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
+       if (res)
+               return res;
+       fd.search_key->cat = HFS_I(inode)->cat_key;
+       res = hfs_brec_find(&fd);
+       if (res)
+               goto out;
+       hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
+                       sizeof(struct hfs_cat_file));
+       file = &rec.file;
+
+       if (!strcmp(name, "hfs.type")) {
+               if (size == 4)
+                       memcpy(&file->UsrWds.fdType, value, 4);
+               else
+                       res = -ERANGE;
+       } else if (!strcmp(name, "hfs.creator")) {
+               if (size == 4)
+                       memcpy(&file->UsrWds.fdCreator, value, 4);
+               else
+                       res = -ERANGE;
+       } else
+               res = -EOPNOTSUPP;
+       if (!res)
+               hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
+                               sizeof(struct hfs_cat_file));
+out:
+       hfs_find_exit(&fd);
+       return res;
+}
+
+ssize_t hfs_getxattr(struct dentry *dentry, const char *name,
+                        void *value, size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       struct hfs_find_data fd;
+       hfs_cat_rec rec;
+       struct hfs_cat_file *file;
+       ssize_t res = 0;
+
+       if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
+               return -EOPNOTSUPP;
+
+       if (size) {
+               res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
+               if (res)
+                       return res;
+               fd.search_key->cat = HFS_I(inode)->cat_key;
+               res = hfs_brec_find(&fd);
+               if (res)
+                       goto out;
+               hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
+                               sizeof(struct hfs_cat_file));
+       }
+       file = &rec.file;
+
+       if (!strcmp(name, "hfs.type")) {
+               if (size >= 4) {
+                       memcpy(value, &file->UsrWds.fdType, 4);
+                       res = 4;
+               } else
+                       res = size ? -ERANGE : 4;
+       } else if (!strcmp(name, "hfs.creator")) {
+               if (size >= 4) {
+                       memcpy(value, &file->UsrWds.fdCreator, 4);
+                       res = 4;
+               } else
+                       res = size ? -ERANGE : 4;
+       } else
+               res = -ENODATA;
+out:
+       if (size)
+               hfs_find_exit(&fd);
+       return res;
+}
+
+#define HFS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
+
+ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+
+       if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
+               return -EOPNOTSUPP;
+
+       if (!buffer || !size)
+               return HFS_ATTRLIST_SIZE;
+       if (size < HFS_ATTRLIST_SIZE)
+               return -ERANGE;
+       strcpy(buffer, "hfs.type");
+       strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
+
+       return HFS_ATTRLIST_SIZE;
+}
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
new file mode 100644 (file)
index 0000000..ad7677b
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * linux/fs/nfs/callback.c
+ *
+ * Copyright (C) 2004 Trond Myklebust
+ *
+ * NFSv4 callback handling
+ */
+
+#include <linux/config.h>
+#include <linux/completion.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/nfs_fs.h>
+#include "callback.h"
+
+#define NFSDBG_FACILITY NFSDBG_CALLBACK
+
+struct nfs_callback_data {
+       unsigned int users;
+       struct svc_serv *serv;
+       pid_t pid;
+       struct completion started;
+       struct completion stopped;
+};
+
+static struct nfs_callback_data nfs_callback_info;
+static DECLARE_MUTEX(nfs_callback_sema);
+static struct svc_program nfs4_callback_program;
+
+unsigned short nfs_callback_tcpport;
+
+/*
+ * This is the callback kernel thread.
+ */
+static void nfs_callback_svc(struct svc_rqst *rqstp)
+{
+       struct svc_serv *serv = rqstp->rq_server;
+       int err;
+
+       __module_get(THIS_MODULE);
+       lock_kernel();
+
+       nfs_callback_info.pid = current->pid;
+       daemonize("nfsv4-svc");
+       /* Process request with signals blocked, but allow SIGKILL.  */
+       allow_signal(SIGKILL);
+
+       complete(&nfs_callback_info.started);
+
+       while (nfs_callback_info.users != 0 || !signalled()) {
+               /*
+                * Listen for a request on the socket
+                */
+               err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT);
+               if (err == -EAGAIN || err == -EINTR)
+                       continue;
+               if (err < 0) {
+                       printk(KERN_WARNING
+                                       "%s: terminating on error %d\n",
+                                       __FUNCTION__, -err);
+                       break;
+               }
+               dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
+                               NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
+               svc_process(serv, rqstp);
+       }
+
+       nfs_callback_info.pid = 0;
+       complete(&nfs_callback_info.stopped);
+       unlock_kernel();
+       module_put_and_exit(0);
+}
+
+/*
+ * Bring up the server process if it is not already up.
+ */
+int nfs_callback_up(void)
+{
+       struct svc_serv *serv;
+       struct svc_sock *svsk;
+       int ret = 0;
+
+       lock_kernel();
+       down(&nfs_callback_sema);
+       if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
+               goto out;
+       init_completion(&nfs_callback_info.started);
+       init_completion(&nfs_callback_info.stopped);
+       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
+       ret = -ENOMEM;
+       if (!serv)
+               goto out_err;
+       /* FIXME: We don't want to register this socket with the portmapper */
+       ret = svc_makesock(serv, IPPROTO_TCP, 0);
+       if (ret < 0)
+               goto out_destroy;
+       if (!list_empty(&serv->sv_permsocks)) {
+               svsk = list_entry(serv->sv_permsocks.next,
+                               struct svc_sock, sk_list);
+               nfs_callback_tcpport = ntohs(inet_sk(svsk->sk_sk)->sport);
+               dprintk ("Callback port = 0x%x\n", nfs_callback_tcpport);
+       } else
+               BUG();
+       ret = svc_create_thread(nfs_callback_svc, serv);
+       if (ret < 0)
+               goto out_destroy;
+       nfs_callback_info.serv = serv;
+       wait_for_completion(&nfs_callback_info.started);
+out:
+       up(&nfs_callback_sema);
+       unlock_kernel();
+       return ret;
+out_destroy:
+       svc_destroy(serv);
+out_err:
+       nfs_callback_info.users--;
+       goto out;
+}
+
+/*
+ * Kill the server process if it is not already up.
+ */
+int nfs_callback_down(void)
+{
+       int ret = 0;
+
+       lock_kernel();
+       down(&nfs_callback_sema);
+       if (--nfs_callback_info.users || nfs_callback_info.pid == 0)
+               goto out;
+       kill_proc(nfs_callback_info.pid, SIGKILL, 1);
+       wait_for_completion(&nfs_callback_info.stopped);
+out:
+       up(&nfs_callback_sema);
+       unlock_kernel();
+       return ret;
+}
+
+/*
+ * AUTH_NULL authentication
+ */
+static int nfs_callback_null_accept(struct svc_rqst *rqstp, u32 *authp)
+{
+       struct kvec    *argv = &rqstp->rq_arg.head[0];
+       struct kvec    *resv = &rqstp->rq_res.head[0];
+
+       if (argv->iov_len < 3*4)
+               return SVC_GARBAGE;
+
+       if (svc_getu32(argv) != 0) {
+               dprintk("svc: bad null cred\n");
+               *authp = rpc_autherr_badcred;
+               return SVC_DENIED;
+       }
+       if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
+               dprintk("svc: bad null verf\n");
+                *authp = rpc_autherr_badverf;
+                return SVC_DENIED;
+       }
+
+       /* Signal that mapping to nobody uid/gid is required */
+       rqstp->rq_cred.cr_uid = (uid_t) -1;
+       rqstp->rq_cred.cr_gid = (gid_t) -1;
+       rqstp->rq_cred.cr_group_info = groups_alloc(0);
+       if (rqstp->rq_cred.cr_group_info == NULL)
+               return SVC_DROP; /* kmalloc failure - client must retry */
+
+       /* Put NULL verifier */
+       svc_putu32(resv, RPC_AUTH_NULL);
+       svc_putu32(resv, 0);
+       dprintk("%s: success, returning %d!\n", __FUNCTION__, SVC_OK);
+       return SVC_OK;
+}
+
+static int nfs_callback_null_release(struct svc_rqst *rqstp)
+{
+       if (rqstp->rq_cred.cr_group_info)
+               put_group_info(rqstp->rq_cred.cr_group_info);
+       rqstp->rq_cred.cr_group_info = NULL;
+       return 0; /* don't drop */
+}
+
+static struct auth_ops nfs_callback_auth_null = {
+       .name = "null",
+       .flavour = RPC_AUTH_NULL,
+       .accept = nfs_callback_null_accept,
+       .release = nfs_callback_null_release,
+};
+
+/*
+ * AUTH_SYS authentication
+ */
+static int nfs_callback_unix_accept(struct svc_rqst *rqstp, u32 *authp)
+{
+       struct kvec    *argv = &rqstp->rq_arg.head[0];
+       struct kvec    *resv = &rqstp->rq_res.head[0];
+       struct svc_cred *cred = &rqstp->rq_cred;
+       u32 slen, i;
+       int len = argv->iov_len;
+
+       dprintk("%s: start\n", __FUNCTION__);
+       cred->cr_group_info = NULL;
+       rqstp->rq_client = NULL;
+       if ((len -= 3*4) < 0)
+               return SVC_GARBAGE;
+
+       /* Get length, time stamp and machine name */
+       svc_getu32(argv);
+       svc_getu32(argv);
+       slen = XDR_QUADLEN(ntohl(svc_getu32(argv)));
+       if (slen > 64 || (len -= (slen + 3)*4) < 0)
+               goto badcred;
+       argv->iov_base = (void*)((u32*)argv->iov_base + slen);
+       argv->iov_len -= slen*4;
+
+       cred->cr_uid = ntohl(svc_getu32(argv));
+       cred->cr_gid = ntohl(svc_getu32(argv));
+       slen = ntohl(svc_getu32(argv));
+       if (slen > 16 || (len -= (slen + 2)*4) < 0)
+               goto badcred;
+       cred->cr_group_info = groups_alloc(slen);
+       if (cred->cr_group_info == NULL)
+               return SVC_DROP;
+       for (i = 0; i < slen; i++)
+               GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
+
+       if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
+               *authp = rpc_autherr_badverf;
+               return SVC_DENIED;
+       }
+       /* Put NULL verifier */
+       svc_putu32(resv, RPC_AUTH_NULL);
+       svc_putu32(resv, 0);
+       dprintk("%s: success, returning %d!\n", __FUNCTION__, SVC_OK);
+       return SVC_OK;
+badcred:
+       *authp = rpc_autherr_badcred;
+       return SVC_DENIED;
+}
+
+static int nfs_callback_unix_release(struct svc_rqst *rqstp)
+{
+       if (rqstp->rq_cred.cr_group_info)
+               put_group_info(rqstp->rq_cred.cr_group_info);
+       rqstp->rq_cred.cr_group_info = NULL;
+       return 0;
+}
+
+static struct auth_ops nfs_callback_auth_unix = {
+       .name = "unix",
+       .flavour = RPC_AUTH_UNIX,
+       .accept = nfs_callback_unix_accept,
+       .release = nfs_callback_unix_release,
+};
+
+/*
+ * Hook the authentication protocol
+ */
+static int nfs_callback_auth(struct svc_rqst *rqstp, u32 *authp)
+{
+       struct in_addr *addr = &rqstp->rq_addr.sin_addr;
+       struct nfs4_client *clp;
+       struct kvec *argv = &rqstp->rq_arg.head[0];
+       int flavour;
+       int retval;
+
+       /* Don't talk to strangers */
+       clp = nfs4_find_client(addr);
+       if (clp == NULL)
+               return SVC_DROP;
+       dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
+       nfs4_put_client(clp);
+       flavour = ntohl(svc_getu32(argv));
+       switch(flavour) {
+               case RPC_AUTH_NULL:
+                       if (rqstp->rq_proc != CB_NULL) {
+                               *authp = rpc_autherr_tooweak;
+                               retval = SVC_DENIED;
+                               break;
+                       }
+                       rqstp->rq_authop = &nfs_callback_auth_null;
+                       retval = nfs_callback_null_accept(rqstp, authp);
+                       break;
+               case RPC_AUTH_UNIX:
+                       /* Eat the authentication flavour */
+                       rqstp->rq_authop = &nfs_callback_auth_unix;
+                       retval = nfs_callback_unix_accept(rqstp, authp);
+                       break;
+               default:
+                       /* FIXME: need to add RPCSEC_GSS upcalls */
+#if 0
+                       svc_ungetu32(argv);
+                       retval = svc_authenticate(rqstp, authp);
+#else
+                       *authp = rpc_autherr_rejectedcred;
+                       retval = SVC_DENIED;
+#endif
+       }
+       dprintk("%s: flavour %d returning error %d\n", __FUNCTION__, flavour, retval);
+       return retval;
+}
+
+/*
+ * Define NFS4 callback program
+ */
+extern struct svc_version nfs4_callback_version1;
+
+static struct svc_version *nfs4_callback_version[] = {
+       [1] = &nfs4_callback_version1,
+};
+
+static struct svc_stat nfs4_callback_stats;
+
+static struct svc_program nfs4_callback_program = {
+       .pg_prog = NFS4_CALLBACK,                       /* RPC service number */
+       .pg_nvers = ARRAY_SIZE(nfs4_callback_version),  /* Number of entries */
+       .pg_vers = nfs4_callback_version,               /* version table */
+       .pg_name = "NFSv4 callback",                    /* service name */
+       .pg_class = "nfs",                              /* authentication class */
+       .pg_stats = &nfs4_callback_stats,
+       .pg_authenticate = nfs_callback_auth,
+};
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
new file mode 100644 (file)
index 0000000..a0db2d4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * linux/fs/nfs/callback.h
+ *
+ * Copyright (C) 2004 Trond Myklebust
+ *
+ * NFSv4 callback definitions
+ */
+#ifndef __LINUX_FS_NFS_CALLBACK_H
+#define __LINUX_FS_NFS_CALLBACK_H
+
+#define NFS4_CALLBACK 0x40000000
+#define NFS4_CALLBACK_XDRSIZE 2048
+#define NFS4_CALLBACK_BUFSIZE (1024 + NFS4_CALLBACK_XDRSIZE)
+
+enum nfs4_callback_procnum {
+       CB_NULL = 0,
+       CB_COMPOUND = 1,
+};
+
+enum nfs4_callback_opnum {
+       OP_CB_GETATTR = 3,
+       OP_CB_RECALL  = 4,
+       OP_CB_ILLEGAL = 10044,
+};
+
+struct cb_compound_hdr_arg {
+       int taglen;
+       const char *tag;
+       unsigned int callback_ident;
+       unsigned nops;
+};
+
+struct cb_compound_hdr_res {
+       uint32_t *status;
+       int taglen;
+       const char *tag;
+       uint32_t *nops;
+};
+
+struct cb_getattrargs {
+       struct sockaddr_in *addr;
+       struct nfs_fh fh;
+       uint32_t bitmap[2];
+};
+
+struct cb_getattrres {
+       uint32_t status;
+       uint32_t bitmap[2];
+       uint64_t size;
+       uint64_t change_attr;
+       struct timespec ctime;
+       struct timespec mtime;
+};
+
+struct cb_recallargs {
+       struct sockaddr_in *addr;
+       struct nfs_fh fh;
+       nfs4_stateid stateid;
+       uint32_t truncate;
+};
+
+extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
+extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
+
+extern int nfs_callback_up(void);
+extern int nfs_callback_down(void);
+
+extern unsigned short nfs_callback_tcpport;
+
+#endif /* __LINUX_FS_NFS_CALLBACK_H */
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
new file mode 100644 (file)
index 0000000..ece27e4
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * linux/fs/nfs/callback_proc.c
+ *
+ * Copyright (C) 2004 Trond Myklebust
+ *
+ * NFSv4 callback procedures
+ */
+#include <linux/config.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include "callback.h"
+#include "delegation.h"
+
+#define NFSDBG_FACILITY NFSDBG_CALLBACK
+unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
+{
+       struct nfs4_client *clp;
+       struct nfs_delegation *delegation;
+       struct nfs_inode *nfsi;
+       struct inode *inode;
+       
+       res->bitmap[0] = res->bitmap[1] = 0;
+       res->status = htonl(NFS4ERR_BADHANDLE);
+       clp = nfs4_find_client(&args->addr->sin_addr);
+       if (clp == NULL)
+               goto out;
+       inode = nfs_delegation_find_inode(clp, &args->fh);
+       if (inode == NULL)
+               goto out_putclient;
+       nfsi = NFS_I(inode);
+       down_read(&nfsi->rwsem);
+       delegation = nfsi->delegation;
+       if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
+               goto out_iput;
+       res->size = i_size_read(inode);
+       res->change_attr = NFS_CHANGE_ATTR(inode);
+       res->ctime = inode->i_ctime;
+       res->mtime = inode->i_mtime;
+       res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
+               args->bitmap[0];
+       res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
+               args->bitmap[1];
+       res->status = 0;
+out_iput:
+       up_read(&nfsi->rwsem);
+       iput(inode);
+out_putclient:
+       nfs4_put_client(clp);
+out:
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
+       return res->status;
+}
+
+unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
+{
+       struct nfs4_client *clp;
+       struct inode *inode;
+       unsigned res;
+       
+       res = htonl(NFS4ERR_BADHANDLE);
+       clp = nfs4_find_client(&args->addr->sin_addr);
+       if (clp == NULL)
+               goto out;
+       inode = nfs_delegation_find_inode(clp, &args->fh);
+       if (inode == NULL)
+               goto out_putclient;
+       /* Set up a helper thread to actually return the delegation */
+       switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
+               case 0:
+                       res = 0;
+                       break;
+               case -ENOENT:
+                       res = htonl(NFS4ERR_BAD_STATEID);
+                       break;
+               default:
+                       res = htonl(NFS4ERR_RESOURCE);
+       }
+       iput(inode);
+out_putclient:
+       nfs4_put_client(clp);
+out:
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
+       return res;
+}
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
new file mode 100644 (file)
index 0000000..d271df9
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * linux/fs/nfs/callback_xdr.c
+ *
+ * Copyright (C) 2004 Trond Myklebust
+ *
+ * NFSv4 callback encode/decode procedures
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include "callback.h"
+
+#define CB_OP_TAGLEN_MAXSZ     (512)
+#define CB_OP_HDR_RES_MAXSZ    (2 + CB_OP_TAGLEN_MAXSZ)
+#define CB_OP_GETATTR_BITMAP_MAXSZ     (4)
+#define CB_OP_GETATTR_RES_MAXSZ        (CB_OP_HDR_RES_MAXSZ + \
+                               CB_OP_GETATTR_BITMAP_MAXSZ + \
+                               2 + 2 + 3 + 3)
+#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
+
+#define NFSDBG_FACILITY NFSDBG_CALLBACK
+
+typedef unsigned (*callback_process_op_t)(void *, void *);
+typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
+typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
+
+
+struct callback_op {
+       callback_process_op_t process_op;
+       callback_decode_arg_t decode_args;
+       callback_encode_res_t encode_res;
+       long res_maxsize;
+};
+
+static struct callback_op callback_ops[];
+
+static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+       return htonl(NFS4_OK);
+}
+
+static int nfs4_decode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
+{
+       return xdr_argsize_check(rqstp, p);
+}
+
+static int nfs4_encode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
+{
+       return xdr_ressize_check(rqstp, p);
+}
+
+static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes)
+{
+       uint32_t *p;
+
+       p = xdr_inline_decode(xdr, nbytes);
+       if (unlikely(p == NULL))
+               printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n");
+       return p;
+}
+
+static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
+{
+       uint32_t *p;
+
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       *len = ntohl(*p);
+
+       if (*len != 0) {
+               p = read_buf(xdr, *len);
+               if (unlikely(p == NULL))
+                       return htonl(NFS4ERR_RESOURCE);
+               *str = (const char *)p;
+       } else
+               *str = NULL;
+
+       return 0;
+}
+
+static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
+{
+       uint32_t *p;
+
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       fh->size = ntohl(*p);
+       if (fh->size > NFS4_FHSIZE)
+               return htonl(NFS4ERR_BADHANDLE);
+       p = read_buf(xdr, fh->size);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       memcpy(&fh->data[0], p, fh->size);
+       memset(&fh->data[fh->size], 0, sizeof(fh->data) - fh->size);
+       return 0;
+}
+
+static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+{
+       uint32_t *p;
+       unsigned int attrlen;
+
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       attrlen = ntohl(*p);
+       p = read_buf(xdr, attrlen << 2);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       if (likely(attrlen > 0))
+               bitmap[0] = ntohl(*p++);
+       if (attrlen > 1)
+               bitmap[1] = ntohl(*p);
+       return 0;
+}
+
+static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
+{
+       uint32_t *p;
+
+       p = read_buf(xdr, 16);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       memcpy(stateid->data, p, 16);
+       return 0;
+}
+
+static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
+{
+       uint32_t *p;
+       unsigned int minor_version;
+       unsigned status;
+
+       status = decode_string(xdr, &hdr->taglen, &hdr->tag);
+       if (unlikely(status != 0))
+               return status;
+       /* We do not like overly long tags! */
+       if (hdr->taglen > CB_OP_TAGLEN_MAXSZ-12 || hdr->taglen < 0) {
+               printk("NFSv4 CALLBACK %s: client sent tag of length %u\n",
+                               __FUNCTION__, hdr->taglen);
+               return htonl(NFS4ERR_RESOURCE);
+       }
+       p = read_buf(xdr, 12);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       minor_version = ntohl(*p++);
+       /* Check minor version is zero. */
+       if (minor_version != 0) {
+               printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n",
+                               __FUNCTION__, minor_version);
+               return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
+       }
+       hdr->callback_ident = ntohl(*p++);
+       hdr->nops = ntohl(*p);
+       return 0;
+}
+
+static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
+{
+       uint32_t *p;
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       *op = ntohl(*p);
+       return 0;
+}
+
+static unsigned decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
+{
+       unsigned status;
+
+       status = decode_fh(xdr, &args->fh);
+       if (unlikely(status != 0))
+               goto out;
+       args->addr = &rqstp->rq_addr;
+       status = decode_bitmap(xdr, args->bitmap);
+out:
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+       return status;
+}
+
+static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
+{
+       uint32_t *p;
+       unsigned status;
+
+       args->addr = &rqstp->rq_addr;
+       status = decode_stateid(xdr, &args->stateid);
+       if (unlikely(status != 0))
+               goto out;
+       p = read_buf(xdr, 4);
+       if (unlikely(p == NULL)) {
+               status = htonl(NFS4ERR_RESOURCE);
+               goto out;
+       }
+       args->truncate = ntohl(*p);
+       status = decode_fh(xdr, &args->fh);
+out:
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+       return 0;
+}
+
+static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
+{
+       uint32_t *p;
+
+       p = xdr_reserve_space(xdr, 4 + len);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       xdr_encode_opaque(p, str, len);
+       return 0;
+}
+
+#define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
+#define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
+static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep)
+{
+       uint32_t bm[2];
+       uint32_t *p;
+
+       bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
+       bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
+       if (bm[1] != 0) {
+               p = xdr_reserve_space(xdr, 16);
+               if (unlikely(p == NULL))
+                       return htonl(NFS4ERR_RESOURCE);
+               *p++ = htonl(2);
+               *p++ = bm[0];
+               *p++ = bm[1];
+       } else if (bm[0] != 0) {
+               p = xdr_reserve_space(xdr, 12);
+               if (unlikely(p == NULL))
+                       return htonl(NFS4ERR_RESOURCE);
+               *p++ = htonl(1);
+               *p++ = bm[0];
+       } else {
+               p = xdr_reserve_space(xdr, 8);
+               if (unlikely(p == NULL))
+                       return htonl(NFS4ERR_RESOURCE);
+               *p++ = htonl(0);
+       }
+       *savep = p;
+       return 0;
+}
+
+static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
+{
+       uint32_t *p;
+
+       if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
+               return 0;
+       p = xdr_reserve_space(xdr, 8);
+       if (unlikely(p == 0))
+               return htonl(NFS4ERR_RESOURCE);
+       p = xdr_encode_hyper(p, change);
+       return 0;
+}
+
+static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
+{
+       uint32_t *p;
+
+       if (!(bitmap[0] & FATTR4_WORD0_SIZE))
+               return 0;
+       p = xdr_reserve_space(xdr, 8);
+       if (unlikely(p == 0))
+               return htonl(NFS4ERR_RESOURCE);
+       p = xdr_encode_hyper(p, size);
+       return 0;
+}
+
+static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
+{
+       uint32_t *p;
+
+       p = xdr_reserve_space(xdr, 12);
+       if (unlikely(p == 0))
+               return htonl(NFS4ERR_RESOURCE);
+       p = xdr_encode_hyper(p, time->tv_sec);
+       *p = htonl(time->tv_nsec);
+       return 0;
+}
+
+static unsigned encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+{
+       if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
+               return 0;
+       return encode_attr_time(xdr,time);
+}
+
+static unsigned encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+{
+       if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
+               return 0;
+       return encode_attr_time(xdr,time);
+}
+
+static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
+{
+       unsigned status;
+
+       hdr->status = xdr_reserve_space(xdr, 4);
+       if (unlikely(hdr->status == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       status = encode_string(xdr, hdr->taglen, hdr->tag);
+       if (unlikely(status != 0))
+               return status;
+       hdr->nops = xdr_reserve_space(xdr, 4);
+       if (unlikely(hdr->nops == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       return 0;
+}
+
+static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
+{
+       uint32_t *p;
+       
+       p = xdr_reserve_space(xdr, 8);
+       if (unlikely(p == NULL))
+               return htonl(NFS4ERR_RESOURCE);
+       *p++ = htonl(op);
+       *p = res;
+       return 0;
+}
+
+static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
+{
+       uint32_t *savep;
+       unsigned status = res->status;
+       
+       if (unlikely(status != 0))
+               goto out;
+       status = encode_attr_bitmap(xdr, res->bitmap, &savep);
+       if (unlikely(status != 0))
+               goto out;
+       status = encode_attr_change(xdr, res->bitmap, res->change_attr);
+       if (unlikely(status != 0))
+               goto out;
+       status = encode_attr_size(xdr, res->bitmap, res->size);
+       if (unlikely(status != 0))
+               goto out;
+       status = encode_attr_ctime(xdr, res->bitmap, &res->ctime);
+       if (unlikely(status != 0))
+               goto out;
+       status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
+       *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
+out:
+       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+       return status;
+}
+
+static unsigned process_op(struct svc_rqst *rqstp,
+               struct xdr_stream *xdr_in, void *argp,
+               struct xdr_stream *xdr_out, void *resp)
+{
+       struct callback_op *op;
+       unsigned int op_nr;
+       unsigned int status = 0;
+       long maxlen;
+       unsigned res;
+
+       dprintk("%s: start\n", __FUNCTION__);
+       status = decode_op_hdr(xdr_in, &op_nr);
+       if (unlikely(status != 0)) {
+               op_nr = OP_CB_ILLEGAL;
+               op = &callback_ops[0];
+       } else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL)) {
+               op_nr = OP_CB_ILLEGAL;
+               op = &callback_ops[0];
+               status = htonl(NFS4ERR_OP_ILLEGAL);
+       } else
+               op = &callback_ops[op_nr];
+
+       maxlen = xdr_out->end - xdr_out->p;
+       if (maxlen > 0 && maxlen < PAGE_SIZE) {
+               if (likely(status == 0 && op->decode_args != NULL))
+                       status = op->decode_args(rqstp, xdr_in, argp);
+               if (likely(status == 0 && op->process_op != NULL))
+                       status = op->process_op(argp, resp);
+       } else
+               status = htonl(NFS4ERR_RESOURCE);
+
+       res = encode_op_hdr(xdr_out, op_nr, status);
+       if (status == 0)
+               status = res;
+       if (op->encode_res != NULL && status == 0)
+               status = op->encode_res(rqstp, xdr_out, resp);
+       dprintk("%s: done, status = %d\n", __FUNCTION__, status);
+       return status;
+}
+
+/*
+ * Decode, process and encode a COMPOUND
+ */
+static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+       struct cb_compound_hdr_arg hdr_arg;
+       struct cb_compound_hdr_res hdr_res;
+       struct xdr_stream xdr_in, xdr_out;
+       uint32_t *p;
+       unsigned int status;
+       unsigned int nops = 1;
+
+       dprintk("%s: start\n", __FUNCTION__);
+
+       xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
+
+       p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
+       rqstp->rq_res.head[0].iov_len = PAGE_SIZE;
+       xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
+
+       decode_compound_hdr_arg(&xdr_in, &hdr_arg);
+       hdr_res.taglen = hdr_arg.taglen;
+       hdr_res.tag = hdr_arg.tag;
+       encode_compound_hdr_res(&xdr_out, &hdr_res);
+
+       for (;;) {
+               status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp);
+               if (status != 0)
+                       break;
+               if (nops == hdr_arg.nops)
+                       break;
+               nops++;
+       }
+       *hdr_res.status = status;
+       *hdr_res.nops = htonl(nops);
+       dprintk("%s: done, status = %u\n", __FUNCTION__, status);
+       return rpc_success;
+}
+
+/*
+ * Define NFS4 callback COMPOUND ops.
+ */
+static struct callback_op callback_ops[] = {
+       [0] = {
+               .res_maxsize = CB_OP_HDR_RES_MAXSZ,
+       },
+       [OP_CB_GETATTR] = {
+               .process_op = (callback_process_op_t)nfs4_callback_getattr,
+               .decode_args = (callback_decode_arg_t)decode_getattr_args,
+               .encode_res = (callback_encode_res_t)encode_getattr_res,
+               .res_maxsize = CB_OP_GETATTR_RES_MAXSZ,
+       },
+       [OP_CB_RECALL] = {
+               .process_op = (callback_process_op_t)nfs4_callback_recall,
+               .decode_args = (callback_decode_arg_t)decode_recall_args,
+               .res_maxsize = CB_OP_RECALL_RES_MAXSZ,
+       }
+};
+
+/*
+ * Define NFS4 callback procedures
+ */
+static struct svc_procedure nfs4_callback_procedures1[] = {
+       [CB_NULL] = {
+               .pc_func = nfs4_callback_null,
+               .pc_decode = (kxdrproc_t)nfs4_decode_void,
+               .pc_encode = (kxdrproc_t)nfs4_encode_void,
+               .pc_xdrressize = 1,
+       },
+       [CB_COMPOUND] = {
+               .pc_func = nfs4_callback_compound,
+               .pc_encode = (kxdrproc_t)nfs4_encode_void,
+               .pc_argsize = 256,
+               .pc_ressize = 256,
+               .pc_xdrressize = NFS4_CALLBACK_BUFSIZE,
+       }
+};
+
+struct svc_version nfs4_callback_version1 = {
+       .vs_vers = 1,
+       .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
+       .vs_proc = nfs4_callback_procedures1,
+       .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
+       .vs_dispatch = NULL,
+};
+
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
new file mode 100644 (file)
index 0000000..5b9c60f
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * linux/fs/nfs/delegation.c
+ *
+ * Copyright (C) 2004 Trond Myklebust
+ *
+ * NFS file delegation management
+ *
+ */
+#include <linux/config.h>
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_xdr.h>
+
+#include "delegation.h"
+
+static struct nfs_delegation *nfs_alloc_delegation(void)
+{
+       return (struct nfs_delegation *)kmalloc(sizeof(struct nfs_delegation), GFP_KERNEL);
+}
+
+static void nfs_free_delegation(struct nfs_delegation *delegation)
+{
+       if (delegation->cred)
+               put_rpccred(delegation->cred);
+       kfree(delegation);
+}
+
+static void nfs_delegation_claim_opens(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_open_context *ctx;
+       struct nfs4_state *state;
+
+again:
+       spin_lock(&inode->i_lock);
+       list_for_each_entry(ctx, &nfsi->open_files, list) {
+               state = ctx->state;
+               if (state == NULL)
+                       continue;
+               if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
+                       continue;
+               get_nfs_open_context(ctx);
+               spin_unlock(&inode->i_lock);
+               if (nfs4_open_delegation_recall(ctx->dentry, state) < 0)
+                       return;
+               put_nfs_open_context(ctx);
+               goto again;
+       }
+       spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Set up a delegation on an inode
+ */
+void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
+{
+       struct nfs_delegation *delegation = NFS_I(inode)->delegation;
+
+       if (delegation == NULL)
+               return;
+       memcpy(delegation->stateid.data, res->delegation.data,
+                       sizeof(delegation->stateid.data));
+       delegation->type = res->delegation_type;
+       delegation->maxsize = res->maxsize;
+       put_rpccred(cred);
+       delegation->cred = get_rpccred(cred);
+       delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
+       NFS_I(inode)->delegation_state = delegation->type;
+       smp_wmb();
+}
+
+/*
+ * Set up a delegation on an inode
+ */
+int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
+{
+       struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_delegation *delegation;
+       int status = 0;
+
+       delegation = nfs_alloc_delegation();
+       if (delegation == NULL)
+               return -ENOMEM;
+       memcpy(delegation->stateid.data, res->delegation.data,
+                       sizeof(delegation->stateid.data));
+       delegation->type = res->delegation_type;
+       delegation->maxsize = res->maxsize;
+       delegation->cred = get_rpccred(cred);
+       delegation->inode = inode;
+
+       spin_lock(&clp->cl_lock);
+       if (nfsi->delegation == NULL) {
+               list_add(&delegation->super_list, &clp->cl_delegations);
+               nfsi->delegation = delegation;
+               nfsi->delegation_state = delegation->type;
+               delegation = NULL;
+       } else {
+               if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
+                                       sizeof(delegation->stateid)) != 0 ||
+                               delegation->type != nfsi->delegation->type) {
+                       printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n",
+                                       __FUNCTION__, NIPQUAD(clp->cl_addr));
+                       status = -EIO;
+               }
+       }
+       spin_unlock(&clp->cl_lock);
+       if (delegation != NULL)
+               kfree(delegation);
+       return status;
+}
+
+static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
+{
+       int res = 0;
+
+       __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+
+       res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
+       nfs_free_delegation(delegation);
+       return res;
+}
+
+/* Sync all data to disk upon delegation return */
+static void nfs_msync_inode(struct inode *inode)
+{
+       filemap_fdatawrite(inode->i_mapping);
+       nfs_wb_all(inode);
+       filemap_fdatawait(inode->i_mapping);
+}
+
+/*
+ * Basic procedure for returning a delegation to the server
+ */
+int nfs_inode_return_delegation(struct inode *inode)
+{
+       struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_delegation *delegation;
+       int res = 0;
+
+       nfs_msync_inode(inode);
+       down_read(&clp->cl_sem);
+       /* Guard against new delegated open calls */
+       down_write(&nfsi->rwsem);
+       spin_lock(&clp->cl_lock);
+       delegation = nfsi->delegation;
+       if (delegation != NULL) {
+               list_del_init(&delegation->super_list);
+               nfsi->delegation = NULL;
+               nfsi->delegation_state = 0;
+       }
+       spin_unlock(&clp->cl_lock);
+       nfs_delegation_claim_opens(inode);
+       up_write(&nfsi->rwsem);
+       up_read(&clp->cl_sem);
+       nfs_msync_inode(inode);
+
+       if (delegation != NULL)
+               res = nfs_do_return_delegation(inode, delegation);
+       return res;
+}
+
+/*
+ * Return all delegations associated to a super block
+ */
+void nfs_return_all_delegations(struct super_block *sb)
+{
+       struct nfs4_client *clp = NFS_SB(sb)->nfs4_state;
+       struct nfs_delegation *delegation;
+       struct inode *inode;
+
+       if (clp == NULL)
+               return;
+restart:
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+               if (delegation->inode->i_sb != sb)
+                       continue;
+               inode = igrab(delegation->inode);
+               if (inode == NULL)
+                       continue;
+               spin_unlock(&clp->cl_lock);
+               nfs_inode_return_delegation(inode);
+               iput(inode);
+               goto restart;
+       }
+       spin_unlock(&clp->cl_lock);
+}
+
+/*
+ * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
+ */
+void nfs_handle_cb_pathdown(struct nfs4_client *clp)
+{
+       struct nfs_delegation *delegation;
+       struct inode *inode;
+
+       if (clp == NULL)
+               return;
+restart:
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+               inode = igrab(delegation->inode);
+               if (inode == NULL)
+                       continue;
+               spin_unlock(&clp->cl_lock);
+               nfs_inode_return_delegation(inode);
+               iput(inode);
+               goto restart;
+       }
+       spin_unlock(&clp->cl_lock);
+}
+
+struct recall_threadargs {
+       struct inode *inode;
+       struct nfs4_client *clp;
+       const nfs4_stateid *stateid;
+
+       struct completion started;
+       int result;
+};
+
+static int recall_thread(void *data)
+{
+       struct recall_threadargs *args = (struct recall_threadargs *)data;
+       struct inode *inode = igrab(args->inode);
+       struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_delegation *delegation;
+
+       daemonize("nfsv4-delegreturn");
+
+       nfs_msync_inode(inode);
+       down_read(&clp->cl_sem);
+       down_write(&nfsi->rwsem);
+       spin_lock(&clp->cl_lock);
+       delegation = nfsi->delegation;
+       if (delegation != NULL && memcmp(delegation->stateid.data,
+                               args->stateid->data,
+                               sizeof(delegation->stateid.data)) == 0) {
+               list_del_init(&delegation->super_list);
+               nfsi->delegation = NULL;
+               nfsi->delegation_state = 0;
+               args->result = 0;
+       } else {
+               delegation = NULL;
+               args->result = -ENOENT;
+       }
+       spin_unlock(&clp->cl_lock);
+       complete(&args->started);
+       nfs_delegation_claim_opens(inode);
+       up_write(&nfsi->rwsem);
+       up_read(&clp->cl_sem);
+       nfs_msync_inode(inode);
+
+       if (delegation != NULL)
+               nfs_do_return_delegation(inode, delegation);
+       iput(inode);
+       module_put_and_exit(0);
+}
+
+/*
+ * Asynchronous delegation recall!
+ */
+int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
+{
+       struct recall_threadargs data = {
+               .inode = inode,
+               .stateid = stateid,
+       };
+       int status;
+
+       init_completion(&data.started);
+       __module_get(THIS_MODULE);
+       status = kernel_thread(recall_thread, &data, CLONE_KERNEL);
+       if (status < 0)
+               goto out_module_put;
+       wait_for_completion(&data.started);
+       return data.result;
+out_module_put:
+       module_put(THIS_MODULE);
+       return status;
+}
+
+/*
+ * Retrieve the inode associated with a delegation
+ */
+struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle)
+{
+       struct nfs_delegation *delegation;
+       struct inode *res = NULL;
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+               if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
+                       res = igrab(delegation->inode);
+                       break;
+               }
+       }
+       spin_unlock(&clp->cl_lock);
+       return res;
+}
+
+/*
+ * Mark all delegations as needing to be reclaimed
+ */
+void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
+{
+       struct nfs_delegation *delegation;
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry(delegation, &clp->cl_delegations, super_list)
+               delegation->flags |= NFS_DELEGATION_NEED_RECLAIM;
+       spin_unlock(&clp->cl_lock);
+}
+
+/*
+ * Reap all unclaimed delegations after reboot recovery is done
+ */
+void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
+{
+       struct nfs_delegation *delegation, *n;
+       LIST_HEAD(head);
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) {
+               if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
+                       continue;
+               list_move(&delegation->super_list, &head);
+               NFS_I(delegation->inode)->delegation = NULL;
+               NFS_I(delegation->inode)->delegation_state = 0;
+       }
+       spin_unlock(&clp->cl_lock);
+       while(!list_empty(&head)) {
+               delegation = list_entry(head.next, struct nfs_delegation, super_list);
+               list_del(&delegation->super_list);
+               nfs_free_delegation(delegation);
+       }
+}
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
new file mode 100644 (file)
index 0000000..3f6c45a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * linux/fs/nfs/delegation.h
+ *
+ * Copyright (c) Trond Myklebust
+ *
+ * Definitions pertaining to NFS delegated files
+ */
+#ifndef FS_NFS_DELEGATION_H
+#define FS_NFS_DELEGATION_H
+
+#if defined(CONFIG_NFS_V4)
+/*
+ * NFSv4 delegation
+ */
+struct nfs_delegation {
+       struct list_head super_list;
+       struct rpc_cred *cred;
+       struct inode *inode;
+       nfs4_stateid stateid;
+       int type;
+#define NFS_DELEGATION_NEED_RECLAIM 1
+       long flags;
+       loff_t maxsize;
+};
+
+int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
+void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
+int nfs_inode_return_delegation(struct inode *inode);
+int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
+
+struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
+void nfs_return_all_delegations(struct super_block *sb);
+void nfs_handle_cb_pathdown(struct nfs4_client *clp);
+
+void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
+void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
+
+/* NFSv4 delegation-related procedures */
+int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
+int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
+
+static inline int nfs_have_delegation(struct inode *inode, int flags)
+{
+       flags &= FMODE_READ|FMODE_WRITE;
+       smp_rmb();
+       if ((NFS_I(inode)->delegation_state & flags) == flags)
+               return 1;
+       return 0;
+}
+#else
+static inline int nfs_have_delegation(struct inode *inode, int flags)
+{
+       return 0;
+}
+#endif
+
+#endif
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
new file mode 100644 (file)
index 0000000..1723939
--- /dev/null
@@ -0,0 +1,974 @@
+/*
+ *  fs/nfs4acl/acl.c
+ *
+ *  Common NFSv4 ACL handling code.
+ *
+ *  Copyright (c) 2002, 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ *  Jeff Sedlak <jsedlak@umich.edu>
+ *  J. Bruce Fields <bfields@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/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/nfs_fs.h>
+#include <linux/posix_acl.h>
+#include <linux/nfs4.h>
+#include <linux/nfs4_acl.h>
+
+
+/* mode bit translations: */
+#define NFS4_READ_MODE (NFS4_ACE_READ_DATA | NFS4_ACE_READ_NAMED_ATTRS)
+#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_WRITE_NAMED_ATTRS | NFS4_ACE_APPEND_DATA)
+#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
+#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
+#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
+
+/* flags used to simulate posix default ACLs */
+#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
+               | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
+
+#define MASK_EQUAL(mask1, mask2) \
+       ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
+
+static u32
+mask_from_posix(unsigned short perm, unsigned int flags)
+{
+       int mask = NFS4_ANYONE_MODE;
+
+       if (flags & NFS4_ACL_OWNER)
+               mask |= NFS4_OWNER_MODE;
+       if (perm & ACL_READ)
+               mask |= NFS4_READ_MODE;
+       if (perm & ACL_WRITE)
+               mask |= NFS4_WRITE_MODE;
+       if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
+               mask |= NFS4_ACE_DELETE_CHILD;
+       if (perm & ACL_EXECUTE)
+               mask |= NFS4_EXECUTE_MODE;
+       return mask;
+}
+
+static u32
+deny_mask(u32 allow_mask, unsigned int flags)
+{
+       u32 ret = ~allow_mask & ~NFS4_ACE_DELETE;
+       if (!(flags & NFS4_ACL_DIR))
+               ret &= ~NFS4_ACE_DELETE_CHILD;
+       return ret;
+}
+
+static int
+mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
+{
+       u32 ignore = 0;
+
+       if (!(flags & NFS4_ACL_DIR))
+               ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */
+       perm |= ignore;
+       *mode = 0;
+       if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
+               *mode |= ACL_READ;
+       if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
+               *mode |= ACL_WRITE;
+       if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
+               *mode |= ACL_EXECUTE;
+       if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
+               return -EINVAL;
+       return 0;
+}
+
+struct ace_container {
+       struct nfs4_ace  *ace;
+       struct list_head  ace_l;
+};
+
+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 *);
+
+struct nfs4_acl *
+nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
+                       unsigned int flags)
+{
+       struct nfs4_acl *acl;
+       int error = -EINVAL;
+
+       if ((pacl != NULL &&
+               (posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) ||
+           (dpacl != NULL &&
+               (posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0)))
+               goto out_err;
+
+       acl = nfs4_acl_new();
+       if (acl == NULL) {
+               error = -ENOMEM;
+               goto out_err;
+       }
+
+       if (pacl != NULL) {
+               error = _posix_to_nfsv4_one(pacl, acl,
+                                               flags & ~NFS4_ACL_TYPE_DEFAULT);
+               if (error < 0)
+                       goto out_acl;
+       }
+
+       if (dpacl != NULL) {
+               error = _posix_to_nfsv4_one(dpacl, acl,
+                                               flags | NFS4_ACL_TYPE_DEFAULT);
+               if (error < 0)
+                       goto out_acl;
+       }
+
+       return acl;
+
+out_acl:
+       nfs4_acl_free(acl);
+out_err:
+       acl = ERR_PTR(error);
+
+       return acl;
+}
+
+static int
+nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype,
+               uid_t owner, unsigned int flags)
+{
+       int error;
+
+       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+                                eflag, mask, whotype, owner);
+       if (error < 0)
+               return error;
+       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+                               eflag, deny_mask(mask, flags), whotype, owner);
+       return error;
+}
+
+/* We assume the acl has been verified with posix_acl_valid. */
+static int
+_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
+                                               unsigned int flags)
+{
+       struct posix_acl_entry *pa, *pe, *group_owner_entry;
+       int error = -EINVAL;
+       u32 mask, mask_mask;
+       int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
+                                       NFS4_INHERITANCE_FLAGS : 0);
+
+       BUG_ON(pacl->a_count < 3);
+       pe = pacl->a_entries + pacl->a_count;
+       pa = pe - 2; /* if mask entry exists, it's second from the last. */
+       if (pa->e_tag == ACL_MASK)
+               mask_mask = deny_mask(mask_from_posix(pa->e_perm, flags), flags);
+       else
+               mask_mask = 0;
+
+       pa = pacl->a_entries;
+       BUG_ON(pa->e_tag != ACL_USER_OBJ);
+       mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
+       error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags);
+       if (error < 0)
+               goto out;
+       pa++;
+
+       while (pa->e_tag == ACL_USER) {
+               mask = mask_from_posix(pa->e_perm, flags);
+               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+                               eflag,  mask_mask, NFS4_ACL_WHO_NAMED, pa->e_id);
+               if (error < 0)
+                       goto out;
+
+
+               error = nfs4_acl_add_pair(acl, eflag, mask,
+                               NFS4_ACL_WHO_NAMED, pa->e_id, flags);
+               if (error < 0)
+                       goto out;
+               pa++;
+       }
+
+       /* In the case of groups, we apply allow ACEs first, then deny ACEs,
+        * since a user can be in more than one group.  */
+
+       /* allow ACEs */
+
+       if (pacl->a_count > 3) {
+               BUG_ON(pa->e_tag != ACL_GROUP_OBJ);
+               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
+                               NFS4_ACL_WHO_GROUP, 0);
+               if (error < 0)
+                       goto out;
+       }
+       group_owner_entry = pa;
+       mask = mask_from_posix(pa->e_perm, flags);
+       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+                       NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
+                       NFS4_ACL_WHO_GROUP, 0);
+       if (error < 0)
+               goto out;
+       pa++;
+
+       while (pa->e_tag == ACL_GROUP) {
+               mask = mask_from_posix(pa->e_perm, flags);
+               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
+                               NFS4_ACL_WHO_NAMED, pa->e_id);
+               if (error < 0)
+                       goto out;
+
+               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
+                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
+                               NFS4_ACL_WHO_NAMED, pa->e_id);
+               if (error < 0)
+                       goto out;
+               pa++;
+       }
+
+       /* deny ACEs */
+
+       pa = group_owner_entry;
+       mask = mask_from_posix(pa->e_perm, flags);
+       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+                       NFS4_ACE_IDENTIFIER_GROUP | eflag,
+                       deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0);
+       if (error < 0)
+               goto out;
+       pa++;
+       while (pa->e_tag == ACL_GROUP) {
+               mask = mask_from_posix(pa->e_perm, flags);
+               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
+                               NFS4_ACE_IDENTIFIER_GROUP | eflag,
+                               deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id);
+               if (error < 0)
+                       goto out;
+               pa++;
+       }
+
+       if (pa->e_tag == ACL_MASK)
+               pa++;
+       BUG_ON(pa->e_tag != ACL_OTHER);
+       mask = mask_from_posix(pa->e_perm, flags);
+       error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags);
+
+out:
+       return error;
+}
+
+static void
+sort_pacl_range(struct posix_acl *pacl, int start, int end) {
+       int sorted = 0, i;
+       struct posix_acl_entry tmp;
+
+       /* We just do a bubble sort; easy to do in place, and we're not
+        * expecting acl's to be long enough to justify anything more. */
+       while (!sorted) {
+               sorted = 1;
+               for (i = start; i < end; i++) {
+                       if (pacl->a_entries[i].e_id
+                                       > pacl->a_entries[i+1].e_id) {
+                               sorted = 0;
+                               tmp = pacl->a_entries[i];
+                               pacl->a_entries[i] = pacl->a_entries[i+1];
+                               pacl->a_entries[i+1] = tmp;
+                       }
+               }
+       }
+}
+
+static void
+sort_pacl(struct posix_acl *pacl)
+{
+       /* posix_acl_valid requires that users and groups be in order
+        * by uid/gid. */
+       int i, j;
+
+       if (pacl->a_count <= 4)
+               return; /* no users or groups */
+       i = 1;
+       while (pacl->a_entries[i].e_tag == ACL_USER)
+               i++;
+       sort_pacl_range(pacl, 1, i-1);
+
+       BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
+       j = i++;
+       while (pacl->a_entries[j].e_tag == ACL_GROUP)
+               j++;
+       sort_pacl_range(pacl, i, j-1);
+       return;
+}
+
+static int
+write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
+               struct posix_acl_entry **pace, short tag, unsigned int flags)
+{
+       struct posix_acl_entry *this = *pace;
+
+       if (*pace == pacl->a_entries + pacl->a_count)
+               return -EINVAL; /* fell off the end */
+       (*pace)++;
+       this->e_tag = tag;
+       if (tag == ACL_USER_OBJ)
+               flags |= NFS4_ACL_OWNER;
+       if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
+               return -EINVAL;
+       this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
+                       ace->who : ACL_UNDEFINED_ID);
+       return 0;
+}
+
+static struct nfs4_ace *
+get_next_v4_ace(struct list_head **p, struct list_head *head)
+{
+       struct nfs4_ace *ace;
+
+       *p = (*p)->next;
+       if (*p == head)
+               return NULL;
+       ace = list_entry(*p, struct nfs4_ace, l_ace);
+
+       return ace;
+}
+
+int
+nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
+               struct posix_acl **dpacl, unsigned int flags)
+{
+       struct nfs4_acl *dacl;
+       int error = -ENOMEM;
+
+       *pacl = NULL;
+       *dpacl = NULL;
+
+       dacl = nfs4_acl_new();
+       if (dacl == NULL)
+               goto out;
+
+       error = nfs4_acl_split(acl, dacl);
+       if (error < 0)
+               goto out_acl;
+
+       if (pacl != NULL) {
+               if (acl->naces == 0) {
+                       error = -ENODATA;
+                       goto try_dpacl;
+               }
+
+               *pacl = _nfsv4_to_posix_one(acl, flags);
+               if (IS_ERR(*pacl)) {
+                       error = PTR_ERR(*pacl);
+                       *pacl = NULL;
+                       goto out_acl;
+               }
+       }
+
+try_dpacl:
+       if (dpacl != NULL) {
+               if (dacl->naces == 0) {
+                       if (pacl == NULL || *pacl == NULL)
+                               error = -ENODATA;
+                       goto out_acl;
+               }
+
+               error = 0;
+               *dpacl = _nfsv4_to_posix_one(dacl, flags);
+               if (IS_ERR(*dpacl)) {
+                       error = PTR_ERR(*dpacl);
+                       *dpacl = NULL;
+                       goto out_acl;
+               }
+       }
+
+out_acl:
+       if (error && pacl) {
+               posix_acl_release(*pacl);
+               *pacl = NULL;
+       }
+       nfs4_acl_free(dacl);
+out:
+       return error;
+}
+
+static int
+same_who(struct nfs4_ace *a, struct nfs4_ace *b)
+{
+       return a->whotype == b->whotype &&
+               (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
+}
+
+static int
+complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny,
+               unsigned int flags)
+{
+       int ignore = 0;
+       if (!(flags & NFS4_ACL_DIR))
+               ignore |= NFS4_ACE_DELETE_CHILD;
+       return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
+                         ignore|deny->access_mask) &&
+               allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
+               deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
+               allow->flag == deny->flag &&
+               same_who(allow, deny);
+}
+
+static inline int
+user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+               struct posix_acl *pacl, struct posix_acl_entry **pace,
+               unsigned int flags)
+{
+       int error = -EINVAL;
+       struct nfs4_ace *ace, *ace2;
+
+       ace = get_next_v4_ace(p, &n4acl->ace_head);
+       if (ace == NULL)
+               goto out;
+       if (ace2type(ace) != ACL_USER_OBJ)
+               goto out;
+       error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
+       if (error < 0)
+               goto out;
+       error = -EINVAL;
+       ace2 = get_next_v4_ace(p, &n4acl->ace_head);
+       if (ace2 == NULL)
+               goto out;
+       if (!complementary_ace_pair(ace, ace2, flags))
+               goto out;
+       error = 0;
+out:
+       return error;
+}
+
+static inline int
+users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+               struct nfs4_ace **mask_ace,
+               struct posix_acl *pacl, struct posix_acl_entry **pace,
+               unsigned int flags)
+{
+       int error = -EINVAL;
+       struct nfs4_ace *ace, *ace2;
+
+       ace = get_next_v4_ace(p, &n4acl->ace_head);
+       if (ace == NULL)
+               goto out;
+       while (ace2type(ace) == ACL_USER) {
+               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+                       goto out;
+               if (*mask_ace &&
+                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
+                       goto out;
+               *mask_ace = ace;
+               ace = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace == NULL)
+                       goto out;
+               if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+                       goto out;
+               error = write_pace(ace, pacl, pace, ACL_USER, flags);
+               if (error < 0)
+                       goto out;
+               error = -EINVAL;
+               ace2 = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace2 == NULL)
+                       goto out;
+               if (!complementary_ace_pair(ace, ace2, flags))
+                       goto out;
+               if ((*mask_ace)->flag != ace2->flag ||
+                               !same_who(*mask_ace, ace2))
+                       goto out;
+               ace = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace == NULL)
+                       goto out;
+       }
+       error = 0;
+out:
+       return error;
+}
+
+static inline int
+group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+               struct nfs4_ace **mask_ace,
+               struct posix_acl *pacl, struct posix_acl_entry **pace,
+               unsigned int flags)
+{
+       int error = -EINVAL;
+       struct nfs4_ace *ace, *ace2;
+       struct ace_container *ac;
+       struct list_head group_l;
+
+       INIT_LIST_HEAD(&group_l);
+       ace = list_entry(*p, struct nfs4_ace, l_ace);
+
+       /* group owner (mask and allow aces) */
+
+       if (pacl->a_count != 3) {
+               /* then the group owner should be preceded by mask */
+               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+                       goto out;
+               if (*mask_ace &&
+                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
+                       goto out;
+               *mask_ace = ace;
+               ace = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace == NULL)
+                       goto out;
+
+               if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace))
+                       goto out;
+       }
+
+       if (ace2type(ace) != ACL_GROUP_OBJ)
+               goto out;
+
+       ac = kmalloc(sizeof(*ac), GFP_KERNEL);
+       error = -ENOMEM;
+       if (ac == NULL)
+               goto out;
+       ac->ace = ace;
+       list_add_tail(&ac->ace_l, &group_l);
+
+       error = -EINVAL;
+       if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+               goto out;
+
+       error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags);
+       if (error < 0)
+               goto out;
+
+       error = -EINVAL;
+       ace = get_next_v4_ace(p, &n4acl->ace_head);
+       if (ace == NULL)
+               goto out;
+
+       /* groups (mask and allow aces) */
+
+       while (ace2type(ace) == ACL_GROUP) {
+               if (*mask_ace == NULL)
+                       goto out;
+
+               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
+                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
+                       goto out;
+               *mask_ace = ace;
+
+               ace = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace == NULL)
+                       goto out;
+               ac = kmalloc(sizeof(*ac), GFP_KERNEL);
+               error = -ENOMEM;
+               if (ac == NULL)
+                       goto out;
+               error = -EINVAL;
+               if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
+                               !same_who(ace, *mask_ace))
+                       goto out;
+
+               ac->ace = ace;
+               list_add_tail(&ac->ace_l, &group_l);
+
+               error = write_pace(ace, pacl, pace, ACL_GROUP, flags);
+               if (error < 0)
+                       goto out;
+               error = -EINVAL;
+               ace = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace == NULL)
+                       goto out;
+       }
+
+       /* group owner (deny ace) */
+
+       if (ace2type(ace) != ACL_GROUP_OBJ)
+               goto out;
+       ac = list_entry(group_l.next, struct ace_container, ace_l);
+       ace2 = ac->ace;
+       if (!complementary_ace_pair(ace2, ace, flags))
+               goto out;
+       list_del(group_l.next);
+       kfree(ac);
+
+       /* groups (deny aces) */
+
+       while (!list_empty(&group_l)) {
+               ace = get_next_v4_ace(p, &n4acl->ace_head);
+               if (ace == NULL)
+                       goto out;
+               if (ace2type(ace) != ACL_GROUP)
+                       goto out;
+               ac = list_entry(group_l.next, struct ace_container, ace_l);
+               ace2 = ac->ace;
+               if (!complementary_ace_pair(ace2, ace, flags))
+                       goto out;
+               list_del(group_l.next);
+               kfree(ac);
+       }
+
+       ace = get_next_v4_ace(p, &n4acl->ace_head);
+       if (ace == NULL)
+               goto out;
+       if (ace2type(ace) != ACL_OTHER)
+               goto out;
+       error = 0;
+out:
+       while (!list_empty(&group_l)) {
+               ac = list_entry(group_l.next, struct ace_container, ace_l);
+               list_del(group_l.next);
+               kfree(ac);
+       }
+       return error;
+}
+
+static inline int
+mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+               struct nfs4_ace **mask_ace,
+               struct posix_acl *pacl, struct posix_acl_entry **pace,
+               unsigned int flags)
+{
+       int error = -EINVAL;
+       struct nfs4_ace *ace;
+
+       ace = list_entry(*p, struct nfs4_ace, l_ace);
+       if (pacl->a_count != 3) {
+               if (*mask_ace == NULL)
+                       goto out;
+               (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
+               write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
+       }
+       error = 0;
+out:
+       return error;
+}
+
+static inline int
+other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
+               struct posix_acl *pacl, struct posix_acl_entry **pace,
+               unsigned int flags)
+{
+       int error = -EINVAL;
+       struct nfs4_ace *ace, *ace2;
+
+       ace = list_entry(*p, struct nfs4_ace, l_ace);
+       if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
+               goto out;
+       error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
+       if (error < 0)
+               goto out;
+       error = -EINVAL;
+       ace2 = get_next_v4_ace(p, &n4acl->ace_head);
+       if (ace2 == NULL)
+               goto out;
+       if (!complementary_ace_pair(ace, ace2, flags))
+               goto out;
+       error = 0;
+out:
+       return error;
+}
+
+static int
+calculate_posix_ace_count(struct nfs4_acl *n4acl)
+{
+       if (n4acl->naces == 6) /* owner, owner group, and other only */
+               return 3;
+       else { /* Otherwise there must be a mask entry. */
+               /* Also, the remaining entries are for named users and
+                * groups, and come in threes (mask, allow, deny): */
+               if (n4acl->naces < 7)
+                       return -1;
+               if ((n4acl->naces - 7) % 3)
+                       return -1;
+               return 4 + (n4acl->naces - 7)/3;
+       }
+}
+
+
+static struct posix_acl *
+_nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
+{
+       struct posix_acl *pacl;
+       int error = -EINVAL, nace = 0;
+       struct list_head *p;
+       struct nfs4_ace *mask_ace = NULL;
+       struct posix_acl_entry *pace;
+
+       nace = calculate_posix_ace_count(n4acl);
+       if (nace < 0)
+               goto out_err;
+
+       pacl = posix_acl_alloc(nace, GFP_KERNEL);
+       error = -ENOMEM;
+       if (pacl == NULL)
+               goto out_err;
+
+       pace = &pacl->a_entries[0];
+       p = &n4acl->ace_head;
+
+       error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
+       if (error)
+               goto out_acl;
+
+       error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
+       if (error)
+               goto out_acl;
+
+       error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
+                                               flags);
+       if (error)
+               goto out_acl;
+
+       error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
+       if (error)
+               goto out_acl;
+       error = other_from_v4(n4acl, &p, pacl, &pace, flags);
+       if (error)
+               goto out_acl;
+
+       error = -EINVAL;
+       if (p->next != &n4acl->ace_head)
+               goto out_acl;
+       if (pace != pacl->a_entries + pacl->a_count)
+               goto out_acl;
+
+       sort_pacl(pacl);
+
+       return pacl;
+out_acl:
+       posix_acl_release(pacl);
+out_err:
+       pacl = ERR_PTR(error);
+       return pacl;
+}
+
+int
+nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
+{
+       struct list_head *h, *n;
+       struct nfs4_ace *ace;
+       int error = 0;
+
+       list_for_each_safe(h, n, &acl->ace_head) {
+               ace = list_entry(h, struct nfs4_ace, l_ace);
+
+               if ((ace->flag & NFS4_INHERITANCE_FLAGS)
+                               != NFS4_INHERITANCE_FLAGS)
+                       continue;
+
+               error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+                               ace->access_mask, ace->whotype, ace->who) == -1;
+               if (error < 0)
+                       goto out;
+
+               list_del(h);
+               kfree(ace);
+               acl->naces--;
+       }
+
+out:
+       return error;
+}
+
+static short
+ace2type(struct nfs4_ace *ace)
+{
+       switch (ace->whotype) {
+               case NFS4_ACL_WHO_NAMED:
+                       return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
+                                       ACL_GROUP : ACL_USER);
+               case NFS4_ACL_WHO_OWNER:
+                       return ACL_USER_OBJ;
+               case NFS4_ACL_WHO_GROUP:
+                       return ACL_GROUP_OBJ;
+               case NFS4_ACL_WHO_EVERYONE:
+                       return ACL_OTHER;
+       }
+       BUG();
+       return -1;
+}
+
+EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
+EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
+
+struct nfs4_acl *
+nfs4_acl_new(void)
+{
+       struct nfs4_acl *acl;
+
+       if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL)
+               return NULL;
+
+       acl->naces = 0;
+       INIT_LIST_HEAD(&acl->ace_head);
+
+       return acl;
+}
+
+void
+nfs4_acl_free(struct nfs4_acl *acl)
+{
+       struct list_head *h;
+       struct nfs4_ace *ace;
+
+       if (!acl)
+               return;
+
+       while (!list_empty(&acl->ace_head)) {
+               h = acl->ace_head.next;
+               list_del(h);
+               ace = list_entry(h, struct nfs4_ace, l_ace);
+               kfree(ace);
+       }
+
+       kfree(acl);
+
+       return;
+}
+
+int
+nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
+               int whotype, uid_t who)
+{
+       struct nfs4_ace *ace;
+
+       if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
+               return -1;
+
+       ace->type = type;
+       ace->flag = flag;
+       ace->access_mask = access_mask;
+       ace->whotype = whotype;
+       ace->who = who;
+
+       list_add_tail(&ace->l_ace, &acl->ace_head);
+       acl->naces++;
+
+       return 0;
+}
+
+static struct {
+       char *string;
+       int   stringlen;
+       int type;
+} s2t_map[] = {
+       {
+               .string    = "OWNER@",
+               .stringlen = sizeof("OWNER@") - 1,
+               .type      = NFS4_ACL_WHO_OWNER,
+       },
+       {
+               .string    = "GROUP@",
+               .stringlen = sizeof("GROUP@") - 1,
+               .type      = NFS4_ACL_WHO_GROUP,
+       },
+       {
+               .string    = "EVERYONE@",
+               .stringlen = sizeof("EVERYONE@") - 1,
+               .type      = NFS4_ACL_WHO_EVERYONE,
+       },
+};
+
+int
+nfs4_acl_get_whotype(char *p, u32 len)
+{
+       int i;
+
+       for (i=0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++) {
+               if (s2t_map[i].stringlen == len &&
+                               0 == memcmp(s2t_map[i].string, p, len))
+                       return s2t_map[i].type;
+       }
+       return NFS4_ACL_WHO_NAMED;
+}
+
+int
+nfs4_acl_write_who(int who, char *p)
+{
+       int i;
+
+       for (i=0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++) {
+               if (s2t_map[i].type == who) {
+                       memcpy(p, s2t_map[i].string, s2t_map[i].stringlen);
+                       return s2t_map[i].stringlen;
+               }
+       }
+       BUG();
+       return -1;
+}
+
+static inline int
+match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
+{
+       switch (ace->whotype) {
+               case NFS4_ACL_WHO_NAMED:
+                       return who == ace->who;
+               case NFS4_ACL_WHO_OWNER:
+                       return who == owner;
+               case NFS4_ACL_WHO_GROUP:
+                       return who == group;
+               case NFS4_ACL_WHO_EVERYONE:
+                       return 1;
+               default:
+                       return 0;
+       }
+}
+
+/* 0 = granted, -EACCES = denied; mask is an nfsv4 mask, not mode bits */
+int
+nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
+                       uid_t who, u32 mask)
+{
+       struct nfs4_ace *ace;
+       u32 allowed = 0;
+
+       list_for_each_entry(ace, &acl->ace_head, l_ace) {
+               if (!match_who(ace, group, owner, who))
+                       continue;
+               switch (ace->type) {
+                       case NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE:
+                               allowed |= ace->access_mask;
+                               if ((allowed & mask) == mask)
+                                       return 0;
+                               break;
+                       case NFS4_ACE_ACCESS_DENIED_ACE_TYPE:
+                               if (ace->access_mask & mask)
+                                       return -EACCES;
+                               break;
+               }
+       }
+       return -EACCES;
+}
+
+EXPORT_SYMBOL(nfs4_acl_new);
+EXPORT_SYMBOL(nfs4_acl_free);
+EXPORT_SYMBOL(nfs4_acl_add_ace);
+EXPORT_SYMBOL(nfs4_acl_get_whotype);
+EXPORT_SYMBOL(nfs4_acl_write_who);
+EXPORT_SYMBOL(nfs4_acl_permission);
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
new file mode 100644 (file)
index 0000000..3b74e66
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * aops.h - Defines for NTFS kernel address space operations and page cache
+ *         handling.  Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2002 Richard Russon
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_NTFS_AOPS_H
+#define _LINUX_NTFS_AOPS_H
+
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+
+#include "inode.h"
+
+/**
+ * ntfs_unmap_page - release a page that was mapped using ntfs_map_page()
+ * @page:      the page to release
+ *
+ * Unpin, unmap and release a page that was obtained from ntfs_map_page().
+ */
+static inline void ntfs_unmap_page(struct page *page)
+{
+       kunmap(page);
+       page_cache_release(page);
+}
+
+/**
+ * ntfs_map_page - map a page into accessible memory, reading it if necessary
+ * @mapping:   address space for which to obtain the page
+ * @index:     index into the page cache for @mapping of the page to map
+ *
+ * Read a page from the page cache of the address space @mapping at position
+ * @index, where @index is in units of PAGE_CACHE_SIZE, and not in bytes.
+ *
+ * If the page is not in memory it is loaded from disk first using the readpage
+ * method defined in the address space operations of @mapping and the page is
+ * added to the page cache of @mapping in the process.
+ *
+ * If the page belongs to an mst protected attribute and it is marked as such
+ * in its ntfs inode (NInoMstProtected()) the mst fixups are applied but no
+ * error checking is performed.  This means the caller has to verify whether
+ * the ntfs record(s) contained in the page are valid or not using one of the
+ * ntfs_is_XXXX_record{,p}() macros, where XXXX is the record type you are
+ * expecting to see.  (For details of the macros, see fs/ntfs/layout.h.)
+ *
+ * If the page is in high memory it is mapped into memory directly addressible
+ * by the kernel.
+ *
+ * Finally the page count is incremented, thus pinning the page into place.
+ *
+ * The above means that page_address(page) can be used on all pages obtained
+ * with ntfs_map_page() to get the kernel virtual address of the page.
+ *
+ * When finished with the page, the caller has to call ntfs_unmap_page() to
+ * unpin, unmap and release the page.
+ *
+ * Note this does not grant exclusive access. If such is desired, the caller
+ * must provide it independently of the ntfs_{un}map_page() calls by using
+ * a {rw_}semaphore or other means of serialization. A spin lock cannot be
+ * used as ntfs_map_page() can block.
+ *
+ * The unlocked and uptodate page is returned on success or an encoded error
+ * on failure. Caller has to test for error using the IS_ERR() macro on the
+ * return value. If that evaluates to TRUE, the negative error code can be
+ * obtained using PTR_ERR() on the return value of ntfs_map_page().
+ */
+static inline struct page *ntfs_map_page(struct address_space *mapping,
+               unsigned long index)
+{
+       struct page *page = read_cache_page(mapping, index,
+                       (filler_t*)mapping->a_ops->readpage, NULL);
+
+       if (!IS_ERR(page)) {
+               wait_on_page_locked(page);
+               kmap(page);
+               if (PageUptodate(page) && !PageError(page))
+                       return page;
+               ntfs_unmap_page(page);
+               return ERR_PTR(-EIO);
+       }
+       return page;
+}
+
+#ifdef NTFS_RW
+
+extern void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs);
+
+#endif /* NTFS_RW */
+
+#endif /* _LINUX_NTFS_AOPS_H */
diff --git a/fs/ntfs/bitmap.c b/fs/ntfs/bitmap.c
new file mode 100644 (file)
index 0000000..b8f0611
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * bitmap.c - NTFS kernel bitmap handling.  Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2004 Anton Altaparmakov
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef NTFS_RW
+
+#include <linux/pagemap.h>
+
+#include "bitmap.h"
+#include "debug.h"
+#include "ntfs.h"
+
+/**
+ * __ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
+ * @vi:                        vfs inode describing the bitmap
+ * @start_bit:         first bit to set
+ * @count:             number of bits to set
+ * @value:             value to set the bits to (i.e. 0 or 1)
+ * @is_rollback:       if TRUE this is a rollback operation
+ *
+ * Set @count bits starting at bit @start_bit in the bitmap described by the
+ * vfs inode @vi to @value, where @value is either 0 or 1.
+ *
+ * @is_rollback should always be FALSE, it is for internal use to rollback
+ * errors.  You probably want to use ntfs_bitmap_set_bits_in_run() instead.
+ *
+ * Return 0 on success and -errno on error.
+ */
+int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
+               const s64 count, const u8 value, const BOOL is_rollback)
+{
+       s64 cnt = count;
+       pgoff_t index, end_index;
+       struct address_space *mapping;
+       struct page *page;
+       u8 *kaddr;
+       int pos, len;
+       u8 bit;
+
+       BUG_ON(!vi);
+       ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, "
+                       "value %u.%s", vi->i_ino, (unsigned long long)start_bit,
+                       (unsigned long long)cnt, (unsigned int)value,
+                       is_rollback ? " (rollback)" : "");
+       BUG_ON(start_bit < 0);
+       BUG_ON(cnt < 0);
+       BUG_ON(value > 1);
+       /*
+        * Calculate the indices for the pages containing the first and last
+        * bits, i.e. @start_bit and @start_bit + @cnt - 1, respectively.
+        */
+       index = start_bit >> (3 + PAGE_CACHE_SHIFT);
+       end_index = (start_bit + cnt - 1) >> (3 + PAGE_CACHE_SHIFT);
+
+       /* Get the page containing the first bit (@start_bit). */
+       mapping = vi->i_mapping;
+       page = ntfs_map_page(mapping, index);
+       if (IS_ERR(page)) {
+               if (!is_rollback)
+                       ntfs_error(vi->i_sb, "Failed to map first page (error "
+                                       "%li), aborting.", PTR_ERR(page));
+               return PTR_ERR(page);
+       }
+       kaddr = page_address(page);
+
+       /* Set @pos to the position of the byte containing @start_bit. */
+       pos = (start_bit >> 3) & ~PAGE_CACHE_MASK;
+
+       /* Calculate the position of @start_bit in the first byte. */
+       bit = start_bit & 7;
+
+       /* If the first byte is partial, modify the appropriate bits in it. */
+       if (bit) {
+               u8 *byte = kaddr + pos;
+               while ((bit & 7) && cnt--) {
+                       if (value)
+                               *byte |= 1 << bit++;
+                       else
+                               *byte &= ~(1 << bit++);
+               }
+               /* If we are done, unmap the page and return success. */
+               if (!cnt)
+                       goto done;
+
+               /* Update @pos to the new position. */
+               pos++;
+       }
+       /*
+        * Depending on @value, modify all remaining whole bytes in the page up
+        * to @cnt.
+        */
+       len = min_t(s64, cnt >> 3, PAGE_CACHE_SIZE - pos);
+       memset(kaddr + pos, value ? 0xff : 0, len);
+       cnt -= len << 3;
+
+       /* Update @len to point to the first not-done byte in the page. */
+       if (cnt < 8)
+               len += pos;
+
+       /* If we are not in the last page, deal with all subsequent pages. */
+       while (index < end_index) {
+               BUG_ON(cnt <= 0);
+
+               /* Update @index and get the next page. */
+               flush_dcache_page(page);
+               set_page_dirty(page);
+               ntfs_unmap_page(page);
+               page = ntfs_map_page(mapping, ++index);
+               if (IS_ERR(page))
+                       goto rollback;
+               kaddr = page_address(page);
+               /*
+                * Depending on @value, modify all remaining whole bytes in the
+                * page up to @cnt.
+                */
+               len = min_t(s64, cnt >> 3, PAGE_CACHE_SIZE);
+               memset(kaddr, value ? 0xff : 0, len);
+               cnt -= len << 3;
+       }
+       /*
+        * The currently mapped page is the last one.  If the last byte is
+        * partial, modify the appropriate bits in it.  Note, @len is the
+        * position of the last byte inside the page.
+        */
+       if (cnt) {
+               u8 *byte;
+
+               BUG_ON(cnt > 7);
+
+               bit = cnt;
+               byte = kaddr + len;
+               while (bit--) {
+                       if (value)
+                               *byte |= 1 << bit;
+                       else
+                               *byte &= ~(1 << bit);
+               }
+       }
+done:
+       /* We are done.  Unmap the page and return success. */
+       flush_dcache_page(page);
+       set_page_dirty(page);
+       ntfs_unmap_page(page);
+       ntfs_debug("Done.");
+       return 0;
+rollback:
+       /*
+        * Current state:
+        *      - no pages are mapped
+        *      - @count - @cnt is the number of bits that have been modified
+        */
+       if (is_rollback)
+               return PTR_ERR(page);
+       if (count != cnt)
+               pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt,
+                               value ? 0 : 1, TRUE);
+       else
+               pos = 0;
+       if (!pos) {
+               /* Rollback was successful. */
+               ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
+                               "%li), aborting.", PTR_ERR(page));
+       } else {
+               /* Rollback failed. */
+               ntfs_error(vi->i_sb, "Failed to map subsequent page (error "
+                               "%li) and rollback failed (error %i).  "
+                               "Aborting and leaving inconsistent metadata.  "
+                               "Unmount and run chkdsk.", PTR_ERR(page), pos);
+               NVolSetErrors(NTFS_SB(vi->i_sb));
+       }
+       return PTR_ERR(page);
+}
+
+#endif /* NTFS_RW */
diff --git a/fs/ntfs/bitmap.h b/fs/ntfs/bitmap.h
new file mode 100644 (file)
index 0000000..bb50d6b
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * bitmap.h - Defines for NTFS kernel bitmap handling.  Part of the Linux-NTFS
+ *           project.
+ *
+ * Copyright (c) 2004 Anton Altaparmakov
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_NTFS_BITMAP_H
+#define _LINUX_NTFS_BITMAP_H
+
+#ifdef NTFS_RW
+
+#include <linux/fs.h>
+
+#include "types.h"
+
+extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
+               const s64 count, const u8 value, const BOOL is_rollback);
+
+/**
+ * ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
+ * @vi:                        vfs inode describing the bitmap
+ * @start_bit:         first bit to set
+ * @count:             number of bits to set
+ * @value:             value to set the bits to (i.e. 0 or 1)
+ *
+ * Set @count bits starting at bit @start_bit in the bitmap described by the
+ * vfs inode @vi to @value, where @value is either 0 or 1.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_bitmap_set_bits_in_run(struct inode *vi,
+               const s64 start_bit, const s64 count, const u8 value)
+{
+       return __ntfs_bitmap_set_bits_in_run(vi, start_bit, count, value,
+                       FALSE);
+}
+
+/**
+ * ntfs_bitmap_set_run - set a run of bits in a bitmap
+ * @vi:                vfs inode describing the bitmap
+ * @start_bit: first bit to set
+ * @count:     number of bits to set
+ *
+ * Set @count bits starting at bit @start_bit in the bitmap described by the
+ * vfs inode @vi.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_bitmap_set_run(struct inode *vi, const s64 start_bit,
+               const s64 count)
+{
+       return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 1);
+}
+
+/**
+ * ntfs_bitmap_clear_run - clear a run of bits in a bitmap
+ * @vi:                vfs inode describing the bitmap
+ * @start_bit: first bit to clear
+ * @count:     number of bits to clear
+ *
+ * Clear @count bits starting at bit @start_bit in the bitmap described by the
+ * vfs inode @vi.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_bitmap_clear_run(struct inode *vi, const s64 start_bit,
+               const s64 count)
+{
+       return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 0);
+}
+
+/**
+ * ntfs_bitmap_set_bit - set a bit in a bitmap
+ * @vi:                vfs inode describing the bitmap
+ * @bit:       bit to set
+ *
+ * Set bit @bit in the bitmap described by the vfs inode @vi.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_bitmap_set_bit(struct inode *vi, const s64 bit)
+{
+       return ntfs_bitmap_set_run(vi, bit, 1);
+}
+
+/**
+ * ntfs_bitmap_clear_bit - clear a bit in a bitmap
+ * @vi:                vfs inode describing the bitmap
+ * @bit:       bit to clear
+ *
+ * Clear bit @bit in the bitmap described by the vfs inode @vi.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_bitmap_clear_bit(struct inode *vi, const s64 bit)
+{
+       return ntfs_bitmap_clear_run(vi, bit, 1);
+}
+
+#endif /* NTFS_RW */
+
+#endif /* defined _LINUX_NTFS_BITMAP_H */
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c
new file mode 100644 (file)
index 0000000..748ed0d
--- /dev/null
@@ -0,0 +1,1001 @@
+/*
+ * lcnalloc.c - Cluster (de)allocation code.  Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2004 Anton Altaparmakov
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef NTFS_RW
+
+#include <linux/pagemap.h>
+
+#include "lcnalloc.h"
+#include "debug.h"
+#include "bitmap.h"
+#include "inode.h"
+#include "volume.h"
+#include "attrib.h"
+#include "malloc.h"
+#include "ntfs.h"
+
+/**
+ * ntfs_cluster_free_from_rl_nolock - free clusters from runlist
+ * @vol:       mounted ntfs volume on which to free the clusters
+ * @rl:                runlist describing the clusters to free
+ *
+ * Free all the clusters described by the runlist @rl on the volume @vol.  In
+ * the case of an error being returned, at least some of the clusters were not
+ * freed.
+ *
+ * Return 0 on success and -errno on error.
+ *
+ * Locking: - The volume lcn bitmap must be locked for writing on entry and is
+ *           left locked on return.
+ */
+static int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
+               const runlist_element *rl)
+{
+       struct inode *lcnbmp_vi = vol->lcnbmp_ino;
+       int ret = 0;
+
+       ntfs_debug("Entering.");
+       for (; rl->length; rl++) {
+               int err;
+
+               if (rl->lcn < 0)
+                       continue;
+               err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length);
+               if (unlikely(err && (!ret || ret == ENOMEM) && ret != err))
+                       ret = err;
+       }
+       ntfs_debug("Done.");
+       return ret;
+}
+
+/**
+ * ntfs_cluster_alloc - allocate clusters on an ntfs volume
+ * @vol:       mounted ntfs volume on which to allocate the clusters
+ * @start_vcn: vcn to use for the first allocated cluster
+ * @count:     number of clusters to allocate
+ * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
+ * @zone:      zone from which to allocate the clusters
+ *
+ * Allocate @count clusters preferably starting at cluster @start_lcn or at the
+ * current allocator position if @start_lcn is -1, on the mounted ntfs volume
+ * @vol. @zone is either DATA_ZONE for allocation of normal clusters or
+ * MFT_ZONE for allocation of clusters for the master file table, i.e. the
+ * $MFT/$DATA attribute.
+ *
+ * @start_vcn specifies the vcn of the first allocated cluster.  This makes
+ * merging the resulting runlist with the old runlist easier.
+ *
+ * You need to check the return value with IS_ERR().  If this is false, the
+ * function was successful and the return value is a runlist describing the
+ * allocated cluster(s).  If IS_ERR() is true, the function failed and
+ * PTR_ERR() gives you the error code.
+ *
+ * Notes on the allocation algorithm
+ * =================================
+ *
+ * There are two data zones.  First is the area between the end of the mft zone
+ * and the end of the volume, and second is the area between the start of the
+ * volume and the start of the mft zone.  On unmodified/standard NTFS 1.x
+ * volumes, the second data zone does not exist due to the mft zone being
+ * expanded to cover the start of the volume in order to reserve space for the
+ * mft bitmap attribute.
+ *
+ * This is not the prettiest function but the complexity stems from the need of
+ * implementing the mft vs data zoned approach and from the fact that we have
+ * access to the lcn bitmap in portions of up to 8192 bytes at a time, so we
+ * need to cope with crossing over boundaries of two buffers.  Further, the
+ * fact that the allocator allows for caller supplied hints as to the location
+ * of where allocation should begin and the fact that the allocator keeps track
+ * of where in the data zones the next natural allocation should occur,
+ * contribute to the complexity of the function.  But it should all be
+ * worthwhile, because this allocator should: 1) be a full implementation of
+ * the MFT zone approach used by Windows NT, 2) cause reduction in
+ * fragmentation, and 3) be speedy in allocations (the code is not optimized
+ * for speed, but the algorithm is, so further speed improvements are probably
+ * possible).
+ *
+ * FIXME: We should be monitoring cluster allocation and increment the MFT zone
+ * size dynamically but this is something for the future.  We will just cause
+ * heavier fragmentation by not doing it and I am not even sure Windows would
+ * grow the MFT zone dynamically, so it might even be correct not to do this.
+ * The overhead in doing dynamic MFT zone expansion would be very large and
+ * unlikely worth the effort. (AIA)
+ *
+ * TODO: I have added in double the required zone position pointer wrap around
+ * logic which can be optimized to having only one of the two logic sets.
+ * However, having the double logic will work fine, but if we have only one of
+ * the sets and we get it wrong somewhere, then we get into trouble, so
+ * removing the duplicate logic requires _very_ careful consideration of _all_
+ * possible code paths.  So at least for now, I am leaving the double logic -
+ * better safe than sorry... (AIA)
+ *
+ * Locking: - The volume lcn bitmap must be unlocked on entry and is unlocked
+ *           on return.
+ *         - This function takes the volume lcn bitmap lock for writing and
+ *           modifies the bitmap contents.
+ */
+runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
+               const s64 count, const LCN start_lcn,
+               const NTFS_CLUSTER_ALLOCATION_ZONES zone)
+{
+       LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
+       LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
+       s64 clusters;
+       struct inode *lcnbmp_vi;
+       runlist_element *rl = NULL;
+       struct address_space *mapping;
+       struct page *page = NULL;
+       u8 *buf, *byte;
+       int err = 0, rlpos, rlsize, buf_size;
+       u8 pass, done_zones, search_zone, need_writeback = 0, bit;
+
+       ntfs_debug("Entering for start_vcn 0x%llx, count 0x%llx, start_lcn "
+                       "0x%llx, zone %s_ZONE.", (unsigned long long)start_vcn,
+                       (unsigned long long)count,
+                       (unsigned long long)start_lcn,
+                       zone == MFT_ZONE ? "MFT" : "DATA");
+       BUG_ON(!vol);
+       lcnbmp_vi = vol->lcnbmp_ino;
+       BUG_ON(!lcnbmp_vi);
+       BUG_ON(start_vcn < 0);
+       BUG_ON(count < 0);
+       BUG_ON(start_lcn < -1);
+       BUG_ON(zone < FIRST_ZONE);
+       BUG_ON(zone > LAST_ZONE);
+
+       /* Return empty runlist if @count == 0 */
+       // FIXME: Do we want to just return NULL instead? (AIA)
+       if (!count) {
+               rl = ntfs_malloc_nofs(PAGE_SIZE);
+               if (!rl)
+                       return ERR_PTR(-ENOMEM);
+               rl[0].vcn = start_vcn;
+               rl[0].lcn = LCN_RL_NOT_MAPPED;
+               rl[0].length = 0;
+               return rl;
+       }
+       /* Take the lcnbmp lock for writing. */
+       down_write(&vol->lcnbmp_lock);
+       /*
+        * If no specific @start_lcn was requested, use the current data zone
+        * position, otherwise use the requested @start_lcn but make sure it
+        * lies outside the mft zone.  Also set done_zones to 0 (no zones done)
+        * and pass depending on whether we are starting inside a zone (1) or
+        * at the beginning of a zone (2).  If requesting from the MFT_ZONE,
+        * we either start at the current position within the mft zone or at
+        * the specified position.  If the latter is out of bounds then we start
+        * at the beginning of the MFT_ZONE.
+        */
+       done_zones = 0;
+       pass = 1;
+       /*
+        * zone_start and zone_end are the current search range.  search_zone
+        * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of
+        * volume) and 4 for data zone 2 (start of volume till start of mft
+        * zone).
+        */
+       zone_start = start_lcn;
+       if (zone_start < 0) {
+               if (zone == DATA_ZONE)
+                       zone_start = vol->data1_zone_pos;
+               else
+                       zone_start = vol->mft_zone_pos;
+               if (!zone_start) {
+                       /*
+                        * Zone starts at beginning of volume which means a
+                        * single pass is sufficient.
+                        */
+                       pass = 2;
+               }
+       } else if (zone == DATA_ZONE && zone_start >= vol->mft_zone_start &&
+                       zone_start < vol->mft_zone_end) {
+               zone_start = vol->mft_zone_end;
+               /*
+                * Starting at beginning of data1_zone which means a single
+                * pass in this zone is sufficient.
+                */
+               pass = 2;
+       } else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start ||
+                       zone_start >= vol->mft_zone_end)) {
+               zone_start = vol->mft_lcn;
+               if (!vol->mft_zone_end)
+                       zone_start = 0;
+               /*
+                * Starting at beginning of volume which means a single pass
+                * is sufficient.
+                */
+               pass = 2;
+       }
+       if (zone == MFT_ZONE) {
+               zone_end = vol->mft_zone_end;
+               search_zone = 1;
+       } else /* if (zone == DATA_ZONE) */ {
+               /* Skip searching the mft zone. */
+               done_zones |= 1;
+               if (zone_start >= vol->mft_zone_end) {
+                       zone_end = vol->nr_clusters;
+                       search_zone = 2;
+               } else {
+                       zone_end = vol->mft_zone_start;
+                       search_zone = 4;
+               }
+       }
+       /*
+        * bmp_pos is the current bit position inside the bitmap.  We use
+        * bmp_initial_pos to determine whether or not to do a zone switch.
+        */
+       bmp_pos = bmp_initial_pos = zone_start;
+
+       /* Loop until all clusters are allocated, i.e. clusters == 0. */
+       clusters = count;
+       rlpos = rlsize = 0;
+       mapping = lcnbmp_vi->i_mapping;
+       while (1) {
+               ntfs_debug("Start of outer while loop: done_zones 0x%x, "
+                               "search_zone %i, pass %i, zone_start 0x%llx, "
+                               "zone_end 0x%llx, bmp_initial_pos 0x%llx, "
+                               "bmp_pos 0x%llx, rlpos %i, rlsize %i.",
+                               done_zones, search_zone, pass,
+                               (unsigned long long)zone_start,
+                               (unsigned long long)zone_end,
+                               (unsigned long long)bmp_initial_pos,
+                               (unsigned long long)bmp_pos, rlpos, rlsize);
+               /* Loop until we run out of free clusters. */
+               last_read_pos = bmp_pos >> 3;
+               ntfs_debug("last_read_pos 0x%llx.",
+                               (unsigned long long)last_read_pos);
+               if (last_read_pos > lcnbmp_vi->i_size) {
+                       ntfs_debug("End of attribute reached.  "
+                                       "Skipping to zone_pass_done.");
+                       goto zone_pass_done;
+               }
+               if (likely(page)) {
+                       if (need_writeback) {
+                               ntfs_debug("Marking page dirty.");
+                               flush_dcache_page(page);
+                               set_page_dirty(page);
+                               need_writeback = 0;
+                       }
+                       ntfs_unmap_page(page);
+               }
+               page = ntfs_map_page(mapping, last_read_pos >>
+                               PAGE_CACHE_SHIFT);
+               if (IS_ERR(page)) {
+                       err = PTR_ERR(page);
+                       ntfs_error(vol->sb, "Failed to map page.");
+                       goto out;
+               }
+               buf_size = last_read_pos & ~PAGE_CACHE_MASK;
+               buf = page_address(page) + buf_size;
+               buf_size = PAGE_CACHE_SIZE - buf_size;
+               if (unlikely(last_read_pos + buf_size > lcnbmp_vi->i_size))
+                       buf_size = lcnbmp_vi->i_size - last_read_pos;
+               buf_size <<= 3;
+               lcn = bmp_pos & 7;
+               bmp_pos &= ~7;
+               ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, "
+                               "bmp_pos 0x%llx, need_writeback %i.", buf_size,
+                               (unsigned long long)lcn,
+                               (unsigned long long)bmp_pos, need_writeback);
+               while (lcn < buf_size && lcn + bmp_pos < zone_end) {
+                       byte = buf + (lcn >> 3);
+                       ntfs_debug("In inner while loop: buf_size %i, "
+                                       "lcn 0x%llx, bmp_pos 0x%llx, "
+                                       "need_writeback %i, byte ofs 0x%x, "
+                                       "*byte 0x%x.", buf_size,
+                                       (unsigned long long)lcn,
+                                       (unsigned long long)bmp_pos,
+                                       need_writeback,
+                                       (unsigned int)(lcn >> 3),
+                                       (unsigned int)*byte);
+                       /* Skip full bytes. */
+                       if (*byte == 0xff) {
+                               lcn = (lcn + 8) & ~7;
+                               ntfs_debug("Continuing while loop 1.");
+                               continue;
+                       }
+                       bit = 1 << (lcn & 7);
+                       ntfs_debug("bit %i.", bit);
+                       /* If the bit is already set, go onto the next one. */
+                       if (*byte & bit) {
+                               lcn++;
+                               ntfs_debug("Continuing while loop 2.");
+                               continue;
+                       }
+                       /*
+                        * Allocate more memory if needed, including space for
+                        * the terminator element.
+                        * ntfs_malloc_nofs() operates on whole pages only.
+                        */
+                       if ((rlpos + 2) * sizeof(*rl) > rlsize) {
+                               runlist_element *rl2;
+
+                               ntfs_debug("Reallocating memory.");
+                               if (!rl)
+                                       ntfs_debug("First free bit is at LCN "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       (lcn + bmp_pos));
+                               rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);
+                               if (unlikely(!rl2)) {
+                                       err = -ENOMEM;
+                                       ntfs_error(vol->sb, "Failed to "
+                                                       "allocate memory.");
+                                       goto out;
+                               }
+                               memcpy(rl2, rl, rlsize);
+                               ntfs_free(rl);
+                               rl = rl2;
+                               rlsize += PAGE_SIZE;
+                               ntfs_debug("Reallocated memory, rlsize 0x%x.",
+                                               rlsize);
+                       }
+                       /* Allocate the bitmap bit. */
+                       *byte |= bit;
+                       /* We need to write this bitmap page to disk. */
+                       need_writeback = 1;
+                       ntfs_debug("*byte 0x%x, need_writeback is set.",
+                                       (unsigned int)*byte);
+                       /*
+                        * Coalesce with previous run if adjacent LCNs.
+                        * Otherwise, append a new run.
+                        */
+                       ntfs_debug("Adding run (lcn 0x%llx, len 0x%llx), "
+                                       "prev_lcn 0x%llx, lcn 0x%llx, "
+                                       "bmp_pos 0x%llx, prev_run_len 0x%llx, "
+                                       "rlpos %i.",
+                                       (unsigned long long)(lcn + bmp_pos),
+                                       1ULL, (unsigned long long)prev_lcn,
+                                       (unsigned long long)lcn,
+                                       (unsigned long long)bmp_pos,
+                                       (unsigned long long)prev_run_len,
+                                       rlpos);
+                       if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
+                               ntfs_debug("Coalescing to run (lcn 0x%llx, "
+                                               "len 0x%llx).",
+                                               (unsigned long long)
+                                               rl[rlpos - 1].lcn,
+                                               (unsigned long long)
+                                               rl[rlpos - 1].length);
+                               rl[rlpos - 1].length = ++prev_run_len;
+                               ntfs_debug("Run now (lcn 0x%llx, len 0x%llx), "
+                                               "prev_run_len 0x%llx.",
+                                               (unsigned long long)
+                                               rl[rlpos - 1].lcn,
+                                               (unsigned long long)
+                                               rl[rlpos - 1].length,
+                                               (unsigned long long)
+                                               prev_run_len);
+                       } else {
+                               if (likely(rlpos)) {
+                                       ntfs_debug("Adding new run, (previous "
+                                                       "run lcn 0x%llx, "
+                                                       "len 0x%llx).",
+                                                       (unsigned long long)
+                                                       rl[rlpos - 1].lcn,
+                                                       (unsigned long long)
+                                                       rl[rlpos - 1].length);
+                                       rl[rlpos].vcn = rl[rlpos - 1].vcn +
+                                                       prev_run_len;
+                               } else {
+                                       ntfs_debug("Adding new run, is first "
+                                                       "run.");
+                                       rl[rlpos].vcn = start_vcn;
+                               }
+                               rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
+                               rl[rlpos].length = prev_run_len = 1;
+                               rlpos++;
+                       }
+                       /* Done? */
+                       if (!--clusters) {
+                               LCN tc;
+                               /*
+                                * Update the current zone position.  Positions
+                                * of already scanned zones have been updated
+                                * during the respective zone switches.
+                                */
+                               tc = lcn + bmp_pos + 1;
+                               ntfs_debug("Done. Updating current zone "
+                                               "position, tc 0x%llx, "
+                                               "search_zone %i.",
+                                               (unsigned long long)tc,
+                                               search_zone);
+                               switch (search_zone) {
+                               case 1:
+                                       ntfs_debug("Before checks, "
+                                                       "vol->mft_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->mft_zone_pos);
+                                       if (tc >= vol->mft_zone_end) {
+                                               vol->mft_zone_pos =
+                                                               vol->mft_lcn;
+                                               if (!vol->mft_zone_end)
+                                                       vol->mft_zone_pos = 0;
+                                       } else if ((bmp_initial_pos >=
+                                                       vol->mft_zone_pos ||
+                                                       tc > vol->mft_zone_pos)
+                                                       && tc >= vol->mft_lcn)
+                                               vol->mft_zone_pos = tc;
+                                       ntfs_debug("After checks, "
+                                                       "vol->mft_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->mft_zone_pos);
+                                       break;
+                               case 2:
+                                       ntfs_debug("Before checks, "
+                                                       "vol->data1_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data1_zone_pos);
+                                       if (tc >= vol->nr_clusters)
+                                               vol->data1_zone_pos =
+                                                            vol->mft_zone_end;
+                                       else if ((bmp_initial_pos >=
+                                                   vol->data1_zone_pos ||
+                                                   tc > vol->data1_zone_pos)
+                                                   && tc >= vol->mft_zone_end)
+                                               vol->data1_zone_pos = tc;
+                                       ntfs_debug("After checks, "
+                                                       "vol->data1_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data1_zone_pos);
+                                       break;
+                               case 4:
+                                       ntfs_debug("Before checks, "
+                                                       "vol->data2_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data2_zone_pos);
+                                       if (tc >= vol->mft_zone_start)
+                                               vol->data2_zone_pos = 0;
+                                       else if (bmp_initial_pos >=
+                                                     vol->data2_zone_pos ||
+                                                     tc > vol->data2_zone_pos)
+                                               vol->data2_zone_pos = tc;
+                                       ntfs_debug("After checks, "
+                                                       "vol->data2_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data2_zone_pos);
+                                       break;
+                               default:
+                                       BUG();
+                               }
+                               ntfs_debug("Finished.  Going to out.");
+                               goto out;
+                       }
+                       lcn++;
+               }
+               bmp_pos += buf_size;
+               ntfs_debug("After inner while loop: buf_size 0x%x, lcn "
+                               "0x%llx, bmp_pos 0x%llx, need_writeback %i.",
+                               buf_size, (unsigned long long)lcn,
+                               (unsigned long long)bmp_pos, need_writeback);
+               if (bmp_pos < zone_end) {
+                       ntfs_debug("Continuing outer while loop, "
+                                       "bmp_pos 0x%llx, zone_end 0x%llx.",
+                                       (unsigned long long)bmp_pos,
+                                       (unsigned long long)zone_end);
+                       continue;
+               }
+zone_pass_done:        /* Finished with the current zone pass. */
+               ntfs_debug("At zone_pass_done, pass %i.", pass);
+               if (pass == 1) {
+                       /*
+                        * Now do pass 2, scanning the first part of the zone
+                        * we omitted in pass 1.
+                        */
+                       pass = 2;
+                       zone_end = zone_start;
+                       switch (search_zone) {
+                       case 1: /* mft_zone */
+                               zone_start = vol->mft_zone_start;
+                               break;
+                       case 2: /* data1_zone */
+                               zone_start = vol->mft_zone_end;
+                               break;
+                       case 4: /* data2_zone */
+                               zone_start = 0;
+                               break;
+                       default:
+                               BUG();
+                       }
+                       /* Sanity check. */
+                       if (zone_end < zone_start)
+                               zone_end = zone_start;
+                       bmp_pos = zone_start;
+                       ntfs_debug("Continuing outer while loop, pass 2, "
+                                       "zone_start 0x%llx, zone_end 0x%llx, "
+                                       "bmp_pos 0x%llx.",
+                                       (unsigned long long)zone_start,
+                                       (unsigned long long)zone_end,
+                                       (unsigned long long)bmp_pos);
+                       continue;
+               } /* pass == 2 */
+done_zones_check:
+               ntfs_debug("At done_zones_check, search_zone %i, done_zones "
+                               "before 0x%x, done_zones after 0x%x.",
+                               search_zone, done_zones,
+                               done_zones | search_zone);
+               done_zones |= search_zone;
+               if (done_zones < 7) {
+                       ntfs_debug("Switching zone.");
+                       /* Now switch to the next zone we haven't done yet. */
+                       pass = 1;
+                       switch (search_zone) {
+                       case 1:
+                               ntfs_debug("Switching from mft zone to data1 "
+                                               "zone.");
+                               /* Update mft zone position. */
+                               if (rlpos) {
+                                       LCN tc;
+
+                                       ntfs_debug("Before checks, "
+                                                       "vol->mft_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->mft_zone_pos);
+                                       tc = rl[rlpos - 1].lcn +
+                                                       rl[rlpos - 1].length;
+                                       if (tc >= vol->mft_zone_end) {
+                                               vol->mft_zone_pos =
+                                                               vol->mft_lcn;
+                                               if (!vol->mft_zone_end)
+                                                       vol->mft_zone_pos = 0;
+                                       } else if ((bmp_initial_pos >=
+                                                       vol->mft_zone_pos ||
+                                                       tc > vol->mft_zone_pos)
+                                                       && tc >= vol->mft_lcn)
+                                               vol->mft_zone_pos = tc;
+                                       ntfs_debug("After checks, "
+                                                       "vol->mft_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->mft_zone_pos);
+                               }
+                               /* Switch from mft zone to data1 zone. */
+switch_to_data1_zone:          search_zone = 2;
+                               zone_start = bmp_initial_pos =
+                                               vol->data1_zone_pos;
+                               zone_end = vol->nr_clusters;
+                               if (zone_start == vol->mft_zone_end)
+                                       pass = 2;
+                               if (zone_start >= zone_end) {
+                                       vol->data1_zone_pos = zone_start =
+                                                       vol->mft_zone_end;
+                                       pass = 2;
+                               }
+                               break;
+                       case 2:
+                               ntfs_debug("Switching from data1 zone to "
+                                               "data2 zone.");
+                               /* Update data1 zone position. */
+                               if (rlpos) {
+                                       LCN tc;
+
+                                       ntfs_debug("Before checks, "
+                                                       "vol->data1_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data1_zone_pos);
+                                       tc = rl[rlpos - 1].lcn +
+                                                       rl[rlpos - 1].length;
+                                       if (tc >= vol->nr_clusters)
+                                               vol->data1_zone_pos =
+                                                            vol->mft_zone_end;
+                                       else if ((bmp_initial_pos >=
+                                                   vol->data1_zone_pos ||
+                                                   tc > vol->data1_zone_pos)
+                                                   && tc >= vol->mft_zone_end)
+                                               vol->data1_zone_pos = tc;
+                                       ntfs_debug("After checks, "
+                                                       "vol->data1_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data1_zone_pos);
+                               }
+                               /* Switch from data1 zone to data2 zone. */
+                               search_zone = 4;
+                               zone_start = bmp_initial_pos =
+                                               vol->data2_zone_pos;
+                               zone_end = vol->mft_zone_start;
+                               if (!zone_start)
+                                       pass = 2;
+                               if (zone_start >= zone_end) {
+                                       vol->data2_zone_pos = zone_start =
+                                                       bmp_initial_pos = 0;
+                                       pass = 2;
+                               }
+                               break;
+                       case 4:
+                               ntfs_debug("Switching from data2 zone to "
+                                               "data1 zone.");
+                               /* Update data2 zone position. */
+                               if (rlpos) {
+                                       LCN tc;
+
+                                       ntfs_debug("Before checks, "
+                                                       "vol->data2_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data2_zone_pos);
+                                       tc = rl[rlpos - 1].lcn +
+                                                       rl[rlpos - 1].length;
+                                       if (tc >= vol->mft_zone_start)
+                                               vol->data2_zone_pos = 0;
+                                       else if (bmp_initial_pos >=
+                                                     vol->data2_zone_pos ||
+                                                     tc > vol->data2_zone_pos)
+                                               vol->data2_zone_pos = tc;
+                                       ntfs_debug("After checks, "
+                                                       "vol->data2_zone_pos "
+                                                       "0x%llx.",
+                                                       (unsigned long long)
+                                                       vol->data2_zone_pos);
+                               }
+                               /* Switch from data2 zone to data1 zone. */
+                               goto switch_to_data1_zone;
+                       default:
+                               BUG();
+                       }
+                       ntfs_debug("After zone switch, search_zone %i, "
+                                       "pass %i, bmp_initial_pos 0x%llx, "
+                                       "zone_start 0x%llx, zone_end 0x%llx.",
+                                       search_zone, pass,
+                                       (unsigned long long)bmp_initial_pos,
+                                       (unsigned long long)zone_start,
+                                       (unsigned long long)zone_end);
+                       bmp_pos = zone_start;
+                       if (zone_start == zone_end) {
+                               ntfs_debug("Empty zone, going to "
+                                               "done_zones_check.");
+                               /* Empty zone. Don't bother searching it. */
+                               goto done_zones_check;
+                       }
+                       ntfs_debug("Continuing outer while loop.");
+                       continue;
+               } /* done_zones == 7 */
+               ntfs_debug("All zones are finished.");
+               /*
+                * All zones are finished!  If DATA_ZONE, shrink mft zone.  If
+                * MFT_ZONE, we have really run out of space.
+                */
+               mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
+               ntfs_debug("vol->mft_zone_start 0x%llx, vol->mft_zone_end "
+                               "0x%llx, mft_zone_size 0x%llx.",
+                               (unsigned long long)vol->mft_zone_start,
+                               (unsigned long long)vol->mft_zone_end,
+                               (unsigned long long)mft_zone_size);
+               if (zone == MFT_ZONE || mft_zone_size <= 0) {
+                       ntfs_debug("No free clusters left, going to out.");
+                       /* Really no more space left on device. */
+                       err = ENOSPC;
+                       goto out;
+               } /* zone == DATA_ZONE && mft_zone_size > 0 */
+               ntfs_debug("Shrinking mft zone.");
+               zone_end = vol->mft_zone_end;
+               mft_zone_size >>= 1;
+               if (mft_zone_size > 0)
+                       vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;
+               else /* mft zone and data2 zone no longer exist. */
+                       vol->data2_zone_pos = vol->mft_zone_start =
+                                       vol->mft_zone_end = 0;
+               if (vol->mft_zone_pos >= vol->mft_zone_end) {
+                       vol->mft_zone_pos = vol->mft_lcn;
+                       if (!vol->mft_zone_end)
+                               vol->mft_zone_pos = 0;
+               }
+               bmp_pos = zone_start = bmp_initial_pos =
+                               vol->data1_zone_pos = vol->mft_zone_end;
+               search_zone = 2;
+               pass = 2;
+               done_zones &= ~2;
+               ntfs_debug("After shrinking mft zone, mft_zone_size 0x%llx, "
+                               "vol->mft_zone_start 0x%llx, "
+                               "vol->mft_zone_end 0x%llx, "
+                               "vol->mft_zone_pos 0x%llx, search_zone 2, "
+                               "pass 2, dones_zones 0x%x, zone_start 0x%llx, "
+                               "zone_end 0x%llx, vol->data1_zone_pos 0x%llx, "
+                               "continuing outer while loop.",
+                               (unsigned long long)mft_zone_size,
+                               (unsigned long long)vol->mft_zone_start,
+                               (unsigned long long)vol->mft_zone_end,
+                               (unsigned long long)vol->mft_zone_pos,
+                               done_zones, (unsigned long long)zone_start,
+                               (unsigned long long)zone_end,
+                               (unsigned long long)vol->data1_zone_pos);
+       }
+       ntfs_debug("After outer while loop.");
+out:
+       ntfs_debug("At out.");
+       /* Add runlist terminator element. */
+       if (likely(rl)) {
+               rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
+               rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
+               rl[rlpos].length = 0;
+       }
+       if (likely(page && !IS_ERR(page))) {
+               if (need_writeback) {
+                       ntfs_debug("Marking page dirty.");
+                       flush_dcache_page(page);
+                       set_page_dirty(page);
+                       need_writeback = 0;
+               }
+               ntfs_unmap_page(page);
+       }
+       if (likely(!err)) {
+               up_write(&vol->lcnbmp_lock);
+               ntfs_debug("Done.");
+               return rl;
+       }
+       ntfs_error(vol->sb, "Failed to allocate clusters, aborting "
+                       "(error %i).", err);
+       if (rl) {
+               int err2;
+
+               if (err == ENOSPC)
+                       ntfs_debug("Not enough space to complete allocation, "
+                                       "err ENOSPC, first free lcn 0x%llx, "
+                                       "could allocate up to 0x%llx "
+                                       "clusters.",
+                                       (unsigned long long)rl[0].lcn,
+                                       (unsigned long long)count - clusters);
+               /* Deallocate all allocated clusters. */
+               ntfs_debug("Attempting rollback...");
+               err2 = ntfs_cluster_free_from_rl_nolock(vol, rl);
+               if (err2) {
+                       ntfs_error(vol->sb, "Failed to rollback (error %i).  "
+                                       "Leaving inconsistent metadata!  "
+                                       "Unmount and run chkdsk.", err2);
+                       NVolSetErrors(vol);
+               }
+               /* Free the runlist. */
+               ntfs_free(rl);
+       } else if (err == ENOSPC)
+               ntfs_debug("No space left at all, err = ENOSPC, "
+                               "first free lcn = 0x%llx.",
+                               (unsigned long long)vol->data1_zone_pos);
+       up_write(&vol->lcnbmp_lock);
+       return ERR_PTR(err);
+}
+
+/**
+ * __ntfs_cluster_free - free clusters on an ntfs volume
+ * @vi:                vfs inode whose runlist describes the clusters to free
+ * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters
+ * @count:     number of clusters to free or -1 for all clusters
+ * @is_rollback:       if TRUE this is a rollback operation
+ *
+ * Free @count clusters starting at the cluster @start_vcn in the runlist
+ * described by the vfs inode @vi.
+ *
+ * If @count is -1, all clusters from @start_vcn to the end of the runlist are
+ * deallocated.  Thus, to completely free all clusters in a runlist, use
+ * @start_vcn = 0 and @count = -1.
+ *
+ * @is_rollback should always be FALSE, it is for internal use to rollback
+ * errors.  You probably want to use ntfs_cluster_free() instead.
+ *
+ * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller
+ * has to deal with it later.
+ *
+ * Return the number of deallocated clusters (not counting sparse ones) on
+ * success and -errno on error.
+ *
+ * Locking: - The runlist described by @vi must be unlocked on entry and is
+ *           unlocked on return.
+ *         - This function takes the runlist lock of @vi for reading and
+ *           sometimes for writing and sometimes modifies the runlist.
+ *         - The volume lcn bitmap must be unlocked on entry and is unlocked
+ *           on return.
+ *         - This function takes the volume lcn bitmap lock for writing and
+ *           modifies the bitmap contents.
+ */
+s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
+               const BOOL is_rollback)
+{
+       s64 delta, to_free, total_freed, real_freed;
+       ntfs_inode *ni;
+       ntfs_volume *vol;
+       struct inode *lcnbmp_vi;
+       runlist_element *rl;
+       int err;
+
+       BUG_ON(!vi);
+       ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count "
+                       "0x%llx.%s", vi->i_ino, (unsigned long long)start_vcn,
+                       (unsigned long long)count,
+                       is_rollback ? " (rollback)" : "");
+       ni = NTFS_I(vi);
+       vol = ni->vol;
+       lcnbmp_vi = vol->lcnbmp_ino;
+       BUG_ON(!lcnbmp_vi);
+       BUG_ON(start_vcn < 0);
+       BUG_ON(count < -1);
+       /*
+        * Lock the lcn bitmap for writing but only if not rolling back.  We
+        * must hold the lock all the way including through rollback otherwise
+        * rollback is not possible because once we have cleared a bit and
+        * dropped the lock, anyone could have set the bit again, thus
+        * allocating the cluster for another use.
+        */
+       if (likely(!is_rollback))
+               down_write(&vol->lcnbmp_lock);
+
+       total_freed = real_freed = 0;
+
+       /* This returns with ni->runlist locked for reading on success. */
+       rl = ntfs_find_vcn(ni, start_vcn, FALSE);
+       if (IS_ERR(rl)) {
+               if (!is_rollback)
+                       ntfs_error(vol->sb, "Failed to find first runlist "
+                                       "element (error %li), aborting.",
+                                       PTR_ERR(rl));
+               err = PTR_ERR(rl);
+               goto err_out;
+       }
+       if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {
+               if (!is_rollback)
+                       ntfs_error(vol->sb, "First runlist element has "
+                                       "invalid lcn, aborting.");
+               err = -EIO;
+               goto unl_err_out;
+       }
+       /* Find the starting cluster inside the run that needs freeing. */
+       delta = start_vcn - rl->vcn;
+
+       /* The number of clusters in this run that need freeing. */
+       to_free = rl->length - delta;
+       if (count >= 0 && to_free > count)
+               to_free = count;
+
+       if (likely(rl->lcn >= 0)) {
+               /* Do the actual freeing of the clusters in this run. */
+               err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn + delta,
+                               to_free, likely(!is_rollback) ? 0 : 1);
+               if (unlikely(err)) {
+                       if (!is_rollback)
+                               ntfs_error(vol->sb, "Failed to clear first run "
+                                               "(error %i), aborting.", err);
+                       goto unl_err_out;
+               }
+               /* We have freed @to_free real clusters. */
+               real_freed = to_free;
+       };
+       /* Go to the next run and adjust the number of clusters left to free. */
+       ++rl;
+       if (count >= 0)
+               count -= to_free;
+
+       /* Keep track of the total "freed" clusters, including sparse ones. */
+       total_freed = to_free;
+       /*
+        * Loop over the remaining runs, using @count as a capping value, and
+        * free them.
+        */
+       for (; rl->length && count != 0; ++rl) {
+               if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {
+                       VCN vcn;
+
+                       /*
+                        * Attempt to map runlist, dropping runlist lock for
+                        * the duration.
+                        */
+                       up_read(&ni->runlist.lock);
+                       vcn = rl->vcn;
+                       err = ntfs_map_runlist(ni, vcn);
+                       if (err) {
+                               if (!is_rollback)
+                                       ntfs_error(vol->sb, "Failed to map "
+                                                       "runlist fragment.");
+                               if (err == -EINVAL || err == -ENOENT)
+                                       err = -EIO;
+                               goto err_out;
+                       }
+                       /*
+                        * This returns with ni->runlist locked for reading on
+                        * success.
+                        */
+                       rl = ntfs_find_vcn(ni, vcn, FALSE);
+                       if (IS_ERR(rl)) {
+                               err = PTR_ERR(rl);
+                               if (!is_rollback)
+                                       ntfs_error(vol->sb, "Failed to find "
+                                                       "subsequent runlist "
+                                                       "element.");
+                               goto err_out;
+                       }
+                       if (unlikely(rl->lcn < (LCN)LCN_HOLE)) {
+                               if (!is_rollback)
+                                       ntfs_error(vol->sb, "Runlist element "
+                                                       "has invalid lcn "
+                                                       "(0x%llx).",
+                                                       (unsigned long long)
+                                                       rl->lcn);
+                               err = -EIO;
+                               goto unl_err_out;
+                       }
+               }
+               /* The number of clusters in this run that need freeing. */
+               to_free = rl->length;
+               if (count >= 0 && to_free > count)
+                       to_free = count;
+
+               if (likely(rl->lcn >= 0)) {
+                       /* Do the actual freeing of the clusters in the run. */
+                       err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn,
+                                       to_free, likely(!is_rollback) ? 0 : 1);
+                       if (unlikely(err)) {
+                               if (!is_rollback)
+                                       ntfs_error(vol->sb, "Failed to clear "
+                                                       "subsequent run.");
+                               goto unl_err_out;
+                       }
+                       /* We have freed @to_free real clusters. */
+                       real_freed += to_free;
+               }
+               /* Adjust the number of clusters left to free. */
+               if (count >= 0)
+                       count -= to_free;
+       
+               /* Update the total done clusters. */
+               total_freed += to_free;
+       }
+       up_read(&ni->runlist.lock);
+       if (likely(!is_rollback))
+               up_write(&vol->lcnbmp_lock);
+
+       BUG_ON(count > 0);
+
+       /* We are done.  Return the number of actually freed clusters. */
+       ntfs_debug("Done.");
+       return real_freed;
+unl_err_out:
+       up_read(&ni->runlist.lock);
+err_out:
+       if (is_rollback)
+               return err;
+       /* If no real clusters were freed, no need to rollback. */
+       if (!real_freed) {
+               up_write(&vol->lcnbmp_lock);
+               return err;
+       }
+       /*
+        * Attempt to rollback and if that succeeds just return the error code.
+        * If rollback fails, set the volume errors flag, emit an error
+        * message, and return the error code.
+        */
+       delta = __ntfs_cluster_free(vi, start_vcn, total_freed, TRUE);
+       if (delta < 0) {
+               ntfs_error(vol->sb, "Failed to rollback (error %i).  Leaving "
+                               "inconsistent metadata!  Unmount and run "
+                               "chkdsk.", (int)delta);
+               NVolSetErrors(vol);
+       }
+       up_write(&vol->lcnbmp_lock);
+       ntfs_error(vol->sb, "Aborting (error %i).", err);
+       return err;
+}
+
+#endif /* NTFS_RW */
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
new file mode 100644 (file)
index 0000000..f9292e8
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * lcnalloc.h - Exports for NTFS kernel cluster (de)allocation.  Part of the
+ *             Linux-NTFS project.
+ *
+ * Copyright (c) 2004 Anton Altaparmakov
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_NTFS_LCNALLOC_H
+#define _LINUX_NTFS_LCNALLOC_H
+
+#ifdef NTFS_RW
+
+#include <linux/fs.h>
+
+#include "types.h"
+#include "volume.h"
+
+typedef enum {
+       FIRST_ZONE      = 0,    /* For sanity checking. */
+       MFT_ZONE        = 0,    /* Allocate from $MFT zone. */
+       DATA_ZONE       = 1,    /* Allocate from $DATA zone. */
+       LAST_ZONE       = 1,    /* For sanity checking. */
+} NTFS_CLUSTER_ALLOCATION_ZONES;
+
+extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
+               const VCN start_vcn, const s64 count, const LCN start_lcn,
+               const NTFS_CLUSTER_ALLOCATION_ZONES zone);
+
+extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
+               s64 count, const BOOL is_rollback);
+
+/**
+ * ntfs_cluster_free - free clusters on an ntfs volume
+ * @vi:                vfs inode whose runlist describes the clusters to free
+ * @start_vcn: vcn in the runlist of @vi at which to start freeing clusters
+ * @count:     number of clusters to free or -1 for all clusters
+ *
+ * Free @count clusters starting at the cluster @start_vcn in the runlist
+ * described by the vfs inode @vi.
+ *
+ * If @count is -1, all clusters from @start_vcn to the end of the runlist are
+ * deallocated.  Thus, to completely free all clusters in a runlist, use
+ * @start_vcn = 0 and @count = -1.
+ *
+ * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller
+ * has to deal with it later.
+ *
+ * Return the number of deallocated clusters (not counting sparse ones) on
+ * success and -errno on error.
+ *
+ * Locking: - The runlist described by @vi must be unlocked on entry and is
+ *           unlocked on return.
+ *         - This function takes the runlist lock of @vi for reading and
+ *           sometimes for writing and sometimes modifies the runlist.
+ *         - The volume lcn bitmap must be unlocked on entry and is unlocked
+ *           on return.
+ *         - This function takes the volume lcn bitmap lock for writing and
+ *           modifies the bitmap contents.
+ */
+static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
+               s64 count)
+{
+       return __ntfs_cluster_free(vi, start_vcn, count, FALSE);
+}
+
+#endif /* NTFS_RW */
+
+#endif /* defined _LINUX_NTFS_LCNALLOC_H */
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
new file mode 100644 (file)
index 0000000..8438fb1
--- /dev/null
@@ -0,0 +1,1438 @@
+/**
+ * runlist.c - NTFS runlist handling code.  Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2002 Richard Russon
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "debug.h"
+#include "dir.h"
+#include "endian.h"
+#include "malloc.h"
+#include "ntfs.h"
+
+/**
+ * ntfs_rl_mm - runlist memmove
+ *
+ * It is up to the caller to serialize access to the runlist @base.
+ */
+static inline void ntfs_rl_mm(runlist_element *base, int dst, int src,
+               int size)
+{
+       if (likely((dst != src) && (size > 0)))
+               memmove(base + dst, base + src, size * sizeof (*base));
+}
+
+/**
+ * ntfs_rl_mc - runlist memory copy
+ *
+ * It is up to the caller to serialize access to the runlists @dstbase and
+ * @srcbase.
+ */
+static inline void ntfs_rl_mc(runlist_element *dstbase, int dst,
+               runlist_element *srcbase, int src, int size)
+{
+       if (likely(size > 0))
+               memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));
+}
+
+/**
+ * ntfs_rl_realloc - Reallocate memory for runlists
+ * @rl:                original runlist
+ * @old_size:  number of runlist elements in the original runlist @rl
+ * @new_size:  number of runlist elements we need space for
+ *
+ * As the runlists grow, more memory will be required.  To prevent the
+ * kernel having to allocate and reallocate large numbers of small bits of
+ * memory, this function returns and entire page of memory.
+ *
+ * It is up to the caller to serialize access to the runlist @rl.
+ *
+ * N.B.  If the new allocation doesn't require a different number of pages in
+ *       memory, the function will return the original pointer.
+ *
+ * On success, return a pointer to the newly allocated, or recycled, memory.
+ * On error, return -errno. The following error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EINVAL - Invalid parameters were passed in.
+ */
+static inline runlist_element *ntfs_rl_realloc(runlist_element *rl,
+               int old_size, int new_size)
+{
+       runlist_element *new_rl;
+
+       old_size = PAGE_ALIGN(old_size * sizeof(*rl));
+       new_size = PAGE_ALIGN(new_size * sizeof(*rl));
+       if (old_size == new_size)
+               return rl;
+
+       new_rl = ntfs_malloc_nofs(new_size);
+       if (unlikely(!new_rl))
+               return ERR_PTR(-ENOMEM);
+
+       if (likely(rl != NULL)) {
+               if (unlikely(old_size > new_size))
+                       old_size = new_size;
+               memcpy(new_rl, rl, old_size);
+               ntfs_free(rl);
+       }
+       return new_rl;
+}
+
+/**
+ * ntfs_are_rl_mergeable - test if two runlists can be joined together
+ * @dst:       original runlist
+ * @src:       new runlist to test for mergeability with @dst
+ *
+ * Test if two runlists can be joined together. For this, their VCNs and LCNs
+ * must be adjacent.
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ *
+ * Return: TRUE   Success, the runlists can be merged.
+ *        FALSE  Failure, the runlists cannot be merged.
+ */
+static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst,
+               runlist_element *src)
+{
+       BUG_ON(!dst);
+       BUG_ON(!src);
+
+       if ((dst->lcn < 0) || (src->lcn < 0))     /* Are we merging holes? */
+               return FALSE;
+       if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */
+               return FALSE;
+       if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */
+               return FALSE;
+
+       return TRUE;
+}
+
+/**
+ * __ntfs_rl_merge - merge two runlists without testing if they can be merged
+ * @dst:       original, destination runlist
+ * @src:       new runlist to merge with @dst
+ *
+ * Merge the two runlists, writing into the destination runlist @dst. The
+ * caller must make sure the runlists can be merged or this will corrupt the
+ * destination runlist.
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ */
+static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src)
+{
+       dst->length += src->length;
+}
+
+/**
+ * ntfs_rl_append - append a runlist after a given element
+ * @dst:       original runlist to be worked on
+ * @dsize:     number of elements in @dst (including end marker)
+ * @src:       runlist to be inserted into @dst
+ * @ssize:     number of elements in @src (excluding end marker)
+ * @loc:       append the new runlist @src after this element in @dst
+ *
+ * Append the runlist @src after element @loc in @dst.  Merge the right end of
+ * the new runlist, if necessary. Adjust the size of the hole before the
+ * appended runlist.
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, runlist. Note, both
+ * runlists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned runlist
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both runlists are left unmodified. The following
+ * error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EINVAL - Invalid parameters were passed in.
+ */
+static inline runlist_element *ntfs_rl_append(runlist_element *dst,
+               int dsize, runlist_element *src, int ssize, int loc)
+{
+       BOOL right;
+       int magic;
+
+       BUG_ON(!dst);
+       BUG_ON(!src);
+
+       /* First, check if the right hand end needs merging. */
+       right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
+
+       /* Space required: @dst size + @src size, less one if we merged. */
+       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right);
+       if (IS_ERR(dst))
+               return dst;
+       /*
+        * We are guaranteed to succeed from here so can start modifying the
+        * original runlists.
+        */
+
+       /* First, merge the right hand end, if necessary. */
+       if (right)
+               __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
+
+       magic = loc + ssize;
+
+       /* Move the tail of @dst out of the way, then copy in @src. */
+       ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right);
+       ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
+
+       /* Adjust the size of the preceding hole. */
+       dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
+
+       /* We may have changed the length of the file, so fix the end marker */
+       if (dst[magic + 1].lcn == LCN_ENOENT)
+               dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length;
+
+       return dst;
+}
+
+/**
+ * ntfs_rl_insert - insert a runlist into another
+ * @dst:       original runlist to be worked on
+ * @dsize:     number of elements in @dst (including end marker)
+ * @src:       new runlist to be inserted
+ * @ssize:     number of elements in @src (excluding end marker)
+ * @loc:       insert the new runlist @src before this element in @dst
+ *
+ * Insert the runlist @src before element @loc in the runlist @dst. Merge the
+ * left end of the new runlist, if necessary. Adjust the size of the hole
+ * after the inserted runlist.
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, runlist. Note, both
+ * runlists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned runlist
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both runlists are left unmodified. The following
+ * error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EINVAL - Invalid parameters were passed in.
+ */
+static inline runlist_element *ntfs_rl_insert(runlist_element *dst,
+               int dsize, runlist_element *src, int ssize, int loc)
+{
+       BOOL left = FALSE;
+       BOOL disc = FALSE;      /* Discontinuity */
+       BOOL hole = FALSE;      /* Following a hole */
+       int magic;
+
+       BUG_ON(!dst);
+       BUG_ON(!src);
+
+       /* disc => Discontinuity between the end of @dst and the start of @src.
+        *         This means we might need to insert a hole.
+        * hole => @dst ends with a hole or an unmapped region which we can
+        *         extend to match the discontinuity. */
+       if (loc == 0)
+               disc = (src[0].vcn > 0);
+       else {
+               s64 merged_length;
+
+               left = ntfs_are_rl_mergeable(dst + loc - 1, src);
+
+               merged_length = dst[loc - 1].length;
+               if (left)
+                       merged_length += src->length;
+
+               disc = (src[0].vcn > dst[loc - 1].vcn + merged_length);
+               if (disc)
+                       hole = (dst[loc - 1].lcn == LCN_HOLE);
+       }
+
+       /* Space required: @dst size + @src size, less one if we merged, plus
+        * one if there was a discontinuity, less one for a trailing hole. */
+       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole);
+       if (IS_ERR(dst))
+               return dst;
+       /*
+        * We are guaranteed to succeed from here so can start modifying the
+        * original runlist.
+        */
+
+       if (left)
+               __ntfs_rl_merge(dst + loc - 1, src);
+
+       magic = loc + ssize - left + disc - hole;
+
+       /* Move the tail of @dst out of the way, then copy in @src. */
+       ntfs_rl_mm(dst, magic, loc, dsize - loc);
+       ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left);
+
+       /* Adjust the VCN of the last run ... */
+       if (dst[magic].lcn <= LCN_HOLE)
+               dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
+       /* ... and the length. */
+       if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED)
+               dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn;
+
+       /* Writing beyond the end of the file and there's a discontinuity. */
+       if (disc) {
+               if (hole)
+                       dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn;
+               else {
+                       if (loc > 0) {
+                               dst[loc].vcn = dst[loc - 1].vcn +
+                                               dst[loc - 1].length;
+                               dst[loc].length = dst[loc + 1].vcn -
+                                               dst[loc].vcn;
+                       } else {
+                               dst[loc].vcn = 0;
+                               dst[loc].length = dst[loc + 1].vcn;
+                       }
+                       dst[loc].lcn = LCN_RL_NOT_MAPPED;
+               }
+
+               magic += hole;
+
+               if (dst[magic].lcn == LCN_ENOENT)
+                       dst[magic].vcn = dst[magic - 1].vcn +
+                                       dst[magic - 1].length;
+       }
+       return dst;
+}
+
+/**
+ * ntfs_rl_replace - overwrite a runlist element with another runlist
+ * @dst:       original runlist to be worked on
+ * @dsize:     number of elements in @dst (including end marker)
+ * @src:       new runlist to be inserted
+ * @ssize:     number of elements in @src (excluding end marker)
+ * @loc:       index in runlist @dst to overwrite with @src
+ *
+ * Replace the runlist element @dst at @loc with @src. Merge the left and
+ * right ends of the inserted runlist, if necessary.
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, runlist. Note, both
+ * runlists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned runlist
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both runlists are left unmodified. The following
+ * error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EINVAL - Invalid parameters were passed in.
+ */
+static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
+               int dsize, runlist_element *src, int ssize, int loc)
+{
+       BOOL left = FALSE;
+       BOOL right;
+       int magic;
+
+       BUG_ON(!dst);
+       BUG_ON(!src);
+
+       /* First, merge the left and right ends, if necessary. */
+       right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
+       if (loc > 0)
+               left = ntfs_are_rl_mergeable(dst + loc - 1, src);
+
+       /* Allocate some space. We'll need less if the left, right, or both
+        * ends were merged. */
+       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right);
+       if (IS_ERR(dst))
+               return dst;
+       /*
+        * We are guaranteed to succeed from here so can start modifying the
+        * original runlists.
+        */
+       if (right)
+               __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
+       if (left)
+               __ntfs_rl_merge(dst + loc - 1, src);
+
+       /* FIXME: What does this mean? (AIA) */
+       magic = loc + ssize - left;
+
+       /* Move the tail of @dst out of the way, then copy in @src. */
+       ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1);
+       ntfs_rl_mc(dst, loc, src, left, ssize - left);
+
+       /* We may have changed the length of the file, so fix the end marker */
+       if (dst[magic].lcn == LCN_ENOENT)
+               dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
+       return dst;
+}
+
+/**
+ * ntfs_rl_split - insert a runlist into the centre of a hole
+ * @dst:       original runlist to be worked on
+ * @dsize:     number of elements in @dst (including end marker)
+ * @src:       new runlist to be inserted
+ * @ssize:     number of elements in @src (excluding end marker)
+ * @loc:       index in runlist @dst at which to split and insert @src
+ *
+ * Split the runlist @dst at @loc into two and insert @new in between the two
+ * fragments. No merging of runlists is necessary. Adjust the size of the
+ * holes either side.
+ *
+ * It is up to the caller to serialize access to the runlists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, runlist. Note, both
+ * runlists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned runlist
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both runlists are left unmodified. The following
+ * error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EINVAL - Invalid parameters were passed in.
+ */
+static inline runlist_element *ntfs_rl_split(runlist_element *dst, int dsize,
+               runlist_element *src, int ssize, int loc)
+{
+       BUG_ON(!dst);
+       BUG_ON(!src);
+
+       /* Space required: @dst size + @src size + one new hole. */
+       dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
+       if (IS_ERR(dst))
+               return dst;
+       /*
+        * We are guaranteed to succeed from here so can start modifying the
+        * original runlists.
+        */
+
+       /* Move the tail of @dst out of the way, then copy in @src. */
+       ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc);
+       ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
+
+       /* Adjust the size of the holes either size of @src. */
+       dst[loc].length         = dst[loc+1].vcn       - dst[loc].vcn;
+       dst[loc+ssize+1].vcn    = dst[loc+ssize].vcn   + dst[loc+ssize].length;
+       dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn;
+
+       return dst;
+}
+
+/**
+ * ntfs_runlists_merge - merge two runlists into one
+ * @drl:       original runlist to be worked on
+ * @srl:       new runlist to be merged into @drl
+ *
+ * First we sanity check the two runlists @srl and @drl to make sure that they
+ * are sensible and can be merged. The runlist @srl must be either after the
+ * runlist @drl or completely within a hole (or unmapped region) in @drl.
+ *
+ * It is up to the caller to serialize access to the runlists @drl and @srl.
+ *
+ * Merging of runlists is necessary in two cases:
+ *   1. When attribute lists are used and a further extent is being mapped.
+ *   2. When new clusters are allocated to fill a hole or extend a file.
+ *
+ * There are four possible ways @srl can be merged. It can:
+ *     - be inserted at the beginning of a hole,
+ *     - split the hole in two and be inserted between the two fragments,
+ *     - be appended at the end of a hole, or it can
+ *     - replace the whole hole.
+ * It can also be appended to the end of the runlist, which is just a variant
+ * of the insert case.
+ *
+ * On success, return a pointer to the new, combined, runlist. Note, both
+ * runlists @drl and @srl are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned runlist
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both runlists are left unmodified. The following
+ * error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EINVAL - Invalid parameters were passed in.
+ *     -ERANGE - The runlists overlap and cannot be merged.
+ */
+runlist_element *ntfs_runlists_merge(runlist_element *drl,
+               runlist_element *srl)
+{
+       int di, si;             /* Current index into @[ds]rl. */
+       int sstart;             /* First index with lcn > LCN_RL_NOT_MAPPED. */
+       int dins;               /* Index into @drl at which to insert @srl. */
+       int dend, send;         /* Last index into @[ds]rl. */
+       int dfinal, sfinal;     /* The last index into @[ds]rl with
+                                  lcn >= LCN_HOLE. */
+       int marker = 0;
+       VCN marker_vcn = 0;
+
+#ifdef DEBUG
+       ntfs_debug("dst:");
+       ntfs_debug_dump_runlist(drl);
+       ntfs_debug("src:");
+       ntfs_debug_dump_runlist(srl);
+#endif
+
+       /* Check for silly calling... */
+       if (unlikely(!srl))
+               return drl;
+       if (IS_ERR(srl) || IS_ERR(drl))
+               return ERR_PTR(-EINVAL);
+
+       /* Check for the case where the first mapping is being done now. */
+       if (unlikely(!drl)) {
+               drl = srl;
+               /* Complete the source runlist if necessary. */
+               if (unlikely(drl[0].vcn)) {
+                       /* Scan to the end of the source runlist. */
+                       for (dend = 0; likely(drl[dend].length); dend++)
+                               ;
+                       drl = ntfs_rl_realloc(drl, dend, dend + 1);
+                       if (IS_ERR(drl))
+                               return drl;
+                       /* Insert start element at the front of the runlist. */
+                       ntfs_rl_mm(drl, 1, 0, dend);
+                       drl[0].vcn = 0;
+                       drl[0].lcn = LCN_RL_NOT_MAPPED;
+                       drl[0].length = drl[1].vcn;
+               }
+               goto finished;
+       }
+
+       si = di = 0;
+
+       /* Skip any unmapped start element(s) in the source runlist. */
+       while (srl[si].length && srl[si].lcn < LCN_HOLE)
+               si++;
+
+       /* Can't have an entirely unmapped source runlist. */
+       BUG_ON(!srl[si].length);
+
+       /* Record the starting points. */
+       sstart = si;
+
+       /*
+        * Skip forward in @drl until we reach the position where @srl needs to
+        * be inserted. If we reach the end of @drl, @srl just needs to be
+        * appended to @drl.
+        */
+       for (; drl[di].length; di++) {
+               if (drl[di].vcn + drl[di].length > srl[sstart].vcn)
+                       break;
+       }
+       dins = di;
+
+       /* Sanity check for illegal overlaps. */
+       if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
+                       (srl[si].lcn >= 0)) {
+               ntfs_error(NULL, "Run lists overlap. Cannot merge!");
+               return ERR_PTR(-ERANGE);
+       }
+
+       /* Scan to the end of both runlists in order to know their sizes. */
+       for (send = si; srl[send].length; send++)
+               ;
+       for (dend = di; drl[dend].length; dend++)
+               ;
+
+       if (srl[send].lcn == LCN_ENOENT)
+               marker_vcn = srl[marker = send].vcn;
+
+       /* Scan to the last element with lcn >= LCN_HOLE. */
+       for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--)
+               ;
+       for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--)
+               ;
+
+       {
+       BOOL start;
+       BOOL finish;
+       int ds = dend + 1;              /* Number of elements in drl & srl */
+       int ss = sfinal - sstart + 1;
+
+       start  = ((drl[dins].lcn <  LCN_RL_NOT_MAPPED) ||    /* End of file   */
+                 (drl[dins].vcn == srl[sstart].vcn));       /* Start of hole */
+       finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) &&    /* End of file   */
+                ((drl[dins].vcn + drl[dins].length) <=      /* End of hole   */
+                 (srl[send - 1].vcn + srl[send - 1].length)));
+
+       /* Or we'll lose an end marker */
+       if (start && finish && (drl[dins].length == 0))
+               ss++;
+       if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
+               finish = FALSE;
+#if 0
+       ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
+       ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
+       ntfs_debug("start = %i, finish = %i", start, finish);
+       ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins);
+#endif
+       if (start) {
+               if (finish)
+                       drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins);
+               else
+                       drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins);
+       } else {
+               if (finish)
+                       drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins);
+               else
+                       drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins);
+       }
+       if (IS_ERR(drl)) {
+               ntfs_error(NULL, "Merge failed.");
+               return drl;
+       }
+       ntfs_free(srl);
+       if (marker) {
+               ntfs_debug("Triggering marker code.");
+               for (ds = dend; drl[ds].length; ds++)
+                       ;
+               /* We only need to care if @srl ended after @drl. */
+               if (drl[ds].vcn <= marker_vcn) {
+                       int slots = 0;
+
+                       if (drl[ds].vcn == marker_vcn) {
+                               ntfs_debug("Old marker = 0x%llx, replacing "
+                                               "with LCN_ENOENT.",
+                                               (unsigned long long)
+                                               drl[ds].lcn);
+                               drl[ds].lcn = LCN_ENOENT;
+                               goto finished;
+                       }
+                       /*
+                        * We need to create an unmapped runlist element in
+                        * @drl or extend an existing one before adding the
+                        * ENOENT terminator.
+                        */
+                       if (drl[ds].lcn == LCN_ENOENT) {
+                               ds--;
+                               slots = 1;
+                       }
+                       if (drl[ds].lcn != LCN_RL_NOT_MAPPED) {
+                               /* Add an unmapped runlist element. */
+                               if (!slots) {
+                                       /* FIXME/TODO: We need to have the
+                                        * extra memory already! (AIA) */
+                                       drl = ntfs_rl_realloc(drl, ds, ds + 2);
+                                       if (!drl)
+                                               goto critical_error;
+                                       slots = 2;
+                               }
+                               ds++;
+                               /* Need to set vcn if it isn't set already. */
+                               if (slots != 1)
+                                       drl[ds].vcn = drl[ds - 1].vcn +
+                                                       drl[ds - 1].length;
+                               drl[ds].lcn = LCN_RL_NOT_MAPPED;
+                               /* We now used up a slot. */
+                               slots--;
+                       }
+                       drl[ds].length = marker_vcn - drl[ds].vcn;
+                       /* Finally add the ENOENT terminator. */
+                       ds++;
+                       if (!slots) {
+                               /* FIXME/TODO: We need to have the extra
+                                * memory already! (AIA) */
+                               drl = ntfs_rl_realloc(drl, ds, ds + 1);
+                               if (!drl)
+                                       goto critical_error;
+                       }
+                       drl[ds].vcn = marker_vcn;
+                       drl[ds].lcn = LCN_ENOENT;
+                       drl[ds].length = (s64)0;
+               }
+       }
+       }
+
+finished:
+       /* The merge was completed successfully. */
+       ntfs_debug("Merged runlist:");
+       ntfs_debug_dump_runlist(drl);
+       return drl;
+
+critical_error:
+       /* Critical error! We cannot afford to fail here. */
+       ntfs_error(NULL, "Critical error! Not enough memory.");
+       panic("NTFS: Cannot continue.");
+}
+
+/**
+ * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist
+ * @vol:       ntfs volume on which the attribute resides
+ * @attr:      attribute record whose mapping pairs array to decompress
+ * @old_rl:    optional runlist in which to insert @attr's runlist
+ *
+ * It is up to the caller to serialize access to the runlist @old_rl.
+ *
+ * Decompress the attribute @attr's mapping pairs array into a runlist. On
+ * success, return the decompressed runlist.
+ *
+ * If @old_rl is not NULL, decompressed runlist is inserted into the
+ * appropriate place in @old_rl and the resultant, combined runlist is
+ * returned. The original @old_rl is deallocated.
+ *
+ * On error, return -errno. @old_rl is left unmodified in that case.
+ *
+ * The following error codes are defined:
+ *     -ENOMEM - Not enough memory to allocate runlist array.
+ *     -EIO    - Corrupt runlist.
+ *     -EINVAL - Invalid parameters were passed in.
+ *     -ERANGE - The two runlists overlap.
+ *
+ * FIXME: For now we take the conceptionally simplest approach of creating the
+ * new runlist disregarding the already existing one and then splicing the
+ * two into one, if that is possible (we check for overlap and discard the new
+ * runlist if overlap present before returning ERR_PTR(-ERANGE)).
+ */
+runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
+               const ATTR_RECORD *attr, runlist_element *old_rl)
+{
+       VCN vcn;                /* Current vcn. */
+       LCN lcn;                /* Current lcn. */
+       s64 deltaxcn;           /* Change in [vl]cn. */
+       runlist_element *rl;    /* The output runlist. */
+       u8 *buf;                /* Current position in mapping pairs array. */
+       u8 *attr_end;           /* End of attribute. */
+       int rlsize;             /* Size of runlist buffer. */
+       u16 rlpos;              /* Current runlist position in units of
+                                  runlist_elements. */
+       u8 b;                   /* Current byte offset in buf. */
+
+#ifdef DEBUG
+       /* Make sure attr exists and is non-resident. */
+       if (!attr || !attr->non_resident || sle64_to_cpu(
+                       attr->data.non_resident.lowest_vcn) < (VCN)0) {
+               ntfs_error(vol->sb, "Invalid arguments.");
+               return ERR_PTR(-EINVAL);
+       }
+#endif
+       /* Start at vcn = lowest_vcn and lcn 0. */
+       vcn = sle64_to_cpu(attr->data.non_resident.lowest_vcn);
+       lcn = 0;
+       /* Get start of the mapping pairs array. */
+       buf = (u8*)attr + le16_to_cpu(
+                       attr->data.non_resident.mapping_pairs_offset);
+       attr_end = (u8*)attr + le32_to_cpu(attr->length);
+       if (unlikely(buf < (u8*)attr || buf > attr_end)) {
+               ntfs_error(vol->sb, "Corrupt attribute.");
+               return ERR_PTR(-EIO);
+       }
+       /* Current position in runlist array. */
+       rlpos = 0;
+       /* Allocate first page and set current runlist size to one page. */
+       rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE);
+       if (unlikely(!rl))
+               return ERR_PTR(-ENOMEM);
+       /* Insert unmapped starting element if necessary. */
+       if (vcn) {
+               rl->vcn = 0;
+               rl->lcn = LCN_RL_NOT_MAPPED;
+               rl->length = vcn;
+               rlpos++;
+       }
+       while (buf < attr_end && *buf) {
+               /*
+                * Allocate more memory if needed, including space for the
+                * not-mapped and terminator elements. ntfs_malloc_nofs()
+                * operates on whole pages only.
+                */
+               if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
+                       runlist_element *rl2;
+
+                       rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);
+                       if (unlikely(!rl2)) {
+                               ntfs_free(rl);
+                               return ERR_PTR(-ENOMEM);
+                       }
+                       memcpy(rl2, rl, rlsize);
+                       ntfs_free(rl);
+                       rl = rl2;
+                       rlsize += PAGE_SIZE;
+               }
+               /* Enter the current vcn into the current runlist element. */
+               rl[rlpos].vcn = vcn;
+               /*
+                * Get the change in vcn, i.e. the run length in clusters.
+                * Doing it this way ensures that we signextend negative values.
+                * A negative run length doesn't make any sense, but hey, I
+                * didn't make up the NTFS specs and Windows NT4 treats the run
+                * length as a signed value so that's how it is...
+                */
+               b = *buf & 0xf;
+               if (b) {
+                       if (unlikely(buf + b > attr_end))
+                               goto io_error;
+                       for (deltaxcn = (s8)buf[b--]; b; b--)
+                               deltaxcn = (deltaxcn << 8) + buf[b];
+               } else { /* The length entry is compulsory. */
+                       ntfs_error(vol->sb, "Missing length entry in mapping "
+                                       "pairs array.");
+                       deltaxcn = (s64)-1;
+               }
+               /*
+                * Assume a negative length to indicate data corruption and
+                * hence clean-up and return NULL.
+                */
+               if (unlikely(deltaxcn < 0)) {
+                       ntfs_error(vol->sb, "Invalid length in mapping pairs "
+                                       "array.");
+                       goto err_out;
+               }
+               /*
+                * Enter the current run length into the current runlist
+                * element.
+                */
+               rl[rlpos].length = deltaxcn;
+               /* Increment the current vcn by the current run length. */
+               vcn += deltaxcn;
+               /*
+                * There might be no lcn change at all, as is the case for
+                * sparse clusters on NTFS 3.0+, in which case we set the lcn
+                * to LCN_HOLE.
+                */
+               if (!(*buf & 0xf0))
+                       rl[rlpos].lcn = LCN_HOLE;
+               else {
+                       /* Get the lcn change which really can be negative. */
+                       u8 b2 = *buf & 0xf;
+                       b = b2 + ((*buf >> 4) & 0xf);
+                       if (buf + b > attr_end)
+                               goto io_error;
+                       for (deltaxcn = (s8)buf[b--]; b > b2; b--)
+                               deltaxcn = (deltaxcn << 8) + buf[b];
+                       /* Change the current lcn to its new value. */
+                       lcn += deltaxcn;
+#ifdef DEBUG
+                       /*
+                        * On NTFS 1.2-, apparently can have lcn == -1 to
+                        * indicate a hole. But we haven't verified ourselves
+                        * whether it is really the lcn or the deltaxcn that is
+                        * -1. So if either is found give us a message so we
+                        * can investigate it further!
+                        */
+                       if (vol->major_ver < 3) {
+                               if (unlikely(deltaxcn == (LCN)-1))
+                                       ntfs_error(vol->sb, "lcn delta == -1");
+                               if (unlikely(lcn == (LCN)-1))
+                                       ntfs_error(vol->sb, "lcn == -1");
+                       }
+#endif
+                       /* Check lcn is not below -1. */
+                       if (unlikely(lcn < (LCN)-1)) {
+                               ntfs_error(vol->sb, "Invalid LCN < -1 in "
+                                               "mapping pairs array.");
+                               goto err_out;
+                       }
+                       /* Enter the current lcn into the runlist element. */
+                       rl[rlpos].lcn = lcn;
+               }
+               /* Get to the next runlist element. */
+               rlpos++;
+               /* Increment the buffer position to the next mapping pair. */
+               buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1;
+       }
+       if (unlikely(buf >= attr_end))
+               goto io_error;
+       /*
+        * If there is a highest_vcn specified, it must be equal to the final
+        * vcn in the runlist - 1, or something has gone badly wrong.
+        */
+       deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);
+       if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) {
+mpa_err:
+               ntfs_error(vol->sb, "Corrupt mapping pairs array in "
+                               "non-resident attribute.");
+               goto err_out;
+       }
+       /* Setup not mapped runlist element if this is the base extent. */
+       if (!attr->data.non_resident.lowest_vcn) {
+               VCN max_cluster;
+
+               max_cluster = (sle64_to_cpu(
+                               attr->data.non_resident.allocated_size) +
+                               vol->cluster_size - 1) >>
+                               vol->cluster_size_bits;
+               /*
+                * If there is a difference between the highest_vcn and the
+                * highest cluster, the runlist is either corrupt or, more
+                * likely, there are more extents following this one.
+                */
+               if (deltaxcn < --max_cluster) {
+                       ntfs_debug("More extents to follow; deltaxcn = 0x%llx, "
+                                       "max_cluster = 0x%llx",
+                                       (unsigned long long)deltaxcn,
+                                       (unsigned long long)max_cluster);
+                       rl[rlpos].vcn = vcn;
+                       vcn += rl[rlpos].length = max_cluster - deltaxcn;
+                       rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
+                       rlpos++;
+               } else if (unlikely(deltaxcn > max_cluster)) {
+                       ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = "
+                                       "0x%llx, max_cluster = 0x%llx",
+                                       (unsigned long long)deltaxcn,
+                                       (unsigned long long)max_cluster);
+                       goto mpa_err;
+               }
+               rl[rlpos].lcn = LCN_ENOENT;
+       } else /* Not the base extent. There may be more extents to follow. */
+               rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
+
+       /* Setup terminating runlist element. */
+       rl[rlpos].vcn = vcn;
+       rl[rlpos].length = (s64)0;
+       /* If no existing runlist was specified, we are done. */
+       if (!old_rl) {
+               ntfs_debug("Mapping pairs array successfully decompressed:");
+               ntfs_debug_dump_runlist(rl);
+               return rl;
+       }
+       /* Now combine the new and old runlists checking for overlaps. */
+       old_rl = ntfs_runlists_merge(old_rl, rl);
+       if (likely(!IS_ERR(old_rl)))
+               return old_rl;
+       ntfs_free(rl);
+       ntfs_error(vol->sb, "Failed to merge runlists.");
+       return old_rl;
+io_error:
+       ntfs_error(vol->sb, "Corrupt attribute.");
+err_out:
+       ntfs_free(rl);
+       return ERR_PTR(-EIO);
+}
+
+/**
+ * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist
+ * @rl:                runlist to use for conversion
+ * @vcn:       vcn to convert
+ *
+ * Convert the virtual cluster number @vcn of an attribute into a logical
+ * cluster number (lcn) of a device using the runlist @rl to map vcns to their
+ * corresponding lcns.
+ *
+ * It is up to the caller to serialize access to the runlist @rl.
+ *
+ * Since lcns must be >= 0, we use negative return values with special meaning:
+ *
+ * Return value                        Meaning / Description
+ * ==================================================
+ *  -1 = LCN_HOLE              Hole / not allocated on disk.
+ *  -2 = LCN_RL_NOT_MAPPED     This is part of the runlist which has not been
+ *                             inserted into the runlist yet.
+ *  -3 = LCN_ENOENT            There is no such vcn in the attribute.
+ *
+ * Locking: - The caller must have locked the runlist (for reading or writing).
+ *         - This function does not touch the lock.
+ */
+LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
+{
+       int i;
+
+       BUG_ON(vcn < 0);
+       /*
+        * If rl is NULL, assume that we have found an unmapped runlist. The
+        * caller can then attempt to map it and fail appropriately if
+        * necessary.
+        */
+       if (unlikely(!rl))
+               return LCN_RL_NOT_MAPPED;
+
+       /* Catch out of lower bounds vcn. */
+       if (unlikely(vcn < rl[0].vcn))
+               return LCN_ENOENT;
+
+       for (i = 0; likely(rl[i].length); i++) {
+               if (unlikely(vcn < rl[i+1].vcn)) {
+                       if (likely(rl[i].lcn >= (LCN)0))
+                               return rl[i].lcn + (vcn - rl[i].vcn);
+                       return rl[i].lcn;
+               }
+       }
+       /*
+        * The terminator element is setup to the correct value, i.e. one of
+        * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT.
+        */
+       if (likely(rl[i].lcn < (LCN)0))
+               return rl[i].lcn;
+       /* Just in case... We could replace this with BUG() some day. */
+       return LCN_ENOENT;
+}
+
+/**
+ * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number
+ * @n:         number for which to get the number of bytes for
+ *
+ * Return the number of bytes required to store @n unambiguously as
+ * a signed number.
+ *
+ * This is used in the context of the mapping pairs array to determine how
+ * many bytes will be needed in the array to store a given logical cluster
+ * number (lcn) or a specific run length.
+ *
+ * Return the number of bytes written.  This function cannot fail.
+ */
+static inline int ntfs_get_nr_significant_bytes(const s64 n)
+{
+       s64 l = n;
+       int i;
+       s8 j;
+
+       i = 0;
+       do {
+               l >>= 8;
+               i++;
+       } while (l != 0 && l != -1);
+       j = (n >> 8 * (i - 1)) & 0xff;
+       /* If the sign bit is wrong, we need an extra byte. */
+       if ((n < 0 && j >= 0) || (n > 0 && j < 0))
+               i++;
+       return i;
+}
+
+/**
+ * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array
+ * @vol:       ntfs volume (needed for the ntfs version)
+ * @rl:                locked runlist to determine the size of the mapping pairs of
+ * @start_vcn: vcn at which to start the mapping pairs array
+ *
+ * Walk the locked runlist @rl and calculate the size in bytes of the mapping
+ * pairs array corresponding to the runlist @rl, starting at vcn @start_vcn.
+ * This for example allows us to allocate a buffer of the right size when
+ * building the mapping pairs array.
+ *
+ * If @rl is NULL, just return 1 (for the single terminator byte).
+ *
+ * Return the calculated size in bytes on success.  On error, return -errno.
+ * The following error codes are defined:
+ *     -EINVAL - Run list contains unmapped elements.  Make sure to only pass
+ *               fully mapped runlists to this function.
+ *     -EIO    - The runlist is corrupt.
+ *
+ * Locking: @rl must be locked on entry (either for reading or writing), it
+ *         remains locked throughout, and is left locked upon return.
+ */
+int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
+               const runlist_element *rl, const VCN start_vcn)
+{
+       LCN prev_lcn;
+       int rls;
+
+       BUG_ON(start_vcn < 0);
+       if (!rl) {
+               BUG_ON(start_vcn);
+               return 1;
+       }
+       /* Skip to runlist element containing @start_vcn. */
+       while (rl->length && start_vcn >= rl[1].vcn)
+               rl++;
+       if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn)
+               return -EINVAL;
+       prev_lcn = 0;
+       /* Always need the termining zero byte. */
+       rls = 1;
+       /* Do the first partial run if present. */
+       if (start_vcn > rl->vcn) {
+               s64 delta;
+
+               /* We know rl->length != 0 already. */
+               if (rl->length < 0 || rl->lcn < LCN_HOLE)
+                       goto err_out;
+               delta = start_vcn - rl->vcn;
+               /* Header byte + length. */
+               rls += 1 + ntfs_get_nr_significant_bytes(rl->length - delta);
+               /*
+                * If the logical cluster number (lcn) denotes a hole and we
+                * are on NTFS 3.0+, we don't store it at all, i.e. we need
+                * zero space.  On earlier NTFS versions we just store the lcn.
+                * Note: this assumes that on NTFS 1.2-, holes are stored with
+                * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
+                */
+               if (rl->lcn >= 0 || vol->major_ver < 3) {
+                       prev_lcn = rl->lcn;
+                       if (rl->lcn >= 0)
+                               prev_lcn += delta;
+                       /* Change in lcn. */
+                       rls += ntfs_get_nr_significant_bytes(prev_lcn);
+               }
+               /* Go to next runlist element. */
+               rl++;
+       }
+       /* Do the full runs. */
+       for (; rl->length; rl++) {
+               if (rl->length < 0 || rl->lcn < LCN_HOLE)
+                       goto err_out;
+               /* Header byte + length. */
+               rls += 1 + ntfs_get_nr_significant_bytes(rl->length);
+               /*
+                * If the logical cluster number (lcn) denotes a hole and we
+                * are on NTFS 3.0+, we don't store it at all, i.e. we need
+                * zero space.  On earlier NTFS versions we just store the lcn.
+                * Note: this assumes that on NTFS 1.2-, holes are stored with
+                * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
+                */
+               if (rl->lcn >= 0 || vol->major_ver < 3) {
+                       /* Change in lcn. */
+                       rls += ntfs_get_nr_significant_bytes(rl->lcn -
+                                       prev_lcn);
+                       prev_lcn = rl->lcn;
+               }
+       }
+       return rls;
+err_out:
+       if (rl->lcn == LCN_RL_NOT_MAPPED)
+               rls = -EINVAL;
+       else
+               rls = -EIO;
+       return rls;
+}
+
+/**
+ * ntfs_write_significant_bytes - write the significant bytes of a number
+ * @dst:       destination buffer to write to
+ * @dst_max:   pointer to last byte of destination buffer for bounds checking
+ * @n:         number whose significant bytes to write
+ *
+ * Store in @dst, the minimum bytes of the number @n which are required to
+ * identify @n unambiguously as a signed number, taking care not to exceed
+ * @dest_max, the maximum position within @dst to which we are allowed to
+ * write.
+ *
+ * This is used when building the mapping pairs array of a runlist to compress
+ * a given logical cluster number (lcn) or a specific run length to the minumum
+ * size possible.
+ *
+ * Return the number of bytes written on success.  On error, i.e. the
+ * destination buffer @dst is too small, return -ENOSPC.
+ */
+static inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max,
+               const s64 n)
+{
+       s64 l = n;
+       int i;
+       s8 j;
+
+       i = 0;
+       do {
+               if (dst > dst_max)
+                       goto err_out;
+               *dst++ = l & 0xffll;
+               l >>= 8;
+               i++;
+       } while (l != 0 && l != -1);
+       j = (n >> 8 * (i - 1)) & 0xff;
+       /* If the sign bit is wrong, we need an extra byte. */
+       if (n < 0 && j >= 0) {
+               if (dst > dst_max)
+                       goto err_out;
+               i++;
+               *dst = (s8)-1;
+       } else if (n > 0 && j < 0) {
+               if (dst > dst_max)
+                       goto err_out;
+               i++;
+               *dst = (s8)0;
+       }
+       return i;
+err_out:
+       return -ENOSPC;
+}
+
+/**
+ * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist
+ * @vol:       ntfs volume (needed for the ntfs version)
+ * @dst:       destination buffer to which to write the mapping pairs array
+ * @dst_len:   size of destination buffer @dst in bytes
+ * @rl:                locked runlist for which to build the mapping pairs array
+ * @start_vcn: vcn at which to start the mapping pairs array
+ * @stop_vcn:  first vcn outside destination buffer on success or -ENOSPC
+ *
+ * Create the mapping pairs array from the locked runlist @rl, starting at vcn
+ * @start_vcn and save the array in @dst.  @dst_len is the size of @dst in
+ * bytes and it should be at least equal to the value obtained by calling
+ * ntfs_get_size_for_mapping_pairs().
+ *
+ * If @rl is NULL, just write a single terminator byte to @dst.
+ *
+ * On success or -ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to
+ * the first vcn outside the destination buffer.  Note that on error, @dst has
+ * been filled with all the mapping pairs that will fit, thus it can be treated
+ * as partial success, in that a new attribute extent needs to be created or
+ * the next extent has to be used and the mapping pairs build has to be
+ * continued with @start_vcn set to *@stop_vcn.
+ *
+ * Return 0 on success and -errno on error.  The following error codes are
+ * defined:
+ *     -EINVAL - Run list contains unmapped elements.  Make sure to only pass
+ *               fully mapped runlists to this function.
+ *     -EIO    - The runlist is corrupt.
+ *     -ENOSPC - The destination buffer is too small.
+ *
+ * Locking: @rl must be locked on entry (either for reading or writing), it
+ *         remains locked throughout, and is left locked upon return.
+ */
+int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
+               const int dst_len, const runlist_element *rl,
+               const VCN start_vcn, VCN *const stop_vcn)
+{
+       LCN prev_lcn;
+       s8 *dst_max, *dst_next;
+       int err = -ENOSPC;
+       s8 len_len, lcn_len;
+
+       BUG_ON(start_vcn < 0);
+       BUG_ON(dst_len < 1);
+       if (!rl) {
+               BUG_ON(start_vcn);
+               if (stop_vcn)
+                       *stop_vcn = 0;
+               /* Terminator byte. */
+               *dst = 0;
+               return 0;
+       }
+       /* Skip to runlist element containing @start_vcn. */
+       while (rl->length && start_vcn >= rl[1].vcn)
+               rl++;
+       if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn)
+               return -EINVAL;
+       /*
+        * @dst_max is used for bounds checking in
+        * ntfs_write_significant_bytes().
+        */
+       dst_max = dst + dst_len - 1;
+       prev_lcn = 0;
+       /* Do the first partial run if present. */
+       if (start_vcn > rl->vcn) {
+               s64 delta;
+
+               /* We know rl->length != 0 already. */
+               if (rl->length < 0 || rl->lcn < LCN_HOLE)
+                       goto err_out;
+               delta = start_vcn - rl->vcn;
+               /* Write length. */
+               len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
+                               rl->length - delta);
+               if (len_len < 0)
+                       goto size_err;
+               /*
+                * If the logical cluster number (lcn) denotes a hole and we
+                * are on NTFS 3.0+, we don't store it at all, i.e. we need
+                * zero space.  On earlier NTFS versions we just write the lcn
+                * change.  FIXME: Do we need to write the lcn change or just
+                * the lcn in that case?  Not sure as I have never seen this
+                * case on NT4. - We assume that we just need to write the lcn
+                * change until someone tells us otherwise... (AIA)
+                */
+               if (rl->lcn >= 0 || vol->major_ver < 3) {
+                       prev_lcn = rl->lcn;
+                       if (rl->lcn >= 0)
+                               prev_lcn += delta;
+                       /* Write change in lcn. */
+                       lcn_len = ntfs_write_significant_bytes(dst + 1 +
+                                       len_len, dst_max, prev_lcn);
+                       if (lcn_len < 0)
+                               goto size_err;
+               } else
+                       lcn_len = 0;
+               dst_next = dst + len_len + lcn_len + 1;
+               if (dst_next > dst_max)
+                       goto size_err;
+               /* Update header byte. */
+               *dst = lcn_len << 4 | len_len;
+               /* Position at next mapping pairs array element. */
+               dst = dst_next;
+               /* Go to next runlist element. */
+               rl++;
+       }
+       /* Do the full runs. */
+       for (; rl->length; rl++) {
+               if (rl->length < 0 || rl->lcn < LCN_HOLE)
+                       goto err_out;
+               /* Write length. */
+               len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
+                               rl->length);
+               if (len_len < 0)
+                       goto size_err;
+               /*
+                * If the logical cluster number (lcn) denotes a hole and we
+                * are on NTFS 3.0+, we don't store it at all, i.e. we need
+                * zero space.  On earlier NTFS versions we just write the lcn
+                * change.  FIXME: Do we need to write the lcn change or just
+                * the lcn in that case?  Not sure as I have never seen this
+                * case on NT4. - We assume that we just need to write the lcn
+                * change until someone tells us otherwise... (AIA)
+                */
+               if (rl->lcn >= 0 || vol->major_ver < 3) {
+                       /* Write change in lcn. */
+                       lcn_len = ntfs_write_significant_bytes(dst + 1 +
+                                       len_len, dst_max, rl->lcn - prev_lcn);
+                       if (lcn_len < 0)
+                               goto size_err;
+                       prev_lcn = rl->lcn;
+               } else
+                       lcn_len = 0;
+               dst_next = dst + len_len + lcn_len + 1;
+               if (dst_next > dst_max)
+                       goto size_err;
+               /* Update header byte. */
+               *dst = lcn_len << 4 | len_len;
+               /* Position at next mapping pairs array element. */
+               dst = dst_next;
+       }
+       /* Success. */
+       err = 0;
+size_err:
+       /* Set stop vcn. */
+       if (stop_vcn)
+               *stop_vcn = rl->vcn;
+       /* Add terminator byte. */
+       *dst = 0;
+       return err;
+err_out:
+       if (rl->lcn == LCN_RL_NOT_MAPPED)
+               err = -EINVAL;
+       else
+               err = -EIO;
+       return err;
+}
+
+/**
+ * ntfs_rl_truncate_nolock - truncate a runlist starting at a specified vcn
+ * @runlist:   runlist to truncate
+ * @new_length:        the new length of the runlist in VCNs
+ *
+ * Truncate the runlist described by @runlist as well as the memory buffer
+ * holding the runlist elements to a length of @new_length VCNs.
+ *
+ * If @new_length lies within the runlist, the runlist elements with VCNs of
+ * @new_length and above are discarded.
+ *
+ * If @new_length lies beyond the runlist, a sparse runlist element is added to
+ * the end of the runlist @runlist or if the last runlist element is a sparse
+ * one already, this is extended.
+ *
+ * Return 0 on success and -errno on error.
+ *
+ * Locking: The caller must hold @runlist->lock for writing.
+ */
+int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist,
+               const s64 new_length)
+{
+       runlist_element *rl;
+       int old_size;
+
+       ntfs_debug("Entering for new_length 0x%llx.", (long long)new_length);
+       BUG_ON(!runlist);
+       BUG_ON(new_length < 0);
+       rl = runlist->rl;
+       if (unlikely(!rl)) {
+               /*
+                * Create a runlist consisting of a sparse runlist element of
+                * length @new_length followed by a terminator runlist element.
+                */
+               rl = ntfs_malloc_nofs(PAGE_SIZE);
+               if (unlikely(!rl)) {
+                       ntfs_error(vol->sb, "Not enough memory to allocate "
+                                       "runlist element buffer.");
+                       return -ENOMEM;
+               }
+               runlist->rl = rl;
+               rl[1].length = rl->vcn = 0;
+               rl->lcn = LCN_HOLE;
+               rl[1].vcn = rl->length = new_length;
+               rl[1].lcn = LCN_ENOENT;
+               return 0;
+       }
+       BUG_ON(new_length < rl->vcn);
+       /* Find @new_length in the runlist. */
+       while (likely(rl->length && new_length >= rl[1].vcn))
+               rl++;
+       /*
+        * If not at the end of the runlist we need to shrink it.
+        * If at the end of the runlist we need to expand it.
+        */
+       if (rl->length) {
+               runlist_element *trl;
+               BOOL is_end;
+
+               ntfs_debug("Shrinking runlist.");
+               /* Determine the runlist size. */
+               trl = rl + 1;
+               while (likely(trl->length))
+                       trl++;
+               old_size = trl - runlist->rl + 1;
+               /* Truncate the run. */
+               rl->length = new_length - rl->vcn;
+               /*
+                * If a run was partially truncated, make the following runlist
+                * element a terminator.
+                */
+               is_end = FALSE;
+               if (rl->length) {
+                       rl++;
+                       if (!rl->length)
+                               is_end = TRUE;
+                       rl->vcn = new_length;
+                       rl->length = 0;
+               }
+               rl->lcn = LCN_ENOENT;
+               /* Reallocate memory if necessary. */
+               if (!is_end) {
+                       int new_size = rl - runlist->rl + 1;
+                       rl = ntfs_rl_realloc(runlist->rl, old_size, new_size);
+                       if (IS_ERR(rl))
+                               ntfs_warning(vol->sb, "Failed to shrink "
+                                               "runlist buffer.  This just "
+                                               "wastes a bit of memory "
+                                               "temporarily so we ignore it "
+                                               "and return success.");
+                       else
+                               runlist->rl = rl;
+               }
+       } else if (likely(/* !rl->length && */ new_length > rl->vcn)) {
+               ntfs_debug("Expanding runlist.");
+               /*
+                * If there is a previous runlist element and it is a sparse
+                * one, extend it.  Otherwise need to add a new, sparse runlist
+                * element.
+                */
+               if ((rl > runlist->rl) && ((rl - 1)->lcn == LCN_HOLE))
+                       (rl - 1)->length = new_length - (rl - 1)->vcn;
+               else {
+                       /* Determine the runlist size. */
+                       old_size = rl - runlist->rl + 1;
+                       /* Reallocate memory if necessary. */
+                       rl = ntfs_rl_realloc(runlist->rl, old_size,
+                                       old_size + 1);
+                       if (IS_ERR(rl)) {
+                               ntfs_error(vol->sb, "Failed to expand runlist "
+                                               "buffer, aborting.");
+                               return PTR_ERR(rl);
+                       }
+                       runlist->rl = rl;
+                       /*
+                        * Set @rl to the same runlist element in the new
+                        * runlist as before in the old runlist.
+                        */
+                       rl += old_size - 1;
+                       /* Add a new, sparse runlist element. */
+                       rl->lcn = LCN_HOLE;
+                       rl->length = new_length - rl->vcn;
+                       /* Add a new terminator runlist element. */
+                       rl++;
+                       rl->length = 0;
+               }
+               rl->vcn = new_length;
+               rl->lcn = LCN_ENOENT;
+       } else /* if (unlikely(!rl->length && new_length == rl->vcn)) */ {
+               /* Runlist already has same size as requested. */
+               rl->lcn = LCN_ENOENT;
+       }
+       ntfs_debug("Done.");
+       return 0;
+}
diff --git a/fs/ntfs/runlist.h b/fs/ntfs/runlist.h
new file mode 100644 (file)
index 0000000..7107fde
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * runlist.h - Defines for runlist handling in NTFS Linux kernel driver.
+ *            Part of the Linux-NTFS project.
+ *
+ * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2002 Richard Russon
+ *
+ * This program/include 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program/include 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 (in the main directory of the Linux-NTFS
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_NTFS_RUNLIST_H
+#define _LINUX_NTFS_RUNLIST_H
+
+#include "types.h"
+#include "layout.h"
+#include "volume.h"
+
+/**
+ * runlist_element - in memory vcn to lcn mapping array element
+ * @vcn:       starting vcn of the current array element
+ * @lcn:       starting lcn of the current array element
+ * @length:    length in clusters of the current array element
+ *
+ * The last vcn (in fact the last vcn + 1) is reached when length == 0.
+ *
+ * When lcn == -1 this means that the count vcns starting at vcn are not
+ * physically allocated (i.e. this is a hole / data is sparse).
+ */
+typedef struct {       /* In memory vcn to lcn mapping structure element. */
+       VCN vcn;        /* vcn = Starting virtual cluster number. */
+       LCN lcn;        /* lcn = Starting logical cluster number. */
+       s64 length;     /* Run length in clusters. */
+} runlist_element;
+
+/**
+ * runlist - in memory vcn to lcn mapping array including a read/write lock
+ * @rl:                pointer to an array of runlist elements
+ * @lock:      read/write spinlock for serializing access to @rl
+ *
+ */
+typedef struct {
+       runlist_element *rl;
+       struct rw_semaphore lock;
+} runlist;
+
+static inline void ntfs_init_runlist(runlist *rl)
+{
+       rl->rl = NULL;
+       init_rwsem(&rl->lock);
+}
+
+typedef enum {
+       LCN_HOLE                = -1,   /* Keep this as highest value or die! */
+       LCN_RL_NOT_MAPPED       = -2,
+       LCN_ENOENT              = -3,
+} LCN_SPECIAL_VALUES;
+
+extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
+               runlist_element *srl);
+
+extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
+               const ATTR_RECORD *attr, runlist_element *old_rl);
+
+extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);
+
+extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
+               const runlist_element *rl, const VCN start_vcn);
+
+extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
+               const int dst_len, const runlist_element *rl,
+               const VCN start_vcn, VCN *const stop_vcn);
+
+extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol,
+               runlist *const runlist, const s64 new_length);
+
+#endif /* _LINUX_NTFS_RUNLIST_H */
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
new file mode 100644 (file)
index 0000000..f375331
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 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.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <linux/config.h>
+#include <linux/compat.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/ioctl32.h>
+#include <linux/syscalls.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+
+#include "xfs_types.h"
+#include "xfs_fs.h"
+#include "xfs_dfrag.h"
+
+#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+#define BROKEN_X86_ALIGNMENT
+#else
+
+typedef struct xfs_fsop_bulkreq32 {
+       compat_uptr_t   lastip;         /* last inode # pointer         */
+       __s32           icount;         /* count of entries in buffer   */
+       compat_uptr_t   ubuffer;        /* user buffer for inode desc.  */
+       __s32           ocount;         /* output count pointer         */
+} xfs_fsop_bulkreq32_t;
+
+static int
+xfs_ioctl32_bulkstat(
+       unsigned int            fd,
+       unsigned int            cmd,
+       unsigned long           arg,
+       struct file *           file)
+{
+       xfs_fsop_bulkreq32_t    __user *p32 = (void __user *)arg;
+       xfs_fsop_bulkreq_t      __user *p = compat_alloc_user_space(sizeof(*p));
+       u32                     addr;
+
+       if (get_user(addr, &p32->lastip) ||
+           put_user(compat_ptr(addr), &p->lastip) ||
+           copy_in_user(&p->icount, &p32->icount, sizeof(s32)) ||
+           get_user(addr, &p32->ubuffer) ||
+           put_user(compat_ptr(addr), &p->ubuffer) ||
+           get_user(addr, &p32->ocount) ||
+           put_user(compat_ptr(addr), &p->ocount))
+               return -EFAULT;
+
+       return sys_ioctl(fd, cmd, (unsigned long)p);
+}
+#endif
+
+struct ioctl_trans xfs_ioctl32_trans[] = {
+       { XFS_IOC_DIOINFO, },
+       { XFS_IOC_FSGEOMETRY_V1, },
+       { XFS_IOC_FSGEOMETRY, },
+       { XFS_IOC_GETVERSION, },
+       { XFS_IOC_GETXFLAGS, },
+       { XFS_IOC_SETXFLAGS, },
+       { XFS_IOC_FSGETXATTR, },
+       { XFS_IOC_FSSETXATTR, },
+       { XFS_IOC_FSGETXATTRA, },
+       { XFS_IOC_FSSETDM, },
+       { XFS_IOC_GETBMAP, },
+       { XFS_IOC_GETBMAPA, },
+       { XFS_IOC_GETBMAPX, },
+/* not handled
+       { XFS_IOC_FD_TO_HANDLE, },
+       { XFS_IOC_PATH_TO_HANDLE, },
+       { XFS_IOC_PATH_TO_HANDLE, },
+       { XFS_IOC_PATH_TO_FSHANDLE, },
+       { XFS_IOC_OPEN_BY_HANDLE, },
+       { XFS_IOC_FSSETDM_BY_HANDLE, },
+       { XFS_IOC_READLINK_BY_HANDLE, },
+       { XFS_IOC_ATTRLIST_BY_HANDLE, },
+       { XFS_IOC_ATTRMULTI_BY_HANDLE, },
+*/
+       { XFS_IOC_FSCOUNTS, NULL, },
+       { XFS_IOC_SET_RESBLKS, NULL, },
+       { XFS_IOC_GET_RESBLKS, NULL, },
+       { XFS_IOC_FSGROWFSDATA, NULL, },
+       { XFS_IOC_FSGROWFSLOG, NULL, },
+       { XFS_IOC_FSGROWFSRT, NULL, },
+       { XFS_IOC_FREEZE, NULL, },
+       { XFS_IOC_THAW, NULL, },
+       { XFS_IOC_GOINGDOWN, NULL, },
+       { XFS_IOC_ERROR_INJECTION, NULL, },
+       { XFS_IOC_ERROR_CLEARALL, NULL, },
+#ifndef BROKEN_X86_ALIGNMENT
+       /* xfs_flock_t and xfs_bstat_t have wrong u32 vs u64 alignment */
+       { XFS_IOC_ALLOCSP, },
+       { XFS_IOC_FREESP, },
+       { XFS_IOC_RESVSP, },
+       { XFS_IOC_UNRESVSP, },
+       { XFS_IOC_ALLOCSP64, },
+       { XFS_IOC_FREESP64, },
+       { XFS_IOC_RESVSP64, },
+       { XFS_IOC_UNRESVSP64, },
+       { XFS_IOC_SWAPEXT, },
+       { XFS_IOC_FSBULKSTAT_SINGLE, xfs_ioctl32_bulkstat },
+       { XFS_IOC_FSBULKSTAT, xfs_ioctl32_bulkstat},
+       { XFS_IOC_FSINUMBERS, xfs_ioctl32_bulkstat},
+#endif
+       { 0, },
+};
+
+int __init
+xfs_ioctl32_init(void)
+{
+       int error, i;
+
+       for (i = 0; xfs_ioctl32_trans[i].cmd != 0; i++) {
+               error = register_ioctl32_conversion(xfs_ioctl32_trans[i].cmd,
+                               xfs_ioctl32_trans[i].handler);
+               if (error)
+                       goto fail;
+       }
+
+       return 0;
+
+ fail:
+       while (--i)
+               unregister_ioctl32_conversion(xfs_ioctl32_trans[i].cmd);
+       return error;
+}
+
+void
+xfs_ioctl32_exit(void)
+{
+       int i;
+
+       for (i = 0; xfs_ioctl32_trans[i].cmd != 0; i++)
+               unregister_ioctl32_conversion(xfs_ioctl32_trans[i].cmd);
+}
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/linux-2.6/xfs_ioctl32.h
new file mode 100644 (file)
index 0000000..0e24f08
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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 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.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_COMPAT
+extern int xfs_ioctl32_init(void);
+extern void xfs_ioctl32_exit(void);
+#else
+static inline int xfs_ioctl32_init(void) { return 0; }
+static inline void xfs_ioctl32_exit(void) { }
+#endif
diff --git a/include/asm-alpha/io_trivial.h b/include/asm-alpha/io_trivial.h
new file mode 100644 (file)
index 0000000..cfe1f86
--- /dev/null
@@ -0,0 +1,127 @@
+/* Trivial implementations of basic i/o routines.  Assumes that all
+   of the hard work has been done by ioremap and ioportmap, and that
+   access to i/o space is linear.  */
+
+/* This file may be included multiple times.  */
+
+#if IO_CONCAT(__IO_PREFIX,trivial_io_bw)
+__EXTERN_INLINE unsigned int
+IO_CONCAT(__IO_PREFIX,ioread8)(void __iomem *a)
+{
+       return __kernel_ldbu(*(volatile u8 __force *)a);
+}
+
+__EXTERN_INLINE unsigned int
+IO_CONCAT(__IO_PREFIX,ioread16)(void __iomem *a)
+{
+       return __kernel_ldwu(*(volatile u16 __force *)a);
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,iowrite8)(u8 b, void __iomem *a)
+{
+       __kernel_stb(b, *(volatile u8 __force *)a);
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,iowrite16)(u16 b, void __iomem *a)
+{
+       __kernel_stb(b, *(volatile u16 __force *)a);
+}
+#endif
+
+#if IO_CONCAT(__IO_PREFIX,trivial_io_lq)
+__EXTERN_INLINE unsigned int
+IO_CONCAT(__IO_PREFIX,ioread32)(void __iomem *a)
+{
+       return *(volatile u32 __force *)a;
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,iowrite32)(u32 b, void __iomem *a)
+{
+       *(volatile u32 __force *)a = b;
+}
+#endif
+
+#if IO_CONCAT(__IO_PREFIX,trivial_rw_bw) == 1
+__EXTERN_INLINE u8
+IO_CONCAT(__IO_PREFIX,readb)(const volatile void __iomem *a)
+{
+       return __kernel_ldbu(*(const volatile u8 __force *)a);
+}
+
+__EXTERN_INLINE u16
+IO_CONCAT(__IO_PREFIX,readw)(const volatile void __iomem *a)
+{
+       return __kernel_ldwu(*(const volatile u16 __force *)a);
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,writeb)(u8 b, volatile void __iomem *a)
+{
+       __kernel_stb(b, *(volatile u8 __force *)a);
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,writew)(u16 b, volatile void __iomem *a)
+{
+       __kernel_stb(b, *(volatile u16 __force *)a);
+}
+#elif IO_CONCAT(__IO_PREFIX,trivial_rw_bw) == 2
+__EXTERN_INLINE u8
+IO_CONCAT(__IO_PREFIX,readb)(const volatile void __iomem *a)
+{
+       return IO_CONCAT(__IO_PREFIX,ioread8)((void __iomem *)a);
+}
+
+__EXTERN_INLINE u16
+IO_CONCAT(__IO_PREFIX,readw)(const volatile void __iomem *a)
+{
+       return IO_CONCAT(__IO_PREFIX,ioread16)((void __iomem *)a);
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,writeb)(u8 b, volatile void __iomem *a)
+{
+       IO_CONCAT(__IO_PREFIX,iowrite8)(b, (void __iomem *)a);
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,writew)(u16 b, volatile void __iomem *a)
+{
+       IO_CONCAT(__IO_PREFIX,iowrite16)(b, (void __iomem *)a);
+}
+#endif
+
+#if IO_CONCAT(__IO_PREFIX,trivial_rw_lq) == 1
+__EXTERN_INLINE u32
+IO_CONCAT(__IO_PREFIX,readl)(const volatile void __iomem *a)
+{
+       return *(const volatile u32 __force *)a;
+}
+
+__EXTERN_INLINE u64
+IO_CONCAT(__IO_PREFIX,readq)(const volatile void __iomem *a)
+{
+       return *(const volatile u64 __force *)a;
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,writel)(u32 b, volatile void __iomem *a)
+{
+       *(volatile u32 __force *)a = b;
+}
+
+__EXTERN_INLINE void
+IO_CONCAT(__IO_PREFIX,writeq)(u64 b, volatile void __iomem *a)
+{
+       *(volatile u64 __force *)a = b;
+}
+#endif
+
+#if IO_CONCAT(__IO_PREFIX,trivial_iounmap)
+__EXTERN_INLINE void IO_CONCAT(__IO_PREFIX,iounmap)(volatile void __iomem *a)
+{
+}
+#endif
diff --git a/include/asm-arm/arch-h720x/boards.h b/include/asm-arm/arch-h720x/boards.h
new file mode 100644 (file)
index 0000000..8021f81
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * linux/include/asm-arm/arch-h720x/boards.h
+ *
+ * Copyright (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *           (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *
+ * This file contains the board specific defines for various devices
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_INCMACH_H
+#error Do not include this file directly. Include asm/hardware.h instead !
+#endif
+
+/* Hynix H7202 developer board specific device defines */
+#ifdef CONFIG_ARCH_H7202
+
+/* FLASH */
+#define FLASH_VIRT             0xd0000000
+#define FLASH_PHYS             0x00000000
+#define FLASH_SIZE             0x02000000
+
+/* onboard LAN controller */
+# define ETH0_PHYS             0x08000000
+
+/* Touch screen defines */
+/* GPIO Port */
+#define PEN_GPIO               GPIO_B_VIRT
+/* Bitmask for pen down interrupt */
+#define PEN_INT_BIT            (1<<7)
+/* Bitmask for pen up interrupt */
+#define PEN_ENA_BIT            (1<<6)
+/* pen up interrupt */
+#define IRQ_PEN                        IRQ_MUX_GPIOB(7)
+
+#endif
+
+/* Hynix H7201 developer board specific device defines */
+#if defined (CONFIG_ARCH_H7201)
+/* ROM DISK SPACE */
+#define ROM_DISK_BASE           0xc1800000
+#define ROM_DISK_START          0x41800000
+#define ROM_DISK_SIZE           0x00700000
+
+/* SRAM DISK SPACE */
+#define SRAM_DISK_BASE          0xf1000000
+#define SRAM_DISK_START         0x04000000
+#define SRAM_DISK_SIZE          0x00400000
+#endif
+
diff --git a/include/asm-arm/arch-h720x/dma.h b/include/asm-arm/arch-h720x/dma.h
new file mode 100644 (file)
index 0000000..bfc6636
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * linux/include/asm-arm/arch-h720x/dma.h
+ *
+ * Architecture DMA routes
+ *
+ * Copyright (C) 1997.1998 Russell King
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+/*
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
+ */
+#define MAX_DMA_ADDRESS                0xd0000000
+
+#if defined (CONFIG_CPU_H7201)
+#define MAX_DMA_CHANNELS       3
+#elif defined (CONFIG_CPU_H7202)
+#define MAX_DMA_CHANNELS       4
+#else
+#error processor definition missmatch
+#endif
+
+#endif /* __ASM_ARCH_DMA_H */
diff --git a/include/asm-arm/arch-h720x/h7201-regs.h b/include/asm-arm/arch-h720x/h7201-regs.h
new file mode 100644 (file)
index 0000000..49d4f6b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * linux/include/asm-arm/arch-h720x/h7201-regs.h
+ *
+ * Copyright (C) 2000 Jungjun Kim, Hynix Semiconductor Inc.
+ *           (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *           (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *           (C) 2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * This file contains the hardware definitions of the h720x processors
+ *
+ * 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.
+ *
+ * Do not add implementations specific defines here. This files contains
+ * only defines of the onchip peripherals. Add those defines to boards.h,
+ * which is included by this file.
+ */
+
+#define SERIAL2_VIRT           (IO_VIRT + 0x50100)
+#define SERIAL3_VIRT           (IO_VIRT + 0x50200)
+
+/*
+ * PCMCIA
+ */
+#define PCMCIA0_ATT_BASE        0xe5000000
+#define PCMCIA0_ATT_SIZE        0x00200000
+#define PCMCIA0_ATT_START       0x20000000
+#define PCMCIA0_MEM_BASE        0xe5200000
+#define PCMCIA0_MEM_SIZE        0x00200000
+#define PCMCIA0_MEM_START       0x24000000
+#define PCMCIA0_IO_BASE         0xe5400000
+#define PCMCIA0_IO_SIZE         0x00200000
+#define PCMCIA0_IO_START        0x28000000
+
+#define PCMCIA1_ATT_BASE        0xe5600000
+#define PCMCIA1_ATT_SIZE        0x00200000
+#define PCMCIA1_ATT_START       0x30000000
+#define PCMCIA1_MEM_BASE        0xe5800000
+#define PCMCIA1_MEM_SIZE        0x00200000
+#define PCMCIA1_MEM_START       0x34000000
+#define PCMCIA1_IO_BASE         0xe5a00000
+#define PCMCIA1_IO_SIZE         0x00200000
+#define PCMCIA1_IO_START        0x38000000
+
+#define PRIME3C_BASE            0xf0050000
+#define PRIME3C_SIZE            0x00001000
+#define PRIME3C_START           0x10000000
+
+/* VGA Controller */
+#define VGA_RAMBASE            0x50
+#define VGA_TIMING0            0x60
+#define VGA_TIMING1            0x64
+#define VGA_TIMING2            0x68
+#define VGA_TIMING3            0x6c
+
+#define LCD_CTRL_VGA_ENABLE    0x00000100
+#define LCD_CTRL_VGA_BPP_MASK  0x00000600
+#define LCD_CTRL_VGA_4BPP      0x00000000
+#define LCD_CTRL_VGA_8BPP      0x00000200
+#define LCD_CTRL_VGA_16BPP     0x00000300
+#define LCD_CTRL_SHARE_DMA     0x00000800
+#define LCD_CTRL_VDE           0x00100000
+#define LCD_CTRL_LPE           0x00400000      /* LCD Power enable */
+#define LCD_CTRL_BLE           0x00800000      /* LCD backlight enable */
+
+#define VGA_PALETTE_BASE       (IO_VIRT + 0x10800)
diff --git a/include/asm-arm/arch-h720x/h7202-regs.h b/include/asm-arm/arch-h720x/h7202-regs.h
new file mode 100644 (file)
index 0000000..d5c8671
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * linux/include/asm-arm/arch-h720x/h7202-regs.h
+ *
+ * Copyright (C) 2000 Jungjun Kim, Hynix Semiconductor Inc.
+ *           (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *           (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *           (C) 2004 Sascha Hauer    <s.hauer@pengutronix.de>
+ *
+ * This file contains the hardware definitions of the h720x processors
+ *
+ * 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.
+ *
+ * Do not add implementations specific defines here. This files contains
+ * only defines of the onchip peripherals. Add those defines to boards.h,
+ * which is included by this file.
+ */
+
+#define SERIAL2_VIRT           (IO_VIRT + 0x2d000)
+#define SERIAL3_VIRT           (IO_VIRT + 0x2e000)
+
+/* Matrix Keyboard Controller */
+#define KBD_VIRT               (IO_VIRT + 0x22000)
+#define KBD_KBCR               0x00
+#define KBD_KBSC               0x04
+#define KBD_KBTR               0x08
+#define KBD_KBVR0              0x0C
+#define KBD_KBVR1              0x10
+#define KBD_KBSR               0x18
+
+#define KBD_KBCR_SCANENABLE    (1 << 7)
+#define KBD_KBCR_NPOWERDOWN    (1 << 2)
+#define KBD_KBCR_CLKSEL_MASK   (3)
+#define KBD_KBCR_CLKSEL_PCLK2  0x0
+#define KBD_KBCR_CLKSEL_PCLK128        0x1
+#define KBD_KBCR_CLKSEL_PCLK256        0x2
+#define KBD_KBCR_CLKSEL_PCLK512        0x3
+
+#define KBD_KBSR_INTR          (1 << 0)
+#define KBD_KBSR_WAKEUP                (1 << 1)
+
+/* USB device controller */
+
+#define USBD_BASE              (IO_VIRT + 0x12000)
+#define USBD_LENGTH            0x3C
+
+#define USBD_GCTRL             0x00
+#define USBD_EPCTRL            0x04
+#define USBD_INTMASK           0x08
+#define USBD_INTSTAT           0x0C
+#define USBD_PWR               0x10
+#define USBD_DMARXTX           0x14
+#define USBD_DEVID             0x18
+#define USBD_DEVCLASS          0x1C
+#define USBD_INTCLASS          0x20
+#define USBD_SETUP0            0x24
+#define USBD_SETUP1            0x28
+#define USBD_ENDP0RD           0x2C
+#define USBD_ENDP0WT           0x30
+#define USBD_ENDP1RD           0x34
+#define USBD_ENDP2WT           0x38
+
+/* PS/2 port */
+#define PSDATA 0x00
+#define PSSTAT 0x04
+#define PSSTAT_TXEMPTY (1<<0)
+#define PSSTAT_TXBUSY (1<<1)
+#define PSSTAT_RXFULL (1<<2)
+#define PSSTAT_RXBUSY (1<<3)
+#define PSSTAT_CLKIN (1<<4)
+#define PSSTAT_DATAIN (1<<5)
+#define PSSTAT_PARITY (1<<6)
+
+#define PSCONF 0x08
+#define PSCONF_ENABLE (1<<0)
+#define PSCONF_TXINTEN (1<<2)
+#define PSCONF_RXINTEN (1<<3)
+#define PSCONF_FORCECLKLOW (1<<4)
+#define PSCONF_FORCEDATLOW (1<<5)
+#define PSCONF_LCE (1<<6)
+
+#define PSINTR 0x0C
+#define PSINTR_TXINT (1<<0)
+#define PSINTR_RXINT (1<<1)
+#define PSINTR_PAR (1<<2)
+#define PSINTR_RXTO (1<<3)
+#define PSINTR_TXTO (1<<4)
+
+#define PSTDLO 0x10 /* clk low before start transmission */
+#define PSTPRI 0x14 /* PRI clock */
+#define PSTXMT 0x18 /* maximum transmission time */
+#define PSTREC 0x20 /* maximum receive time */
+#define PSPWDN 0x3c
+
+/* ADC converter */
+#define ADC_BASE               (IO_VIRT + 0x29000)
+#define ADC_CR                         0x00
+#define ADC_TSCTRL             0x04
+#define ADC_BT_CTRL            0x08
+#define ADC_MC_CTRL            0x0C
+#define ADC_STATUS             0x10
+
+/* ADC control register bits */
+#define ADC_CR_PW_CTRL                 0x80
+#define ADC_CR_DIRECTC         0x04
+#define ADC_CR_CONTIME_NO      0x00
+#define ADC_CR_CONTIME_2       0x04
+#define ADC_CR_CONTIME_4       0x08
+#define ADC_CR_CONTIME_ADE     0x0c
+#define ADC_CR_LONGCALTIME     0x01
+
+/* ADC touch panel register bits */
+#define ADC_TSCTRL_ENABLE      0x80
+#define ADC_TSCTRL_INTR        0x40
+#define        ADC_TSCTRL_SWBYPSS      0x20
+#define ADC_TSCTRL_SWINVT      0x10
+#define ADC_TSCTRL_S400        0x03
+#define ADC_TSCTRL_S200        0x02
+#define ADC_TSCTRL_S100        0x01
+#define ADC_TSCTRL_S50         0x00
+
+/* ADC Interrupt Status Register bits */
+#define ADC_STATUS_TS_BIT      0x80
+#define ADC_STATUS_MBT_BIT     0x40
+#define ADC_STATUS_BBT_BIT     0x20
+#define ADC_STATUS_MIC_BIT     0x10
+
+/* Touch data registers */
+#define ADC_TS_X0X1            0x30
+#define ADC_TS_X2X3            0x34
+#define ADC_TS_Y0Y1            0x38
+#define ADC_TS_Y2Y3            0x3c
+#define ADC_TS_X4X5            0x40
+#define ADC_TS_X6X7            0x44
+#define ADC_TS_Y4Y5            0x48
+#define ADC_TS_Y6Y7            0x50
+
+/* battery data */
+#define ADC_MB_DATA            0x54
+#define ADC_BB_DATA            0x58
+
+/* Sound data register */
+#define ADC_SD_DAT0            0x60
+#define ADC_SD_DAT1            0x64
+#define ADC_SD_DAT2            0x68
+#define ADC_SD_DAT3            0x6c
+#define ADC_SD_DAT4            0x70
+#define ADC_SD_DAT5            0x74
+#define ADC_SD_DAT6            0x78
+#define ADC_SD_DAT7            0x7c
diff --git a/include/asm-arm/arch-h720x/hardware.h b/include/asm-arm/arch-h720x/hardware.h
new file mode 100644 (file)
index 0000000..864dc1f
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * linux/include/asm-arm/arch-h720x/hardware.h
+ *
+ * Copyright (C) 2000 Jungjun Kim, Hynix Semiconductor Inc.
+ *           (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *           (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *
+ * This file contains the hardware definitions of the h720x processors
+ *
+ * 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.
+ *
+ * Do not add implementations specific defines here. This files contains
+ * only defines of the onchip peripherals. Add those defines to boards.h,
+ * which is included by this file.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#define IOCLK (3686400L)
+
+/* Onchip peripherals */
+
+#define IO_VIRT                        0xf0000000      /* IO peripherals */
+#define IO_PHYS                        0x80000000
+#define IO_SIZE                        0x00050000
+
+#ifdef CONFIG_CPU_H7202
+#include "h7202-regs.h"
+#elif defined CONFIG_CPU_H7201
+#include "h7201-regs.h"
+#else
+#error machine definition mismatch
+#endif
+
+/* Macro to access the CPU IO */
+#define CPU_IO(x) (*(volatile u32*)(x))
+
+/* Macro to access general purpose regs (base, offset) */
+#define CPU_REG(x,y) CPU_IO(x+y)
+
+/* Macro to access irq related regs */
+#define IRQ_REG(x) CPU_REG(IRQC_VIRT,x)
+
+/* CPU registers */
+/* general purpose I/O */
+#define GPIO_VIRT(x)           (IO_VIRT + 0x23000 + ((x)<<5))
+#define GPIO_A_VIRT            (GPIO_VIRT(0))
+#define GPIO_B_VIRT            (GPIO_VIRT(1))
+#define GPIO_C_VIRT            (GPIO_VIRT(2))
+#define GPIO_D_VIRT            (GPIO_VIRT(3))
+#define GPIO_E_VIRT            (GPIO_VIRT(4))
+#define GPIO_AMULSEL           (GPIO_VIRT + 0xA4)
+/* Register offsets general purpose I/O */
+#define GPIO_DATA              0x00
+#define GPIO_DIR               0x04
+#define GPIO_MASK              0x08
+#define GPIO_STAT              0x0C
+#define GPIO_EDGE              0x10
+#define GPIO_CLR               0x14
+#define GPIO_POL               0x18
+#define GPIO_EN                        0x1C
+
+/*interrupt controller */
+#define IRQC_VIRT              (IO_VIRT + 0x24000)
+/* register offset interrupt controller */
+#define IRQC_IER               0x00
+#define IRQC_ISR               0x04
+
+/* timer unit */
+#define TIMER_VIRT             (IO_VIRT + 0x25000)
+/* Register offsets timer unit */
+#define TM0_PERIOD             0x00
+#define TM0_COUNT              0x08
+#define TM0_CTRL               0x10
+#define TM1_PERIOD             0x20
+#define TM1_COUNT              0x28
+#define TM1_CTRL               0x30
+#define TM2_PERIOD             0x40
+#define TM2_COUNT              0x48
+#define TM2_CTRL               0x50
+#define TIMER_TOPCTRL          0x60
+#define TIMER_TOPSTAT          0x64
+#define T64_COUNTL             0x80
+#define T64_COUNTH             0x84
+#define T64_CTRL               0x88
+#define T64_BASEL              0x94
+#define T64_BASEH              0x98
+/* Bitmaks timer unit TOPSTAT reg */
+#define TSTAT_T0INT            0x1
+#define TSTAT_T1INT            0x2
+#define TSTAT_T2INT            0x4
+#define TSTAT_T3INT            0x8
+/* Bit description of TMx_CTRL register */
+#define TM_START               0x1
+#define TM_REPEAT              0x2
+#define TM_RESET               0x4
+/* Bit description of TIMER_CTRL register */
+#define ENABLE_TM0_INTR        0x1
+#define ENABLE_TM1_INTR        0x2
+#define ENABLE_TM2_INTR        0x4
+#define TIMER_ENABLE_BIT       0x8
+#define ENABLE_TIMER64         0x10
+#define ENABLE_TIMER64_INT     0x20
+
+/* PMU & PLL */
+#define PMU_BASE               (IO_VIRT + 0x1000)
+#define PMU_MODE               0x00
+#define PMU_STAT               0x20
+#define PMU_PLL_CTRL           0x28
+
+/* PMU Mode bits */
+#define PMU_MODE_SLOW          0x00
+#define PMU_MODE_RUN           0x01
+#define PMU_MODE_IDLE          0x02
+#define PMU_MODE_SLEEP         0x03
+#define PMU_MODE_INIT          0x04
+#define PMU_MODE_DEEPSLEEP     0x07
+#define PMU_MODE_WAKEUP                0x08
+
+/* PMU ... */
+#define PLL_2_EN               0x8000
+#define PLL_1_EN               0x4000
+#define PLL_3_MUTE             0x0080
+
+/* Control bits for PMU/ PLL */
+#define PMU_WARMRESET          0x00010000
+#define PLL_CTRL_MASK23                0x000080ff
+
+/* LCD Controller */
+#define LCD_BASE               (IO_VIRT + 0x10000)
+#define LCD_CTRL               0x00
+#define LCD_STATUS             0x04
+#define LCD_STATUS_M           0x08
+#define LCD_INTERRUPT          0x0C
+#define LCD_DBAR               0x10
+#define LCD_DCAR               0x14
+#define LCD_TIMING0            0x20
+#define LCD_TIMING1            0x24
+#define LCD_TIMING2            0x28
+#define LCD_TEST               0x40
+
+/* LCD Control Bits */
+#define LCD_CTRL_LCD_ENABLE    0x00000001
+/* Bits per pixel */
+#define LCD_CTRL_LCD_BPP_MASK  0x00000006
+#define LCD_CTRL_LCD_4BPP      0x00000000
+#define LCD_CTRL_LCD_8BPP      0x00000002
+#define LCD_CTRL_LCD_16BPP     0x00000004
+#define LCD_CTRL_LCD_BW                0x00000008
+#define LCD_CTRL_LCD_TFT       0x00000010
+#define LCD_CTRL_BGR           0x00001000
+#define LCD_CTRL_LCD_VCOMP     0x00080000
+#define LCD_CTRL_LCD_MONO8     0x00200000
+#define LCD_CTRL_LCD_PWR       0x00400000
+#define LCD_CTRL_LCD_BLE       0x00800000
+#define LCD_CTRL_LDBUSEN       0x01000000
+
+/* Palette */
+#define LCD_PALETTE_BASE       (IO_VIRT + 0x10400)
+
+/* Serial ports */
+#define SERIAL0_VIRT           (IO_VIRT + 0x20000)
+#define SERIAL1_VIRT           (IO_VIRT + 0x21000)
+
+#define SERIAL0_BASE           SERIAL0_VIRT
+#define SERIAL1_BASE           SERIAL1_VIRT
+#define SERIAL2_BASE           SERIAL2_VIRT
+#define SERIAL3_BASE           SERIAL3_VIRT
+
+
+/* General defines to pacify gcc */
+#define PCIO_BASE              (0)     /* for inb, outb and friends */
+#define PCIO_VIRT              PCIO_BASE
+
+#define __ASM_ARCH_HARDWARE_INCMACH_H
+#include "boards.h"
+#undef __ASM_ARCH_HARDWARE_INCMACH_H
+
+#endif                         /* __ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-h720x/io.h b/include/asm-arm/arch-h720x/io.h
new file mode 100644 (file)
index 0000000..c5b737a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * linux/include/asm-arm/arch-h720x/io.h
+ *
+ * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
+ *
+ * Changelog:
+ *
+ *  09-19-2001 JJKIM
+ *             Created from linux/include/asm-arm/arch-l7200/io.h
+ *
+ *  03-27-2003  Robert Schwebel <r.schwebel@pengutronix.de>:
+ *             re-unified header files for h720x
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <asm/arch/hardware.h>
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a) (a)
+#define __mem_pci(a) (a)
+
+#endif
diff --git a/include/asm-arm/arch-h720x/irq.h b/include/asm-arm/arch-h720x/irq.h
new file mode 100644 (file)
index 0000000..b3821e9
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * include/asm-arm/arch-h720x/irq.h
+ *
+ * Copyright (C) 2000-2002 Jungjun Kim
+ *           (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *           (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ */
+
+#ifndef __ASM_ARCH_IRQ_H
+#define __ASM_ARCH_IRQ_H
+
+extern void __init h720x_init_irq (void);
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/include/asm-arm/arch-h720x/irqs.h b/include/asm-arm/arch-h720x/irqs.h
new file mode 100644 (file)
index 0000000..8244413
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * linux/include/asm-arm/arch-h720x/irqs.h
+ *
+ * Copyright (C) 2000 Jungjun Kim
+ *           (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>
+ *           (C) 2003 Thomas Gleixner <tglx@linutronix.de>
+ *
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+#if defined (CONFIG_CPU_H7201)
+
+#define IRQ_PMU                0               /* 0x000001 */
+#define IRQ_DMA                1               /* 0x000002 */
+#define IRQ_LCD                2               /* 0x000004 */
+#define IRQ_VGA                3               /* 0x000008 */
+#define IRQ_PCMCIA1    4               /* 0x000010 */
+#define IRQ_PCMCIA2    5               /* 0x000020 */
+#define IRQ_AFE                6               /* 0x000040 */
+#define IRQ_AIC                7               /* 0x000080 */
+#define IRQ_KEYBOARD   8               /* 0x000100 */
+#define IRQ_TIMER0     9               /* 0x000200 */
+#define IRQ_RTC                10              /* 0x000400 */
+#define IRQ_SOUND      11              /* 0x000800 */
+#define IRQ_USB                12              /* 0x001000 */
+#define IRQ_IrDA       13              /* 0x002000 */
+#define IRQ_UART0      14              /* 0x004000 */
+#define IRQ_UART1      15              /* 0x008000 */
+#define IRQ_SPI                16              /* 0x010000 */
+#define IRQ_GPIOA      17              /* 0x020000 */
+#define IRQ_GPIOB      18              /* 0x040000 */
+#define IRQ_GPIOC      19              /* 0x080000 */
+#define IRQ_GPIOD      20              /* 0x100000 */
+#define IRQ_CommRX     21              /* 0x200000 */
+#define IRQ_CommTX     22              /* 0x400000 */
+#define IRQ_Soft       23              /* 0x800000 */
+
+#define NR_GLBL_IRQS   24
+
+#define IRQ_CHAINED_GPIOA(x)  (NR_GLBL_IRQS + x)
+#define IRQ_CHAINED_GPIOB(x)  (IRQ_CHAINED_GPIOA(32) + x)
+#define IRQ_CHAINED_GPIOC(x)  (IRQ_CHAINED_GPIOB(32) + x)
+#define IRQ_CHAINED_GPIOD(x)  (IRQ_CHAINED_GPIOC(32) + x)
+#define NR_IRQS               IRQ_CHAINED_GPIOD(32)
+
+/* Enable mask for multiplexed interrupts */
+#define IRQ_ENA_MUX    (1<<IRQ_GPIOA) | (1<<IRQ_GPIOB) \
+                       | (1<<IRQ_GPIOC) | (1<<IRQ_GPIOD)
+
+
+#elif defined (CONFIG_CPU_H7202)
+
+#define IRQ_PMU                0               /* 0x00000001 */
+#define IRQ_DMA                1               /* 0x00000002 */
+#define IRQ_LCD                2               /* 0x00000004 */
+#define IRQ_SOUND      3               /* 0x00000008 */
+#define IRQ_I2S                4               /* 0x00000010 */
+#define IRQ_USB        5               /* 0x00000020 */
+#define IRQ_MMC        6               /* 0x00000040 */
+#define IRQ_RTC        7               /* 0x00000080 */
+#define IRQ_UART0      8               /* 0x00000100 */
+#define IRQ_UART1      9               /* 0x00000200 */
+#define IRQ_UART2      10              /* 0x00000400 */
+#define IRQ_UART3      11              /* 0x00000800 */
+#define IRQ_KBD        12              /* 0x00001000 */
+#define IRQ_PS2        13              /* 0x00002000 */
+#define IRQ_AIC        14              /* 0x00004000 */
+#define IRQ_TIMER0     15              /* 0x00008000 */
+#define IRQ_TIMERX     16              /* 0x00010000 */
+#define IRQ_WDT        17              /* 0x00020000 */
+#define IRQ_CAN0       18              /* 0x00040000 */
+#define IRQ_CAN1       19              /* 0x00080000 */
+#define IRQ_EXT0       20              /* 0x00100000 */
+#define IRQ_EXT1       21              /* 0x00200000 */
+#define IRQ_GPIOA      22              /* 0x00400000 */
+#define IRQ_GPIOB      23              /* 0x00800000 */
+#define IRQ_GPIOC      24              /* 0x01000000 */
+#define IRQ_GPIOD      25              /* 0x02000000 */
+#define IRQ_GPIOE      26              /* 0x04000000 */
+#define IRQ_COMMRX     27              /* 0x08000000 */
+#define IRQ_COMMTX     28              /* 0x10000000 */
+#define IRQ_SMC        29              /* 0x20000000 */
+#define IRQ_Soft       30              /* 0x40000000 */
+#define IRQ_RESERVED1  31              /* 0x80000000 */
+#define NR_GLBL_IRQS   32
+
+#define NR_TIMERX_IRQS 3
+
+#define IRQ_CHAINED_GPIOA(x)  (NR_GLBL_IRQS + x)
+#define IRQ_CHAINED_GPIOB(x)  (IRQ_CHAINED_GPIOA(32) + x)
+#define IRQ_CHAINED_GPIOC(x)  (IRQ_CHAINED_GPIOB(32) + x)
+#define IRQ_CHAINED_GPIOD(x)  (IRQ_CHAINED_GPIOC(32) + x)
+#define IRQ_CHAINED_GPIOE(x)  (IRQ_CHAINED_GPIOD(32) + x)
+#define IRQ_CHAINED_TIMERX(x) (IRQ_CHAINED_GPIOE(32) + x)
+#define IRQ_TIMER1            (IRQ_CHAINED_TIMERX(0))
+#define IRQ_TIMER2            (IRQ_CHAINED_TIMERX(1))
+#define IRQ_TIMER64B          (IRQ_CHAINED_TIMERX(2))
+
+#define NR_IRQS                (IRQ_CHAINED_TIMERX(NR_TIMERX_IRQS))
+
+/* Enable mask for multiplexed interrupts */
+#define IRQ_ENA_MUX    (1<<IRQ_TIMERX) | (1<<IRQ_GPIOA) | (1<<IRQ_GPIOB) | \
+                       (1<<IRQ_GPIOC)  | (1<<IRQ_GPIOD) | (1<<IRQ_GPIOE) | \
+                       (1<<IRQ_TIMERX)
+
+#else
+#error cpu definition mismatch
+#endif
+
+/* decode irq number to register number */
+#define IRQ_TO_REGNO(irq) ((irq - NR_GLBL_IRQS) >> 5)
+#define IRQ_TO_BIT(irq) (1 << ((irq - NR_GLBL_IRQS) % 32))
+
+#endif
diff --git a/include/asm-arm/arch-h720x/memory.h b/include/asm-arm/arch-h720x/memory.h
new file mode 100644 (file)
index 0000000..5633447
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * linux/include/asm-arm/arch-h720x/memory.h
+ *
+ * Copyright (c) 2000 Jungjun Kim
+ *
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Page offset:
+ *    ( 0xc0000000UL )
+ */
+#define PHYS_OFFSET    (0x40000000UL)
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ *
+ * There is something to do here later !, Mar 2000, Jungjun Kim
+ */
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)       __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)       __phys_to_virt(x)
+
+#endif
diff --git a/include/asm-arm/arch-h720x/param.h b/include/asm-arm/arch-h720x/param.h
new file mode 100644 (file)
index 0000000..2b80235
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * linux/include/asm-arm/arch-h720x/param.h
+ *
+ * Copyright (C) 2000 Jungjun Kim
+ */
+
+#ifndef __ASM_ARCH_PARAM_H
+#define __ASM_ARCH_PARAM_H
+
+#endif
diff --git a/include/asm-arm/arch-h720x/system.h b/include/asm-arm/arch-h720x/system.h
new file mode 100644 (file)
index 0000000..0b025e2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/arm/mach-h720x/system.h
+ *
+ * Copyright (C) 2001-2002 Jungjun Kim, Hynix Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ * linux/include/asm-arm/arch-h720x/system.h
+ *
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+#include <asm/hardware.h>
+
+static void arch_idle(void)
+{
+       CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_IDLE;
+       __asm__ __volatile__(
+       "mov    r0, r0\n\t"
+       "mov    r0, r0");
+}
+
+
+static __inline__ void arch_reset(char mode)
+{
+       CPU_REG (PMU_BASE, PMU_STAT) |= PMU_WARMRESET;
+}
+
+#endif
diff --git a/include/asm-arm/arch-h720x/timex.h b/include/asm-arm/arch-h720x/timex.h
new file mode 100644 (file)
index 0000000..48a391c
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * linux/include/asm-arm/arch-h720x/timex.h
+ * Copyright (C) 2000 Jungjun Kim, Hynix Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_TIMEX
+#define __ASM_ARCH_TIMEX
+
+#define CLOCK_TICK_RATE                3686400
+
+#endif
diff --git a/include/asm-arm/arch-h720x/uncompress.h b/include/asm-arm/arch-h720x/uncompress.h
new file mode 100644 (file)
index 0000000..2fffacf
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * linux/include/asm-arm/arch-h720x/uncompress.h
+ *
+ * Copyright (C) 2001-2002 Jungjun Kim
+ */
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <asm/arch/hardware.h>
+
+#define LSR    0x14
+#define TEMPTY         0x40
+
+static void putstr(const char *s)
+{
+       char c;
+       volatile unsigned char *p = (volatile unsigned char *)(IO_PHYS+0x20000);
+
+       while ( (c = *s++) != '\0') {
+               /* wait until transmit buffer is empty */
+               while((p[LSR] & TEMPTY) == 0x0);
+               /* write next character */
+               *p = c;
+
+               if(c == '\n') {
+                       while((p[LSR] & TEMPTY) == 0x0);
+                       *p = '\r';
+               }
+       }
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
+
+#endif
diff --git a/include/asm-arm/arch-h720x/vmalloc.h b/include/asm-arm/arch-h720x/vmalloc.h
new file mode 100644 (file)
index 0000000..4af523a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * linux/include/asm-arm/arch-h720x/vmalloc.h
+ */
+
+#ifndef __ARCH_ARM_VMALLOC_H
+#define __ARCH_ARM_VMALLOC_H
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET   (8*1024*1024)
+#define VMALLOC_START    (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+
+#endif
diff --git a/include/asm-arm/arch-imx/dma.h b/include/asm-arm/arch-imx/dma.h
new file mode 100644 (file)
index 0000000..dbdc017
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  linux/include/asm-arm/imxads/dma.h
+ *
+ *  Copyright (C) 1997,1998 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+#define MAX_DMA_ADDRESS                0xffffffff
+
+#define MAX_DMA_CHANNELS       0
+
+/*
+ * DMA registration
+ */
+
+typedef enum {
+       DMA_PRIO_HIGH = 0,
+       DMA_PRIO_MEDIUM = 3,
+       DMA_PRIO_LOW = 6
+} imx_dma_prio;
+
+int imx_request_dma(char *name, imx_dma_prio prio,
+                   void (*irq_handler) (int, void *, struct pt_regs *),
+                   void (*err_handler) (int, void *, struct pt_regs *),
+                   void *data);
+
+void imx_free_dma(int dma_ch);
+
+
+#define DMA_REQ_UART3_T        2
+#define DMA_REQ_UART3_R        3
+#define DMA_REQ_SSI2_T         4
+#define DMA_REQ_SSI2_R         5
+#define DMA_REQ_CSI_STAT       6
+#define DMA_REQ_CSI_R          7
+#define DMA_REQ_MSHC           8
+#define DMA_REQ_DSPA_DCT_DOUT  9
+#define DMA_REQ_DSPA_DCT_DIN  10
+#define DMA_REQ_DSPA_MAC      11
+#define DMA_REQ_EXT           12
+#define DMA_REQ_SDHC          13
+#define DMA_REQ_SPI1_R        14
+#define DMA_REQ_SPI1_T        15
+#define DMA_REQ_SSI_T         16
+#define DMA_REQ_SSI_R         17
+#define DMA_REQ_ASP_DAC       18
+#define DMA_REQ_ASP_ADC       19
+#define DMA_REQ_USP_EP(x)    (20+(x))
+#define DMA_REQ_SPI2_R        26
+#define DMA_REQ_SPI2_T        27
+#define DMA_REQ_UART2_T       28
+#define DMA_REQ_UART2_R       29
+#define DMA_REQ_UART1_T       30
+#define DMA_REQ_UART1_R       31
+
+#endif                         /* _ASM_ARCH_DMA_H */
diff --git a/include/asm-arm/arch-imx/hardware.h b/include/asm-arm/arch-imx/hardware.h
new file mode 100644 (file)
index 0000000..c5d559f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  linux/include/asm-arm/arch-imx/hardware.h
+ *
+ *  Copyright (C) 1999 ARM Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#include "imx-regs.h"
+
+#ifndef __ASSEMBLY__
+# define __REG(x)      (*((volatile u32 *)IO_ADDRESS(x)))
+
+# define __REG2(x,y)   \
+       ( __builtin_constant_p(y) ? (__REG((x) + (y))) \
+                         : (*(volatile u32 *)((u32)&__REG(x) + (y))) )
+#endif
+
+/*
+ * Memory map
+ */
+
+#define IMX_IO_PHYS            0x00200000
+#define IMX_IO_SIZE            0x00100000
+#define IMX_IO_BASE            0xe0000000
+
+#define IMX_CS0_PHYS           0x10000000
+#define IMX_CS0_SIZE           0x02000000
+#define IMX_CS0_VIRT           0xe8000000
+
+#define IMX_CS1_PHYS           0x12000000
+#define IMX_CS1_SIZE           0x01000000
+#define IMX_CS1_VIRT           0xea000000
+
+#define IMX_CS2_PHYS           0x13000000
+#define IMX_CS2_SIZE           0x01000000
+#define IMX_CS2_VIRT           0xeb000000
+
+#define IMX_CS3_PHYS           0x14000000
+#define IMX_CS3_SIZE           0x01000000
+#define IMX_CS3_VIRT           0xec000000
+
+#define IMX_CS4_PHYS           0x15000000
+#define IMX_CS4_SIZE           0x01000000
+#define IMX_CS4_VIRT           0xed000000
+
+#define IMX_CS5_PHYS           0x16000000
+#define IMX_CS5_SIZE           0x01000000
+#define IMX_CS5_VIRT           0xee000000
+
+#define IMX_FB_VIRT            0xF1000000
+#define IMX_FB_SIZE            (256*1024)
+
+/* macro to get at IO space when running virtually */
+#define IO_ADDRESS(x) ((x) | IMX_IO_BASE)
+
+#ifndef __ASSEMBLY__
+/*
+ * Handy routine to set GPIO functions
+ */
+extern void imx_gpio_mode( int gpio_mode );
+
+/* get frequencies in Hz */
+extern unsigned int imx_get_system_clk(void);
+extern unsigned int imx_get_mcu_clk(void);
+extern unsigned int imx_get_perclk1(void); /* UART[12], Timer[12], PWM */
+extern unsigned int imx_get_perclk2(void); /* LCD, SD, SPI[12]         */
+extern unsigned int imx_get_perclk3(void); /* SSI                      */
+extern unsigned int imx_get_hclk(void);    /* SDRAM, CSI, Memory Stick,*/
+                                           /* I2C, DMA                 */
+#endif
+
+#define MAXIRQNUM                       62
+#define MAXFIQNUM                       62
+#define MAXSWINUM                       62
+
+/*
+ * Use SDRAM for memory
+ */
+#define MEM_SIZE               0x01000000
+
+#ifdef CONFIG_ARCH_MX1ADS
+#include "mx1ads.h"
+#endif
+
+#endif
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
new file mode 100644 (file)
index 0000000..f32c203
--- /dev/null
@@ -0,0 +1,548 @@
+#ifndef _IMX_REGS_H
+#define _IMX_REGS_H
+/* ------------------------------------------------------------------------
+ *  Motorola IMX system registers
+ * ------------------------------------------------------------------------
+ *
+ */
+
+/*
+ *  Register BASEs, based on OFFSETs
+ *
+ */
+#define IMX_AIPI1_BASE             (0x00000 + IMX_IO_BASE)
+#define IMX_WDT_BASE               (0x01000 + IMX_IO_BASE)
+#define IMX_TIM1_BASE              (0x02000 + IMX_IO_BASE)
+#define IMX_TIM2_BASE              (0x03000 + IMX_IO_BASE)
+#define IMX_RTC_BASE               (0x04000 + IMX_IO_BASE)
+#define IMX_LCDC_BASE              (0x05000 + IMX_IO_BASE)
+#define IMX_UART1_BASE             (0x06000 + IMX_IO_BASE)
+#define IMX_UART2_BASE             (0x07000 + IMX_IO_BASE)
+#define IMX_PWM_BASE               (0x08000 + IMX_IO_BASE)
+#define IMX_DMAC_BASE              (0x09000 + IMX_IO_BASE)
+#define IMX_AIPI2_BASE             (0x10000 + IMX_IO_BASE)
+#define IMX_SIM_BASE               (0x11000 + IMX_IO_BASE)
+#define IMX_USBD_BASE              (0x12000 + IMX_IO_BASE)
+#define IMX_SPI1_BASE              (0x13000 + IMX_IO_BASE)
+#define IMX_MMC_BASE               (0x14000 + IMX_IO_BASE)
+#define IMX_ASP_BASE               (0x15000 + IMX_IO_BASE)
+#define IMX_BTA_BASE               (0x16000 + IMX_IO_BASE)
+#define IMX_I2C_BASE               (0x17000 + IMX_IO_BASE)
+#define IMX_SSI_BASE               (0x18000 + IMX_IO_BASE)
+#define IMX_SPI2_BASE              (0x19000 + IMX_IO_BASE)
+#define IMX_MSHC_BASE              (0x1A000 + IMX_IO_BASE)
+#define IMX_PLL_BASE               (0x1B000 + IMX_IO_BASE)
+#define IMX_GPIO_BASE              (0x1C000 + IMX_IO_BASE)
+#define IMX_EIM_BASE               (0x20000 + IMX_IO_BASE)
+#define IMX_SDRAMC_BASE            (0x21000 + IMX_IO_BASE)
+#define IMX_MMA_BASE               (0x22000 + IMX_IO_BASE)
+#define IMX_AITC_BASE              (0x23000 + IMX_IO_BASE)
+#define IMX_CSI_BASE               (0x24000 + IMX_IO_BASE)
+
+/* PLL registers */
+#define CSCR   __REG(IMX_PLL_BASE)        /* Clock Source Control Register */
+#define CSCR_SYSTEM_SEL (1<<16)
+
+#define MPCTL0 __REG(IMX_PLL_BASE + 0x4)  /* MCU PLL Control Register 0 */
+#define MPCTL1 __REG(IMX_PLL_BASE + 0x8)  /* MCU PLL and System Clock Register 1 */
+#define SPCTL0 __REG(IMX_PLL_BASE + 0xc)  /* System PLL Control Register 0 */
+#define SPCTL1 __REG(IMX_PLL_BASE + 0x10) /* System PLL Control Register 1 */
+#define PCDR   __REG(IMX_PLL_BASE + 0x20) /* Peripheral Clock Divider Register */
+
+#define CSCR_MPLL_RESTART (1<<21)
+
+/*
+ *  GPIO Module and I/O Multiplexer
+ *  x = 0..3 for reg_A, reg_B, reg_C, reg_D
+ */
+#define DDIR(x)    __REG2(IMX_GPIO_BASE + 0x00, ((x) & 3) << 8)
+#define OCR1(x)    __REG2(IMX_GPIO_BASE + 0x04, ((x) & 3) << 8)
+#define OCR2(x)    __REG2(IMX_GPIO_BASE + 0x08, ((x) & 3) << 8)
+#define ICONFA1(x) __REG2(IMX_GPIO_BASE + 0x0c, ((x) & 3) << 8)
+#define ICONFA2(x) __REG2(IMX_GPIO_BASE + 0x10, ((x) & 3) << 8)
+#define ICONFB1(x) __REG2(IMX_GPIO_BASE + 0x14, ((x) & 3) << 8)
+#define ICONFB2(x) __REG2(IMX_GPIO_BASE + 0x18, ((x) & 3) << 8)
+#define DR(x)      __REG2(IMX_GPIO_BASE + 0x1c, ((x) & 3) << 8)
+#define GIUS(x)    __REG2(IMX_GPIO_BASE + 0x20, ((x) & 3) << 8)
+#define SSR(x)     __REG2(IMX_GPIO_BASE + 0x24, ((x) & 3) << 8)
+#define ICR1(x)    __REG2(IMX_GPIO_BASE + 0x28, ((x) & 3) << 8)
+#define ICR2(x)    __REG2(IMX_GPIO_BASE + 0x2c, ((x) & 3) << 8)
+#define IMR(x)     __REG2(IMX_GPIO_BASE + 0x30, ((x) & 3) << 8)
+#define ISR(x)     __REG2(IMX_GPIO_BASE + 0x34, ((x) & 3) << 8)
+#define GPR(x)     __REG2(IMX_GPIO_BASE + 0x38, ((x) & 3) << 8)
+#define SWR(x)     __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8)
+#define PUEN(x)    __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8)
+
+#define GPIO_PIN_MASK 0x1f
+#define GPIO_PORT_MASK (0x3 << 5)
+
+#define GPIO_PORTA (0<<5)
+#define GPIO_PORTB (1<<5)
+#define GPIO_PORTC (2<<5)
+#define GPIO_PORTD (3<<5)
+
+#define GPIO_OUT   (1<<7)
+#define GPIO_IN    (0<<7)
+#define GPIO_PUEN  (1<<8)
+
+#define GPIO_PF    (0<<9)
+#define GPIO_AF    (1<<9)
+
+#define GPIO_OCR_MASK (3<<10)
+#define GPIO_AIN   (0<<10)
+#define GPIO_BIN   (1<<10)
+#define GPIO_CIN   (2<<10)
+#define GPIO_GPIO  (3<<10)
+
+#define GPIO_AOUT  (1<<12)
+#define GPIO_BOUT  (1<<13)
+
+/* assignements for GPIO alternate/primary functions */
+
+/* FIXME: This list is not completed. The correct directions are
+ * missing on some (many) pins
+ */
+#define PA0_PF_A24           ( GPIO_PORTA | GPIO_PF | 0 )
+#define PA0_AIN_SPI2_CLK     ( GPIO_PORTA | GPIO_OUT | GPIO_AIN | 0 )
+#define PA0_AF_ETMTRACESYNC  ( GPIO_PORTA | GPIO_AF | 0 )
+#define PA1_AOUT_SPI2_RXD    ( GPIO_PORTA | GPIO_IN | GPIO_AOUT | 1 )
+#define PA1_PF_TIN           ( GPIO_PORTA | GPIO_PF | 1 )
+#define PA2_PF_PWM0          ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 2 )
+#define PA3_PF_CSI_MCLK      ( GPIO_PORTA | GPIO_PF | 3 )
+#define PA4_PF_CSI_D0        ( GPIO_PORTA | GPIO_PF | 4 )
+#define PA5_PF_CSI_D1        ( GPIO_PORTA | GPIO_PF | 5 )
+#define PA6_PF_CSI_D2        ( GPIO_PORTA | GPIO_PF | 6 )
+#define PA7_PF_CSI_D3        ( GPIO_PORTA | GPIO_PF | 7 )
+#define PA8_PF_CSI_D4        ( GPIO_PORTA | GPIO_PF | 8 )
+#define PA9_PF_CSI_D5        ( GPIO_PORTA | GPIO_PF | 9 )
+#define PA10_PF_CSI_D6       ( GPIO_PORTA | GPIO_PF | 10 )
+#define PA11_PF_CSI_D7       ( GPIO_PORTA | GPIO_PF | 11 )
+#define PA12_PF_CSI_VSYNC    ( GPIO_PORTA | GPIO_PF | 12 )
+#define PA13_PF_CSI_HSYNC    ( GPIO_PORTA | GPIO_PF | 13 )
+#define PA14_PF_CSI_PIXCLK   ( GPIO_PORTA | GPIO_PF | 14 )
+#define PA15_PF_I2C_SDA      ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 15 )
+#define PA16_PF_I2C_SCL      ( GPIO_PORTA | GPIO_OUT | GPIO_PF | 16 )
+#define PA17_AF_ETMTRACEPKT4 ( GPIO_PORTA | GPIO_AF | 17 )
+#define PA17_AIN_SPI2_SS     ( GPIO_PORTA | GPIO_AIN | 17 )
+#define PA18_AF_ETMTRACEPKT5 ( GPIO_PORTA | GPIO_AF | 18 )
+#define PA19_AF_ETMTRACEPKT6 ( GPIO_PORTA | GPIO_AF | 19 )
+#define PA20_AF_ETMTRACEPKT7 ( GPIO_PORTA | GPIO_AF | 20 )
+#define PA21_PF_A0           ( GPIO_PORTA | GPIO_PF | 21 )
+#define PA22_PF_CS4          ( GPIO_PORTA | GPIO_PF | 22 )
+#define PA23_PF_CS5          ( GPIO_PORTA | GPIO_PF | 23 )
+#define PA24_PF_A16          ( GPIO_PORTA | GPIO_PF | 24 )
+#define PA24_AF_ETMTRACEPKT0 ( GPIO_PORTA | GPIO_AF | 24 )
+#define PA25_PF_A17          ( GPIO_PORTA | GPIO_PF | 25 )
+#define PA25_AF_ETMTRACEPKT1 ( GPIO_PORTA | GPIO_AF | 25 )
+#define PA26_PF_A18          ( GPIO_PORTA | GPIO_PF | 26 )
+#define PA26_AF_ETMTRACEPKT2 ( GPIO_PORTA | GPIO_AF | 26 )
+#define PA27_PF_A19          ( GPIO_PORTA | GPIO_PF | 27 )
+#define PA27_AF_ETMTRACEPKT3 ( GPIO_PORTA | GPIO_AF | 27 )
+#define PA28_PF_A20          ( GPIO_PORTA | GPIO_PF | 28 )
+#define PA28_AF_ETMPIPESTAT0 ( GPIO_PORTA | GPIO_AF | 28 )
+#define PA29_PF_A21          ( GPIO_PORTA | GPIO_PF | 29 )
+#define PA29_AF_ETMPIPESTAT1 ( GPIO_PORTA | GPIO_AF | 29 )
+#define PA30_PF_A22          ( GPIO_PORTA | GPIO_PF | 30 )
+#define PA30_AF_ETMPIPESTAT2 ( GPIO_PORTA | GPIO_AF | 30 )
+#define PA31_PF_A23          ( GPIO_PORTA | GPIO_PF | 31 )
+#define PA31_AF_ETMTRACECLK  ( GPIO_PORTA | GPIO_AF | 31 )
+#define PB8_PF_SD_DAT0       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 8 )
+#define PB8_AF_MS_PIO        ( GPIO_PORTB | GPIO_AF | 8 )
+#define PB9_PF_SD_DAT1       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 9 )
+#define PB9_AF_MS_PI1        ( GPIO_PORTB | GPIO_AF | 9 )
+#define PB10_PF_SD_DAT2      ( GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 10 )
+#define PB10_AF_MS_SCLKI     ( GPIO_PORTB | GPIO_AF | 10 )
+#define PB11_PF_SD_DAT3      ( GPIO_PORTB | GPIO_PF | 11 )
+#define PB11_AF_MS_SDIO      ( GPIO_PORTB | GPIO_AF | 11 )
+#define PB12_PF_SD_CLK       ( GPIO_PORTB | GPIO_PF | 12 )
+#define PB12_AF_MS_SCLK0     ( GPIO_PORTB | GPIO_AF | 12 )
+#define PB13_PF_SD_CMD       ( GPIO_PORTB | GPIO_PF | GPIO_PUEN | 13 )
+#define PB13_AF_MS_BS        ( GPIO_PORTB | GPIO_AF | 13 )
+#define PB14_AF_SSI_RXFS     ( GPIO_PORTB | GPIO_AF | 14 )
+#define PB15_AF_SSI_RXCLK    ( GPIO_PORTB | GPIO_AF | 15 )
+#define PB16_AF_SSI_RXDAT    ( GPIO_PORTB | GPIO_IN | GPIO_AF | 16 )
+#define PB17_AF_SSI_TXDAT    ( GPIO_PORTB | GPIO_OUT | GPIO_AF | 17 )
+#define PB18_AF_SSI_TXFS     ( GPIO_PORTB | GPIO_AF | 18 )
+#define PB19_AF_SSI_TXCLK    ( GPIO_PORTB | GPIO_AF | 19 )
+#define PB20_PF_USBD_AFE     ( GPIO_PORTB | GPIO_PF | 20 )
+#define PB21_PF_USBD_OE      ( GPIO_PORTB | GPIO_PF | 21 )
+#define PB22_PFUSBD_RCV      ( GPIO_PORTB | GPIO_PF | 22 )
+#define PB23_PF_USBD_SUSPND  ( GPIO_PORTB | GPIO_PF | 23 )
+#define PB24_PF_USBD_VP      ( GPIO_PORTB | GPIO_PF | 24 )
+#define PB25_PF_USBD_VM      ( GPIO_PORTB | GPIO_PF | 25 )
+#define PB26_PF_USBD_VPO     ( GPIO_PORTB | GPIO_PF | 26 )
+#define PB27_PF_USBD_VMO     ( GPIO_PORTB | GPIO_PF | 27 )
+#define PB28_PF_UART2_CTS    ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 28 )
+#define PB29_PF_UART2_RTS    ( GPIO_PORTB | GPIO_IN | GPIO_PF | 29 )
+#define PB30_PF_UART2_TXD    ( GPIO_PORTB | GPIO_OUT | GPIO_PF | 30 )
+#define PB31_PF_UART2_RXD    ( GPIO_PORTB | GPIO_IN | GPIO_PF | 31 )
+#define PC3_PF_SSI_RXFS      ( GPIO_PORTC | GPIO_PF | 3 )
+#define PC4_PF_SSI_RXCLK     ( GPIO_PORTC | GPIO_PF | 4 )
+#define PC5_PF_SSI_RXDAT     ( GPIO_PORTC | GPIO_IN | GPIO_PF | 5 )
+#define PC6_PF_SSI_TXDAT     ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 6 )
+#define PC7_PF_SSI_TXFS      ( GPIO_PORTC | GPIO_PF | 7 )
+#define PC8_PF_SSI_TXCLK     ( GPIO_PORTC | GPIO_PF | 8 )
+#define PC9_PF_UART1_CTS     ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 9 )
+#define PC10_PF_UART1_RTS    ( GPIO_PORTC | GPIO_IN | GPIO_PF | 10 )
+#define PC11_PF_UART1_TXD    ( GPIO_PORTC | GPIO_OUT | GPIO_PF | 11 )
+#define PC12_PF_UART1_RXD    ( GPIO_PORTC | GPIO_IN | GPIO_PF | 12 )
+#define PC13_PF_SPI1_SPI_RDY ( GPIO_PORTC | GPIO_PF | 13 )
+#define PC14_PF_SPI1_SCLK    ( GPIO_PORTC | GPIO_PF | 14 )
+#define PC15_PF_SPI1_SS      ( GPIO_PORTC | GPIO_PF | 15 )
+#define PC16_PF_SPI1_MISO    ( GPIO_PORTC | GPIO_PF | 16 )
+#define PC17_PF_SPI1_MOSI    ( GPIO_PORTC | GPIO_PF | 17 )
+#define PD6_PF_LSCLK         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 6 )
+#define PD7_PF_REV           ( GPIO_PORTD | GPIO_PF | 7 )
+#define PD7_AF_UART2_DTR     ( GPIO_PORTD | GPIO_IN | GPIO_AF | 7 )
+#define PD7_AIN_SPI2_SCLK    ( GPIO_PORTD | GPIO_AIN | 7 )
+#define PD8_PF_CLS           ( GPIO_PORTD | GPIO_PF | 8 )
+#define PD8_AF_UART2_DCD     ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 8 )
+#define PD8_AIN_SPI2_SS      ( GPIO_PORTD | GPIO_AIN | 8 )
+#define PD9_PF_PS            ( GPIO_PORTD | GPIO_PF | 9 )
+#define PD9_AF_UART2_RI      ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 9 )
+#define PD9_AOUT_SPI2_RXD    ( GPIO_PORTD | GPIO_IN | GPIO_AOUT | 9 )
+#define PD10_PF_SPL_SPR      ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 10 )
+#define PD10_AF_UART2_DSR    ( GPIO_PORTD | GPIO_OUT | GPIO_AF | 10 )
+#define PD10_AIN_SPI2_TXD    ( GPIO_PORTD | GPIO_OUT | GPIO_AIN | 10 )
+#define PD11_PF_CONTRAST     ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 11 )
+#define PD12_PF_ACD_OE       ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 12 )
+#define PD13_PF_LP_HSYNC     ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 13 )
+#define PD14_PF_FLM_VSYNC    ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 14 )
+#define PD15_PF_LD0          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 15 )
+#define PD16_PF_LD1          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 16 )
+#define PD17_PF_LD2          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 17 )
+#define PD18_PF_LD3          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 18 )
+#define PD19_PF_LD4          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 19 )
+#define PD20_PF_LD5          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 20 )
+#define PD21_PF_LD6          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 21 )
+#define PD22_PF_LD7          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 22 )
+#define PD23_PF_LD8          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 23 )
+#define PD24_PF_LD9          ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 24 )
+#define PD25_PF_LD10         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 25 )
+#define PD26_PF_LD11         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 26 )
+#define PD27_PF_LD12         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 27 )
+#define PD28_PF_LD13         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 28 )
+#define PD29_PF_LD14         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 29 )
+#define PD30_PF_LD15         ( GPIO_PORTD | GPIO_OUT | GPIO_PF | 30 )
+#define PD31_PF_TMR2OUT      ( GPIO_PORTD | GPIO_PF | 31 )
+#define PD31_BIN_SPI2_TXD    ( GPIO_PORTD | GPIO_BIN | 31 )
+
+/*
+ *  DMA Controller
+ */
+#define DCR     __REG(IMX_DMAC_BASE +0x00)     /* DMA Control Register */
+#define DISR    __REG(IMX_DMAC_BASE +0x04)     /* DMA Interrupt status Register */
+#define DIMR    __REG(IMX_DMAC_BASE +0x08)     /* DMA Interrupt mask Register */
+#define DBTOSR  __REG(IMX_DMAC_BASE +0x0c)     /* DMA Burst timeout status Register */
+#define DRTOSR  __REG(IMX_DMAC_BASE +0x10)     /* DMA Request timeout Register */
+#define DSESR   __REG(IMX_DMAC_BASE +0x14)     /* DMA Transfer Error Status Register */
+#define DBOSR   __REG(IMX_DMAC_BASE +0x18)     /* DMA Buffer overflow status Register */
+#define DBTOCR  __REG(IMX_DMAC_BASE +0x1c)     /* DMA Burst timeout control Register */
+#define WSRA    __REG(IMX_DMAC_BASE +0x40)     /* W-Size Register A */
+#define XSRA    __REG(IMX_DMAC_BASE +0x44)     /* X-Size Register A */
+#define YSRA    __REG(IMX_DMAC_BASE +0x48)     /* Y-Size Register A */
+#define WSRB    __REG(IMX_DMAC_BASE +0x4c)     /* W-Size Register B */
+#define XSRB    __REG(IMX_DMAC_BASE +0x50)     /* X-Size Register B */
+#define YSRB    __REG(IMX_DMAC_BASE +0x54)     /* Y-Size Register B */
+#define SAR(x)  __REG2( IMX_DMAC_BASE + 0x80, (x) << 6)        /* Source Address Registers */
+#define DAR(x)  __REG2( IMX_DMAC_BASE + 0x84, (x) << 6)        /* Destination Address Registers */
+#define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6)        /* Count Registers */
+#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)        /* Control Registers */
+#define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6)        /* Request source select Registers */
+#define BLR(x)  __REG2( IMX_DMAC_BASE + 0x94, (x) << 6)        /* Burst length Registers */
+#define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)        /* Request timeout Registers */
+#define BUCR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)        /* Bus Utilization Registers */
+
+#define DCR_DRST           (1<<1)
+#define DCR_DEN            (1<<0)
+#define DBTOCR_EN          (1<<15)
+#define DBTOCR_CNT(x)      ((x) & 0x7fff )
+#define CNTR_CNT(x)        ((x) & 0xffffff )
+#define CCR_DMOD_LINEAR    ( 0x0 << 12 )
+#define CCR_DMOD_2D        ( 0x1 << 12 )
+#define CCR_DMOD_FIFO      ( 0x2 << 12 )
+#define CCR_DMOD_EOBFIFO   ( 0x3 << 12 )
+#define CCR_SMOD_LINEAR    ( 0x0 << 10 )
+#define CCR_SMOD_2D        ( 0x1 << 10 )
+#define CCR_SMOD_FIFO      ( 0x2 << 10 )
+#define CCR_SMOD_EOBFIFO   ( 0x3 << 10 )
+#define CCR_MDIR_DEC       (1<<9)
+#define CCR_MSEL_B         (1<<8)
+#define CCR_DSIZ_32        ( 0x0 << 6 )
+#define CCR_DSIZ_8         ( 0x1 << 6 )
+#define CCR_DSIZ_16        ( 0x2 << 6 )
+#define CCR_SSIZ_32        ( 0x0 << 4 )
+#define CCR_SSIZ_8         ( 0x1 << 4 )
+#define CCR_SSIZ_16        ( 0x2 << 4 )
+#define CCR_REN            (1<<3)
+#define CCR_RPT            (1<<2)
+#define CCR_FRC            (1<<1)
+#define CCR_CEN            (1<<0)
+#define RTOR_EN            (1<<15)
+#define RTOR_CLK           (1<<14)
+#define RTOR_PSC           (1<<13)
+
+/*
+ *  Interrupt controller
+ */
+
+#define IMX_INTCNTL        __REG(IMX_AITC_BASE+0x00)
+#define INTCNTL_FIAD       (1<<19)
+#define INTCNTL_NIAD       (1<<20)
+
+#define IMX_NIMASK         __REG(IMX_AITC_BASE+0x04)
+#define IMX_INTENNUM       __REG(IMX_AITC_BASE+0x08)
+#define IMX_INTDISNUM      __REG(IMX_AITC_BASE+0x0c)
+#define IMX_INTENABLEH     __REG(IMX_AITC_BASE+0x10)
+#define IMX_INTENABLEL     __REG(IMX_AITC_BASE+0x14)
+
+/*
+ *  General purpose timers
+ */
+#define IMX_TCTL(x)        __REG( 0x00 + (x))
+#define TCTL_SWR           (1<<15)
+#define TCTL_FRR           (1<<8)
+#define TCTL_CAP_RIS       (1<<6)
+#define TCTL_CAP_FAL       (2<<6)
+#define TCTL_CAP_RIS_FAL   (3<<6)
+#define TCTL_OM            (1<<5)
+#define TCTL_IRQEN         (1<<4)
+#define TCTL_CLK_PCLK1     (1<<1)
+#define TCTL_CLK_PCLK1_16  (2<<1)
+#define TCTL_CLK_TIN       (3<<1)
+#define TCTL_CLK_32        (4<<1)
+#define TCTL_TEN           (1<<0)
+
+#define IMX_TPRER(x)       __REG( 0x04 + (x))
+#define IMX_TCMP(x)        __REG( 0x08 + (x))
+#define IMX_TCR(x)         __REG( 0x0C + (x))
+#define IMX_TCN(x)         __REG( 0x10 + (x))
+#define IMX_TSTAT(x)       __REG( 0x14 + (x))
+#define TSTAT_CAPT         (1<<1)
+#define TSTAT_COMP         (1<<0)
+
+/*
+ * LCD Controller
+ */
+
+#define LCDC_SSA       __REG(IMX_LCDC_BASE+0x00)
+
+#define LCDC_SIZE      __REG(IMX_LCDC_BASE+0x04)
+#define SIZE_XMAX(x)   ((((x) >> 4) & 0x3f) << 20)
+#define SIZE_YMAX(y)    ( (y) & 0x1ff )
+
+#define LCDC_VPW       __REG(IMX_LCDC_BASE+0x08)
+#define VPW_VPW(x)     ( (x) & 0x3ff )
+
+#define LCDC_CPOS      __REG(IMX_LCDC_BASE+0x0C)
+#define CPOS_CC1        (1<<31)
+#define CPOS_CC0        (1<<30)
+#define CPOS_OP         (1<<28)
+#define CPOS_CXP(x)     (((x) & 3ff) << 16)
+#define CPOS_CYP(y)     ((y) & 0x1ff)
+
+#define LCDC_LCWHB     __REG(IMX_LCDC_BASE+0x10)
+#define LCWHB_BK_EN     (1<<31)
+#define LCWHB_CW(w)     (((w) & 0x1f) << 24)
+#define LCWHB_CH(h)     (((h) & 0x1f) << 16)
+#define LCWHB_BD(x)     ((x) & 0xff)
+
+#define LCDC_LCHCC     __REG(IMX_LCDC_BASE+0x14)
+#define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11)
+#define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5)
+#define LCHCC_CUR_COL_B(b) ((b) & 0x1f)
+
+#define LCDC_PCR       __REG(IMX_LCDC_BASE+0x18)
+#define PCR_TFT         (1<<31)
+#define PCR_COLOR       (1<<30)
+#define PCR_PBSIZ_1     (0<<28)
+#define PCR_PBSIZ_2     (1<<28)
+#define PCR_PBSIZ_4     (2<<28)
+#define PCR_PBSIZ_8     (3<<28)
+#define PCR_BPIX_1      (0<<25)
+#define PCR_BPIX_2      (1<<25)
+#define PCR_BPIX_4      (2<<25)
+#define PCR_BPIX_8      (3<<25)
+#define PCR_BPIX_12     (4<<25)
+#define PCR_BPIX_16     (4<<25)
+#define PCR_PIXPOL      (1<<24)
+#define PCR_FLMPOL      (1<<23)
+#define PCR_LPPOL       (1<<22)
+#define PCR_CLKPOL      (1<<21)
+#define PCR_OEPOL       (1<<20)
+#define PCR_SCLKIDLE    (1<<19)
+#define PCR_END_SEL     (1<<18)
+#define PCR_END_BYTE_SWAP (1<<17)
+#define PCR_REV_VS      (1<<16)
+#define PCR_ACD_SEL     (1<<15)
+#define PCR_ACD(x)      (((x) & 0x7f) << 8)
+#define PCR_SCLK_SEL    (1<<7)
+#define PCR_SHARP       (1<<6)
+#define PCR_PCD(x)      ((x) & 0x3f)
+
+#define LCDC_HCR       __REG(IMX_LCDC_BASE+0x1C)
+#define HCR_H_WIDTH(x)  (((x) & 0x3f) << 26)
+#define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
+#define HCR_H_WAIT_2(x) ((x) & 0xff)
+
+#define LCDC_VCR       __REG(IMX_LCDC_BASE+0x20)
+#define VCR_V_WIDTH(x)  (((x) & 0x3f) << 26)
+#define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
+#define VCR_V_WAIT_2(x) ((x) & 0xff)
+
+#define LCDC_POS       __REG(IMX_LCDC_BASE+0x24)
+#define POS_POS(x)      ((x) & 1f)
+
+#define LCDC_LSCR1     __REG(IMX_LCDC_BASE+0x28)
+#define LSCR1_PS_RISE_DELAY(x)    (((x) & 0x7f) << 26)
+#define LSCR1_CLS_RISE_DELAY(x)   (((x) & 0x3f) << 16)
+#define LSCR1_REV_TOGGLE_DELAY(x) (((x) & 0xf) << 8)
+#define LSCR1_GRAY2(x)            (((x) & 0xf) << 4)
+#define LSCR1_GRAY1(x)            (((x) & 0xf))
+
+#define LCDC_PWMR      __REG(IMX_LCDC_BASE+0x2C)
+#define PWMR_CLS(x)     (((x) & 0x1ff) << 16)
+#define PWMR_LDMSK      (1<<15)
+#define PWMR_SCR1       (1<<10)
+#define PWMR_SCR0       (1<<9)
+#define PWMR_CC_EN      (1<<8)
+#define PWMR_PW(x)      ((x) & 0xff)
+
+#define LCDC_DMACR     __REG(IMX_LCDC_BASE+0x30)
+#define DMACR_BURST     (1<<31)
+#define DMACR_HM(x)     (((x) & 0xf) << 16)
+#define DMACR_TM(x)     ((x) &0xf)
+
+#define LCDC_RMCR      __REG(IMX_LCDC_BASE+0x34)
+#define RMCR_LCDC_EN           (1<<1)
+#define RMCR_SELF_REF          (1<<0)
+
+#define LCDC_LCDICR    __REG(IMX_LCDC_BASE+0x38)
+#define LCDICR_INT_SYN  (1<<2)
+#define LCDICR_INT_CON  (1)
+
+#define LCDC_LCDISR    __REG(IMX_LCDC_BASE+0x40)
+#define LCDISR_UDR_ERR (1<<3)
+#define LCDISR_ERR_RES (1<<2)
+#define LCDISR_EOF     (1<<1)
+#define LCDISR_BOF     (1<<0)
+
+/*
+ *  UART Module. Takes the UART base address as argument
+ */
+#define URXD0(x) __REG( 0x0 + (x)) /* Receiver Register */
+#define URTX0(x) __REG( 0x40 + (x)) /* Transmitter Register */
+#define UCR1(x)  __REG( 0x80 + (x)) /* Control Register 1 */
+#define UCR2(x)  __REG( 0x84 + (x)) /* Control Register 2 */
+#define UCR3(x)  __REG( 0x88 + (x)) /* Control Register 3 */
+#define UCR4(x)  __REG( 0x8c + (x)) /* Control Register 4 */
+#define UFCR(x)  __REG( 0x90 + (x)) /* FIFO Control Register */
+#define USR1(x)  __REG( 0x94 + (x)) /* Status Register 1 */
+#define USR2(x)  __REG( 0x98 + (x)) /* Status Register 2 */
+#define UESC(x)  __REG( 0x9c + (x)) /* Escape Character Register */
+#define UTIM(x)  __REG( 0xa0 + (x)) /* Escape Timer Register */
+#define UBIR(x)  __REG( 0xa4 + (x)) /* BRM Incremental Register */
+#define UBMR(x)  __REG( 0xa8 + (x)) /* BRM Modulator Register */
+#define UBRC(x)  __REG( 0xac + (x)) /* Baud Rate Count Register */
+#define BIPR1(x) __REG( 0xb0 + (x)) /* Incremental Preset Register 1 */
+#define BIPR2(x) __REG( 0xb4 + (x)) /* Incremental Preset Register 2 */
+#define BIPR3(x) __REG( 0xb8 + (x)) /* Incremental Preset Register 3 */
+#define BIPR4(x) __REG( 0xbc + (x)) /* Incremental Preset Register 4 */
+#define BMPR1(x) __REG( 0xc0 + (x)) /* BRM Modulator Register 1 */
+#define BMPR2(x) __REG( 0xc4 + (x)) /* BRM Modulator Register 2 */
+#define BMPR3(x) __REG( 0xc8 + (x)) /* BRM Modulator Register 3 */
+#define BMPR4(x) __REG( 0xcc + (x)) /* BRM Modulator Register 4 */
+#define UTS(x)   __REG( 0xd0 + (x)) /* UART Test Register */
+
+/* UART Control Register Bit Fields.*/
+#define  URXD_CHARRDY    (1<<15)
+#define  URXD_ERR        (1<<14)
+#define  URXD_OVRRUN     (1<<13)
+#define  URXD_FRMERR     (1<<12)
+#define  URXD_BRK        (1<<11)
+#define  URXD_PRERR      (1<<10)
+#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
+#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
+#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
+#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
+#define  UCR1_RRDYEN     (1<<9)         /* Recv ready interrupt enable */
+#define  UCR1_RDMAEN     (1<<8)         /* Recv ready DMA enable */
+#define  UCR1_IREN       (1<<7)         /* Infrared interface enable */
+#define  UCR1_TXMPTYEN   (1<<6)         /* Transimitter empty interrupt enable */
+#define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
+#define  UCR1_SNDBRK     (1<<4)         /* Send break */
+#define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
+#define  UCR1_UARTCLKEN  (1<<2)         /* UART clock enabled */
+#define  UCR1_DOZE       (1<<1)         /* Doze */
+#define  UCR1_UARTEN     (1<<0)         /* UART enabled */
+#define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
+#define  UCR2_IRTS      (1<<14) /* Ignore RTS pin */
+#define  UCR2_CTSC      (1<<13) /* CTS pin control */
+#define  UCR2_CTS        (1<<12) /* Clear to send */
+#define  UCR2_ESCEN      (1<<11) /* Escape enable */
+#define  UCR2_PREN       (1<<8)  /* Parity enable */
+#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
+#define  UCR2_STPB       (1<<6)         /* Stop */
+#define  UCR2_WS         (1<<5)         /* Word size */
+#define  UCR2_RTSEN      (1<<4)         /* Request to send interrupt enable */
+#define  UCR2_TXEN       (1<<2)         /* Transmitter enabled */
+#define  UCR2_RXEN       (1<<1)         /* Receiver enabled */
+#define  UCR2_SRST      (1<<0)  /* SW reset */
+#define  UCR3_DTREN     (1<<13) /* DTR interrupt enable */
+#define  UCR3_PARERREN   (1<<12) /* Parity enable */
+#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
+#define  UCR3_DSR        (1<<10) /* Data set ready */
+#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
+#define  UCR3_RI         (1<<8)  /* Ring indicator */
+#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
+#define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
+#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
+#define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
+#define  UCR3_REF25     (1<<3)  /* Ref freq 25 MHz */
+#define  UCR3_REF30     (1<<2)  /* Ref Freq 30 MHz */
+#define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
+#define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
+#define  UCR4_CTSTL_32   (32<<10) /* CTS trigger level (32 chars) */
+#define  UCR4_INVR      (1<<9)  /* Inverted infrared reception */
+#define  UCR4_ENIRI     (1<<8)  /* Serial infrared interrupt enable */
+#define  UCR4_WKEN      (1<<7)  /* Wake interrupt enable */
+#define  UCR4_REF16     (1<<6)  /* Ref freq 16 MHz */
+#define  UCR4_IRSC      (1<<5)  /* IR special case */
+#define  UCR4_TCEN      (1<<3)  /* Transmit complete interrupt enable */
+#define  UCR4_BKEN      (1<<2)  /* Break condition interrupt enable */
+#define  UCR4_OREN      (1<<1)  /* Receiver overrun interrupt enable */
+#define  UCR4_DREN      (1<<0)  /* Recv data ready interrupt enable */
+#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
+#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
+#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
+#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
+#define  USR1_RTSS      (1<<14) /* RTS pin status */
+#define  USR1_TRDY      (1<<13) /* Transmitter ready interrupt/dma flag */
+#define  USR1_RTSD      (1<<12) /* RTS delta */
+#define  USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
+#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
+#define  USR1_RRDY       (1<<9)         /* Receiver ready interrupt/dma flag */
+#define  USR1_TIMEOUT    (1<<7)         /* Receive timeout interrupt status */
+#define  USR1_RXDS      (1<<6)  /* Receiver idle interrupt flag */
+#define  USR1_AIRINT    (1<<5)  /* Async IR wake interrupt flag */
+#define  USR1_AWAKE     (1<<4)  /* Aysnc wake interrupt flag */
+#define  USR2_ADET      (1<<15) /* Auto baud rate detect complete */
+#define  USR2_TXFE      (1<<14) /* Transmit buffer FIFO empty */
+#define  USR2_DTRF      (1<<13) /* DTR edge interrupt flag */
+#define  USR2_IDLE      (1<<12) /* Idle condition */
+#define  USR2_IRINT     (1<<8)  /* Serial infrared interrupt flag */
+#define  USR2_WAKE      (1<<7)  /* Wake */
+#define  USR2_RTSF      (1<<4)  /* RTS edge interrupt flag */
+#define  USR2_TXDC      (1<<3)  /* Transmitter complete */
+#define  USR2_BRCD      (1<<2)  /* Break condition */
+#define  USR2_ORE        (1<<1)         /* Overrun error */
+#define  USR2_RDR        (1<<0)         /* Recv data ready */
+#define  UTS_FRCPERR    (1<<13) /* Force parity error */
+#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
+#define  UTS_TXEMPTY    (1<<6)  /* TxFIFO empty */
+#define  UTS_RXEMPTY    (1<<5)  /* RxFIFO empty */
+#define  UTS_TXFULL     (1<<4)  /* TxFIFO full */
+#define  UTS_RXFULL     (1<<3)  /* RxFIFO full */
+#define  UTS_SOFTRST    (1<<0)  /* Software reset */
+
+#endif                         // _IMX_REGS_H
diff --git a/include/asm-arm/arch-imx/io.h b/include/asm-arm/arch-imx/io.h
new file mode 100644 (file)
index 0000000..6c8789f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/asm-arm/arch-imxads/io.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)       (a)
+#define __mem_pci(a)  (a)
+
+#endif
diff --git a/include/asm-arm/arch-imx/irq.h b/include/asm-arm/arch-imx/irq.h
new file mode 100644 (file)
index 0000000..545e065
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  linux/include/asm-arm/arch-imxads/irq.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#define fixup_irq(i)   (i)
diff --git a/include/asm-arm/arch-imx/irqs.h b/include/asm-arm/arch-imx/irqs.h
new file mode 100644 (file)
index 0000000..238197c
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ *  linux/include/asm-arm/arch-imxads/irqs.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ARM_IRQS_H__
+#define __ARM_IRQS_H__
+
+/* Use the imx definitions */
+#include <asm/arch/hardware.h>
+
+/*
+ *  IMX Interrupt numbers
+ *
+ */
+#define INT_SOFTINT                 0
+#define CSI_INT                     6
+#define DSPA_MAC_INT                7
+#define DSPA_INT                    8
+#define COMP_INT                    9
+#define MSHC_XINT                   10
+#define GPIO_INT_PORTA              11
+#define GPIO_INT_PORTB              12
+#define GPIO_INT_PORTC              13
+#define LCDC_INT                    14
+#define SIM_INT                     15
+#define SIM_DATA_INT                16
+#define RTC_INT                     17
+#define RTC_SAMINT                  18
+#define UART2_MINT_PFERR            19
+#define UART2_MINT_RTS              20
+#define UART2_MINT_DTR              21
+#define UART2_MINT_UARTC            22
+#define UART2_MINT_TX               23
+#define UART2_MINT_RX               24
+#define UART1_MINT_PFERR            25
+#define UART1_MINT_RTS              26
+#define UART1_MINT_DTR              27
+#define UART1_MINT_UARTC            28
+#define UART1_MINT_TX               29
+#define UART1_MINT_RX               30
+#define VOICE_DAC_INT               31
+#define VOICE_ADC_INT               32
+#define PEN_DATA_INT                33
+#define PWM_INT                     34
+#define SDHC_INT                    35
+#define I2C_INT                     39
+#define CSPI_INT                    41
+#define SSI_TX_INT                  42
+#define SSI_TX_ERR_INT              43
+#define SSI_RX_INT                  44
+#define SSI_RX_ERR_INT              45
+#define TOUCH_INT                   46
+#define USBD_INT0                   47
+#define USBD_INT1                   48
+#define USBD_INT2                   49
+#define USBD_INT3                   50
+#define USBD_INT4                   51
+#define USBD_INT5                   52
+#define USBD_INT6                   53
+#define BTSYS_INT                   55
+#define BTTIM_INT                   56
+#define BTWUI_INT                   57
+#define TIM2_INT                    58
+#define TIM1_INT                    59
+#define DMA_ERR                     60
+#define DMA_INT                     61
+#define GPIO_INT_PORTD              62
+
+#define IMX_IRQS                         (64)
+
+/* note: the IMX has four gpio ports (A-D), but only
+ *       the following pins are connected to the outside
+ *       world:
+ *
+ * PORT A: bits 0-31
+ * PORT B: bits 8-31
+ * PORT C: bits 3-17
+ * PORT D: bits 6-31
+ *
+ * We map these interrupts straight on. As a result we have
+ * several holes in the interrupt mapping. We do this for two
+ * reasons:
+ *   - mapping the interrupts without holes would get
+ *     far more complicated
+ *   - Motorola could well decide to bring some processor
+ *     with more pins connected
+ */
+
+#define IRQ_GPIOA(x)  (IMX_IRQS + x)
+#define IRQ_GPIOB(x)  (IRQ_GPIOA(32) + x)
+#define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
+#define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
+
+/* decode irq number to use with IMR(x), ISR(x) and friends */
+#define IRQ_TO_REG(irq) ((irq - IMX_IRQS) >> 5)
+
+#define NR_IRQS (IRQ_GPIOD(32) + 1)
+#define IRQ_GPIO(x)
+#endif
diff --git a/include/asm-arm/arch-imx/memory.h b/include/asm-arm/arch-imx/memory.h
new file mode 100644 (file)
index 0000000..116a91f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  linux/include/asm-arm/arch-imx/memory.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+#define PHYS_OFFSET    (0x08000000UL)
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)       (x - PAGE_OFFSET +  PHYS_OFFSET)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)       (x -  PHYS_OFFSET + PAGE_OFFSET)
+
+#endif
diff --git a/include/asm-arm/arch-imx/mx1ads.h b/include/asm-arm/arch-imx/mx1ads.h
new file mode 100644 (file)
index 0000000..d90fa4b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/include/asm-arm/arch-imx/mx1ads.h
+ *
+ * Copyright (C) 2004 Robert Schwebel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __ASM_ARCH_MX1ADS_H
+#define __ASM_ARCH_MX1ADS_H
+
+/* ------------------------------------------------------------------------ */
+/* Memory Map for the M9328MX1ADS (MX1ADS) Board                            */
+/* ------------------------------------------------------------------------ */
+
+#define MX1ADS_FLASH_PHYS              0x10000000
+#define MX1ADS_FLASH_SIZE              (16*1024*1024)
+
+#define IMX_FB_PHYS                    (0x0C000000 - 0x40000)
+
+#define CLK32 32000
+
+#endif /* __ASM_ARCH_MX1ADS_H */
diff --git a/include/asm-arm/arch-imx/param.h b/include/asm-arm/arch-imx/param.h
new file mode 100644 (file)
index 0000000..7c724f0
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  linux/include/asm-arm/arch-imx/param.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This 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
+ */
diff --git a/include/asm-arm/arch-imx/system.h b/include/asm-arm/arch-imx/system.h
new file mode 100644 (file)
index 0000000..c645fe9
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  linux/include/asm-arm/arch-imxads/system.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+static void
+arch_idle(void)
+{
+       /*
+        * This should do all the clock switching
+        * and wait for interrupt tricks
+        */
+       cpu_do_idle();
+}
+
+static inline void
+arch_reset(char mode)
+{
+       cpu_reset(0);
+}
+
+#endif
diff --git a/include/asm-arm/arch-imx/timex.h b/include/asm-arm/arch-imx/timex.h
new file mode 100644 (file)
index 0000000..d65ab3c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  linux/include/asm-arm/imx/timex.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+#include <asm/arch/hardware.h>
+#define CLOCK_TICK_RATE                (CLK32)
+
+#endif
diff --git a/include/asm-arm/arch-imx/uncompress.h b/include/asm-arm/arch-imx/uncompress.h
new file mode 100644 (file)
index 0000000..096077f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  linux/include/asm-arm/arch-imxads/uncompress.h
+ *
+ *
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define UART(x) (*(volatile unsigned long *)(serial_port + (x)))
+
+#define UART1_BASE 0x206000
+#define UART2_BASE 0x207000
+#define USR2 0x98
+#define USR2_TXFE (1<<14)
+#define TXR  0x40
+#define UCR1 0x80
+#define UCR1_UARTEN 1
+
+/*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader.  We search for the first enabled
+ * port in the most probable order.  If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
+ *
+ * This does not append a newline
+ */
+static void
+putstr(const char *s)
+{
+       unsigned long serial_port;
+
+       do {
+               serial_port = UART1_BASE;
+               if ( UART(UCR1) & UCR1_UARTEN )
+                       break;
+               serial_port = UART2_BASE;
+               if ( UART(UCR1) & UCR1_UARTEN )
+                       break;
+               return;
+       } while(0);
+
+       while (*s) {
+               while ( !(UART(USR2) & USR2_TXFE) )
+                       barrier();
+
+               UART(TXR) = *s;
+
+               if (*s == '\n') {
+                       while ( !(UART(USR2) & USR2_TXFE) )
+                               barrier();
+
+                       UART(TXR) = '\r';
+               }
+               s++;
+       }
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff --git a/include/asm-arm/arch-imx/vmalloc.h b/include/asm-arm/arch-imx/vmalloc.h
new file mode 100644 (file)
index 0000000..252038f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  linux/include/asm-arm/arch-imx/vmalloc.h
+ *
+ *  Copyright (C) 2000 Russell King.
+ *
+ * This 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
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET   (8*1024*1024)
+#define VMALLOC_START    (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-iop3xx/iop331-irqs.h b/include/asm-arm/arch-iop3xx/iop331-irqs.h
new file mode 100644 (file)
index 0000000..37063b4
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * linux/include/asm-arm/arch-iop3xx/irqs.h
+ *
+ * Author:     Dave Jiang (dave.jiang@intel.com)
+ * Copyright:  (C) 2003 Intel Corp.
+ *
+ * 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 _IOP331_IRQS_H_
+#define _IOP331_IRQS_H_
+
+/*
+ * IOP80331 chipset interrupts
+ */
+#define IOP331_IRQ_OFS         0
+#define IOP331_IRQ(x)          (IOP331_IRQ_OFS + (x))
+
+/*
+ * On IRQ or FIQ register
+ */
+#define IRQ_IOP331_DMA0_EOT    IOP331_IRQ(0)
+#define IRQ_IOP331_DMA0_EOC    IOP331_IRQ(1)
+#define IRQ_IOP331_DMA1_EOT    IOP331_IRQ(2)
+#define IRQ_IOP331_DMA1_EOC    IOP331_IRQ(3)
+#define IRQ_IOP331_RSVD_4      IOP331_IRQ(4)
+#define IRQ_IOP331_RSVD_5      IOP331_IRQ(5)
+#define IRQ_IOP331_AA_EOT      IOP331_IRQ(6)
+#define IRQ_IOP331_AA_EOC      IOP331_IRQ(7)
+#define IRQ_IOP331_TIMER0      IOP331_IRQ(8)
+#define IRQ_IOP331_TIMER1      IOP331_IRQ(9)
+#define IRQ_IOP331_I2C_0       IOP331_IRQ(10)
+#define IRQ_IOP331_I2C_1       IOP331_IRQ(11)
+#define IRQ_IOP331_MSG     IOP331_IRQ(12)
+#define IRQ_IOP331_MSGIBQ   IOP331_IRQ(13)
+#define IRQ_IOP331_ATU_BIST    IOP331_IRQ(14)
+#define IRQ_IOP331_PERFMON     IOP331_IRQ(15)
+#define IRQ_IOP331_CORE_PMU    IOP331_IRQ(16)
+#define IRQ_IOP331_RSVD_17     IOP331_IRQ(17)
+#define IRQ_IOP331_RSVD_18     IOP331_IRQ(18)
+#define IRQ_IOP331_RSVD_19     IOP331_IRQ(19)
+#define IRQ_IOP331_RSVD_20     IOP331_IRQ(20)
+#define IRQ_IOP331_RSVD_21     IOP331_IRQ(21)
+#define IRQ_IOP331_RSVD_22     IOP331_IRQ(22)
+#define IRQ_IOP331_RSVD_23     IOP331_IRQ(23)
+#define IRQ_IOP331_XINT0       IOP331_IRQ(24)
+#define IRQ_IOP331_XINT1       IOP331_IRQ(25)
+#define IRQ_IOP331_XINT2       IOP331_IRQ(26)
+#define IRQ_IOP331_XINT3       IOP331_IRQ(27)
+#define IRQ_IOP331_RSVD_28  IOP331_IRQ(28)
+#define IRQ_IOP331_RSVD_29  IOP331_IRQ(29)
+#define IRQ_IOP331_RSVD_30  IOP331_IRQ(30)
+#define IRQ_IOP331_RSVD_31  IOP331_IRQ(31)
+#define IRQ_IOP331_XINT8    IOP331_IRQ(32)  // 0
+#define IRQ_IOP331_XINT9    IOP331_IRQ(33)  // 1
+#define IRQ_IOP331_XINT10   IOP331_IRQ(34)  // 2
+#define IRQ_IOP331_XINT11   IOP331_IRQ(35)  // 3
+#define IRQ_IOP331_XINT12   IOP331_IRQ(36)  // 4
+#define IRQ_IOP331_XINT13   IOP331_IRQ(37)  // 5
+#define IRQ_IOP331_XINT14   IOP331_IRQ(38)  // 6
+#define IRQ_IOP331_XINT15   IOP331_IRQ(39)  // 7
+#define IRQ_IOP331_RSVD_40  IOP331_IRQ(40)  // 8
+#define IRQ_IOP331_RSVD_41  IOP331_IRQ(41)  // 9
+#define IRQ_IOP331_RSVD_42  IOP331_IRQ(42)  // 10
+#define IRQ_IOP331_RSVD_43  IOP331_IRQ(43)  // 11
+#define IRQ_IOP331_RSVD_44  IOP331_IRQ(44)  // 12
+#define IRQ_IOP331_RSVD_45  IOP331_IRQ(45)  // 13
+#define IRQ_IOP331_RSVD_46  IOP331_IRQ(46)  // 14
+#define IRQ_IOP331_RSVD_47  IOP331_IRQ(47)  // 15
+#define IRQ_IOP331_RSVD_48  IOP331_IRQ(48)  // 16
+#define IRQ_IOP331_RSVD_49  IOP331_IRQ(49)  // 17
+#define IRQ_IOP331_RSVD_50  IOP331_IRQ(50)  // 18
+#define IRQ_IOP331_UART0    IOP331_IRQ(51)  // 19
+#define IRQ_IOP331_UART1    IOP331_IRQ(52)  // 20
+#define IRQ_IOP331_PBIE     IOP331_IRQ(53)  // 21
+#define IRQ_IOP331_ATU_CRW  IOP331_IRQ(54)  // 22
+#define IRQ_IOP331_ATU_ERR     IOP331_IRQ(55)  // 23
+#define IRQ_IOP331_MCU_ERR     IOP331_IRQ(56)  // 24
+#define IRQ_IOP331_DMA0_ERR    IOP331_IRQ(57)  // 25
+#define IRQ_IOP331_DMA1_ERR    IOP331_IRQ(58)  // 26
+#define IRQ_IOP331_RSVD_59  IOP331_IRQ(59)  // 27
+#define IRQ_IOP331_AA_ERR      IOP331_IRQ(60)  // 28
+#define IRQ_IOP331_RSVD_61  IOP331_IRQ(61)  // 29
+#define IRQ_IOP331_MSG_ERR     IOP331_IRQ(62)  // 30
+#define IRQ_IOP331_HPI         IOP331_IRQ(63)  // 31
+
+#define NR_IOP331_IRQS         (IOP331_IRQ(63) + 1)
+
+#define NR_IRQS                        NR_IOP331_IRQS
+
+
+/*
+ * Interrupts available on the IQ80331 board
+ */
+
+/*
+ * On board devices
+ */
+#define        IRQ_IQ80331_I82544      IRQ_IOP331_XINT0
+#define IRQ_IQ80331_UART0      IRQ_IOP331_UART0
+#define IRQ_IQ80331_UART1      IRQ_IOP331_UART1
+
+/*
+ * PCI interrupts
+ */
+#define        IRQ_IQ80331_INTA        IRQ_IOP331_XINT0
+#define        IRQ_IQ80331_INTB        IRQ_IOP331_XINT1
+#define        IRQ_IQ80331_INTC        IRQ_IOP331_XINT2
+#define        IRQ_IQ80331_INTD        IRQ_IOP331_XINT3
+
+#endif // _IOP331_IRQ_H_
diff --git a/include/asm-arm/arch-iop3xx/iop331.h b/include/asm-arm/arch-iop3xx/iop331.h
new file mode 100644 (file)
index 0000000..c4854a1
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * linux/include/asm/arch-iop3xx/iop331.h
+ *
+ * Intel IOP331 Chip definitions
+ *
+ * Author: Dave Jiang (dave.jiang@intel.com)
+ * Copyright (C) 2003 Intel Corp.
+ *
+ * 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 _IOP331_HW_H_
+#define _IOP331_HW_H_
+
+
+/*
+ * This is needed for mixed drivers that need to work on all
+ * IOP3xx variants but behave slightly differently on each.
+ */
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_ARCH_IOP331
+#define        iop_is_331()    ((processor_id & 0xffffffb0) == 0x69054090)
+#else
+#define        iop_is_331()    0
+#endif
+#endif
+
+/*
+ * IOP331 I/O and Mem space regions for PCI autoconfiguration
+ */
+#define IOP331_PCI_LOWER_IO             0x90000000
+#define IOP331_PCI_UPPER_IO             0x900fffff
+#define IOP331_PCI_LOWER_MEM            0x80000000
+#define IOP331_PCI_UPPER_MEM            0x87ffffff
+
+#define IOP331_PCI_WINDOW_SIZE          128 * 0x100000
+
+
+/*
+ * IOP331 chipset registers
+ */
+#define IOP331_VIRT_MEM_BASE 0xfeffe000  /* chip virtual mem address*/
+// #define IOP331_VIRT_MEM_BASE 0xfff00000  /* chip virtual mem address*/
+
+#define IOP331_PHYS_MEM_BASE  0xffffe000  /* chip physical memory address */
+#define IOP331_REG_ADDR(reg) (IOP331_VIRT_MEM_BASE | (reg))
+
+/* Reserved 0x00000000 through 0x000000FF */
+
+/* Address Translation Unit 0x00000100 through 0x000001FF */
+#define IOP331_ATUVID     (volatile u16 *)IOP331_REG_ADDR(0x00000100)
+#define IOP331_ATUDID     (volatile u16 *)IOP331_REG_ADDR(0x00000102)
+#define IOP331_ATUCMD     (volatile u16 *)IOP331_REG_ADDR(0x00000104)
+#define IOP331_ATUSR      (volatile u16 *)IOP331_REG_ADDR(0x00000106)
+#define IOP331_ATURID     (volatile u8  *)IOP331_REG_ADDR(0x00000108)
+#define IOP331_ATUCCR     (volatile u32 *)IOP331_REG_ADDR(0x00000109)
+#define IOP331_ATUCLSR    (volatile u8  *)IOP331_REG_ADDR(0x0000010C)
+#define IOP331_ATULT      (volatile u8  *)IOP331_REG_ADDR(0x0000010D)
+#define IOP331_ATUHTR     (volatile u8  *)IOP331_REG_ADDR(0x0000010E)
+#define IOP331_ATUBIST    (volatile u8  *)IOP331_REG_ADDR(0x0000010F)
+#define IOP331_IABAR0     (volatile u32 *)IOP331_REG_ADDR(0x00000110)
+#define IOP331_IAUBAR0    (volatile u32 *)IOP331_REG_ADDR(0x00000114)
+#define IOP331_IABAR1     (volatile u32 *)IOP331_REG_ADDR(0x00000118)
+#define IOP331_IAUBAR1    (volatile u32 *)IOP331_REG_ADDR(0x0000011C)
+#define IOP331_IABAR2     (volatile u32 *)IOP331_REG_ADDR(0x00000120)
+#define IOP331_IAUBAR2    (volatile u32 *)IOP331_REG_ADDR(0x00000124)
+#define IOP331_ASVIR      (volatile u16 *)IOP331_REG_ADDR(0x0000012C)
+#define IOP331_ASIR       (volatile u16 *)IOP331_REG_ADDR(0x0000012E)
+#define IOP331_ERBAR      (volatile u32 *)IOP331_REG_ADDR(0x00000130)
+#define IOP331_ATU_CAPPTR (volatile u32 *)IOP331_REG_ADDR(0x00000134)
+/* Reserved 0x00000138 through 0x0000013B */
+#define IOP331_ATUILR     (volatile u8  *)IOP331_REG_ADDR(0x0000013C)
+#define IOP331_ATUIPR     (volatile u8  *)IOP331_REG_ADDR(0x0000013D)
+#define IOP331_ATUMGNT    (volatile u8  *)IOP331_REG_ADDR(0x0000013E)
+#define IOP331_ATUMLAT    (volatile u8  *)IOP331_REG_ADDR(0x0000013F)
+#define IOP331_IALR0      (volatile u32 *)IOP331_REG_ADDR(0x00000140)
+#define IOP331_IATVR0     (volatile u32 *)IOP331_REG_ADDR(0x00000144)
+#define IOP331_ERLR       (volatile u32 *)IOP331_REG_ADDR(0x00000148)
+#define IOP331_ERTVR      (volatile u32 *)IOP331_REG_ADDR(0x0000014C)
+#define IOP331_IALR1      (volatile u32 *)IOP331_REG_ADDR(0x00000150)
+#define IOP331_IALR2      (volatile u32 *)IOP331_REG_ADDR(0x00000154)
+#define IOP331_IATVR2     (volatile u32 *)IOP331_REG_ADDR(0x00000158)
+#define IOP331_OIOWTVR    (volatile u32 *)IOP331_REG_ADDR(0x0000015C)
+#define IOP331_OMWTVR0    (volatile u32 *)IOP331_REG_ADDR(0x00000160)
+#define IOP331_OUMWTVR0   (volatile u32 *)IOP331_REG_ADDR(0x00000164)
+#define IOP331_OMWTVR1    (volatile u32 *)IOP331_REG_ADDR(0x00000168)
+#define IOP331_OUMWTVR1   (volatile u32 *)IOP331_REG_ADDR(0x0000016C)
+/* Reserved 0x00000170 through 0x00000177*/
+#define IOP331_OUDWTVR    (volatile u32 *)IOP331_REG_ADDR(0x00000178)
+/* Reserved 0x0000017C through 0x0000017F*/
+#define IOP331_ATUCR      (volatile u32 *)IOP331_REG_ADDR(0x00000180)
+#define IOP331_PCSR       (volatile u32 *)IOP331_REG_ADDR(0x00000184)
+#define IOP331_ATUISR     (volatile u32 *)IOP331_REG_ADDR(0x00000188)
+#define IOP331_ATUIMR     (volatile u32 *)IOP331_REG_ADDR(0x0000018C)
+#define IOP331_IABAR3     (volatile u32 *)IOP331_REG_ADDR(0x00000190)
+#define IOP331_IAUBAR3    (volatile u32 *)IOP331_REG_ADDR(0x00000194)
+#define IOP331_IALR3      (volatile u32 *)IOP331_REG_ADDR(0x00000198)
+#define IOP331_IATVR3     (volatile u32 *)IOP331_REG_ADDR(0x0000019C)
+/* Reserved 0x000001A0 through 0x000001A3*/
+#define IOP331_OCCAR      (volatile u32 *)IOP331_REG_ADDR(0x000001A4)
+/* Reserved 0x000001A8 through 0x000001AB*/
+#define IOP331_OCCDR      (volatile u32 *)IOP331_REG_ADDR(0x000001AC)
+/* Reserved 0x000001B0 through 0x000001BB*/
+#define IOP331_VPDCAPID   (volatile u8 *)IOP331_REG_ADDR(0x000001B8)
+#define IOP331_VPDNXTP    (volatile u8 *)IOP331_REG_ADDR(0x000001B9)
+#define IOP331_VPDAR     (volatile u16 *)IOP331_REG_ADDR(0x000001BA)
+#define IOP331_VPDDR      (volatile u32 *)IOP331_REG_ADDR(0x000001BC)
+#define IOP331_PMCAPID    (volatile u8 *)IOP331_REG_ADDR(0x000001C0)
+#define IOP331_PMNEXT     (volatile u8 *)IOP331_REG_ADDR(0x000001C1)
+#define IOP331_APMCR      (volatile u16 *)IOP331_REG_ADDR(0x000001C2)
+#define IOP331_APMCSR     (volatile u16 *)IOP331_REG_ADDR(0x000001C4)
+/* Reserved 0x000001C6 through 0x000001CF */
+#define IOP331_MSICAPID   (volatile u8 *)IOP331_REG_ADDR(0x000001D0)
+#define IOP331_MSINXTP   (volatile u8 *)IOP331_REG_ADDR(0x000001D1)
+#define IOP331_MSIMCR     (volatile u16 *)IOP331_REG_ADDR(0x000001D2)
+#define IOP331_MSIMAR     (volatile u32 *)IOP331_REG_ADDR(0x000001D4)
+#define IOP331_MSIMUAR   (volatile u32 *)IOP331_REG_ADDR(0x000001D8)
+#define IOP331_MSIMDR    (volatile u32 *)IOP331_REG_ADDR(0x000001DC)
+#define IOP331_PCIXCAPID  (volatile u8 *)IOP331_REG_ADDR(0x000001E0)
+#define IOP331_PCIXNEXT   (volatile u8 *)IOP331_REG_ADDR(0x000001E1)
+#define IOP331_PCIXCMD    (volatile u16 *)IOP331_REG_ADDR(0x000001E2)
+#define IOP331_PCIXSR     (volatile u32 *)IOP331_REG_ADDR(0x000001E4)
+#define IOP331_PCIIRSR    (volatile u32 *)IOP331_REG_ADDR(0x000001EC)
+
+/* Messaging Unit 0x00000300 through 0x000003FF */
+
+/* Reserved 0x00000300 through 0x0000030c */
+#define IOP331_IMR0       (volatile u32 *)IOP331_REG_ADDR(0x00000310)
+#define IOP331_IMR1       (volatile u32 *)IOP331_REG_ADDR(0x00000314)
+#define IOP331_OMR0       (volatile u32 *)IOP331_REG_ADDR(0x00000318)
+#define IOP331_OMR1       (volatile u32 *)IOP331_REG_ADDR(0x0000031C)
+#define IOP331_IDR        (volatile u32 *)IOP331_REG_ADDR(0x00000320)
+#define IOP331_IISR       (volatile u32 *)IOP331_REG_ADDR(0x00000324)
+#define IOP331_IIMR       (volatile u32 *)IOP331_REG_ADDR(0x00000328)
+#define IOP331_ODR        (volatile u32 *)IOP331_REG_ADDR(0x0000032C)
+#define IOP331_OISR       (volatile u32 *)IOP331_REG_ADDR(0x00000330)
+#define IOP331_OIMR       (volatile u32 *)IOP331_REG_ADDR(0x00000334)
+/* Reserved 0x00000338 through 0x0000034F */
+#define IOP331_MUCR       (volatile u32 *)IOP331_REG_ADDR(0x00000350)
+#define IOP331_QBAR       (volatile u32 *)IOP331_REG_ADDR(0x00000354)
+/* Reserved 0x00000358 through 0x0000035C */
+#define IOP331_IFHPR      (volatile u32 *)IOP331_REG_ADDR(0x00000360)
+#define IOP331_IFTPR      (volatile u32 *)IOP331_REG_ADDR(0x00000364)
+#define IOP331_IPHPR      (volatile u32 *)IOP331_REG_ADDR(0x00000368)
+#define IOP331_IPTPR      (volatile u32 *)IOP331_REG_ADDR(0x0000036C)
+#define IOP331_OFHPR      (volatile u32 *)IOP331_REG_ADDR(0x00000370)
+#define IOP331_OFTPR      (volatile u32 *)IOP331_REG_ADDR(0x00000374)
+#define IOP331_OPHPR      (volatile u32 *)IOP331_REG_ADDR(0x00000378)
+#define IOP331_OPTPR      (volatile u32 *)IOP331_REG_ADDR(0x0000037C)
+#define IOP331_IAR        (volatile u32 *)IOP331_REG_ADDR(0x00000380)
+/* Reserved 0x00000384 through 0x000003FF */
+
+/* DMA Controller 0x00000400 through 0x000004FF */
+#define IOP331_DMA0_CCR   (volatile u32 *)IOP331_REG_ADDR(0x00000400)
+#define IOP331_DMA0_CSR   (volatile u32 *)IOP331_REG_ADDR(0x00000404)
+#define IOP331_DMA0_DAR   (volatile u32 *)IOP331_REG_ADDR(0x0000040C)
+#define IOP331_DMA0_NDAR  (volatile u32 *)IOP331_REG_ADDR(0x00000410)
+#define IOP331_DMA0_PADR  (volatile u32 *)IOP331_REG_ADDR(0x00000414)
+#define IOP331_DMA0_PUADR (volatile u32 *)IOP331_REG_ADDR(0x00000418)
+#define IOP331_DMA0_LADR  (volatile u32 *)IOP331_REG_ADDR(0X0000041C)
+#define IOP331_DMA0_BCR   (volatile u32 *)IOP331_REG_ADDR(0x00000420)
+#define IOP331_DMA0_DCR   (volatile u32 *)IOP331_REG_ADDR(0x00000424)
+/* Reserved 0x00000428 through 0x0000043C */
+#define IOP331_DMA1_CCR   (volatile u32 *)IOP331_REG_ADDR(0x00000440)
+#define IOP331_DMA1_CSR   (volatile u32 *)IOP331_REG_ADDR(0x00000444)
+#define IOP331_DMA1_DAR   (volatile u32 *)IOP331_REG_ADDR(0x0000044C)
+#define IOP331_DMA1_NDAR  (volatile u32 *)IOP331_REG_ADDR(0x00000450)
+#define IOP331_DMA1_PADR  (volatile u32 *)IOP331_REG_ADDR(0x00000454)
+#define IOP331_DMA1_PUADR (volatile u32 *)IOP331_REG_ADDR(0x00000458)
+#define IOP331_DMA1_LADR  (volatile u32 *)IOP331_REG_ADDR(0x0000045C)
+#define IOP331_DMA1_BCR   (volatile u32 *)IOP331_REG_ADDR(0x00000460)
+#define IOP331_DMA1_DCR   (volatile u32 *)IOP331_REG_ADDR(0x00000464)
+/* Reserved 0x00000468 through 0x000004FF */
+
+/* Memory controller 0x00000500 through 0x0005FF */
+
+/* Peripheral bus interface unit 0x00000680 through 0x0006FF */
+#define IOP331_PBCR       (volatile u32 *)IOP331_REG_ADDR(0x00000680)
+#define IOP331_PBISR      (volatile u32 *)IOP331_REG_ADDR(0x00000684)
+#define IOP331_PBBAR0     (volatile u32 *)IOP331_REG_ADDR(0x00000688)
+#define IOP331_PBLR0      (volatile u32 *)IOP331_REG_ADDR(0x0000068C)
+#define IOP331_PBBAR1     (volatile u32 *)IOP331_REG_ADDR(0x00000690)
+#define IOP331_PBLR1      (volatile u32 *)IOP331_REG_ADDR(0x00000694)
+#define IOP331_PBBAR2     (volatile u32 *)IOP331_REG_ADDR(0x00000698)
+#define IOP331_PBLR2      (volatile u32 *)IOP331_REG_ADDR(0x0000069C)
+#define IOP331_PBBAR3     (volatile u32 *)IOP331_REG_ADDR(0x000006A0)
+#define IOP331_PBLR3      (volatile u32 *)IOP331_REG_ADDR(0x000006A4)
+#define IOP331_PBBAR4     (volatile u32 *)IOP331_REG_ADDR(0x000006A8)
+#define IOP331_PBLR4      (volatile u32 *)IOP331_REG_ADDR(0x000006AC)
+#define IOP331_PBBAR5     (volatile u32 *)IOP331_REG_ADDR(0x000006B0)
+#define IOP331_PBLR5      (volatile u32 *)IOP331_REG_ADDR(0x000006B4)
+#define IOP331_PBDSCR     (volatile u32 *)IOP331_REG_ADDR(0x000006B8)
+/* Reserved 0x000006BC */
+#define IOP331_PMBR0      (volatile u32 *)IOP331_REG_ADDR(0x000006C0)
+/* Reserved 0x000006C4 through 0x000006DC */
+#define IOP331_PMBR1      (volatile u32 *)IOP331_REG_ADDR(0x000006E0)
+#define IOP331_PMBR2      (volatile u32 *)IOP331_REG_ADDR(0x000006E4)
+
+#define IOP331_PBCR_EN    0x1
+
+#define IOP331_PBISR_BOOR_ERR 0x1
+
+
+
+/* Peripheral performance monitoring unit 0x00000700 through 0x00077F */
+/* Internal arbitration unit 0x00000780 through 0x0007BF */
+
+/* Interrupt Controller */
+#define IOP331_INTCTL0    (volatile u32 *)IOP331_REG_ADDR(0x00000790)
+#define IOP331_INTCTL1    (volatile u32 *)IOP331_REG_ADDR(0x00000794)
+#define IOP331_INTSTR0    (volatile u32 *)IOP331_REG_ADDR(0x00000798)
+#define IOP331_INTSTR1    (volatile u32 *)IOP331_REG_ADDR(0x0000079C)
+#define IOP331_IINTSRC0   (volatile u32 *)IOP331_REG_ADDR(0x000007A0)
+#define IOP331_IINTSRC1   (volatile u32 *)IOP331_REG_ADDR(0x000007A4)
+#define IOP331_FINTSRC0   (volatile u32 *)IOP331_REG_ADDR(0x000007A8)
+#define IOP331_FINTSRC1   (volatile u32 *)IOP331_REG_ADDR(0x000007AC)
+#define IOP331_IPR0       (volatile u32 *)IOP331_REG_ADDR(0x000007B0)
+#define IOP331_IPR1       (volatile u32 *)IOP331_REG_ADDR(0x000007B4)
+#define IOP331_IPR2       (volatile u32 *)IOP331_REG_ADDR(0x000007B8)
+#define IOP331_IPR3       (volatile u32 *)IOP331_REG_ADDR(0x000007BC)
+#define IOP331_INTBASE    (volatile u32 *)IOP331_REG_ADDR(0x000007C0)
+#define IOP331_INTSIZE    (volatile u32 *)IOP331_REG_ADDR(0x000007C4)
+#define IOP331_IINTVEC    (volatile u32 *)IOP331_REG_ADDR(0x000007C8)
+#define IOP331_FINTVEC    (volatile u32 *)IOP331_REG_ADDR(0x000007CC)
+
+
+/* Timers */
+
+#define IOP331_TU_TMR0         (volatile u32 *)IOP331_REG_ADDR(0x000007D0)
+#define IOP331_TU_TMR1         (volatile u32 *)IOP331_REG_ADDR(0x000007D4)
+
+#define IOP331_TMR_TC          0x01
+#define        IOP331_TMR_EN           0x02
+#define IOP331_TMR_RELOAD      0x04
+#define        IOP331_TMR_PRIVILEGED   0x09
+
+#define        IOP331_TMR_RATIO_1_1    0x00
+#define        IOP331_TMR_RATIO_4_1    0x10
+#define        IOP331_TMR_RATIO_8_1    0x20
+#define        IOP331_TMR_RATIO_16_1   0x30
+
+#define IOP331_TU_TCR0    (volatile u32 *)IOP331_REG_ADDR(0x000007D8)
+#define IOP331_TU_TCR1    (volatile u32 *)IOP331_REG_ADDR(0x000007DC)
+#define IOP331_TU_TRR0    (volatile u32 *)IOP331_REG_ADDR(0x000007E0)
+#define IOP331_TU_TRR1    (volatile u32 *)IOP331_REG_ADDR(0x000007E4)
+#define IOP331_TU_TISR    (volatile u32 *)IOP331_REG_ADDR(0x000007E8)
+#define IOP331_TU_WDTCR   (volatile u32 *)IOP331_REG_ADDR(0x000007EC)
+
+#define        IOP331_TICK_RATE        266000000       /* 266 MHz clock */
+
+
+/* Application accelerator unit 0x00000800 - 0x000008FF */
+#define IOP331_AAU_ACR     (volatile u32 *)IOP331_REG_ADDR(0x00000800)
+#define IOP331_AAU_ASR     (volatile u32 *)IOP331_REG_ADDR(0x00000804)
+#define IOP331_AAU_ADAR    (volatile u32 *)IOP331_REG_ADDR(0x00000808)
+#define IOP331_AAU_ANDAR   (volatile u32 *)IOP331_REG_ADDR(0x0000080C)
+#define IOP331_AAU_SAR1    (volatile u32 *)IOP331_REG_ADDR(0x00000810)
+#define IOP331_AAU_SAR2    (volatile u32 *)IOP331_REG_ADDR(0x00000814)
+#define IOP331_AAU_SAR3    (volatile u32 *)IOP331_REG_ADDR(0x00000818)
+#define IOP331_AAU_SAR4    (volatile u32 *)IOP331_REG_ADDR(0x0000081C)
+#define IOP331_AAU_SAR5    (volatile u32 *)IOP331_REG_ADDR(0x0000082C)
+#define IOP331_AAU_SAR6    (volatile u32 *)IOP331_REG_ADDR(0x00000830)
+#define IOP331_AAU_SAR7    (volatile u32 *)IOP331_REG_ADDR(0x00000834)
+#define IOP331_AAU_SAR8    (volatile u32 *)IOP331_REG_ADDR(0x00000838)
+#define IOP331_AAU_SAR9    (volatile u32 *)IOP331_REG_ADDR(0x00000840)
+#define IOP331_AAU_SAR10   (volatile u32 *)IOP331_REG_ADDR(0x00000844)
+#define IOP331_AAU_SAR11   (volatile u32 *)IOP331_REG_ADDR(0x00000848)
+#define IOP331_AAU_SAR12   (volatile u32 *)IOP331_REG_ADDR(0x0000084C)
+#define IOP331_AAU_SAR13   (volatile u32 *)IOP331_REG_ADDR(0x00000850)
+#define IOP331_AAU_SAR14   (volatile u32 *)IOP331_REG_ADDR(0x00000854)
+#define IOP331_AAU_SAR15   (volatile u32 *)IOP331_REG_ADDR(0x00000858)
+#define IOP331_AAU_SAR16   (volatile u32 *)IOP331_REG_ADDR(0x0000085C)
+#define IOP331_AAU_SAR17   (volatile u32 *)IOP331_REG_ADDR(0x00000864)
+#define IOP331_AAU_SAR18   (volatile u32 *)IOP331_REG_ADDR(0x00000868)
+#define IOP331_AAU_SAR19   (volatile u32 *)IOP331_REG_ADDR(0x0000086C)
+#define IOP331_AAU_SAR20   (volatile u32 *)IOP331_REG_ADDR(0x00000870)
+#define IOP331_AAU_SAR21   (volatile u32 *)IOP331_REG_ADDR(0x00000874)
+#define IOP331_AAU_SAR22   (volatile u32 *)IOP331_REG_ADDR(0x00000878)
+#define IOP331_AAU_SAR23   (volatile u32 *)IOP331_REG_ADDR(0x0000087C)
+#define IOP331_AAU_SAR24   (volatile u32 *)IOP331_REG_ADDR(0x00000880)
+#define IOP331_AAU_SAR25   (volatile u32 *)IOP331_REG_ADDR(0x00000888)
+#define IOP331_AAU_SAR26   (volatile u32 *)IOP331_REG_ADDR(0x0000088C)
+#define IOP331_AAU_SAR27   (volatile u32 *)IOP331_REG_ADDR(0x00000890)
+#define IOP331_AAU_SAR28   (volatile u32 *)IOP331_REG_ADDR(0x00000894)
+#define IOP331_AAU_SAR29   (volatile u32 *)IOP331_REG_ADDR(0x00000898)
+#define IOP331_AAU_SAR30   (volatile u32 *)IOP331_REG_ADDR(0x0000089C)
+#define IOP331_AAU_SAR31   (volatile u32 *)IOP331_REG_ADDR(0x000008A0)
+#define IOP331_AAU_SAR32   (volatile u32 *)IOP331_REG_ADDR(0x000008A4)
+#define IOP331_AAU_DAR     (volatile u32 *)IOP331_REG_ADDR(0x00000820)
+#define IOP331_AAU_ABCR    (volatile u32 *)IOP331_REG_ADDR(0x00000824)
+#define IOP331_AAU_ADCR    (volatile u32 *)IOP331_REG_ADDR(0x00000828)
+#define IOP331_AAU_EDCR0   (volatile u32 *)IOP331_REG_ADDR(0x0000083c)
+#define IOP331_AAU_EDCR1   (volatile u32 *)IOP331_REG_ADDR(0x00000860)
+#define IOP331_AAU_EDCR2   (volatile u32 *)IOP331_REG_ADDR(0x00000884)
+
+
+#define IOP331_SPDSCR    (volatile u32 *)IOP331_REG_ADDR(0x000015C0)
+#define IOP331_PPDSCR    (volatile u32 *)IOP331_REG_ADDR(0x000015C8)
+/* SSP serial port unit 0x00001600 - 0x0000167F */
+
+/* I2C bus interface unit 0x00001680 - 0x000016FF */
+/* for I2C bit defs see drivers/i2c/i2c-iop3xx.h */
+
+#define IOP331_ICR0       (volatile u32 *)IOP331_REG_ADDR(0x00001680)
+#define IOP331_ISR0       (volatile u32 *)IOP331_REG_ADDR(0x00001684)
+#define IOP331_ISAR0      (volatile u32 *)IOP331_REG_ADDR(0x00001688)
+#define IOP331_IDBR0      (volatile u32 *)IOP331_REG_ADDR(0x0000168C)
+/* Reserved 0x00001690 */
+#define IOP331_IBMR0      (volatile u32 *)IOP331_REG_ADDR(0x00001694)
+/* Reserved 0x00001698 */
+/* Reserved 0x0000169C */
+#define IOP331_ICR1       (volatile u32 *)IOP331_REG_ADDR(0x000016A0)
+#define IOP331_ISR1       (volatile u32 *)IOP331_REG_ADDR(0x000016A4)
+#define IOP331_ISAR1      (volatile u32 *)IOP331_REG_ADDR(0x000016A8)
+#define IOP331_IDBR1      (volatile u32 *)IOP331_REG_ADDR(0x000016AC)
+#define IOP331_IBMR1      (volatile u32 *)IOP331_REG_ADDR(0x000016B4)
+/* Reserved 0x000016B8 through 0x000016FF */
+
+/* 0x00001700 through 0x0000172C  UART 0 */
+
+/* Reserved 0x00001730 through 0x0000173F */
+
+/* 0x00001740 through 0x0000176C UART 1 */
+
+/* Reserved 0x00001770 through 0x0000177F */
+
+/* General Purpose I/O Registers */
+#define IOP331_GPOE       (volatile u32 *)IOP331_REG_ADDR(0x00001780)
+#define IOP331_GPID       (volatile u32 *)IOP331_REG_ADDR(0x00001784)
+#define IOP331_GPOD       (volatile u32 *)IOP331_REG_ADDR(0x00001788)
+
+/* Reserved 0x0000178c through 0x000019ff */
+
+#ifndef __ASSEMBLY__
+extern void iop331_map_io(void);
+extern void iop331_init_irq(void);
+extern void iop331_time_init(void);
+#endif
+
+#endif // _IOP331_HW_H_
diff --git a/include/asm-arm/arch-iop3xx/iq31244.h b/include/asm-arm/arch-iop3xx/iq31244.h
new file mode 100644 (file)
index 0000000..c62c216
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * linux/include/asm/arch-iop3xx/iq31244.h
+ *
+ * Intel IQ31244 evaluation board registers
+ */
+
+#ifndef _IQ31244_H_
+#define _IQ31244_H_
+
+#define IQ31244_RAMBASE                0xa0000000
+
+#define        IQ31244_FLASHBASE       0xf0000000      /* Flash */
+#define        IQ31244_FLASHSIZE       0x00800000
+#define        IQ31244_FLASHWIDTH      2
+
+#define IQ31244_UART           0xfe800000      /* UART #1 */
+#define IQ31244_7SEG_1         0xfe840000      /* 7-Segment MSB */
+#define IQ31244_7SEG_0         0xfe850000      /* 7-Segment LSB (WO) */
+#define IQ31244_ROTARY_SW      0xfe8d0000      /* Rotary Switch */
+#define IQ31244_BATT_STAT      0xfe8f0000      /* Battery Status */
+
+/*
+ * IQ31244 PCI I/O and Mem space regions
+ */
+#define IQ31244_PCI_IO_BASE    0x90000000
+#define IQ31244_PCI_IO_SIZE    0x00010000
+#define IQ31244_PCI_MEM_BASE   0x80000000
+//#define IQ31244_PCI_MEM_SIZE 0x04000000
+#define IQ31244_PCI_MEM_SIZE   0x08000000
+#define        IQ31244_PCI_IO_OFFSET   0x6e000000
+
+#ifndef __ASSEMBLY__
+extern void iq31244_map_io(void);
+#endif
+
+#endif // _IQ31244_H_
diff --git a/include/asm-arm/arch-iop3xx/iq80331.h b/include/asm-arm/arch-iop3xx/iq80331.h
new file mode 100644 (file)
index 0000000..a076327
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * linux/include/asm/arch-iop3xx/iq80331.h
+ *
+ * Intel IQ80331 evaluation board registers
+ */
+
+#ifndef _IQ80331_H_
+#define _IQ80331_H_
+
+#define IQ80331_RAMBASE                0x00000000
+
+#define        IQ80331_FLASHBASE       0xc0000000      /* Flash */
+#define        IQ80331_FLASHSIZE       0x00800000
+#define        IQ80331_FLASHWIDTH      1
+
+#define IQ80331_UART0_PHYS  (IOP331_PHYS_MEM_BASE | 0x00001700)        /* UART #1 physical */
+#define IQ80331_UART1_PHYS  (IOP331_PHYS_MEM_BASE | 0x00001740)        /* UART #2 physical */
+#define IQ80331_UART0_VIRT  (IOP331_VIRT_MEM_BASE | 0x00001700) /* UART #1 virtual addr */
+#define IQ80331_UART1_VIRT  (IOP331_VIRT_MEM_BASE | 0x00001740) /* UART #2 virtual addr */
+#define IQ80331_7SEG_1         0xce840000      /* 7-Segment MSB */
+#define IQ80331_7SEG_0         0xce850000      /* 7-Segment LSB (WO) */
+#define IQ80331_ROTARY_SW      0xce8d0000      /* Rotary Switch */
+#define IQ80331_BATT_STAT      0xce8f0000      /* Battery Status */
+
+/*
+ * IQ80331 PCI I/O and Mem space regions
+ */
+#define IQ80331_PCI_IO_BASE    0x90000000
+#define IQ80331_PCI_IO_SIZE    0x00010000
+#define IQ80331_PCI_MEM_BASE   0x80000000
+#define IQ80331_PCI_MEM_SIZE   0x08000000
+#define        IQ80331_PCI_IO_OFFSET   0x6e000000
+
+#ifndef __ASSEMBLY__
+extern void iq80331_map_io(void);
+#endif
+
+#endif // _IQ80331_H_
diff --git a/include/asm-arm/arch-ixp2000/dma.h b/include/asm-arm/arch-ixp2000/dma.h
new file mode 100644 (file)
index 0000000..71520c8
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * linux/include/asm-arm/arch-ixdp2400/dma.h
+ *
+ * Copyright (C) 2002 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+#define MAX_DMA_ADDRESS                0xffffffff
+
+/* No DMA */
+#define MAX_DMA_CHANNELS       0
+
+#endif /* _ASM_ARCH_DMA_H */
diff --git a/include/asm-arm/arch-ixp2000/enp2611.h b/include/asm-arm/arch-ixp2000/enp2611.h
new file mode 100644 (file)
index 0000000..31ae886
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * include/asm-arm/arch-ixp2000/enp2611.h
+ *
+ * Register and other defines for Radisys ENP-2611
+ *
+ * Created 2004 by Lennert Buytenhek from the ixdp2x01 code.  The
+ * original version carries the following notices:
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __ENP2611_H
+#define __ENP2611_H
+
+#define ENP2611_GPIO_SCL       0x07
+#define ENP2611_GPIO_SDA       0x06
+
+
+#endif
diff --git a/include/asm-arm/arch-ixp2000/gpio.h b/include/asm-arm/arch-ixp2000/gpio.h
new file mode 100644 (file)
index 0000000..84634af
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * include/asm-arm/arch-ixp2000/ixp2000-gpio.h
+ *
+ * Copyright (C) 2002 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.
+ */
+
+/*
+ * IXP2000 GPIO in/out, edge/level detection for IRQs:
+ * IRQs are generated on Falling-edge, Rising-Edge, Level-low, Level-High
+ * or both Falling-edge and Rising-edge.  
+ * This must be called *before* the corresponding IRQ is registerd.
+ * 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 __ASSEMBLY__
+#define GPIO_OUT                       0x0
+#define GPIO_IN                                0x80
+
+#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);
+
+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_GPIO_HIGH) {
+               ixp_reg_write(IXP2000_GPIO_POSR, BIT(line));
+       } else if (value == IXP2000_GPIO_LOW)
+               ixp_reg_write(IXP2000_GPIO_POCR, BIT(line));
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
+
diff --git a/include/asm-arm/arch-ixp2000/hardware.h b/include/asm-arm/arch-ixp2000/hardware.h
new file mode 100644 (file)
index 0000000..e7ea781
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * linux/include/asm-arm/arch-ixp2000/hardware.h
+ *
+ * Hardware definitions for IXP2400/2800 based systems
+ *
+ * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
+ *
+ * Maintainer: Deepak Saxena <dsaxena@mvista.com>
+ *
+ * Copyright (C) 2001-2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H__
+#define __ASM_ARCH_HARDWARE_H__
+
+/*
+ * This needs to be platform-specific?
+ */
+#define PCIBIOS_MIN_IO          0x00000000
+#define PCIBIOS_MIN_MEM         0x00000000
+
+#include "ixp2000-regs.h"      /* Chipset Registers */
+
+#define pcibios_assign_all_busses() 0
+
+/*
+ * Platform helper functions
+ */
+#include "platform.h"
+
+/*
+ * Platform-specific bits
+ */
+#include "enp2611.h"           /* ENP-2611 */
+#include "ixdp2x00.h"          /* IXDP2400/2800 */
+#include "ixdp2x01.h"          /* IXDP2401/2801 */
+
+#endif  /* _ASM_ARCH_HARDWARE_H__ */
diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h
new file mode 100644 (file)
index 0000000..7463a32
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * linux/include/asm-arm/arch-ixdp2000/io.h
+ *
+ * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002  Intel Corp.
+ * Copyrgiht (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT         0xffffffff
+#define __mem_pci(a)           ((unsigned long)(a))
+
+/*
+ * Pick up VMALLOC_END
+ */
+#define ___io(p)               ((unsigned long)((p)+IXP2000_PCI_IO_VIRT_BASE))
+
+/*
+ * IXP200 does not do proper byte-lane conversion for PCI addresses,
+ * so we need to override standard functions.
+ */
+#define alignb(addr)           ((addr & ~3) + (3 - (addr & 3)))
+#define alignw(addr)           ((addr & ~2) + (2 - (addr & 2)))
+
+#define outb(v,p)              __raw_writeb(v,alignb(___io(p)))
+#define outw(v,p)              __raw_writew((v),alignw(___io(p)))
+#define outl(v,p)              __raw_writel((v),___io(p))
+
+#define inb(p)         ({ unsigned int __v = __raw_readb(alignb(___io(p))); __v; })
+#define inw(p)         \
+       ({ unsigned int __v = (__raw_readw(alignw(___io(p)))); __v; })
+#define inl(p)         \
+       ({ unsigned int __v = (__raw_readl(___io(p))); __v; })
+
+#define outsb(p,d,l)           __raw_writesb(alignb(___io(p)),d,l)
+#define outsw(p,d,l)           __raw_writesw(alignw(___io(p)),d,l)
+#define outsl(p,d,l)           __raw_writesl(___io(p),d,l)
+
+#define insb(p,d,l)            __raw_readsb(alignb(___io(p)),d,l)
+#define insw(p,d,l)            __raw_readsw(alignw(___io(p)),d,l)
+#define insl(p,d,l)            __raw_readsl(___io(p),d,l)
+
+
+#ifdef CONFIG_ARCH_IXDP2X01
+/*
+ * This is an ugly hack but the CS8900 on the 2x01's does not sit in any sort
+ * of "I/O space" and is just direct mapped into a 32-bit-only addressable
+ * bus. The address space for this bus is such that we can't really easilly
+ * make it contigous to the PCI I/O address range, and it also does not
+ * need swapping like PCI addresses do (IXDP2x01 is a BE platform).
+ * B/C of this we can't use the standard in/out functions and need to
+ * runtime check if the incoming address is a PCI address or for
+ * the CS89x0.
+ */
+#undef inw
+#undef outw
+#undef insw
+#undef outsw
+
+#include <asm/mach-types.h>
+
+static inline void insw(u32 ptr, void *buf, int length)
+{
+       register volatile u32 *port = (volatile u32 *)ptr;
+
+       /*
+        * Is this cycle meant for the CS8900?
+        */
+       if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
+               ((port >= IXDP2X01_CS8900_VIRT_BASE) && 
+                (port <= IXDP2X01_CS8900_VIRT_END))) {
+               u8 *buf8 = (u8*)buf;
+               register u32 tmp32;
+
+               do {
+                       tmp32 = *port;
+                       *buf8++ = (u8)tmp32;
+                       *buf8++ = (u8)(tmp32 >> 8);
+               } while(--length);
+
+               return;
+       }
+
+       __raw_readsw(alignw(___io(ptr)),buf,length);
+}
+
+static inline void outsw(u32 ptr, void *buf, int length)
+{
+       register volatile u32 *port = (volatile u32 *)ptr;
+
+       /*
+        * Is this cycle meant for the CS8900?
+        */
+       if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
+               ((port >= IXDP2X01_CS8900_VIRT_BASE) && 
+                (port <= IXDP2X01_CS8900_VIRT_END))) {
+               register u32 tmp32;
+               u8 *buf8 = (u8*)buf;
+               do {
+                       tmp32 = *buf8++;
+                       tmp32 |= (*buf8++) << 8;
+                       *port = tmp32;
+               } while(--length);
+               return;
+       }
+
+       __raw_writesw(alignw(___io(ptr)),buf,length);
+}
+
+
+static inline u16 inw(u32 ptr)
+{
+       register volatile u32 *port = (volatile u32 *)ptr;
+
+       /*
+        * Is this cycle meant for the CS8900?
+        */
+       if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
+               ((port >= IXDP2X01_CS8900_VIRT_BASE) && 
+                (port <= IXDP2X01_CS8900_VIRT_END))) {
+               return (u16)(*port);  
+       }
+
+       return __raw_readw(alignw(___io(ptr)));
+}
+
+static inline void outw(u16 value, u32 ptr)
+{
+       register volatile u32 *port = (volatile u32 *)ptr;
+
+       if ((machine_is_ixdp2401() || machine_is_ixdp2801()) && 
+               ((port >= IXDP2X01_CS8900_VIRT_BASE) && 
+                (port <= IXDP2X01_CS8900_VIRT_END))) {
+               *port = value;  
+               return;
+       }
+
+       __raw_writew((value),alignw(___io(ptr)));
+}
+#endif /* IXDP2x01 */
+
+#endif
diff --git a/include/asm-arm/arch-ixp2000/irq.h b/include/asm-arm/arch-ixp2000/irq.h
new file mode 100644 (file)
index 0000000..ba00b23
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *  linux/include/asm-arm/arch-ixp2000/irq.h
+ *
+ *  Copyright (C) 2002 Intel Corp.
+ *
+ * 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.
+ */
+
+#define fixup_irq(irq)  (irq)
+
+
diff --git a/include/asm-arm/arch-ixp2000/irqs.h b/include/asm-arm/arch-ixp2000/irqs.h
new file mode 100644 (file)
index 0000000..a6b104f
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * linux/include/asm-arm/arch-ixp2000/irqs.h
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _IRQS_H
+#define _IRQS_H
+
+/*
+ * Do NOT add #ifdef MACHINE_FOO in here.
+ * Simpy add your machine IRQs here and increase NR_IRQS if needed to
+ * hold your machine's IRQ table.
+ */
+
+/*
+ * Some interrupt numbers go unused b/c the IRQ mask/ummask/status
+ * register has those bit reserved. We just mark those interrupts
+ * as invalid and this allows us to do mask/unmask with a single
+ * shift operation instead of having to map the IRQ number to
+ * a HW IRQ number.
+ */
+#define        IRQ_IXP2000_SWI                 0 /* soft interrupt */
+#define        IRQ_IXP2000_ERRSUM              1 /* OR of all bits in ErrorStatus reg*/
+#define        IRQ_IXP2000_UART                2
+#define        IRQ_IXP2000_GPIO                3
+#define        IRQ_IXP2000_TIMER1              4
+#define        IRQ_IXP2000_TIMER2              5
+#define        IRQ_IXP2000_TIMER3              6
+#define        IRQ_IXP2000_TIMER4              7
+#define        IRQ_IXP2000_PMU                 8               
+#define        IRQ_IXP2000_SPF                 9  /* Slow port framer IRQ */
+#define        IRQ_IXP2000_DMA1                10
+#define        IRQ_IXP2000_DMA2                11
+#define        IRQ_IXP2000_DMA3                12
+#define        IRQ_IXP2000_PCI_DOORBELL        13
+#define        IRQ_IXP2000_ME_ATTN             14 
+#define        IRQ_IXP2000_PCI                 15 /* PCI INTA or INTB */
+#define        IRQ_IXP2000_THDA0               16 /* thread 0-31A */
+#define        IRQ_IXP2000_THDA1               17 /* thread 32-63A */
+#define        IRQ_IXP2000_THDA2               18 /* thread 64-95A */
+#define        IRQ_IXP2000_THDA3               19 /* thread 96-127A */
+#define        IRQ_IXP2000_THDB0               24 /* thread 0-31 B */
+#define        IRQ_IXP2000_THDB1               25 /* thread 32-63B */
+/* only 64 threads supported for IXP2400, rest or for IXP2800*/
+#define        IRQ_IXP2000_THDB2               26 /* thread 64-95B */
+#define        IRQ_IXP2000_THDB3               27 /* thread 96-127B */
+
+/* define generic GPIOs */
+#define IRQ_IXP2000_GPIO0              32
+#define IRQ_IXP2000_GPIO1              33
+#define IRQ_IXP2000_GPIO2              34
+#define IRQ_IXP2000_GPIO3              35
+#define IRQ_IXP2000_GPIO4              36
+#define IRQ_IXP2000_GPIO5              37
+#define IRQ_IXP2000_GPIO6              38
+#define IRQ_IXP2000_GPIO7              39
+
+/* split off the 2 PCI sources */
+#define IRQ_IXP2000_PCIA               40
+#define IRQ_IXP2000_PCIB               41
+
+/* Int sources from IRQ_ERROR_STATUS */
+#define IRQ_IXP2000_DRAM0_MIN_ERR      42
+#define IRQ_IXP2000_DRAM0_MAJ_ERR      43
+#define IRQ_IXP2000_DRAM1_MIN_ERR      44
+#define IRQ_IXP2000_DRAM1_MAJ_ERR      45
+#define IRQ_IXP2000_DRAM2_MIN_ERR      46
+#define IRQ_IXP2000_DRAM2_MAJ_ERR      47
+#define IRQ_IXP2000_SRAM0_ERR          48
+#define IRQ_IXP2000_SRAM1_ERR          49
+#define IRQ_IXP2000_SRAM2_ERR           50
+#define IRQ_IXP2000_SRAM3_ERR          51
+#define IRQ_IXP2000_MEDIA_ERR          52
+#define IRQ_IXP2000_PCI_ERR            53
+#define IRQ_IXP2000_SP_INT             54
+
+#define NR_IXP2000_IRQS                 55
+
+#define        IXP2000_BOARD_IRQ(x)            (NR_IXP2000_IRQS + (x))
+
+#define        IXP2000_BOARD_IRQ_MASK(irq)     (1 << (irq - NR_IXP2000_IRQS))  
+
+/*
+ * This allows for all the on-chip sources plus up to 32 CPLD based
+ * IRQs. Should be more than enough.
+ */
+#define        IXP2000_BOARD_IRQS              32
+#define NR_IRQS                                (NR_IXP2000_IRQS + IXP2000_BOARD_IRQS)
+
+
+/* 
+ * IXDP2400 specific IRQs
+ */
+#define        IRQ_IXDP2400_INGRESS_NPU        IXP2000_BOARD_IRQ(0) 
+#define        IRQ_IXDP2400_ENET               IXP2000_BOARD_IRQ(1) 
+#define        IRQ_IXDP2400_MEDIA_PCI          IXP2000_BOARD_IRQ(2) 
+#define        IRQ_IXDP2400_MEDIA_SP           IXP2000_BOARD_IRQ(3) 
+#define        IRQ_IXDP2400_SF_PCI             IXP2000_BOARD_IRQ(4) 
+#define        IRQ_IXDP2400_SF_SP              IXP2000_BOARD_IRQ(5) 
+#define        IRQ_IXDP2400_PMC                IXP2000_BOARD_IRQ(6) 
+#define        IRQ_IXDP2400_TVM                IXP2000_BOARD_IRQ(7) 
+
+#define        NR_IXDP2400_IRQS                ((IRQ_IXDP2400_TVM)+1)  
+#define        IXDP2400_NR_IRQS                NR_IXDP2400_IRQS - NR_IXP2000_IRQS
+
+/* IXDP2800 specific IRQs */
+#define IRQ_IXDP2800_EGRESS_ENET       IXP2000_BOARD_IRQ(0)
+#define IRQ_IXDP2800_INGRESS_NPU       IXP2000_BOARD_IRQ(1)
+#define IRQ_IXDP2800_PMC               IXP2000_BOARD_IRQ(2)
+#define IRQ_IXDP2800_FABRIC_PCI                IXP2000_BOARD_IRQ(3)
+#define IRQ_IXDP2800_FABRIC            IXP2000_BOARD_IRQ(4)
+#define IRQ_IXDP2800_MEDIA             IXP2000_BOARD_IRQ(5)
+
+#define        NR_IXDP2800_IRQS                ((IRQ_IXDP2800_MEDIA)+1)
+#define        IXDP2800_NR_IRQS                NR_IXDP2800_IRQS - NR_IXP2000_IRQS
+
+/* 
+ * IRQs on both IXDP2x01 boards
+ */
+#define IRQ_IXDP2X01_SPCI_DB_0         IXP2000_BOARD_IRQ(2)
+#define IRQ_IXDP2X01_SPCI_DB_1         IXP2000_BOARD_IRQ(3)
+#define IRQ_IXDP2X01_SPCI_PMC_INTA     IXP2000_BOARD_IRQ(4)
+#define IRQ_IXDP2X01_SPCI_PMC_INTB     IXP2000_BOARD_IRQ(5)
+#define IRQ_IXDP2X01_SPCI_PMC_INTC     IXP2000_BOARD_IRQ(6)
+#define IRQ_IXDP2X01_SPCI_PMC_INTD     IXP2000_BOARD_IRQ(7)
+#define IRQ_IXDP2X01_SPCI_FIC_INT      IXP2000_BOARD_IRQ(8)
+#define IRQ_IXDP2X01_IPMI_FROM         IXP2000_BOARD_IRQ(16)
+#define IRQ_IXDP2X01_125US             IXP2000_BOARD_IRQ(17)
+#define IRQ_IXDP2X01_DB_0_ADD          IXP2000_BOARD_IRQ(18)
+#define IRQ_IXDP2X01_DB_1_ADD          IXP2000_BOARD_IRQ(19)
+#define IRQ_IXDP2X01_UART1             IXP2000_BOARD_IRQ(21)
+#define IRQ_IXDP2X01_UART2             IXP2000_BOARD_IRQ(22)
+#define IRQ_IXDP2X01_FIC_ADD_INT       IXP2000_BOARD_IRQ(24)
+#define IRQ_IXDP2X01_CS8900            IXP2000_BOARD_IRQ(25)
+#define IRQ_IXDP2X01_BBSRAM            IXP2000_BOARD_IRQ(26)
+
+#define IXDP2X01_VALID_IRQ_MASK ( \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_DB_0) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_DB_1) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTA) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTB) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTC) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTD) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_FIC_INT) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_IPMI_FROM) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_125US) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_DB_0_ADD) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_DB_1_ADD) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_UART1) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_UART2) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_FIC_ADD_INT) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_CS8900) | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_BBSRAM) )
+
+/* 
+ * IXDP2401 specific IRQs
+ */
+#define IRQ_IXDP2401_INTA_82546                IXP2000_BOARD_IRQ(0)
+#define IRQ_IXDP2401_INTB_82546                IXP2000_BOARD_IRQ(1)
+
+#define        IXDP2401_VALID_IRQ_MASK ( \
+               IXDP2X01_VALID_IRQ_MASK | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2401_INTA_82546) |\
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2401_INTB_82546))
+
+/*
+ * IXDP2801-specific IRQs
+ */
+#define IRQ_IXDP2801_RIV               IXP2000_BOARD_IRQ(0)
+#define IRQ_IXDP2801_CNFG_MEDIA                IXP2000_BOARD_IRQ(27)
+#define IRQ_IXDP2801_CLOCK_REF         IXP2000_BOARD_IRQ(28)
+
+#define        IXDP2801_VALID_IRQ_MASK ( \
+               IXDP2X01_VALID_IRQ_MASK | \
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_RIV) |\
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_CNFG_MEDIA) |\
+               IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_CLOCK_REF))
+
+#define        NR_IXDP2X01_IRQS                ((IRQ_IXDP2801_CLOCK_REF) + 1)
+
+#endif /*_IRQS_H*/
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x00.h b/include/asm-arm/arch-ixp2000/ixdp2x00.h
new file mode 100644 (file)
index 0000000..e017826
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * include/asm-arm/arch-ixp2000/ixdp2x00.h
+ *
+ * Register and other defines for IXDP2[48]00 platforms
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+#ifndef _IXDP2X00_H_
+#define _IXDP2X00_H_
+
+/*
+ * On board CPLD memory map
+ */
+#define IXDP2X00_PHYS_CPLD_BASE                0xc7000000
+#define IXDP2X00_VIRT_CPLD_BASE                0xfefdd000
+#define IXDP2X00_CPLD_SIZE             0x00001000
+
+
+#define IXDP2X00_CPLD_REG(x)   \
+       (volatile unsigned long *)(IXDP2X00_VIRT_CPLD_BASE | x)
+
+/*
+ * IXDP2400 CPLD registers
+ */
+#define IXDP2400_CPLD_SYSLED           IXDP2X00_CPLD_REG(0x0)  
+#define IXDP2400_CPLD_DISP_DATA                IXDP2X00_CPLD_REG(0x4)
+#define IXDP2400_CPLD_CLOCK_SPEED      IXDP2X00_CPLD_REG(0x8)
+#define IXDP2400_CPLD_INT_STAT         IXDP2X00_CPLD_REG(0xc)
+#define IXDP2400_CPLD_REV              IXDP2X00_CPLD_REG(0x10)
+#define IXDP2400_CPLD_SYS_CLK_M                IXDP2X00_CPLD_REG(0x14)
+#define IXDP2400_CPLD_SYS_CLK_N                IXDP2X00_CPLD_REG(0x18)
+#define IXDP2400_CPLD_INT_MASK         IXDP2X00_CPLD_REG(0x48)
+
+/*
+ * IXDP2800 CPLD registers
+ */
+#define IXDP2800_CPLD_INT_STAT         IXDP2X00_CPLD_REG(0x0)
+#define IXDP2800_CPLD_INT_MASK         IXDP2X00_CPLD_REG(0x140)
+
+
+#define        IXDP2X00_GPIO_I2C_ENABLE        0x02
+#define        IXDP2X00_GPIO_SCL               0x07
+#define        IXDP2X00_GPIO_SDA               0x06
+
+/*
+ * PCI devfns for on-board devices. We need these to be able to
+ * properly translte IRQs and for device removal.
+ */
+#define        IXDP2400_SLAVE_ENET_DEVFN       0x18    /* Bus 1 */
+#define        IXDP2400_MASTER_ENET_DEVFN      0x20    /* Bus 1 */
+#define        IXDP2400_MEDIA_DEVFN            0x28    /* Bus 1 */
+#define        IXDP2400_SWITCH_FABRIC_DEVFN    0x30    /* Bus 1 */
+
+#define        IXDP2800_SLAVE_ENET_DEVFN       0x20    /* Bus 1 */
+#define        IXDP2800_MASTER_ENET_DEVFN      0x18    /* Bus 1 */
+#define        IXDP2800_SWITCH_FABRIC_DEVFN    0x30    /* Bus 1 */
+
+#define        IXDP2X00_P2P_DEVFN              0x20    /* Bus 0 */
+#define        IXDP2X00_21555_DEVFN            0x30    /* Bus 0 */
+#define IXDP2X00_SLAVE_NPU_DEVFN       0x28    /* Bus 1 */
+#define        IXDP2X00_PMC_DEVFN              0x38    /* Bus 1 */
+#define IXDP2X00_MASTER_NPU_DEVFN      0x38    /* Bus 1 */
+
+#ifndef __ASSEMBLY__
+/*
+ * Master NPU will always have flash and be PCI master.
+ * Slave NPU may or may not have flash but will never be PCI master.
+ */
+static inline unsigned int ixdp2x00_master_npu(void)
+{
+       return ((ixp2000_has_flash()) && (ixp2000_is_pcimaster()));
+}
+
+/*
+ * Helper functions used by ixdp2400 and ixdp2800 specific code
+ */
+void ixdp2x00_init_irq(volatile unsigned long*, volatile unsigned long *, unsigned long);
+void ixdp2x00_slave_pci_postinit(void);
+void ixdp2x00_init_machine(void);
+void ixdp2x00_map_io(void);
+
+#endif
+
+#endif /*_IXDP2X00_H_ */
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h
new file mode 100644 (file)
index 0000000..626ed6b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * include/asm/arch/ixdp2x01.h
+ *
+ * Platform definitions for IXDP2X01 && IXDP2801 systems
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista Software, Inc. 
+ *
+ * Based on original code Copyright (c) 2002-2003 Intel Corporation
+ * 
+ * This file is licensed under  the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __IXDP2X01_H__
+#define __IXDP2X01_H__
+
+#define        IXDP2X01_PHYS_CPLD_BASE         0xc6024000
+#define        IXDP2X01_VIRT_CPLD_BASE         0xfefdd000
+#define        IXDP2X01_CPLD_REGION_SIZE       0x1000
+
+#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile u32*)(IXDP2X01_VIRT_CPLD_BASE | reg)
+#define IXDP2X01_CPLD_PHYS_REG(reg) (volatile u32*)(IXDP2X01_PHYS_CPLD_BASE | reg)
+
+#define IXDP2X01_UART1_VIRT_BASE       IXDP2X01_CPLD_VIRT_REG(0x40)
+#define IXDP2X01_UART1_PHYS_BASE       IXDP2X01_CPLD_PHYS_REG(0x40)
+
+#define IXDP2X01_UART2_VIRT_BASE       IXDP2X01_CPLD_VIRT_REG(0x60)
+#define IXDP2X01_UART2_PHYS_BASE       IXDP2X01_CPLD_PHYS_REG(0x60)
+
+#define IXDP2X01_CS8900_VIRT_BASE      IXDP2X01_CPLD_VIRT_REG(0x80)
+#define IXDP2X01_CS8900_VIRT_END       (IXDP2X01_CS8900_VIRT_BASE + 16)
+
+#define IXDP2X01_CPLD_RESET_REG         IXDP2X01_CPLD_VIRT_REG(0x00)
+#define IXDP2X01_INT_MASK_SET_REG      IXDP2X01_CPLD_VIRT_REG(0x08)
+#define IXDP2X01_INT_STAT_REG          IXDP2X01_CPLD_VIRT_REG(0x0C)
+#define IXDP2X01_INT_RAW_REG           IXDP2X01_CPLD_VIRT_REG(0x10) 
+#define IXDP2X01_INT_MASK_CLR_REG      IXDP2X01_INT_RAW_REG
+#define IXDP2X01_INT_SIM_REG           IXDP2X01_CPLD_VIRT_REG(0x14)
+
+#define IXDP2X01_CPLD_FLASH_REG                IXDP2X01_CPLD_VIRT_REG(0x20)
+
+#define IXDP2X01_CPLD_FLASH_INTERN     0x8000
+#define IXDP2X01_CPLD_FLASH_BANK_MASK  0xF
+#define IXDP2X01_FLASH_WINDOW_BITS     25
+#define IXDP2X01_FLASH_WINDOW_SIZE     (1 << IXDP2X01_FLASH_WINDOW_BITS)
+#define IXDP2X01_FLASH_WINDOW_MASK     (IXDP2X01_FLASH_WINDOW_SIZE - 1)
+
+#define        IXDP2X01_UART_CLK               1843200
+
+#endif /* __IXDP2x01_H__ */
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
new file mode 100644 (file)
index 0000000..9c8b21d
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * include/asm-arm/arch-ixp2000/ixp2000-regs.h
+ *
+ * Chipset register definitions for IXP2400/2800 based systems.
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ *
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright (C) 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+#ifndef _IXP2000_REGS_H_
+#define _IXP2000_REGS_H_
+
+/* 
+ * Static I/O regions. The manual defines each region as being several
+ * MB in size, but all the registers are within the first 4K, so there's
+ * no purpose in mapping the whole region in.
+ */
+#define        IXP2000_SLOWPORT_CSR_PHYS_BASE  0xc0080000
+#define        IXP2000_SLOWPORT_CSR_VIRT_BASE  0xfefff000
+#define        IXP2000_SLOWPORT_CSR_SIZE       0x1000
+
+#define        IXP2000_GLOBAL_REG_PHYS_BASE    0xc0004000
+#define        IXP2000_GLOBAL_REG_VIRT_BASE    0xfeffe000
+#define        IXP2000_GLOBAL_REG_SIZE         0x1000
+
+#define        IXP2000_UART_PHYS_BASE          0xc0030000
+#define        IXP2000_UART_VIRT_BASE          0xfef30000
+#define IXP2000_UART_SIZE              0x1000
+
+#define        IXP2000_TIMER_PHYS_BASE         0xc0020000
+#define        IXP2000_TIMER_VIRT_BASE         0xfeffc000
+#define        IXP2000_TIMER_SIZE              0x1000
+
+#define        IXP2000_GPIO_PHYS_BASE          0xc0010000
+#define        IXP2000_GPIO_VIRT_BASE          0xfeffb000
+#define        IXP2000_GPIO_SIZE               0x1000
+
+#define IXP2000_INTCTL_PHYS_BASE       0xd6000000
+#define        IXP2000_INTCTL_VIRT_BASE        0xfeffa000
+#define        IXP2000_INTCTL_SIZE             0x01000
+
+#define IXP2000_PCI_CREG_PHYS_BASE     0xde000000
+#define        IXP2000_PCI_CREG_VIRT_BASE      0xfeff0000
+#define        IXP2000_PCI_CREG_SIZE           0x1000
+
+#define IXP2000_PCI_CSR_PHYS_BASE      0xdf000000
+#define        IXP2000_PCI_CSR_VIRT_BASE       0xfefde000
+#define        IXP2000_PCI_CSR_SIZE            0x1000
+
+#define IXP2000_PCI_IO_PHYS_BASE       0xd8000000
+#define        IXP2000_PCI_IO_VIRT_BASE        0xfd000000
+#define IXP2000_PCI_IO_SIZE            0x01000000
+
+#define IXP2000_PCI_CFG0_PHYS_BASE     0xda000000
+#define IXP2000_PCI_CFG0_VIRT_BASE     0xfc000000
+#define IXP2000_PCI_CFG0_SIZE          0x01000000
+
+#define IXP2000_PCI_CFG1_PHYS_BASE     0xdb000000
+#define IXP2000_PCI_CFG1_VIRT_BASE     0xfb000000
+#define IXP2000_PCI_CFG1_SIZE          0x01000000
+
+
+/* 
+ * Timers
+ */
+#define        IXP2000_TIMER_REG(x)            ((volatile unsigned long*)(IXP2000_TIMER_VIRT_BASE | (x)))
+/* Timer control */
+#define        IXP2000_T1_CTL                  IXP2000_TIMER_REG(0x00)
+#define        IXP2000_T2_CTL                  IXP2000_TIMER_REG(0x04)
+#define        IXP2000_T3_CTL                  IXP2000_TIMER_REG(0x08)
+#define        IXP2000_T4_CTL                  IXP2000_TIMER_REG(0x0c)
+/* Store initial value */
+#define        IXP2000_T1_CLD                  IXP2000_TIMER_REG(0x10)
+#define        IXP2000_T2_CLD                  IXP2000_TIMER_REG(0x14)
+#define        IXP2000_T3_CLD                  IXP2000_TIMER_REG(0x18)
+#define        IXP2000_T4_CLD                  IXP2000_TIMER_REG(0x1c)
+/* Read current value */
+#define        IXP2000_T1_CSR                  IXP2000_TIMER_REG(0x20)
+#define        IXP2000_T2_CSR                  IXP2000_TIMER_REG(0x24)
+#define        IXP2000_T3_CSR                  IXP2000_TIMER_REG(0x28)
+#define        IXP2000_T4_CSR                  IXP2000_TIMER_REG(0x2c)
+/* Clear associated timer interrupt */
+#define        IXP2000_T1_CLR                  IXP2000_TIMER_REG(0x30)
+#define        IXP2000_T2_CLR                  IXP2000_TIMER_REG(0x34)
+#define        IXP2000_T3_CLR                  IXP2000_TIMER_REG(0x38)
+#define        IXP2000_T4_CLR                  IXP2000_TIMER_REG(0x3c)
+/* Timer watchdog enable for T4 */
+#define        IXP2000_TWDE                    IXP2000_TIMER_REG(0x40)
+
+#define        WDT_ENABLE                      0x00000001
+#define        TIMER_DIVIDER_256               0x00000008
+#define        TIMER_ENABLE                    0x00000080
+
+/*
+ * Interrupt controller registers
+ */
+#define IXP2000_INTCTL_REG(x)          (volatile unsigned long*)(IXP2000_INTCTL_VIRT_BASE | (x))
+#define IXP2000_IRQ_STATUS             IXP2000_INTCTL_REG(0x08)
+#define IXP2000_IRQ_ENABLE             IXP2000_INTCTL_REG(0x10)
+#define IXP2000_IRQ_ENABLE_SET         IXP2000_INTCTL_REG(0x10)
+#define IXP2000_IRQ_ENABLE_CLR         IXP2000_INTCTL_REG(0x18)
+#define IXP2000_FIQ_ENABLE_CLR         IXP2000_INTCTL_REG(0x14)
+#define IXP2000_IRQ_ERR_STATUS         IXP2000_INTCTL_REG(0x24)
+#define IXP2000_IRQ_ERR_ENABLE_SET     IXP2000_INTCTL_REG(0x2c)
+#define IXP2000_FIQ_ERR_ENABLE_CLR     IXP2000_INTCTL_REG(0x30)
+#define IXP2000_IRQ_ERR_ENABLE_CLR     IXP2000_INTCTL_REG(0x34)
+
+/*
+ * Mask of valid IRQs in the 32-bit IRQ register. We use
+ * this to mark certain IRQs as being in-valid.
+ */
+#define        IXP2000_VALID_IRQ_MASK  0x0f0fffff
+
+/*
+ * PCI config register access from core
+ */
+#define IXP2000_PCI_CREG(x)            (volatile unsigned long*)(IXP2000_PCI_CREG_VIRT_BASE | (x))
+#define IXP2000_PCI_CMDSTAT            IXP2000_PCI_CREG(0x04)
+#define IXP2000_PCI_CSR_BAR            IXP2000_PCI_CREG(0x10)
+#define IXP2000_PCI_SRAM_BAR           IXP2000_PCI_CREG(0x14)
+#define IXP2000_PCI_SDRAM_BAR          IXP2000_PCI_CREG(0x18)
+
+/*
+ * PCI CSRs
+ */
+#define IXP2000_PCI_CSR(x)             (volatile unsigned long*)(IXP2000_PCI_CSR_VIRT_BASE | (x))
+
+/*
+ * PCI outbound interrupts
+ */
+#define IXP2000_PCI_OUT_INT_STATUS     IXP2000_PCI_CSR(0x30)
+#define IXP2000_PCI_OUT_INT_MASK       IXP2000_PCI_CSR(0x34)
+/*
+ * PCI communications
+ */
+#define IXP2000_PCI_MAILBOX0           IXP2000_PCI_CSR(0x50)
+#define IXP2000_PCI_MAILBOX1           IXP2000_PCI_CSR(0x54)
+#define IXP2000_PCI_MAILBOX2           IXP2000_PCI_CSR(0x58)
+#define IXP2000_PCI_MAILBOX3           IXP2000_PCI_CSR(0x5C)
+#define IXP2000_XSCALE_DOORBELL                IXP2000_PCI_CSR(0x60)
+#define IXP2000_XSCALE_DOORBELL_SETUP  IXP2000_PCI_CSR(0x64)
+#define IXP2000_PCI_DOORBELL           IXP2000_PCI_CSR(0x70)
+#define IXP2000_PCI_DOORBELL_SETUP     IXP2000_PCI_CSR(0x74)
+
+/*
+ * DMA engines
+ */
+#define IXP2000_PCI_CH1_BYTE_CNT       IXP2000_PCI_CSR(0x80)
+#define IXP2000_PCI_CH1_ADDR           IXP2000_PCI_CSR(0x84)
+#define IXP2000_PCI_CH1_DRAM_ADDR      IXP2000_PCI_CSR(0x88)
+#define IXP2000_PCI_CH1_DESC_PTR       IXP2000_PCI_CSR(0x8C)
+#define IXP2000_PCI_CH1_CNTRL          IXP2000_PCI_CSR(0x90)
+#define IXP2000_PCI_CH1_ME_PARAM       IXP2000_PCI_CSR(0x94)
+#define IXP2000_PCI_CH2_BYTE_CNT       IXP2000_PCI_CSR(0xA0)
+#define IXP2000_PCI_CH2_ADDR           IXP2000_PCI_CSR(0xA4)
+#define IXP2000_PCI_CH2_DRAM_ADDR      IXP2000_PCI_CSR(0xA8)
+#define IXP2000_PCI_CH2_DESC_PTR       IXP2000_PCI_CSR(0xAC)
+#define IXP2000_PCI_CH2_CNTRL          IXP2000_PCI_CSR(0xB0)
+#define IXP2000_PCI_CH2_ME_PARAM       IXP2000_PCI_CSR(0xB4)
+#define IXP2000_PCI_CH3_BYTE_CNT       IXP2000_PCI_CSR(0xC0)
+#define IXP2000_PCI_CH3_ADDR           IXP2000_PCI_CSR(0xC4)
+#define IXP2000_PCI_CH3_DRAM_ADDR      IXP2000_PCI_CSR(0xC8)
+#define IXP2000_PCI_CH3_DESC_PTR       IXP2000_PCI_CSR(0xCC)
+#define IXP2000_PCI_CH3_CNTRL          IXP2000_PCI_CSR(0xD0)
+#define IXP2000_PCI_CH3_ME_PARAM       IXP2000_PCI_CSR(0xD4)
+#define IXP2000_DMA_INF_MODE           IXP2000_PCI_CSR(0xE0)
+/*
+ * Size masks for BARs
+ */
+#define IXP2000_PCI_SRAM_BASE_ADDR_MASK        IXP2000_PCI_CSR(0xFC)
+#define IXP2000_PCI_DRAM_BASE_ADDR_MASK        IXP2000_PCI_CSR(0x100)
+/*
+ * Control and uEngine related
+ */
+#define IXP2000_PCI_CONTROL            IXP2000_PCI_CSR(0x13C)
+#define IXP2000_PCI_ADDR_EXT           IXP2000_PCI_CSR(0x140)
+#define IXP2000_PCI_ME_PUSH_STATUS     IXP2000_PCI_CSR(0x148)
+#define IXP2000_PCI_ME_PUSH_EN         IXP2000_PCI_CSR(0x14C)
+#define IXP2000_PCI_ERR_STATUS         IXP2000_PCI_CSR(0x150)
+#define IXP2000_PCI_ERR_ENABLE         IXP2000_PCI_CSR(0x154)
+/*
+ * Inbound PCI interrupt control
+ */
+#define IXP2000_PCI_XSCALE_INT_STATUS  IXP2000_PCI_CSR(0x158)
+#define IXP2000_PCI_XSCALE_INT_ENABLE  IXP2000_PCI_CSR(0x15C)
+
+#define IXP2000_PCICNTL_PNR            (1<<17) /* PCI not Reset bit of PCI_CONTROL */
+#define IXP2000_PCICNTL_PCF            (1<<28) /* PCI Centrolfunction bit */
+#define IXP2000_XSCALE_INT             (1<<1)  /* Interrupt from  XScale to PCI */
+
+/* These are from the IRQ register in the PCI ISR register */
+#define PCI_CONTROL_BE_DEO             (1 << 22)       /* Big Endian Data Enable Out */
+#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 IXP2000_PCI_RST_REL            (1 << 2)
+#define CFG_RST_DIR                    (*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF)
+#define CFG_PCI_BOOT_HOST              (1 << 2)
+#define CFG_BOOT_PROM                  (1 << 1)
+
+/*
+ * SlowPort CSRs
+ *
+ * The slowport is used to access things like flash, SONET framer control
+ * ports, slave microprocessors, CPLDs, and others of chip memory mapped
+ * peripherals.
+ */
+#define        SLOWPORT_CSR(x)         (volatile unsigned long*)(IXP2000_SLOWPORT_CSR_VIRT_BASE | (x))
+
+#define        IXP2000_SLOWPORT_CCR            SLOWPORT_CSR(0x00)
+#define        IXP2000_SLOWPORT_WTC1           SLOWPORT_CSR(0x04)
+#define        IXP2000_SLOWPORT_WTC2           SLOWPORT_CSR(0x08)
+#define        IXP2000_SLOWPORT_RTC1           SLOWPORT_CSR(0x0c)
+#define        IXP2000_SLOWPORT_RTC2           SLOWPORT_CSR(0x10)
+#define        IXP2000_SLOWPORT_FSR            SLOWPORT_CSR(0x14)
+#define        IXP2000_SLOWPORT_PCR            SLOWPORT_CSR(0x18)
+#define        IXP2000_SLOWPORT_ADC            SLOWPORT_CSR(0x1C)
+#define        IXP2000_SLOWPORT_FAC            SLOWPORT_CSR(0x20)
+#define        IXP2000_SLOWPORT_FRM            SLOWPORT_CSR(0x24)
+#define        IXP2000_SLOWPORT_FIN            SLOWPORT_CSR(0x28)
+
+/*
+ * CCR values.  
+ * The CCR configures the clock division for the slowport interface.
+ */
+#define        SLOWPORT_CCR_DIV_1              0x00
+#define        SLOWPORT_CCR_DIV_2              0x01
+#define        SLOWPORT_CCR_DIV_4              0x02
+#define        SLOWPORT_CCR_DIV_6              0x03
+#define        SLOWPORT_CCR_DIV_8              0x04
+#define        SLOWPORT_CCR_DIV_10             0x05
+#define        SLOWPORT_CCR_DIV_12             0x06
+#define        SLOWPORT_CCR_DIV_14             0x07
+#define        SLOWPORT_CCR_DIV_16             0x08
+#define        SLOWPORT_CCR_DIV_18             0x09
+#define        SLOWPORT_CCR_DIV_20             0x0a
+#define        SLOWPORT_CCR_DIV_22             0x0b
+#define        SLOWPORT_CCR_DIV_24             0x0c
+#define        SLOWPORT_CCR_DIV_26             0x0d
+#define        SLOWPORT_CCR_DIV_28             0x0e
+#define        SLOWPORT_CCR_DIV_30             0x0f
+
+/*
+ * PCR values.  PCR configure the mode of the interfac3
+ */
+#define        SLOWPORT_MODE_FLASH             0x00
+#define        SLOWPORT_MODE_LUCENT            0x01
+#define        SLOWPORT_MODE_PMC_SIERRA        0x02
+#define        SLOWPORT_MODE_INTEL_UP          0x03
+#define        SLOWPORT_MODE_MOTOROLA_UP       0x04
+
+/*
+ * ADC values.  Defines data and address bus widths
+ */
+#define        SLOWPORT_ADDR_WIDTH_8           0x00
+#define        SLOWPORT_ADDR_WIDTH_16          0x01
+#define        SLOWPORT_ADDR_WIDTH_24          0x02
+#define        SLOWPORT_ADDR_WIDTH_32          0x03
+#define        SLOWPORT_DATA_WIDTH_8           0x00
+#define        SLOWPORT_DATA_WIDTH_16          0x10
+#define        SLOWPORT_DATA_WIDTH_24          0x20
+#define        SLOWPORT_DATA_WIDTH_32          0x30
+
+/*
+ * Masks and shifts for various fields in the WTC and RTC registers
+ */
+#define        SLOWPORT_WRTC_MASK_HD           0x0003
+#define        SLOWPORT_WRTC_MASK_SU           0x003c
+#define        SLOWPORT_WRTC_MASK_PW           0x03c0
+
+#define        SLOWPORT_WRTC_SHIFT_HD          0x00
+#define        SLOWPORT_WRTC_SHIFT_SU          0x02
+#define        SLOWPORT_WRTC_SHFIT_PW          0x06
+
+
+/*
+ * GPIO registers & GPIO interface
+ */
+#define IXP2000_GPIO_REG(x)            ((volatile unsigned long*)(IXP2000_GPIO_VIRT_BASE+(x)))
+#define IXP2000_GPIO_PLR               IXP2000_GPIO_REG(0x00)
+#define IXP2000_GPIO_PDPR              IXP2000_GPIO_REG(0x04)
+#define IXP2000_GPIO_PDSR              IXP2000_GPIO_REG(0x08)
+#define IXP2000_GPIO_PDCR              IXP2000_GPIO_REG(0x0c)
+#define IXP2000_GPIO_POPR              IXP2000_GPIO_REG(0x10)
+#define IXP2000_GPIO_POSR              IXP2000_GPIO_REG(0x14)
+#define IXP2000_GPIO_POCR              IXP2000_GPIO_REG(0x18)
+#define IXP2000_GPIO_REDR              IXP2000_GPIO_REG(0x1c)
+#define IXP2000_GPIO_FEDR              IXP2000_GPIO_REG(0x20)
+#define IXP2000_GPIO_EDSR              IXP2000_GPIO_REG(0x24)
+#define IXP2000_GPIO_LSHR              IXP2000_GPIO_REG(0x28)
+#define IXP2000_GPIO_LSLR              IXP2000_GPIO_REG(0x2c)
+#define IXP2000_GPIO_LDSR              IXP2000_GPIO_REG(0x30)
+#define IXP2000_GPIO_INER              IXP2000_GPIO_REG(0x34)
+#define IXP2000_GPIO_INSR              IXP2000_GPIO_REG(0x38)
+#define IXP2000_GPIO_INCR              IXP2000_GPIO_REG(0x3c)
+#define IXP2000_GPIO_INST              IXP2000_GPIO_REG(0x40)
+
+/*
+ * "Global" registers...whatever that's supposed to mean.
+ */
+#define GLOBAL_REG_BASE                        (IXP2000_GLOBAL_REG_VIRT_BASE + 0x0a00)
+#define GLOBAL_REG(x)                  (volatile unsigned long*)(GLOBAL_REG_BASE | (x))
+
+#define IXP2000_PROD_ID                        GLOBAL_REG(0x00)
+
+#define IXP2000_MAJ_PROD_TYPE_MASK     0x001F0000
+#define IXP2000_MAJ_PROD_TYPE_IXP2000  0x00000000
+#define IXP2000_MIN_PROD_TYPE_MASK     0x0000FF00
+#define IXP2000_MIN_PROD_TYPE_IXP2400  0x00000200
+#define IXP2000_MIN_PROD_TYPE_IXP2850  0x00000100
+#define IXP2000_MIN_PROD_TYPE_IXP2800  0x00000000
+#define IXP2000_MAJ_REV_MASK           0x000000F0
+#define IXP2000_MIN_REV_MASK           0x0000000F
+#define IXP2000_PROD_ID_MASK           0xFFFFFFFF
+
+#define IXP2000_MISC_CONTROL           GLOBAL_REG(0x04)
+#define IXP2000_MSF_CLK_CNTRL                  GLOBAL_REG(0x08)
+#define IXP2000_RESET0                 GLOBAL_REG(0x0c)
+#define IXP2000_RESET1                 GLOBAL_REG(0x10)
+#define IXP2000_CCR                            GLOBAL_REG(0x14)
+#define        IXP2000_STRAP_OPTIONS           GLOBAL_REG(0x18)
+
+#define        RSTALL                          (1 << 16)
+#define        WDT_RESET_ENABLE                0x01000000
+
+
+#endif                         /* _IXP2000_H_ */
diff --git a/include/asm-arm/arch-ixp2000/memory.h b/include/asm-arm/arch-ixp2000/memory.h
new file mode 100644 (file)
index 0000000..d0f415c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * linux/include/asm-arm/arch-ixp2000/memory.h
+ *
+ * Copyright (c) 2002 Intel Corp.
+ * Copyright (c) 2003-2004 MontaVista Software, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET    (0x00000000UL)
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *             address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *             to an address that the kernel can use.
+ */
+#include <asm/arch/ixp2000-regs.h>
+
+#define __virt_to_bus(v) \
+       (((__virt_to_phys(v) - 0x0) + (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)))
+
+#define __bus_to_virt(b) \
+       __phys_to_virt((((b - (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)) + 0x0)))
+
+#endif
+
diff --git a/include/asm-arm/arch-ixp2000/param.h b/include/asm-arm/arch-ixp2000/param.h
new file mode 100644 (file)
index 0000000..2646d9e
--- /dev/null
@@ -0,0 +1,3 @@
+/*
+ *  linux/include/asm-arm/arch-ixp2000/param.h
+ */
diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h
new file mode 100644 (file)
index 0000000..9f4e315
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * include/asm-arh/arch-ixp2000/platform.h
+ *
+ * Various bits of code used by platform-level code.
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista Software, Inc. 
+ * 
+ * This file is licensed under  the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ */
+
+
+#ifndef __ASSEMBLY__
+
+/*
+ * The IXP2400 B0 silicon contains an errata that causes writes to 
+ * on-chip I/O register to not complete fully. What this means is
+ * that if you have a write to on-chip I/O followed by a back-to-back
+ * read or write, the first write will happend twice. OR...if it's
+ * not a back-to-back trasaction, the read or write will generate 
+ * incorrect data.
+ *
+ * The official work around for this is to set the on-chip I/O regions
+ * as XCB=101 and then force a read-back from the register.
+ *
+ */
+#if defined(CONFIG_ARCH_ENP2611) || defined(CONFIG_ARCH_IXDP2400) || defined(CONFIG_ARCH_IXDP2401)
+
+#include <asm/system.h>                /* Pickup local_irq_ functions */
+
+static inline void ixp2000_reg_write(volatile unsigned long *reg, unsigned long val)
+{
+       volatile unsigned long dummy;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       *reg = val;
+       barrier();
+       dummy = *reg;
+       local_irq_restore(flags);
+}
+#else
+#define        ixp2000_reg_write(reg, val) (*reg = val)
+#endif /* IXDP2400 || IXDP2401 */
+
+/*
+ * Boards may multiplex different devices on the 2nd channel of 
+ * the slowport interface that each need different configuration 
+ * settings.  For example, the IXDP2400 uses channel 2 on the interface 
+ * to access the CPLD, the switch fabric card, and te media card.  Each 
+ * one needs a different mode so drivers must save/restore the mode 
+ * before and after each operation.  
+ *
+ * acquire_slowport(&your_config);
+ * ...
+ * do slowport operations
+ * ...
+ * release_slowport();
+ *
+ * Note that while you have the slowport, you are holding a spinlock,
+ * so your code should be written as if you explicitly acquired a lock.
+ *
+ * The configuration only affects device 2 on the slowport, so the
+ * MTD map driver does not acquire/release the slowport.  
+ */
+struct slowport_cfg {
+       unsigned long CCR;      /* Clock divide */
+       unsigned long WTC;      /* Write Timing Control */
+       unsigned long RTC;      /* Read Timing Control */
+       unsigned long PCR;      /* Protocol Control Register */
+       unsigned long ADC;      /* Address/Data Width Control */
+};
+
+
+void ixp2000_acquire_slowport(struct slowport_cfg *, struct slowport_cfg *);
+void ixp2000_release_slowport(struct slowport_cfg *);
+
+/*
+ * IXP2400 A0/A1 and  IXP2800 A0/A1/A2 have broken slowport that requires
+ * tweaking of addresses in the MTD driver.
+ */
+static inline unsigned ixp2000_has_broken_slowport(void)
+{
+       unsigned long id = *IXP2000_PROD_ID;
+       unsigned long id_prod = id & (IXP2000_MAJ_PROD_TYPE_MASK |
+                                     IXP2000_MIN_PROD_TYPE_MASK);
+       return (((id_prod ==
+                 /* fixed in IXP2400-B0 */
+                 (IXP2000_MAJ_PROD_TYPE_IXP2000 |
+                  IXP2000_MIN_PROD_TYPE_IXP2400)) &&
+                ((id & IXP2000_MAJ_REV_MASK) == 0)) ||
+               ((id_prod ==
+                 /* fixed in IXP2800-B0 */
+                 (IXP2000_MAJ_PROD_TYPE_IXP2000 |
+                  IXP2000_MIN_PROD_TYPE_IXP2800)) &&
+                ((id & IXP2000_MAJ_REV_MASK) == 0)) ||
+               ((id_prod ==
+                 /* fixed in IXP2850-B0 */
+                 (IXP2000_MAJ_PROD_TYPE_IXP2000 |
+                  IXP2000_MIN_PROD_TYPE_IXP2850)) &&
+                ((id & IXP2000_MAJ_REV_MASK) == 0)));
+}
+
+static inline unsigned int ixp2000_has_flash(void)
+{
+       return ((*IXP2000_STRAP_OPTIONS) & (CFG_BOOT_PROM));
+}
+
+static inline unsigned int ixp2000_is_pcimaster(void)
+{
+       return ((*IXP2000_STRAP_OPTIONS) & (CFG_PCI_BOOT_HOST));
+}
+
+void ixp2000_map_io(void);
+void ixp2000_init_irq(void);
+void ixp2000_init_time(unsigned long);
+
+struct pci_sys_data;
+
+void ixp2000_pci_preinit(void);
+int ixp2000_pci_setup(int, struct pci_sys_data*);
+struct pci_bus* ixp2000_pci_scan_bus(int, struct pci_sys_data*);
+int ixp2000_pci_read_config(struct pci_bus*, unsigned int, int, int, u32 *);
+int ixp2000_pci_write_config(struct pci_bus*, unsigned int, int, int, u32);
+
+/*
+ * Several of the IXP2000 systems have banked flash so we need to extend the
+ * flash_platform_data structure with some private pointers
+ */
+struct ixp2000_flash_data {
+       struct flash_platform_data *platform_data;
+       int nr_banks;
+       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__ */
diff --git a/include/asm-arm/arch-ixp2000/system.h b/include/asm-arm/arch-ixp2000/system.h
new file mode 100644 (file)
index 0000000..ec72ba4
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-arm/arch-ixp2400/system.h
+ *
+ * Copyright (C) 2002 Intel Corp.
+ *
+ * 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 <asm/hardware.h>
+#include <asm/mach-types.h>
+
+static inline void arch_idle(void)
+{
+       cpu_do_idle();
+}
+
+static inline void arch_reset(char mode)
+{
+       cli();
+
+       if (machine_is_ixdp2401() || machine_is_ixdp2801()) {
+               *IXDP2X01_CPLD_FLASH_REG = ((0 >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN);
+               *IXDP2X01_CPLD_RESET_REG = 0xffffffff;
+       }
+
+       /*
+        * We do a reset all if we are PCI master. We could be a slave and we
+        * don't want to do anything funky on the PCI bus.
+        */
+       if (*IXP2000_STRAP_OPTIONS & CFG_PCI_BOOT_HOST) {
+               *(IXP2000_RESET0) |= (RSTALL);
+       }
+}
diff --git a/include/asm-arm/arch-ixp2000/timex.h b/include/asm-arm/arch-ixp2000/timex.h
new file mode 100644 (file)
index 0000000..b78a183
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * linux/include/asm-arm/arch-ixp2000/timex.h
+ *
+ * IXP2000 architecture timex specifications
+ */
+
+
+/*
+ * Default clock is 50MHz APB, but platform code can override this
+ */
+#define CLOCK_TICK_RATE        50000000
+
+
diff --git a/include/asm-arm/arch-ixp2000/uncompress.h b/include/asm-arm/arch-ixp2000/uncompress.h
new file mode 100644 (file)
index 0000000..3d3d5b2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * linux/include/asm-arm/arch-ixp2000/uncompress.h
+ *
+ *
+ * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2002 Intel 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 <linux/serial_reg.h>
+
+#define UART_BASE      0xc0030000
+
+#define PHYS(x)          ((volatile unsigned long *)(UART_BASE + x))
+
+#define UARTDR          PHYS(0x00)      /* Transmit reg dlab=0 */
+#define UARTDLL         PHYS(0x00)      /* Divisor Latch reg dlab=1*/
+#define UARTDLM         PHYS(0x04)      /* Divisor Latch reg dlab=1*/
+#define UARTIER         PHYS(0x04)      /* Interrupt enable reg */
+#define UARTFCR         PHYS(0x08)      /* FIFO control reg dlab =0*/
+#define UARTLCR         PHYS(0x0c)      /* Control reg */
+#define UARTSR          PHYS(0x14)      /* Status reg */
+
+
+static __inline__ void putc(char c)
+{
+       int j = 0x1000;
+
+       while (--j && !(*UARTSR & UART_LSR_THRE)); 
+       *UARTDR = c;
+}
+
+static void putstr(const char *s)
+{
+       while (*s)
+       {
+               putc(*s);
+               if (*s == '\n')
+                       putc('\r');
+               s++;
+       }
+}
+
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/include/asm-arm/arch-ixp2000/vmalloc.h b/include/asm-arm/arch-ixp2000/vmalloc.h
new file mode 100644 (file)
index 0000000..f2705a8
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/include/asm-arm/arch-ixp2000/vmalloc.h
+ *
+ * Author: Naeem Afzal <naeem.m.afzal@intel.com>
+ *
+ * Copyright 2002 Intel 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.
+ *
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET     (8*1024*1024)
+#define VMALLOC_START      (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x)   ((unsigned long)(x))
+#define VMALLOC_END        0xfb000000
diff --git a/include/asm-arm/arch-omap/cpu.h b/include/asm-arm/arch-omap/cpu.h
new file mode 100644 (file)
index 0000000..e878671
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * linux/include/asm-arm/arch-omap/cpu.h
+ *
+ * OMAP cpu type detection
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ *
+ * Written by Tony Lindgren <tony.lindgren@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ASM_ARCH_OMAP_CPU_H
+#define __ASM_ARCH_OMAP_CPU_H
+
+extern unsigned int system_rev;
+
+#define OMAP_DIE_ID_0          0xfffe1800
+#define OMAP_DIE_ID_1          0xfffe1804
+#define OMAP_PRODUCTION_ID_0   0xfffe2000
+#define OMAP_PRODUCTION_ID_1   0xfffe2004
+#define OMAP32_ID_0            0xfffed400
+#define OMAP32_ID_1            0xfffed404
+
+/*
+ * Test if multicore OMAP support is needed
+ */
+#undef MULTI_OMAP
+#undef OMAP_NAME
+
+#ifdef CONFIG_ARCH_OMAP730
+# ifdef OMAP_NAME
+#  undef  MULTI_OMAP
+#  define MULTI_OMAP
+# else
+#  define OMAP_NAME omap730
+# endif
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+# ifdef OMAP_NAME
+#  undef  MULTI_OMAP
+#  define MULTI_OMAP
+# else
+#  define OMAP_NAME omap1510
+# endif
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+# ifdef OMAP_NAME
+#  undef  MULTI_OMAP
+#  define MULTI_OMAP
+# else
+#  define OMAP_NAME omap1610
+# endif
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+# ifdef OMAP_NAME
+#  undef  MULTI_OMAP
+#  define MULTI_OMAP
+# else
+#  define OMAP_NAME omap1710
+# endif
+#endif
+
+/*
+ * Generate various OMAP cpu specific macros, and cpu class
+ * specific macros
+ */
+#define GET_OMAP_TYPE  ((system_rev >> 24) & 0xff)
+#define GET_OMAP_CLASS (system_rev & 0xff)
+
+#define IS_OMAP_TYPE(type, id)                         \
+static inline int is_omap ##type (void)                        \
+{                                                      \
+       return (GET_OMAP_TYPE == (id)) ? 1 : 0;         \
+}
+
+#define IS_OMAP_CLASS(class, id)                       \
+static inline int is_omap ##class (void)               \
+{                                                      \
+       return (GET_OMAP_CLASS == (id)) ? 1 : 0;        \
+}
+
+IS_OMAP_TYPE(730, 0x07)
+IS_OMAP_TYPE(1510, 0x15)
+IS_OMAP_TYPE(1610, 0x16)
+IS_OMAP_TYPE(5912, 0x16)
+IS_OMAP_TYPE(1710, 0x17)
+IS_OMAP_TYPE(2420, 0x24)
+
+IS_OMAP_CLASS(7xx, 0x07)
+IS_OMAP_CLASS(15xx, 0x15)
+IS_OMAP_CLASS(16xx, 0x16)
+IS_OMAP_CLASS(24xx, 0x24)
+
+/*
+ * Macros to group OMAP types into cpu classes.
+ * These can be used in most places.
+ * cpu_is_omap15xx():  True for 1510 and 5910
+ * cpu_is_omap16xx():  True for 1610, 5912 and 1710
+ */
+#if defined(MULTI_OMAP)
+# define cpu_is_omap7xx()              is_omap7xx()
+# define cpu_is_omap15xx()             is_omap15xx()
+# if !(defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_ARCH_OMAP730))
+#  define cpu_is_omap16xx()            1
+# else
+#  define cpu_is_omap16xx()            is_omap16xx()
+# endif
+#else
+# if defined(CONFIG_ARCH_OMAP730)
+#  define cpu_is_omap7xx()             1
+# else
+#  define cpu_is_omap7xx()             0
+# endif
+# if defined(CONFIG_ARCH_OMAP1510)
+#  define cpu_is_omap15xx()            1
+# else
+#  define cpu_is_omap15xx()            0
+# endif
+# if defined(CONFIG_ARCH_OMAP16XX)
+#  define cpu_is_omap16xx()            1
+# else
+#  define cpu_is_omap16xx()            0
+# endif
+#endif
+
+#if defined(MULTI_OMAP)
+# define cpu_is_omap730()              is_omap730()
+# define cpu_is_omap1510()             is_omap1510()
+# define cpu_is_omap1610()             is_omap1610()
+# define cpu_is_omap5912()             is_omap5912()
+# define cpu_is_omap1710()             is_omap1710()
+#else
+# if defined(CONFIG_ARCH_OMAP730)
+#  define cpu_is_omap730()             1
+# else
+#  define cpu_is_omap730()             0
+# endif
+# if defined(CONFIG_ARCH_OMAP1510)
+#  define cpu_is_omap1510()            1
+# else
+#  define cpu_is_omap1510()            0
+# endif
+# if defined(CONFIG_ARCH_OMAP16XX)
+#  define cpu_is_omap1610()            1
+# else
+#  define cpu_is_omap1610()            0
+# endif
+# if defined(CONFIG_ARCH_OMAP16XX)
+#  define cpu_is_omap5912()            1
+# else
+#  define cpu_is_omap5912()            0
+# endif
+# if defined(CONFIG_ARCH_OMAP16XX)
+# define cpu_is_omap1610()             is_omap1610()
+# define cpu_is_omap5912()             is_omap5912()
+# define cpu_is_omap1710()             is_omap1710()
+# else
+# define cpu_is_omap1610()             0
+# define cpu_is_omap5912()             0
+# define cpu_is_omap1710()             0
+# endif
+# if defined(CONFIG_ARCH_OMAP2420)
+#  define cpu_is_omap2420()            1
+# else
+#  define cpu_is_omap2420()            0
+# endif
+#endif
+
+#endif
diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h
new file mode 100644 (file)
index 0000000..8e490e3
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * linux/include/asm-arm/arch-omap/gpio.h
+ *
+ * Defines for Multi-Channel Buffered Serial Port
+ *
+ * Copyright (C) 2002 RidgeRun, Inc.
+ * Author: Steve Johnson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __ASM_ARCH_OMAP_MCBSP_H
+#define __ASM_ARCH_OMAP_MCBSP_H
+
+#include <asm/arch/hardware.h>
+
+#define OMAP730_MCBSP1_BASE    0xfffb1000
+#define OMAP730_MCBSP2_BASE    0xfffb1800
+
+#define OMAP1510_MCBSP1_BASE   0xe1011000
+#define OMAP1510_MCBSP2_BASE   0xfffb1000
+#define OMAP1510_MCBSP3_BASE   0xe1017000
+
+#define OMAP1610_MCBSP1_BASE   0xe1011800
+#define OMAP1610_MCBSP2_BASE   0xfffb1000
+#define OMAP1610_MCBSP3_BASE   0xe1017000
+
+#define OMAP_MCBSP_REG_DRR2    0x00
+#define OMAP_MCBSP_REG_DRR1    0x02
+#define OMAP_MCBSP_REG_DXR2    0x04
+#define OMAP_MCBSP_REG_DXR1    0x06
+#define OMAP_MCBSP_REG_SPCR2   0x08
+#define OMAP_MCBSP_REG_SPCR1   0x0a
+#define OMAP_MCBSP_REG_RCR2    0x0c
+#define OMAP_MCBSP_REG_RCR1    0x0e
+#define OMAP_MCBSP_REG_XCR2    0x10
+#define OMAP_MCBSP_REG_XCR1    0x12
+#define OMAP_MCBSP_REG_SRGR2   0x14
+#define OMAP_MCBSP_REG_SRGR1   0x16
+#define OMAP_MCBSP_REG_MCR2    0x18
+#define OMAP_MCBSP_REG_MCR1    0x1a
+#define OMAP_MCBSP_REG_RCERA   0x1c
+#define OMAP_MCBSP_REG_RCERB   0x1e
+#define OMAP_MCBSP_REG_XCERA   0x20
+#define OMAP_MCBSP_REG_XCERB   0x22
+#define OMAP_MCBSP_REG_PCR0    0x24
+#define OMAP_MCBSP_REG_RCERC   0x26
+#define OMAP_MCBSP_REG_RCERD   0x28
+#define OMAP_MCBSP_REG_XCERC   0x2A
+#define OMAP_MCBSP_REG_XCERD   0x2C
+#define OMAP_MCBSP_REG_RCERE   0x2E
+#define OMAP_MCBSP_REG_RCERF   0x30
+#define OMAP_MCBSP_REG_XCERE   0x32
+#define OMAP_MCBSP_REG_XCERF   0x34
+#define OMAP_MCBSP_REG_RCERG   0x36
+#define OMAP_MCBSP_REG_RCERH   0x38
+#define OMAP_MCBSP_REG_XCERG   0x3A
+#define OMAP_MCBSP_REG_XCERH   0x3C
+
+#define OMAP_MAX_MCBSP_COUNT 3
+
+#define OMAP_MCBSP_READ(base, reg)             __raw_readw((base) + OMAP_MCBSP_REG_##reg)
+#define OMAP_MCBSP_WRITE(base, reg, val)       __raw_writew((val), (base) + OMAP_MCBSP_REG_##reg)
+
+/************************** McBSP SPCR1 bit definitions ***********************/
+#define RRST                   0x0001
+#define RRDY                   0x0002
+#define RFULL                  0x0004
+#define RSYNC_ERR              0x0008
+#define RINTM(value)           ((value)<<4)    /* bits 4:5 */
+#define ABIS                   0x0040
+#define DXENA                  0x0080
+#define CLKSTP(value)          ((value)<<11)   /* bits 11:12 */
+#define RJUST(value)           ((value)<<13)   /* bits 13:14 */
+#define DLB                    0x8000
+
+/************************** McBSP SPCR2 bit definitions ***********************/
+#define XRST           0x0001
+#define XRDY           0x0002
+#define XEMPTY         0x0004
+#define XSYNC_ERR      0x0008
+#define XINTM(value)   ((value)<<4)            /* bits 4:5 */
+#define GRST           0x0040
+#define FRST           0x0080
+#define SOFT           0x0100
+#define FREE           0x0200
+
+/************************** McBSP PCR bit definitions *************************/
+#define CLKRP          0x0001
+#define CLKXP          0x0002
+#define FSRP           0x0004
+#define FSXP           0x0008
+#define DR_STAT                0x0010
+#define DX_STAT                0x0020
+#define CLKS_STAT      0x0040
+#define SCLKME         0x0080
+#define CLKRM          0x0100
+#define CLKXM          0x0200
+#define FSRM           0x0400
+#define FSXM           0x0800
+#define RIOEN          0x1000
+#define XIOEN          0x2000
+#define IDLE_EN                0x4000
+
+/************************** McBSP RCR1 bit definitions ************************/
+#define RWDLEN1(value)         ((value)<<5)    /* Bits 5:7 */
+#define RFRLEN1(value)         ((value)<<8)    /* Bits 8:14 */
+
+/************************** McBSP XCR1 bit definitions ************************/
+#define XWDLEN1(value)         ((value)<<5)    /* Bits 5:7 */
+#define XFRLEN1(value)         ((value)<<8)    /* Bits 8:14 */
+
+/*************************** McBSP RCR2 bit definitions ***********************/
+#define RDATDLY(value)         (value)         /* Bits 0:1 */
+#define RFIG                   0x0004
+#define RCOMPAND(value)                ((value)<<3)    /* Bits 3:4 */
+#define RWDLEN2(value)         ((value)<<5)    /* Bits 5:7 */
+#define RFRLEN2(value)         ((value)<<8)    /* Bits 8:14 */
+#define RPHASE                 0x8000
+
+/*************************** McBSP XCR2 bit definitions ***********************/
+#define XDATDLY(value)         (value)         /* Bits 0:1 */
+#define XFIG                   0x0004
+#define XCOMPAND(value)                ((value)<<3)    /* Bits 3:4 */
+#define XWDLEN2(value)         ((value)<<5)    /* Bits 5:7 */
+#define XFRLEN2(value)         ((value)<<8)    /* Bits 8:14 */
+#define XPHASE                 0x8000
+
+/************************* McBSP SRGR1 bit definitions ************************/
+#define CLKGDV(value)          (value)         /* Bits 0:7 */
+#define FWID(value)            ((value)<<8)    /* Bits 8:15 */
+
+/************************* McBSP SRGR2 bit definitions ************************/
+#define FPER(value)            (value)         /* Bits 0:11 */
+#define FSGM                   0x1000
+#define CLKSM                  0x2000
+#define CLKSP                  0x4000
+#define GSYNC                  0x8000
+
+/************************* McBSP MCR1 bit definitions *************************/
+#define RMCM                   0x0001
+#define RCBLK(value)           ((value)<<2)    /* Bits 2:4 */
+#define RPABLK(value)          ((value)<<5)    /* Bits 5:6 */
+#define RPBBLK(value)          ((value)<<7)    /* Bits 7:8 */
+
+/************************* McBSP MCR2 bit definitions *************************/
+#define XMCM(value)            (value)         /* Bits 0:1 */
+#define XCBLK(value)           ((value)<<2)    /* Bits 2:4 */
+#define XPABLK(value)          ((value)<<5)    /* Bits 5:6 */
+#define XPBBLK(value)          ((value)<<7)    /* Bits 7:8 */
+
+
+/* we don't do multichannel for now */
+struct omap_mcbsp_reg_cfg {
+       u16 spcr2;
+       u16 spcr1;
+       u16 rcr2;
+       u16 rcr1;
+       u16 xcr2;
+       u16 xcr1;
+       u16 srgr2;
+       u16 srgr1;
+       u16 mcr2;
+       u16 mcr1;
+       u16 pcr0;
+       u16 rcerc;
+       u16 rcerd;
+       u16 xcerc;
+       u16 xcerd;
+       u16 rcere;
+       u16 rcerf;
+       u16 xcere;
+       u16 xcerf;
+       u16 rcerg;
+       u16 rcerh;
+       u16 xcerg;
+       u16 xcerh;
+};
+
+typedef enum {
+       OMAP_MCBSP1 = 0,
+       OMAP_MCBSP2,
+       OMAP_MCBSP3,
+} omap_mcbsp_id;
+
+typedef enum {
+       OMAP_MCBSP_WORD_8 = 0,
+       OMAP_MCBSP_WORD_12,
+       OMAP_MCBSP_WORD_16,
+       OMAP_MCBSP_WORD_20,
+       OMAP_MCBSP_WORD_24,
+       OMAP_MCBSP_WORD_32,
+} omap_mcbsp_word_length;
+
+typedef enum {
+       OMAP_MCBSP_CLK_RISING = 0,
+       OMAP_MCBSP_CLK_FALLING,
+} omap_mcbsp_clk_polarity;
+
+typedef enum {
+       OMAP_MCBSP_FS_ACTIVE_HIGH = 0,
+       OMAP_MCBSP_FS_ACTIVE_LOW,
+} omap_mcbsp_fs_polarity;
+
+typedef enum {
+       OMAP_MCBSP_CLK_STP_MODE_NO_DELAY = 0,
+       OMAP_MCBSP_CLK_STP_MODE_DELAY,
+} omap_mcbsp_clk_stp_mode;
+
+
+/******* SPI specific mode **********/
+typedef enum {
+       OMAP_MCBSP_SPI_MASTER = 0,
+       OMAP_MCBSP_SPI_SLAVE,
+} omap_mcbsp_spi_mode;
+
+struct omap_mcbsp_spi_cfg {
+       omap_mcbsp_spi_mode             spi_mode;
+       omap_mcbsp_clk_polarity         rx_clock_polarity;
+       omap_mcbsp_clk_polarity         tx_clock_polarity;
+       omap_mcbsp_fs_polarity          fsx_polarity;
+       u8                              clk_div;
+       omap_mcbsp_clk_stp_mode         clk_stp_mode;
+       omap_mcbsp_word_length          word_length;
+};
+
+void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
+int omap_mcbsp_request(unsigned int id);
+void omap_mcbsp_free(unsigned int id);
+void omap_mcbsp_start(unsigned int id);
+void omap_mcbsp_stop(unsigned int id);
+void omap_mcbsp_xmit_word(unsigned int id, u32 word);
+u32 omap_mcbsp_recv_word(unsigned int id);
+
+int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
+int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
+
+/* SPI specific API */
+void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
+
+#endif
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
new file mode 100644 (file)
index 0000000..d6c4a94
--- /dev/null
@@ -0,0 +1,179 @@
+/* linux/include/asm-arm/arch-omap/omap16xx.h
+ *
+ * Hardware definitions for TI OMAP1610/5912/1710 processors.
+ *
+ * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS 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 AUTHOR 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.
+ *
+ * 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 __ASM_ARCH_OMAP16XX_H
+#define __ASM_ARCH_OMAP16XX_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * Base addresses
+ * ----------------------------------------------------------------------------
+ */
+
+/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
+
+#define OMAP16XX_SRAM_BASE     0xD0000000
+#define OMAP1610_SRAM_SIZE     (SZ_16K)
+#define OMAP5912_SRAM_SIZE     0x3E800
+#define OMAP16XX_SRAM_START    0x20000000
+
+#define OMAP16XX_DSP_BASE      0xE0000000
+#define OMAP16XX_DSP_SIZE      0x28000
+#define OMAP16XX_DSP_START     0xE0000000
+
+#define OMAP16XX_DSPREG_BASE   0xE1000000
+#define OMAP16XX_DSPREG_SIZE   SZ_128K
+#define OMAP16XX_DSPREG_START  0xE1000000
+
+/*
+ * ----------------------------------------------------------------------------
+ * Memory used by power management
+ * ----------------------------------------------------------------------------
+ */
+
+#define OMAP1610_SRAM_IDLE_SUSPEND     (OMAP16XX_SRAM_BASE + OMAP1610_SRAM_SIZE - 0x200)
+#define OMAP5912_SRAM_IDLE_SUSPEND     (OMAP16XX_SRAM_BASE + OMAP5912_SRAM_SIZE - 0x200)
+#define OMAP1610_SRAM_API_SUSPEND      (OMAP1610_SRAM_IDLE_SUSPEND + 0x100)
+
+/*
+ * ---------------------------------------------------------------------------
+ * Interrupts
+ * ---------------------------------------------------------------------------
+ */
+#define OMAP_IH2_0_BASE                (0xfffe0000)
+#define OMAP_IH2_1_BASE                (0xfffe0100)
+#define OMAP_IH2_2_BASE                (0xfffe0200)
+#define OMAP_IH2_3_BASE                (0xfffe0300)
+
+#define OMAP_IH2_0_ITR         (OMAP_IH2_0_BASE + 0x00)
+#define OMAP_IH2_0_MIR         (OMAP_IH2_0_BASE + 0x04)
+#define OMAP_IH2_0_SIR_IRQ     (OMAP_IH2_0_BASE + 0x10)
+#define OMAP_IH2_0_SIR_FIQ     (OMAP_IH2_0_BASE + 0x14)
+#define OMAP_IH2_0_CONTROL     (OMAP_IH2_0_BASE + 0x18)
+#define OMAP_IH2_0_ILR0                (OMAP_IH2_0_BASE + 0x1c)
+#define OMAP_IH2_0_ISR         (OMAP_IH2_0_BASE + 0x9c)
+
+#define OMAP_IH2_1_ITR         (OMAP_IH2_1_BASE + 0x00)
+#define OMAP_IH2_1_MIR         (OMAP_IH2_1_BASE + 0x04)
+#define OMAP_IH2_1_SIR_IRQ     (OMAP_IH2_1_BASE + 0x10)
+#define OMAP_IH2_1_SIR_FIQ     (OMAP_IH2_1_BASE + 0x14)
+#define OMAP_IH2_1_CONTROL     (OMAP_IH2_1_BASE + 0x18)
+#define OMAP_IH2_1_ILR1                (OMAP_IH2_1_BASE + 0x1c)
+#define OMAP_IH2_1_ISR         (OMAP_IH2_1_BASE + 0x9c)
+
+#define OMAP_IH2_2_ITR         (OMAP_IH2_2_BASE + 0x00)
+#define OMAP_IH2_2_MIR         (OMAP_IH2_2_BASE + 0x04)
+#define OMAP_IH2_2_SIR_IRQ     (OMAP_IH2_2_BASE + 0x10)
+#define OMAP_IH2_2_SIR_FIQ     (OMAP_IH2_2_BASE + 0x14)
+#define OMAP_IH2_2_CONTROL     (OMAP_IH2_2_BASE + 0x18)
+#define OMAP_IH2_2_ILR2                (OMAP_IH2_2_BASE + 0x1c)
+#define OMAP_IH2_2_ISR         (OMAP_IH2_2_BASE + 0x9c)
+
+#define OMAP_IH2_3_ITR         (OMAP_IH2_3_BASE + 0x00)
+#define OMAP_IH2_3_MIR         (OMAP_IH2_3_BASE + 0x04)
+#define OMAP_IH2_3_SIR_IRQ     (OMAP_IH2_3_BASE + 0x10)
+#define OMAP_IH2_3_SIR_FIQ     (OMAP_IH2_3_BASE + 0x14)
+#define OMAP_IH2_3_CONTROL     (OMAP_IH2_3_BASE + 0x18)
+#define OMAP_IH2_3_ILR3                (OMAP_IH2_3_BASE + 0x1c)
+#define OMAP_IH2_3_ISR         (OMAP_IH2_3_BASE + 0x9c)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Clocks
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP16XX_ARM_IDLECT3   (CLKGEN_REG_BASE + 0x24)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Pin configuration registers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP16XX_CONF_VOLTAGE_VDDSHV6  (1 << 8)
+#define OMAP16XX_CONF_VOLTAGE_VDDSHV7  (1 << 9)
+#define OMAP16XX_CONF_VOLTAGE_VDDSHV8  (1 << 10)
+#define OMAP16XX_CONF_VOLTAGE_VDDSHV9  (1 << 11)
+#define OMAP16XX_SUBLVDS_CONF_VALID    (1 << 13)
+
+/*
+ * ---------------------------------------------------------------------------
+ * TIPB bus interface
+ * ---------------------------------------------------------------------------
+ */
+#define TIPB_SWITCH_BASE                (0xfffbc800)
+#define OMAP16XX_MMCSD2_SSW_MPU_CONF   (TIPB_SWITCH_BASE + 0x160)
+
+/* UART3 Registers Maping through MPU bus */
+#define UART3_RHR               (OMAP_UART3_BASE + 0)
+#define UART3_THR               (OMAP_UART3_BASE + 0)
+#define UART3_DLL               (OMAP_UART3_BASE + 0)
+#define UART3_IER               (OMAP_UART3_BASE + 4)
+#define UART3_DLH               (OMAP_UART3_BASE + 4)
+#define UART3_IIR               (OMAP_UART3_BASE + 8)
+#define UART3_FCR               (OMAP_UART3_BASE + 8)
+#define UART3_EFR               (OMAP_UART3_BASE + 8)
+#define UART3_LCR               (OMAP_UART3_BASE + 0x0C)
+#define UART3_MCR               (OMAP_UART3_BASE + 0x10)
+#define UART3_XON1_ADDR1        (OMAP_UART3_BASE + 0x10)
+#define UART3_XON2_ADDR2        (OMAP_UART3_BASE + 0x14)
+#define UART3_LSR               (OMAP_UART3_BASE + 0x14)
+#define UART3_TCR               (OMAP_UART3_BASE + 0x18)
+#define UART3_MSR               (OMAP_UART3_BASE + 0x18)
+#define UART3_XOFF1             (OMAP_UART3_BASE + 0x18)
+#define UART3_XOFF2             (OMAP_UART3_BASE + 0x1C)
+#define UART3_SPR               (OMAP_UART3_BASE + 0x1C)
+#define UART3_TLR               (OMAP_UART3_BASE + 0x1C)
+#define UART3_MDR1              (OMAP_UART3_BASE + 0x20)
+#define UART3_MDR2              (OMAP_UART3_BASE + 0x24)
+#define UART3_SFLSR             (OMAP_UART3_BASE + 0x28)
+#define UART3_TXFLL             (OMAP_UART3_BASE + 0x28)
+#define UART3_RESUME            (OMAP_UART3_BASE + 0x2C)
+#define UART3_TXFLH             (OMAP_UART3_BASE + 0x2C)
+#define UART3_SFREGL            (OMAP_UART3_BASE + 0x30)
+#define UART3_RXFLL             (OMAP_UART3_BASE + 0x30)
+#define UART3_SFREGH            (OMAP_UART3_BASE + 0x34)
+#define UART3_RXFLH             (OMAP_UART3_BASE + 0x34)
+#define UART3_BLR               (OMAP_UART3_BASE + 0x38)
+#define UART3_ACREG             (OMAP_UART3_BASE + 0x3C)
+#define UART3_DIV16             (OMAP_UART3_BASE + 0x3C)
+#define UART3_SCR               (OMAP_UART3_BASE + 0x40)
+#define UART3_SSR               (OMAP_UART3_BASE + 0x44)
+#define UART3_EBLR              (OMAP_UART3_BASE + 0x48)
+#define UART3_OSC_12M_SEL       (OMAP_UART3_BASE + 0x4C)
+#define UART3_MVR               (OMAP_UART3_BASE + 0x50)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Pulse-Width Light
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP16XX_PWL_BASE      (0xfffb5800)
+#define OMAP16XX_PWL_ENABLE    (OMAP16XX_PWL_BASE + 0x00)
+#define OMAP16XX_PWL_CLK_ENABLE        (OMAP16XX_PWL_BASE + 0x04)
+
+#endif /*  __ASM_ARCH_OMAP16XX_H */
+
diff --git a/include/asm-arm/arch-omap/tc.h b/include/asm-arm/arch-omap/tc.h
new file mode 100644 (file)
index 0000000..a1d2e5a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * linux/include/asm-arm/arch-omap/tc.h
+ *
+ * OMAP Traffic Controller
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __ASM_ARCH_TC_H
+#define __ASM_ARCH_TC_H
+
+#define OMAP_TC_OCPT1_PRIOR    0xFFFECC00
+#define OMAP_TC_EMIFS_PRIOR    0xFFFECC04
+#define OMAP_TC_EMIFF_PRIOR    0xFFFECC08
+#define OMAP_TC_OCPT2_PRIOR    0xFFFECCD0
+
+
+/* EMIF Slow Interface Configuration Register */
+#define        OMAP_EMIFS_CONFIG_REG   __REG32(EMIFS_CONFIG)
+
+#define OMAP_EMIFS_CONFIG_FR           (1 << 4)
+#define OMAP_EMIFS_CONFIG_PDE          (1 << 3)
+#define OMAP_EMIFS_CONFIG_PWD_EN       (1 << 2)
+#define OMAP_EMIFS_CONFIG_BM           (1 << 1)
+#define OMAP_EMIFS_CONFIG_WP           (1 << 0)
+
+/* external EMIFS chipselect regions */
+#define        OMAP_CS1_PHYS           0x04000000
+#define        OMAP_CS1_SIZE           SZ_64M
+
+#define        OMAP_CS1A_PHYS          OMAP_CS1_PHYS
+#define        OMAP_CS1A_SIZE          SZ_32M
+
+#define        OMAP_CS1B_PHYS          (OMAP_CS1A_PHYS + OMAP_CS1A_SIZE)
+#define        OMAP_CS1B_SIZE          SZ_32M
+
+#define        OMAP_CS2_PHYS           0x08000000
+#define        OMAP_CS2_SIZE           SZ_64M
+
+#define        OMAP_CS2A_PHYS          OMAP_CS2_PHYS
+#define        OMAP_CS2A_SIZE          SZ_32M
+
+#define        OMAP_CS2B_PHYS          (OMAP_CS2A_PHYS + OMAP_CS2A_SIZE)
+#define        OMAP_CS2B_SIZE          SZ_32M
+
+#define        OMAP_CS3_PHYS           0x0c000000
+#define        OMAP_CS3_SIZE           SZ_64M
+
+#endif /* __ASM_ARCH_TC_H */
diff --git a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h
new file mode 100644 (file)
index 0000000..0f97bb2
--- /dev/null
@@ -0,0 +1,80 @@
+/* linux/include/asm-arm/arch-omap/tps65010.h
+ *
+ * Functions to access TPS65010 power management device.
+ *
+ * Copyright (C) 2004 Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS 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 AUTHOR 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.
+ *
+ * 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 __ASM_ARCH_TPS65010_H
+#define __ASM_ARCH_TPS65010_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * Macros used by exported functions
+ * ----------------------------------------------------------------------------
+ */
+
+#define LED1  1
+#define LED2  2
+#define OFF   0
+#define ON    1
+#define BLINK 2
+#define GPIO1 1
+#define GPIO2 2
+#define GPIO3 3
+#define GPIO4 4
+#define LOW   0
+#define HIGH  1
+
+/*
+ * ----------------------------------------------------------------------------
+ * Exported functions
+ * ----------------------------------------------------------------------------
+ */
+
+/* Draw from VBUS:
+ *   0 mA -- DON'T DRAW (might supply power instead)
+ * 100 mA -- usb unit load (slowest charge rate)
+ * 500 mA -- usb high power (fast battery charge)
+ */
+extern int tps65010_set_vbus_draw(unsigned mA);
+
+/* tps65010_set_gpio_out_value parameter:
+ * gpio:  GPIO1, GPIO2, GPIO3 or GPIO4
+ * value: LOW or HIGH
+ */
+extern int tps65010_set_gpio_out_value(unsigned gpio, unsigned value);
+
+/* tps65010_set_led parameter:
+ * led:  LED1 or LED2
+ * mode: ON, OFF or BLINK
+ */
+extern int tps65010_set_led(unsigned led, unsigned mode);
+
+/* tps65010_set_low_pwr parameter:
+ * mode: ON or OFF
+ */
+extern int tps65010_set_low_pwr(unsigned mode);
+
+#endif /*  __ASM_ARCH_TPS65010_H */
+
diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h
new file mode 100644 (file)
index 0000000..1438c6c
--- /dev/null
@@ -0,0 +1,108 @@
+// include/asm-arm/mach-omap/usb.h
+
+#ifndef        __ASM_ARCH_OMAP_USB_H
+#define        __ASM_ARCH_OMAP_USB_H
+
+#include <asm/arch/board.h>
+
+/*-------------------------------------------------------------------------*/
+
+#define OTG_BASE                       0xfffb0400
+#define UDC_BASE                       0xfffb4000
+#define OMAP_OHCI_BASE                 0xfffba000
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * OTG and transceiver registers, for OMAPs starting with ARM926
+ */
+#define OTG_REG32(offset)              __REG32(OTG_BASE + (offset))
+#define OTG_REG16(offset)              __REG16(OTG_BASE + (offset))
+
+#define OTG_REV_REG                    OTG_REG32(0x00)
+#define OTG_SYSCON_1_REG               OTG_REG32(0x04)
+#      define   USB2_TRX_MODE(w)       (((w)>>24)&0x07)
+#      define   USB1_TRX_MODE(w)       (((w)>>20)&0x07)
+#      define   USB0_TRX_MODE(w)       (((w)>>16)&0x07)
+#      define   OTG_IDLE_EN            (1 << 15)
+#      define   HST_IDLE_EN            (1 << 14)
+#      define   DEV_IDLE_EN            (1 << 13)
+#      define   OTG_RESET_DONE         (1 << 2)
+#define OTG_SYSCON_2_REG               OTG_REG32(0x08)
+#      define   OTG_EN                 (1 << 31)
+#      define   USBX_SYNCHRO           (1 << 30)
+#      define   OTG_MST16              (1 << 29)
+#      define   SRP_GPDATA             (1 << 28)
+#      define   SRP_GPDVBUS            (1 << 27)
+#      define   SRP_GPUVBUS(w)         (((w)>>24)&0x07)
+#      define   A_WAIT_VRISE(w)        (((w)>>20)&0x07)
+#      define   B_ASE_BRST(w)          (((w)>>16)&0x07)
+#      define   SRP_DPW                (1 << 14)
+#      define   SRP_DATA               (1 << 13)
+#      define   SRP_VBUS               (1 << 12)
+#      define   OTG_PADEN              (1 << 10)
+#      define   HMC_PADEN              (1 << 9)
+#      define   UHOST_EN               (1 << 8)
+#      define   HMC_TLLSPEED           (1 << 7)
+#      define   HMC_TLLATTACH          (1 << 6)
+#      define   OTG_HMC(w)             (((w)>>0)&0x3f)
+#define OTG_CTRL_REG                   OTG_REG32(0x0c)
+#      define   OTG_ASESSVLD           (1 << 20)
+#      define   OTG_BSESSEND           (1 << 19)
+#      define   OTG_BSESSVLD           (1 << 18)
+#      define   OTG_VBUSVLD            (1 << 17)
+#      define   OTG_ID                 (1 << 16)
+#      define   OTG_DRIVER_SEL         (1 << 15)
+#      define   OTG_A_SETB_HNPEN       (1 << 12)
+#      define   OTG_A_BUSREQ           (1 << 11)
+#      define   OTG_B_HNPEN            (1 << 9)
+#      define   OTG_B_BUSREQ           (1 << 8)
+#      define   OTG_BUSDROP            (1 << 7)
+#      define   OTG_PULLDOWN           (1 << 5)
+#      define   OTG_PULLUP             (1 << 4)
+#      define   OTG_DRV_VBUS           (1 << 3)
+#      define   OTG_PD_VBUS            (1 << 2)
+#      define   OTG_PU_VBUS            (1 << 1)
+#      define   OTG_PU_ID              (1 << 0)
+#define OTG_IRQ_EN_REG                 OTG_REG16(0x10)
+#      define   DRIVER_SWITCH          (1 << 15)
+#      define   A_VBUS_ERR             (1 << 13)
+#      define   A_REQ_TMROUT           (1 << 12)
+#      define   A_SRP_DETECT           (1 << 11)
+#      define   B_HNP_FAIL             (1 << 10)
+#      define   B_SRP_TMROUT           (1 << 9)
+#      define   B_SRP_DONE             (1 << 8)
+#      define   B_SRP_STARTED          (1 << 7)
+#      define   OPRT_CHG               (1 << 0)
+#define OTG_IRQ_SRC_REG                        OTG_REG16(0x14)
+       // same bits as in IRQ_EN
+#define OTG_OUTCTRL_REG                        OTG_REG16(0x18)
+#      define   OTGVPD                 (1 << 14)
+#      define   OTGVPU                 (1 << 13)
+#      define   OTGPUID                (1 << 12)
+#      define   USB2VDR                (1 << 10)
+#      define   USB2PDEN               (1 << 9)
+#      define   USB2PUEN               (1 << 8)
+#      define   USB1VDR                (1 << 6)
+#      define   USB1PDEN               (1 << 5)
+#      define   USB1PUEN               (1 << 4)
+#      define   USB0VDR                (1 << 2)
+#      define   USB0PDEN               (1 << 1)
+#      define   USB0PUEN               (1 << 0)
+#define OTG_TEST_REG                   OTG_REG16(0x20)
+#define OTG_VENDOR_CODE_REG            OTG_REG32(0xfc)
+
+/*-------------------------------------------------------------------------*/
+
+#define        USB_TRANSCEIVER_CTRL_REG        __REG32(0xfffe1000 + 0x0064)
+#      define  CONF_USB2_UNI_R         (1 << 8)
+#      define  CONF_USB1_UNI_R         (1 << 7)
+#      define  CONF_USB_PORT0_R(x)     (((x)>>4)&0x7)
+#      define  CONF_USB0_ISOLATE_R     (1 << 3)
+#      define  CONF_USB_PWRDN_DM_R     (1 << 2)
+#      define  CONF_USB_PWRDN_DP_R     (1 << 1)
+
+
+
+
+#endif /* __ASM_ARCH_OMAP_USB_H */
diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
new file mode 100644 (file)
index 0000000..7492ea7
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef ASMARM_ARCH_MMC_H
+#define ASMARM_ARCH_MMC_H
+
+#include <linux/mmc/protocol.h>
+#include <linux/interrupt.h>
+
+struct device;
+struct mmc_host;
+
+struct pxamci_platform_data {
+       unsigned int ocr_mask;                  /* available voltages */
+       int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *);
+       void (*setpower)(struct device *, unsigned int);
+       void (*exit)(struct device *, void *);
+};
+
+extern void pxa_set_mci_info(struct pxamci_platform_data *info);
+
+#endif
diff --git a/include/asm-arm/arch-pxa/ssp.h b/include/asm-arm/arch-pxa/ssp.h
new file mode 100644 (file)
index 0000000..12fc8bf
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  ssp.h
+ *
+ *  Copyright (C) 2003 Russell King, 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver supports the following PXA CPU/SSP ports:-
+ *
+ *       PXA250     SSP
+ *       PXA255     SSP, NSSP
+ *       PXA26x     SSP, NSSP, ASSP
+ *       PXA27x     SSP1, SSP2, SSP3
+ */
+
+#ifndef SSP_H
+#define SSP_H
+
+struct ssp_state {
+       u32     cr0;
+       u32 cr1;
+       u32 to;
+       u32 psp;
+};
+
+struct ssp_dev {
+       u32 port;
+       u32 mode;
+       u32 flags;
+       u32 psp_flags;
+       u32 speed;
+};
+
+int ssp_write_word(struct ssp_dev *dev, u32 data);
+int ssp_read_word(struct ssp_dev *dev);
+void ssp_flush(struct ssp_dev *dev);
+void ssp_enable(struct ssp_dev *dev);
+void ssp_disable(struct ssp_dev *dev);
+void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp);
+void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp);
+int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
+                                               u32 speed);
+void ssp_exit(struct ssp_dev *dev);
+
+#endif
diff --git a/include/asm-arm/arch-s3c2410/bast-pmu.h b/include/asm-arm/arch-s3c2410/bast-pmu.h
new file mode 100644 (file)
index 0000000..758c5c5
--- /dev/null
@@ -0,0 +1,43 @@
+/* linux/include/asm-arm/arch-s3c2410/bast-pmu.h
+ *
+ * (c) 2003,2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Machine BAST - Power Management chip
+ *
+ * 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:
+ *     08-Oct-2003     BJD     Initial creation
+*/
+
+#ifndef __ASM_ARCH_BASTPMU_H
+#define __ASM_ARCH_BASTPMU_H "08_OCT_2004"
+
+#define BASTPMU_REG_IDENT      (0x00)
+#define BASTPMU_REG_VERSION    (0x01)
+#define BASTPMU_REG_DDCCTRL    (0x02)
+#define BASTPMU_REG_POWER      (0x03)
+#define BASTPMU_REG_RESET      (0x04)
+#define BASTPMU_REG_GWO                (0x05)
+#define BASTPMU_REG_WOL                (0x06)
+#define BASTPMU_REG_WOR                (0x07)
+#define BASTPMU_REG_UID                (0x09)
+
+#define BASTPMU_EEPROM         (0xC0)
+
+#define BASTPMU_EEP_UID                (BASTPMU_EEPROM + 0)
+#define BASTPMU_EEP_WOL                (BASTPMU_EEPROM + 8)
+#define BASTPMU_EEP_WOR                (BASTPMU_EEPROM + 9)
+
+#define BASTPMU_IDENT_0                0x53
+#define BASTPMU_IDENT_1                0x42
+#define BASTPMU_IDENT_2                0x50
+#define BASTPMU_IDENT_3                0x4d
+
+#define BASTPMU_RESET_GUARD    (0x55)
+
+#endif /* __ASM_ARCH_BASTPMU_H */
diff --git a/include/asm-arm/arch-s3c2410/idle.h b/include/asm-arm/arch-s3c2410/idle.h
new file mode 100644 (file)
index 0000000..749227c
--- /dev/null
@@ -0,0 +1,28 @@
+/* linux/include/asm-arm/arch-s3c2410/idle.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *             http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 CPU Idle controls
+ *
+ *  Changelog:
+ *     28-Oct-2004  BJD  Initial version
+ *
+*/
+
+#ifndef __ASM_ARCH_IDLE_H
+#define __ASM_ARCH_IDLE_H __FILE__
+
+/* This allows the over-ride of the default idle code, in case there
+ * is any other things to be done over idle (like DVS)
+*/
+
+extern void (*s3c24xx_idle)(void);
+
+extern void s3c24xx_default_idle(void);
+
+#endif /* __ASM_ARCH_IDLE_H */
diff --git a/include/asm-arm/arch-s3c2410/iic.h b/include/asm-arm/arch-s3c2410/iic.h
new file mode 100644 (file)
index 0000000..518547f
--- /dev/null
@@ -0,0 +1,36 @@
+/* linux/include/asm-arm/arch-s3c2410/iic.h
+ *
+ * (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - I2C Controller 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:
+ *     05-Oct-2004 BJD  Created file
+ *     19-Oct-2004 BJD  Updated for s3c2440
+*/
+
+#ifndef __ASM_ARCH_IIC_H
+#define __ASM_ARCH_IIC_H __FILE__
+
+#define S3C_IICFLG_FILTER      (1<<0)  /* enable s3c2440 filter */
+
+/* Notes:
+ *     1) All frequencies are expressed in Hz
+ *     2) A value of zero is `do not care`
+*/
+
+struct s3c2410_platform_i2c {
+       unsigned int    flags;
+       unsigned int    slave_addr;     /* slave address for controller */
+       unsigned long   bus_freq;       /* standard bus frequency */
+       unsigned long   max_freq;       /* max frequency for the bus */
+       unsigned long   min_freq;       /* min frequency for the bus */
+       unsigned int    sda_delay;      /* pclks (s3c2440 only) */
+};
+
+#endif /* __ASM_ARCH_IIC_H */
diff --git a/include/asm-arm/arch-s3c2410/nand.h b/include/asm-arm/arch-s3c2410/nand.h
new file mode 100644 (file)
index 0000000..9148ac0
--- /dev/null
@@ -0,0 +1,48 @@
+/* linux/include/asm-arm/arch-s3c2410/nand.h
+ *
+ * (c) 2004 Simtec Electronics
+ *  Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - NAND device controller 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:
+ *     23-Sep-2004 BJD  Created file
+*/
+
+/* struct s3c2410_nand_set
+ *
+ * define an set of one or more nand chips registered with an unique mtd
+ *
+ * nr_chips     = number of chips in this set
+ * nr_partitions = number of partitions pointed to be partitoons (or zero)
+ * name                 = name of set (optional)
+ * nr_map       = map for low-layer logical to physical chip numbers (option)
+ * partitions   = mtd partition list
+*/
+
+struct s3c2410_nand_set {
+       int                     nr_chips;
+       int                     nr_partitions;
+       char                    *name;
+       int                     *nr_map;
+       struct mtd_partition    *partitions;
+};
+
+struct s3c2410_platform_nand {
+       /* timing information for controller, all times in nanoseconds */
+
+       int     tacls;  /* time for active CLE/ALE to nWE/nOE */
+       int     twrph0; /* active time for nWE/nOE */
+       int     twrph1; /* time for release CLE/ALE from nWE/nOE inactive */
+
+       int                     nr_sets;
+       struct s3c2410_nand_set *sets;
+
+       void                    (*select_chip)(struct s3c2410_nand_set *,
+                                              int chip);
+};
+
diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h
new file mode 100644 (file)
index 0000000..0da1ec7
--- /dev/null
@@ -0,0 +1,183 @@
+/* linux/include/asm/hardware/s3c2410/regs-dsc.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2440 Signal Drive Strength Control
+ *
+ *  Changelog:
+ *    11-Aug-2004     BJD     Created file
+ *    25-Aug-2004     BJD     Added the _SELECT_* defs for using with functions
+*/
+
+
+#ifndef __ASM_ARCH_REGS_DSC_H
+#define __ASM_ARCH_REGS_DSC_H "2440-dsc"
+
+#ifdef CONFIG_CPU_S3C2440
+
+#define S3C2440_DSC0      S3C2410_GPIOREG(0xc0)
+#define S3C2440_DSC1      S3C2410_GPIOREG(0xc4)
+
+#define S3C2440_SELECT_DSC0 (0)
+#define S3C2440_SELECT_DSC1 (1<<31)
+
+#define S3C2440_DSC_GETSHIFT(x) ((x) & 31)
+
+#define S3C2440_DSC0_ENABLE     (1<<31)
+
+#define S3C2440_DSC0_ADDR       (S3C2440_SELECT_DSC0 | 8)
+#define S3C2440_DSC0_ADDR_12mA  (0<<8)
+#define S3C2440_DSC0_ADDR_10mA  (1<<8)
+#define S3C2440_DSC0_ADDR_8mA   (2<<8)
+#define S3C2440_DSC0_ADDR_6mA   (3<<8)
+#define S3C2440_DSC0_ADDR_MASK  (3<<8)
+
+/* D24..D31 */
+#define S3C2440_DSC0_DATA3      (S3C2440_SELECT_DSC0 | 6)
+#define S3C2440_DSC0_DATA3_12mA (0<<6)
+#define S3C2440_DSC0_DATA3_10mA (1<<6)
+#define S3C2440_DSC0_DATA3_8mA  (2<<6)
+#define S3C2440_DSC0_DATA3_6mA  (3<<6)
+#define S3C2440_DSC0_DATA3_MASK (3<<6)
+
+/* D16..D23 */
+#define S3C2440_DSC0_DATA2      (S3C2440_SELECT_DSC0 | 4)
+#define S3C2440_DSC0_DATA2_12mA (0<<4)
+#define S3C2440_DSC0_DATA2_10mA (1<<4)
+#define S3C2440_DSC0_DATA2_8mA  (2<<4)
+#define S3C2440_DSC0_DATA2_6mA  (3<<4)
+#define S3C2440_DSC0_DATA2_MASK (3<<4)
+
+/* D8..D15 */
+#define S3C2440_DSC0_DATA1      (S3C2440_SELECT_DSC0 | 2)
+#define S3C2440_DSC0_DATA1_12mA (0<<2)
+#define S3C2440_DSC0_DATA1_10mA (1<<2)
+#define S3C2440_DSC0_DATA1_8mA  (2<<2)
+#define S3C2440_DSC0_DATA1_6mA  (3<<2)
+#define S3C2440_DSC0_DATA1_MASK (3<<2)
+
+/* D0..D7 */
+#define S3C2440_DSC0_DATA0      (S3C2440_SELECT_DSC0 | 0)
+#define S3C2440_DSC0_DATA0_12mA (0<<0)
+#define S3C2440_DSC0_DATA0_10mA (1<<0)
+#define S3C2440_DSC0_DATA0_8mA  (2<<0)
+#define S3C2440_DSC0_DATA0_6mA  (3<<0)
+#define S3C2440_DSC0_DATA0_MASK (3<<0)
+
+#define S3C2440_DSC1_SCK0       (S3C2440_SELECT_DSC1 | 28)
+#define S3C2440_DSC1_SCK0_12mA  (0<<28)
+#define S3C2440_DSC1_SCK0_10mA  (1<<28)
+#define S3C2440_DSC1_SCK0_8mA   (2<<28)
+#define S3C2440_DSC1_SCK0_6mA   (3<<28)
+#define S3C2440_DSC1_SCK0_MASK  (3<<28)
+
+#define S3C2440_DSC1_SCK1       (S3C2440_SELECT_DSC1 | 26)
+#define S3C2440_DSC1_SCK1_12mA  (0<<26)
+#define S3C2440_DSC1_SCK1_10mA  (1<<26)
+#define S3C2440_DSC1_SCK1_8mA   (2<<26)
+#define S3C2440_DSC1_SCK1_6mA   (3<<26)
+#define S3C2440_DSC1_SCK1_MASK  (3<<26)
+
+#define S3C2440_DSC1_SCKE       (S3C2440_SELECT_DSC1 | 24)
+#define S3C2440_DSC1_SCKE_10mA  (0<<24)
+#define S3C2440_DSC1_SCKE_8mA   (1<<24)
+#define S3C2440_DSC1_SCKE_6mA   (2<<24)
+#define S3C2440_DSC1_SCKE_4mA   (3<<24)
+#define S3C2440_DSC1_SCKE_MASK  (3<<24)
+
+/* SDRAM nRAS/nCAS */
+#define S3C2440_DSC1_SDR        (S3C2440_SELECT_DSC1 | 22)
+#define S3C2440_DSC1_SDR_10mA   (0<<22)
+#define S3C2440_DSC1_SDR_8mA    (1<<22)
+#define S3C2440_DSC1_SDR_6mA    (2<<22)
+#define S3C2440_DSC1_SDR_4mA    (3<<22)
+#define S3C2440_DSC1_SDR_MASK   (3<<22)
+
+/* NAND Flash Controller */
+#define S3C2440_DSC1_NFC        (S3C2440_SELECT_DSC1 | 20)
+#define S3C2440_DSC1_NFC_10mA   (0<<20)
+#define S3C2440_DSC1_NFC_8mA    (1<<20)
+#define S3C2440_DSC1_NFC_6mA    (2<<20)
+#define S3C2440_DSC1_NFC_4mA    (3<<20)
+#define S3C2440_DSC1_NFC_MASK   (3<<20)
+
+/* nBE[0..3] */
+#define S3C2440_DSC1_nBE        (S3C2440_SELECT_DSC1 | 18)
+#define S3C2440_DSC1_nBE_10mA   (0<<18)
+#define S3C2440_DSC1_nBE_8mA    (1<<18)
+#define S3C2440_DSC1_nBE_6mA    (2<<18)
+#define S3C2440_DSC1_nBE_4mA    (3<<18)
+#define S3C2440_DSC1_nBE_MASK   (3<<18)
+
+#define S3C2440_DSC1_WOE        (S3C2440_SELECT_DSC1 | 16)
+#define S3C2440_DSC1_WOE_10mA   (0<<16)
+#define S3C2440_DSC1_WOE_8mA    (1<<16)
+#define S3C2440_DSC1_WOE_6mA    (2<<16)
+#define S3C2440_DSC1_WOE_4mA    (3<<16)
+#define S3C2440_DSC1_WOE_MASK   (3<<16)
+
+#define S3C2440_DSC1_CS7        (S3C2440_SELECT_DSC1 | 14)
+#define S3C2440_DSC1_CS7_10mA   (0<<14)
+#define S3C2440_DSC1_CS7_8mA    (1<<14)
+#define S3C2440_DSC1_CS7_6mA    (2<<14)
+#define S3C2440_DSC1_CS7_4mA    (3<<14)
+#define S3C2440_DSC1_CS7_MASK   (3<<14)
+
+#define S3C2440_DSC1_CS6        (S3C2440_SELECT_DSC1 | 12)
+#define S3C2440_DSC1_CS6_10mA   (0<<12)
+#define S3C2440_DSC1_CS6_8mA    (1<<12)
+#define S3C2440_DSC1_CS6_6mA    (2<<12)
+#define S3C2440_DSC1_CS6_4mA    (3<<12)
+#define S3C2440_DSC1_CS6_MASK   (3<<12)
+
+#define S3C2440_DSC1_CS5        (S3C2440_SELECT_DSC1 | 10)
+#define S3C2440_DSC1_CS5_10mA   (0<<10)
+#define S3C2440_DSC1_CS5_8mA    (1<<10)
+#define S3C2440_DSC1_CS5_6mA    (2<<10)
+#define S3C2440_DSC1_CS5_4mA    (3<<10)
+#define S3C2440_DSC1_CS5_MASK   (3<<10)
+
+#define S3C2440_DSC1_CS4        (S3C2440_SELECT_DSC1 | 8)
+#define S3C2440_DSC1_CS4_10mA   (0<<8)
+#define S3C2440_DSC1_CS4_8mA    (1<<8)
+#define S3C2440_DSC1_CS4_6mA    (2<<8)
+#define S3C2440_DSC1_CS4_4mA    (3<<8)
+#define S3C2440_DSC1_CS4_MASK   (3<<8)
+
+#define S3C2440_DSC1_CS3        (S3C2440_SELECT_DSC1 | 6)
+#define S3C2440_DSC1_CS3_10mA   (0<<6)
+#define S3C2440_DSC1_CS3_8mA    (1<<6)
+#define S3C2440_DSC1_CS3_6mA    (2<<6)
+#define S3C2440_DSC1_CS3_4mA    (3<<6)
+#define S3C2440_DSC1_CS3_MASK   (3<<6)
+
+#define S3C2440_DSC1_CS2        (S3C2440_SELECT_DSC1 | 4)
+#define S3C2440_DSC1_CS2_10mA   (0<<4)
+#define S3C2440_DSC1_CS2_8mA    (1<<4)
+#define S3C2440_DSC1_CS2_6mA    (2<<4)
+#define S3C2440_DSC1_CS2_4mA    (3<<4)
+#define S3C2440_DSC1_CS2_MASK   (3<<4)
+
+#define S3C2440_DSC1_CS1        (S3C2440_SELECT_DSC1 | 2)
+#define S3C2440_DSC1_CS1_10mA   (0<<2)
+#define S3C2440_DSC1_CS1_8mA    (1<<2)
+#define S3C2440_DSC1_CS1_6mA    (2<<2)
+#define S3C2440_DSC1_CS1_4mA    (3<<2)
+#define S3C2440_DSC1_CS1_MASK   (3<<2)
+
+#define S3C2440_DSC1_CS0        (S3C2440_SELECT_DSC1 | 0
+#define S3C2440_DSC1_CS0_10mA   (0<<0)
+#define S3C2440_DSC1_CS0_8mA    (1<<0)
+#define S3C2440_DSC1_CS0_6mA    (2<<0)
+#define S3C2440_DSC1_CS0_4mA    (3<<0)
+#define S3C2440_DSC1_CS0_MASK   (3<<0)
+
+#endif /* CONFIG_CPU_S3C2440 */
+
+#endif /* __ASM_ARCH_REGS_DSC_H */
+
diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h
new file mode 100644 (file)
index 0000000..ca91645
--- /dev/null
@@ -0,0 +1,100 @@
+/* linux/include/asm/hardware/s3c2410/regs-gpioj.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2440 GPIO J register definitions
+ *
+ *  Changelog:
+ *    11-Aug-2004     BJD     Created file
+*/
+
+
+#ifndef __ASM_ARCH_REGS_GPIOJ_H
+#define __ASM_ARCH_REGS_GPIOJ_H "gpioj"
+
+/* Port J consists of 13 GPIO/Camera pins
+ *
+ * GPJCON has 2 bits for each of the input pins on port F
+ *   00 = 0 input, 1 output, 2 Camera
+ *
+ * pull up works like all other ports.
+*/
+
+#define S3C2440_GPIO_BANKJ  (416)
+
+#define S3C2440_GPJCON     S3C2410_GPIOREG(0xd0)
+#define S3C2440_GPJDAT     S3C2410_GPIOREG(0xd4)
+#define S3C2440_GPJUP      S3C2410_GPIOREG(0xd8)
+
+#define S3C2440_GPJ0            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 0)
+#define S3C2440_GPJ0_INP        (0x00 << 0)
+#define S3C2440_GPJ0_OUTP       (0x01 << 0)
+#define S3C2440_GPJ0_CAMDATA0   (0x02 << 0)
+
+#define S3C2440_GPJ1            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 1)
+#define S3C2440_GPJ1_INP        (0x00 << 2)
+#define S3C2440_GPJ1_OUTP       (0x01 << 2)
+#define S3C2440_GPJ1_CAMDATA1   (0x02 << 2)
+
+#define S3C2440_GPJ2            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 2)
+#define S3C2440_GPJ2_INP        (0x00 << 4)
+#define S3C2440_GPJ2_OUTP       (0x01 << 4)
+#define S3C2440_GPJ2_CAMDATA2   (0x02 << 4)
+
+#define S3C2440_GPJ3            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 3)
+#define S3C2440_GPJ3_INP        (0x00 << 6)
+#define S3C2440_GPJ3_OUTP       (0x01 << 6)
+#define S3C2440_GPJ3_CAMDATA3   (0x02 << 6)
+
+#define S3C2440_GPJ4            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 4)
+#define S3C2440_GPJ4_INP        (0x00 << 8)
+#define S3C2440_GPJ4_OUTP       (0x01 << 8)
+#define S3C2440_GPJ4_CAMDATA4   (0x02 << 8)
+
+#define S3C2440_GPJ5            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 5)
+#define S3C2440_GPJ5_INP        (0x00 << 10)
+#define S3C2440_GPJ5_OUTP       (0x01 << 10)
+#define S3C2440_GPJ5_CAMDATA5   (0x02 << 10)
+
+#define S3C2440_GPJ6            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 6)
+#define S3C2440_GPJ6_INP        (0x00 << 12)
+#define S3C2440_GPJ6_OUTP       (0x01 << 12)
+#define S3C2440_GPJ6_CAMDATA6   (0x02 << 12)
+
+#define S3C2440_GPJ7            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 7)
+#define S3C2440_GPJ7_INP        (0x00 << 14)
+#define S3C2440_GPJ7_OUTP       (0x01 << 14)
+#define S3C2440_GPJ7_CAMDATA7   (0x02 << 14)
+
+#define S3C2440_GPJ8            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 8)
+#define S3C2440_GPJ8_INP        (0x00 << 16)
+#define S3C2440_GPJ8_OUTP       (0x01 << 16)
+#define S3C2440_GPJ8_CAMPCLK    (0x02 << 16)
+
+#define S3C2440_GPJ9            S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 9)
+#define S3C2440_GPJ9_INP        (0x00 << 18)
+#define S3C2440_GPJ9_OUTP       (0x01 << 18)
+#define S3C2440_GPJ9_CAMVSYNC   (0x02 << 18)
+
+#define S3C2440_GPJ10           S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 10)
+#define S3C2440_GPJ10_INP       (0x00 << 20)
+#define S3C2440_GPJ10_OUTP      (0x01 << 20)
+#define S3C2440_GPJ10_CAMHREF   (0x02 << 20)
+
+#define S3C2440_GPJ11           S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 11)
+#define S3C2440_GPJ11_INP       (0x00 << 22)
+#define S3C2440_GPJ11_OUTP      (0x01 << 22)
+#define S3C2440_GPJ11_CAMCLKOUT (0x02 << 22)
+
+#define S3C2440_GPJ12           S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 12)
+#define S3C2440_GPJ12_INP       (0x00 << 24)
+#define S3C2440_GPJ12_OUTP      (0x01 << 24)
+#define S3C2440_GPJ12_CAMCLKOUT (0x02 << 24)
+
+#endif /* __ASM_ARCH_REGS_GPIOJ_H */
+
diff --git a/include/asm-arm/arch-s3c2410/regs-iic.h b/include/asm-arm/arch-s3c2410/regs-iic.h
new file mode 100644 (file)
index 0000000..028ab20
--- /dev/null
@@ -0,0 +1,50 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-iic.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *             http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 I2C Controller
+ *
+ *  Changelog:
+ *     03-Oct-2004  BJD  Initial include for Linux
+*/
+
+#ifndef __ASM_ARCH_IIC_H
+#define __ASM_ARCH_IIC_H __FILE__
+
+/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */
+
+#define S3C2410_IICREG(x) (x)
+
+#define S3C2410_IICCON    S3C2410_IICREG(0x00)
+#define S3C2410_IICSTAT   S3C2410_IICREG(0x04)
+#define S3C2410_IICADD    S3C2410_IICREG(0x08)
+#define S3C2410_IICDS     S3C2410_IICREG(0x0C)
+
+#define S3C2410_IICCON_ACKEN           (1<<7)
+#define S3C2410_IICCON_TXDIV_16                (0<<6)
+#define S3C2410_IICCON_TXDIV_512       (1<<6)
+#define S3C2410_IICCON_IRQEN           (1<<5)
+#define S3C2410_IICCON_IRQPEND         (1<<4)
+#define S3C2410_IICCON_SCALE(x)                ((x)&15)
+#define S3C2410_IICCON_SCALEMASK       (0xf)
+
+#define S3C2410_IICSTAT_MASTER_RX      (2<<6)
+#define S3C2410_IICSTAT_MASTER_TX      (3<<6)
+#define S3C2410_IICSTAT_SLAVE_RX       (0<<6)
+#define S3C2410_IICSTAT_SLAVE_TX       (1<<6)
+#define S3C2410_IICSTAT_MODEMASK       (3<<6)
+
+#define S3C2410_IICSTAT_START          (1<<5)
+#define S3C2410_IICSTAT_BUSBUSY                (1<<5)
+#define S3C2410_IICSTAT_TXRXEN         (1<<4)
+#define S3C2410_IICSTAT_ARBITR         (1<<3)
+#define S3C2410_IICSTAT_ASSLAVE                (1<<2)
+#define S3C2410_IICSTAT_ADDR0          (1<<1)
+#define S3C2410_IICSTAT_LASTBIT                (1<<0)
+
+#endif /* __ASM_ARCH_IIC_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-mem.h b/include/asm-arm/arch-s3c2410/regs-mem.h
new file mode 100644 (file)
index 0000000..400fbd7
--- /dev/null
@@ -0,0 +1,190 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-mem.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *             http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 Memory Control register definitions
+ *
+ *  Changelog:
+ *     29-Sep-2004  BJD  Initial include for Linux
+ *
+*/
+
+#ifndef __ASM_ARM_MEMREGS_H
+#define __ASM_ARM_MEMREGS_H "$Id: regs.h,v 1.8 2003/05/01 15:55:41 ben Exp $"
+
+#ifndef S3C2410_MEMREG
+#define S3C2410_MEMREG(x) (S3C2410_VA_MEMCTRL + (x))
+#endif
+
+/* bus width, and wait state control */
+#define S3C2410_BWSCON                 S3C2410_MEMREG(0x0000)
+
+/* bank zero config - note, pinstrapped from OM pins! */
+#define S3C2410_BWSCON_DW0_16          (1<<1)
+#define S3C2410_BWSCON_DW0_32          (2<<1)
+
+/* bank one configs */
+#define S3C2410_BWSCON_DW1_8           (0<<4)
+#define S3C2410_BWSCON_DW1_16          (1<<4)
+#define S3C2410_BWSCON_DW1_32          (2<<4)
+#define S3C2410_BWSCON_WS1             (1<<6)
+#define S3C2410_BWSCON_ST1             (1<<7)
+
+/* bank 2 configurations */
+#define S3C2410_BWSCON_DW2_8           (0<<8)
+#define S3C2410_BWSCON_DW2_16          (1<<8)
+#define S3C2410_BWSCON_DW2_32          (2<<8)
+#define S3C2410_BWSCON_WS2             (1<<10)
+#define S3C2410_BWSCON_ST2             (1<<11)
+
+/* bank 3 configurations */
+#define S3C2410_BWSCON_DW3_8           (0<<12)
+#define S3C2410_BWSCON_DW3_16          (1<<12)
+#define S3C2410_BWSCON_DW3_32          (2<<12)
+#define S3C2410_BWSCON_WS3             (1<<14)
+#define S3C2410_BWSCON_ST3             (1<<15)
+
+/* bank 4 configurations */
+#define S3C2410_BWSCON_DW4_8           (0<<16)
+#define S3C2410_BWSCON_DW4_16          (1<<16)
+#define S3C2410_BWSCON_DW4_32          (2<<16)
+#define S3C2410_BWSCON_WS4             (1<<18)
+#define S3C2410_BWSCON_ST4             (1<<19)
+
+/* bank 5 configurations */
+#define S3C2410_BWSCON_DW5_8           (0<<20)
+#define S3C2410_BWSCON_DW5_16          (1<<20)
+#define S3C2410_BWSCON_DW5_32          (2<<20)
+#define S3C2410_BWSCON_WS5             (1<<22)
+#define S3C2410_BWSCON_ST5             (1<<23)
+
+/* bank 6 configurations */
+#define S3C2410_BWSCON_DW6_8           (0<<24)
+#define S3C2410_BWSCON_DW6_16          (1<<24)
+#define S3C2410_BWSCON_DW6_32          (2<<24)
+#define S3C2410_BWSCON_WS6             (1<<26)
+#define S3C2410_BWSCON_ST6             (1<<27)
+
+/* bank 7 configurations */
+#define S3C2410_BWSCON_DW7_8           (0<<28)
+#define S3C2410_BWSCON_DW7_16          (1<<28)
+#define S3C2410_BWSCON_DW7_32          (2<<28)
+#define S3C2410_BWSCON_WS7             (1<<30)
+#define S3C2410_BWSCON_ST7             (1<<31)
+
+/* memory set (rom, ram) */
+#define S3C2410_BANKCON0               S3C2410_MEMREG(0x0004)
+#define S3C2410_BANKCON1               S3C2410_MEMREG(0x0008)
+#define S3C2410_BANKCON2               S3C2410_MEMREG(0x000C)
+#define S3C2410_BANKCON3               S3C2410_MEMREG(0x0010)
+#define S3C2410_BANKCON4               S3C2410_MEMREG(0x0014)
+#define S3C2410_BANKCON5               S3C2410_MEMREG(0x0018)
+#define S3C2410_BANKCON6               S3C2410_MEMREG(0x001C)
+#define S3C2410_BANKCON7               S3C2410_MEMREG(0x0020)
+
+/* bank configuration registers */
+
+#define S3C2410_BANKCON_PMCnorm                (0x00)
+#define S3C2410_BANKCON_PMC4           (0x01)
+#define S3C2410_BANKCON_PMC8           (0x02)
+#define S3C2410_BANKCON_PMC16          (0x03)
+
+/* bank configurations for banks 0..7, note banks
+ * 6 and 7 have differnt configurations depending on
+ * the memory type bits */
+
+#define S3C2410_BANKCON_Tacp2          (0x0 << 2)
+#define S3C2410_BANKCON_Tacp3          (0x1 << 2)
+#define S3C2410_BANKCON_Tacp4          (0x2 << 2)
+#define S3C2410_BANKCON_Tacp6          (0x3 << 2)
+
+#define S3C2410_BANKCON_Tcah0          (0x0 << 4)
+#define S3C2410_BANKCON_Tcah1          (0x1 << 4)
+#define S3C2410_BANKCON_Tcah2          (0x2 << 4)
+#define S3C2410_BANKCON_Tcah4          (0x3 << 4)
+
+#define S3C2410_BANKCON_Tcoh0          (0x0 << 6)
+#define S3C2410_BANKCON_Tcoh1          (0x1 << 6)
+#define S3C2410_BANKCON_Tcoh2          (0x2 << 6)
+#define S3C2410_BANKCON_Tcoh4          (0x3 << 6)
+
+#define S3C2410_BANKCON_Tacc1          (0x0 << 8)
+#define S3C2410_BANKCON_Tacc2          (0x1 << 8)
+#define S3C2410_BANKCON_Tacc3          (0x2 << 8)
+#define S3C2410_BANKCON_Tacc4          (0x3 << 8)
+#define S3C2410_BANKCON_Tacc6          (0x4 << 8)
+#define S3C2410_BANKCON_Tacc8          (0x5 << 8)
+#define S3C2410_BANKCON_Tacc10         (0x6 << 8)
+#define S3C2410_BANKCON_Tacc14         (0x7 << 8)
+
+#define S3C2410_BANKCON_Tcos0          (0x0 << 11)
+#define S3C2410_BANKCON_Tcos1          (0x1 << 11)
+#define S3C2410_BANKCON_Tcos2          (0x2 << 11)
+#define S3C2410_BANKCON_Tcos4          (0x3 << 11)
+
+#define S3C2410_BANKCON_Tacs0          (0x0 << 13)
+#define S3C2410_BANKCON_Tacs1          (0x1 << 13)
+#define S3C2410_BANKCON_Tacs2          (0x2 << 13)
+#define S3C2410_BANKCON_Tacs4          (0x3 << 13)
+
+#define S3C2410_BANKCON_SRAM           (0x0 << 15)
+#define S3C2410_BANKCON_SDRAM          (0x3 << 15)
+
+/* next bits only for SDRAM in 6,7 */
+#define S3C2410_BANKCON_Trdc2          (0x00 << 2)
+#define S3C2410_BANKCON_Trdc3          (0x01 << 2)
+#define S3C2410_BANKCON_Trdc4          (0x02 << 2)
+
+/* control column address select */
+#define S3C2410_BANKCON_SCANb8         (0x00 << 0)
+#define S3C2410_BANKCON_SCANb9         (0x01 << 0)
+#define S3C2410_BANKCON_SCANb10                (0x02 << 0)
+
+#define S3C2410_REFRESH                        S3C2410_MEMREG(0x0024)
+#define S3C2410_BANKSIZE               S3C2410_MEMREG(0x0028)
+#define S3C2410_MRSRB6                 S3C2410_MEMREG(0x002C)
+#define S3C2410_MRSRB7                 S3C2410_MEMREG(0x0030)
+
+/* refresh control */
+
+#define S3C2410_REFRESH_REFEN          (1<<23)
+#define S3C2410_REFRESH_SELF           (1<<22)
+#define S3C2410_REFRESH_REFCOUNTER     ((1<<11)-1)
+
+#define S3C2410_REFRESH_TRP_MASK       (3<<20)
+#define S3C2410_REFRESH_TRP_2clk       (0<<20)
+#define S3C2410_REFRESH_TRP_3clk       (1<<20)
+#define S3C2410_REFRESH_TRP_4clk       (2<<20)
+
+#define S3C2410_REFRESH_TSRC_MASK      (3<<18)
+#define S3C2410_REFRESH_TSRC_4clk      (0<<18)
+#define S3C2410_REFRESH_TSRC_5clk      (1<<18)
+#define S3C2410_REFRESH_TSRC_6clk      (2<<18)
+#define S3C2410_REFRESH_TSRC_7clk      (3<<18)
+
+
+/* mode select register(s) */
+
+#define  S3C2410_MRSRB_CL1             (0x00 << 4)
+#define  S3C2410_MRSRB_CL2             (0x02 << 4)
+#define  S3C2410_MRSRB_CL3             (0x03 << 4)
+
+/* bank size register */
+#define S3C2410_BANKSIZE_128M          (0x2 << 0)
+#define S3C2410_BANKSIZE_64M           (0x1 << 0)
+#define S3C2410_BANKSIZE_32M           (0x0 << 0)
+#define S3C2410_BANKSIZE_16M           (0x7 << 0)
+#define S3C2410_BANKSIZE_8M            (0x6 << 0)
+#define S3C2410_BANKSIZE_4M            (0x5 << 0)
+#define S3C2410_BANKSIZE_2M            (0x4 << 0)
+#define S3C2410_BANKSIZE_MASK          (0x7 << 0)
+#define S3C2410_BANKSIZE_SCLK_EN       (1<<4)
+#define S3C2410_BANKSIZE_SCKE_EN       (1<<5)
+#define S3C2410_BANKSIZE_BURST         (1<<7)
+
+#endif /* __ASM_ARM_MEMREGS_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-nand.h b/include/asm-arm/arch-s3c2410/regs-nand.h
new file mode 100644 (file)
index 0000000..c443ac8
--- /dev/null
@@ -0,0 +1,43 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-nand.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 clock register definitions
+ *
+ *  Changelog:
+ *    18-Aug-2004    BJD     Copied file from 2.4 and updated
+*/
+
+#ifndef __ASM_ARM_REGS_NAND
+#define __ASM_ARM_REGS_NAND "$Id: nand.h,v 1.3 2003/12/09 11:36:29 ben Exp $"
+
+
+#define S3C2410_NFREG(x) (x)
+
+#define S3C2410_NFCONF  S3C2410_NFREG(0x00)
+#define S3C2410_NFCMD   S3C2410_NFREG(0x04)
+#define S3C2410_NFADDR  S3C2410_NFREG(0x08)
+#define S3C2410_NFDATA  S3C2410_NFREG(0x0C)
+#define S3C2410_NFSTAT  S3C2410_NFREG(0x10)
+#define S3C2410_NFECC   S3C2410_NFREG(0x14)
+
+#define S3C2410_NFCONF_EN          (1<<15)
+#define S3C2410_NFCONF_512BYTE     (1<<14)
+#define S3C2410_NFCONF_4STEP       (1<<13)
+#define S3C2410_NFCONF_INITECC     (1<<12)
+#define S3C2410_NFCONF_nFCE        (1<<11)
+#define S3C2410_NFCONF_TACLS(x)    ((x)<<8)
+#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<4)
+#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<0)
+
+#define S3C2410_NFSTAT_BUSY        (1<<0)
+
+/* think ECC can only be 8bit read? */
+
+#endif /* __ASM_ARM_REGS_NAND */
+
diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h
new file mode 100644 (file)
index 0000000..fd688ad
--- /dev/null
@@ -0,0 +1,112 @@
+/* linux/include/asm/arch-s3c2410/regs-sdi.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 MMC/SDIO register definitions
+ *
+ *  Changelog:
+ *    18-Aug-2004 Ben Dooks      Created initial file
+*/
+
+#ifndef __ASM_ARM_REGS_SDI
+#define __ASM_ARM_REGS_SDI "regs-sdi.h"
+
+#define S3C2410_SDICON                (0x00)
+#define S3C2410_SDIPRE                (0x04)
+#define S3C2410_SDICMDARG             (0x08)
+#define S3C2410_SDICMDCON             (0x0C)
+#define S3C2410_SDICMDSTAT            (0x10)
+#define S3C2410_SDIRSP0               (0x14)
+#define S3C2410_SDIRSP1               (0x18)
+#define S3C2410_SDIRSP2               (0x1C)
+#define S3C2410_SDIRSP3               (0x20)
+#define S3C2410_SDITIMER              (0x24)
+#define S3C2410_SDIBSIZE              (0x28)
+#define S3C2410_SDIDCON               (0x2C)
+#define S3C2410_SDIDCNT               (0x30)
+#define S3C2410_SDIDSTA               (0x34)
+#define S3C2410_SDIFSTA               (0x38)
+#define S3C2410_SDIDATA               (0x3C)
+#define S3C2410_SDIIMSK               (0x40)
+
+#define S3C2410_SDICON_BYTEORDER      (1<<4)
+#define S3C2410_SDICON_SDIOIRQ        (1<<3)
+#define S3C2410_SDICON_RWAITEN        (1<<2)
+#define S3C2410_SDICON_FIFORESET      (1<<1)
+#define S3C2410_SDICON_CLOCKTYPE      (1<<0)
+
+#define S3C2410_SDICMDCON_ABORT       (1<<12)
+#define S3C2410_SDICMDCON_WITHDATA    (1<<11)
+#define S3C2410_SDICMDCON_LONGRSP     (1<<10)
+#define S3C2410_SDICMDCON_WAITRSP     (1<<9)
+#define S3C2410_SDICMDCON_CMDSTART    (1<<8)
+#define S3C2410_SDICMDCON_INDEX       (0xff)
+
+#define S3C2410_SDICMDSTAT_CRCFAIL    (1<<12)
+#define S3C2410_SDICMDSTAT_CMDSENT    (1<<11)
+#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10)
+#define S3C2410_SDICMDSTAT_RSPFIN     (1<<9)
+#define S3C2410_SDICMDSTAT_XFERING    (1<<8)
+#define S3C2410_SDICMDSTAT_INDEX      (0xff)
+
+#define S3C2410_SDIDCON_IRQPERIOD     (1<<21)
+#define S3C2410_SDIDCON_TXAFTERRESP   (1<<20)
+#define S3C2410_SDIDCON_RXAFTERCMD    (1<<19)
+#define S3C2410_SDIDCON_BUSYAFTERCMD  (1<<18)
+#define S3C2410_SDIDCON_BLOCKMODE     (1<<17)
+#define S3C2410_SDIDCON_WIDEBUS       (1<<16)
+#define S3C2410_SDIDCON_DMAEN         (1<<15)
+#define S3C2410_SDIDCON_STOP          (1<<14)
+
+#define S3C2410_SDIDCON_XFER_MASK     (3<<12)
+#define S3C2410_SDIDCON_XFER_READY    (0<<12)
+#define S3C2410_SDIDCON_XFER_CHKSTART (1<<12)
+#define S3C2410_SDIDCON_XFER_RXSTART  (2<<12)
+#define S3C2410_SDIDCON_XFER_TXSTART  (3<<12)
+
+#define S3C2410_SDIDCNT_BLKNUM_SHIFT  (12)
+
+#define S3C2410_SDIDSTA_RDYWAITREQ    (1<<10)
+#define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9)
+#define S3C2410_SDIDSTA_FIFOFAIL      (1<<8)
+#define S3C2410_SDIDSTA_CRCFAIL       (1<<7)
+#define S3C2410_SDIDSTA_RXCRCFAIL     (1<<6)
+#define S3C2410_SDIDSTA_DATATIMEOUT   (1<<5)
+#define S3C2410_SDIDSTA_XFERFINISH    (1<<4)
+#define S3C2410_SDIDSTA_BUSYFINISH    (1<<3)
+#define S3C2410_SDIDSTA_TXDATAON      (1<<1)
+#define S3C2410_SDIDSTA_RXDATAON      (1<<0)
+
+#define S3C2410_SDIFSTA_TXFULL         (1<<13)
+#define S3C2410_SDIFSTA_RXFULL         (1<<12)
+#define S3C2410_SDIFSTA_TXHALF         (1<<11)
+#define S3C2410_SDIFSTA_TXEMPTY        (1<<10)
+#define S3C2410_SDIFSTA_RXLAST         (1<<9)
+#define S3C2410_SDIFSTA_RXFULL         (1<<8)
+#define S3C2410_SDIFSTA_RXHALF         (1<<7)
+#define S3C2410_SDIFSTA_COUNTMASK      (0x7f)
+
+#define S3C2410_SDIIMSK_RESPONSECRC    (1<<17)
+#define S3C2410_SDIIMSK_CMDSENT        (1<<16)
+#define S3C2410_SDIIMSK_CMDTIMEOUT     (1<<15)
+#define S3C2410_SDIIMSK_RESPONSEND     (1<<14)
+#define S3C2410_SDIIMSK_READWAIT       (1<<13)
+#define S3C2410_SDIIMSK_SDIOIRQ        (1<<12)
+#define S3C2410_SDIIMSK_FIFOFAIL       (1<<11)
+#define S3C2410_SDIIMSK_CRCSTATUS      (1<<10)
+#define S3C2410_SDIIMSK_DATACRC        (1<<9)
+#define S3C2410_SDIIMSK_DATATIMEOUT    (1<<8)
+#define S3C2410_SDIIMSK_DATAFINISH     (1<<7)
+#define S3C2410_SDIIMSK_BUSYFINISH     (1<<6)
+#define S3C2410_SDIIMSK_TXFIFOHALF     (1<<4)
+#define S3C2410_SDIIMSK_TXFIFOEMPTY    (1<<3)
+#define S3C2410_SDIIMSK_RXFIFOLAST     (1<<2)
+#define S3C2410_SDIIMSK_RXFIFOFULL     (1<<1)
+#define S3C2410_SDIIMSK_RXFIFOHALF     (1<<0)
+
+#endif /* __ASM_ARM_REGS_SDI */
diff --git a/include/asm-arm/arch-s3c2410/regs-spi.h b/include/asm-arm/arch-s3c2410/regs-spi.h
new file mode 100644 (file)
index 0000000..cb502a8
--- /dev/null
@@ -0,0 +1,56 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-spi.h
+ *
+ * Copyright (c) 2004 Fetron GmbH
+ *
+ * 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.
+ *
+ * S3C2410 SPI register definition
+ *
+ *  Changelog:
+ *    20-04-2004     KF      Created file
+ *    04-10-2004     BJD     Removed VA address (no longer mapped)
+ *                          tidied file for submission
+ */
+
+#ifndef __ASM_ARCH_REGS_SPI_H
+#define __ASM_ARCH_REGS_SPI_H
+
+
+#define S3C2410_SPCON  (0x00)
+
+#define S3C2410_SPCON_SMOD_DMA   (2<<5)        /* DMA mode */
+#define S3C2410_SPCON_SMOD_INT   (1<<5)        /* interrupt mode */
+#define S3C2410_SPCON_SMOD_POLL   (0<<5)       /* polling mode */
+#define S3C2410_SPCON_ENSCK      (1<<4)        /* Enable SCK */
+#define S3C2410_SPCON_MSTR       (1<<3)        /* Master/Slave select
+                                                  0: slave, 1: master */
+#define S3C2410_SPCON_CPOL_HIGH          (1<<2)        /* Clock polarity select */
+#define S3C2410_SPCON_CPOL_LOW   (0<<2)        /* Clock polarity select */
+
+#define S3C2410_SPCON_CPHA_FMTB          (1<<1)        /* Clock Phase Select */
+#define S3C2410_SPCON_CPHA_FMTA          (0<<1)        /* Clock Phase Select */
+
+#define S3C2410_SPCON_TAGD       (1<<0)        /* Tx auto garbage data mode */
+
+
+#define S3C2410_SPSTA   (0x04)
+
+#define S3C2410_SPSTA_DCOL       (1<<2)        /* Data Collision Error */
+#define S3C2410_SPSTA_MULD       (1<<1)        /* Multi Master Error */
+#define S3C2410_SPSTA_READY      (1<<0)        /* Data Tx/Rx ready */
+
+
+#define S3C2410_SPPIN   (0x08)
+
+#define S3C2410_SPPIN_ENMUL      (1<<2)        /* Multi Master Error detect */
+#define S3C2410_SPPIN_RESERVED   (1<<1)
+#define S3C2410_SPPIN_KEEP       (1<<0)        /* Master Out keep */
+
+
+#define S3C2410_SPPRE   (0x0C)
+#define S3C2410_SPTDAT  (0x10)
+#define S3C2410_SPRDAT  (0x14)
+
+#endif /* __ASM_ARCH_REGS_SPI_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
new file mode 100644 (file)
index 0000000..aee2805
--- /dev/null
@@ -0,0 +1,162 @@
+/* linux/include/asm/arch-s3c2410/regs-udc.h
+ *
+ * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
+ *
+ * This include 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 of
+ * the License, or (at your option) any later version.
+ *
+ *  Changelog:
+ *    01-08-2004       initial creation
+ *    12-09-2004       cleanup for submission
+ */
+
+#ifndef __ASM_ARCH_REGS_UDC_H
+#define __ASM_ARCH_REGS_UDC_H
+
+
+#define S3C2410_USBDREG(x) ((x) + S3C2410_VA_USBDEV)
+
+#define S3C2410_UDC_FUNC_ADDR_REG      S3C2410_USBDREG(0x0140)
+#define S3C2410_UDC_PWR_REG            S3C2410_USBDREG(0x0144)
+#define S3C2410_UDC_EP_INT_REG         S3C2410_USBDREG(0x0148)
+
+#define S3C2410_UDC_USB_INT_REG                S3C2410_USBDREG(0x0158)
+#define S3C2410_UDC_EP_INT_EN_REG      S3C2410_USBDREG(0x015c)
+
+#define S3C2410_UDC_USB_INT_EN_REG     S3C2410_USBDREG(0x016c)
+
+#define S3C2410_UDC_FRAME_NUM1_REG     S3C2410_USBDREG(0x0170)
+#define S3C2410_UDC_FRAME_NUM2_REG     S3C2410_USBDREG(0x0174)
+
+#define S3C2410_UDC_EP0_FIFO_REG       S3C2410_USBDREG(0x01c0)
+#define S3C2410_UDC_EP1_FIFO_REG       S3C2410_USBDREG(0x01c4)
+#define S3C2410_UDC_EP2_FIFO_REG       S3C2410_USBDREG(0x01c8)
+#define S3C2410_UDC_EP3_FIFO_REG       S3C2410_USBDREG(0x01cc)
+#define S3C2410_UDC_EP4_FIFO_REG       S3C2410_USBDREG(0x01d0)
+
+#define S3C2410_UDC_EP1_DMA_CON                S3C2410_USBDREG(0x0200)
+#define S3C2410_UDC_EP1_DMA_UNIT       S3C2410_USBDREG(0x0204)
+#define S3C2410_UDC_EP1_DMA_FIFO       S3C2410_USBDREG(0x0208)
+#define S3C2410_UDC_EP1_DMA_TTC_L      S3C2410_USBDREG(0x020c)
+#define S3C2410_UDC_EP1_DMA_TTC_M      S3C2410_USBDREG(0x0210)
+#define S3C2410_UDC_EP1_DMA_TTC_H      S3C2410_USBDREG(0x0214)
+
+#define S3C2410_UDC_EP2_DMA_CON                S3C2410_USBDREG(0x0218)
+#define S3C2410_UDC_EP2_DMA_UNIT       S3C2410_USBDREG(0x021c)
+#define S3C2410_UDC_EP2_DMA_FIFO       S3C2410_USBDREG(0x0220)
+#define S3C2410_UDC_EP2_DMA_TTC_L      S3C2410_USBDREG(0x0224)
+#define S3C2410_UDC_EP2_DMA_TTC_M      S3C2410_USBDREG(0x0228)
+#define S3C2410_UDC_EP2_DMA_TTC_H      S3C2410_USBDREG(0x022c)
+
+#define S3C2410_UDC_EP3_DMA_CON                S3C2410_USBDREG(0x0240)
+#define S3C2410_UDC_EP3_DMA_UNIT       S3C2410_USBDREG(0x0244)
+#define S3C2410_UDC_EP3_DMA_FIFO       S3C2410_USBDREG(0x0248)
+#define S3C2410_UDC_EP3_DMA_TTC_L      S3C2410_USBDREG(0x024c)
+#define S3C2410_UDC_EP3_DMA_TTC_M      S3C2410_USBDREG(0x0250)
+#define S3C2410_UDC_EP3_DMA_TTC_H      S3C2410_USBDREG(0x0254)
+
+#define S3C2410_UDC_EP4_DMA_CON                S3C2410_USBDREG(0x0258)
+#define S3C2410_UDC_EP4_DMA_UNIT       S3C2410_USBDREG(0x025c)
+#define S3C2410_UDC_EP4_DMA_FIFO       S3C2410_USBDREG(0x0260)
+#define S3C2410_UDC_EP4_DMA_TTC_L      S3C2410_USBDREG(0x0264)
+#define S3C2410_UDC_EP4_DMA_TTC_M      S3C2410_USBDREG(0x0268)
+#define S3C2410_UDC_EP4_DMA_TTC_H      S3C2410_USBDREG(0x026c)
+
+#define S3C2410_UDC_INDEX_REG          S3C2410_USBDREG(0x0178)
+
+/* indexed registers */
+
+#define S3C2410_UDC_MAXP_REG           S3C2410_USBDREG(0x018c)
+
+#define S3C2410_UDC_EP0_CSR_REG                S3C2410_USBDREG(0x0184)
+
+#define S3C2410_UDC_IN_CSR1_REG                S3C2410_USBDREG(0x0184)
+#define S3C2410_UDC_IN_CSR2_REG                S3C2410_USBDREG(0x0188)
+
+#define S3C2410_UDC_OUT_CSR1_REG       S3C2410_USBDREG(0x0190)
+#define S3C2410_UDC_OUT_CSR2_REG       S3C2410_USBDREG(0x0194)
+#define S3C2410_UDC_OUT_FIFO_CNT1_REG  S3C2410_USBDREG(0x0198)
+#define S3C2410_UDC_OUT_FIFO_CNT2_REG  S3C2410_USBDREG(0x019c)
+
+
+
+#define S3C2410_UDC_PWR_ISOUP          (1<<7) // R/W
+#define S3C2410_UDC_PWR_RESET          (1<<3) // R
+#define S3C2410_UDC_PWR_RESUME         (1<<2) // R/W
+#define S3C2410_UDC_PWR_SUSPEND                (1<<1) // R
+#define S3C2410_UDC_PWR_ENSUSPEND      (1<<0) // R/W
+
+#define S3C2410_UDC_PWR_DEFAULT                0x00
+
+#define S3C2410_UDC_INT_EP4            (1<<4) // R/W (clear only)
+#define S3C2410_UDC_INT_EP3            (1<<3) // R/W (clear only)
+#define S3C2410_UDC_INT_EP2            (1<<2) // R/W (clear only)
+#define S3C2410_UDC_INT_EP1            (1<<1) // R/W (clear only)
+#define S3C2410_UDC_INT_EP0            (1<<0) // R/W (clear only)
+
+#define S3C2410_UDC_USBINT_RESET       (1<<2) // R/W (clear only)
+#define S3C2410_UDC_USBINT_RESUME      (1<<1) // R/W (clear only)
+#define S3C2410_UDC_USBINT_SUSPEND     (1<<0) // R/W (clear only)
+
+#define S3C2410_UDC_INTE_EP4           (1<<4) // R/W
+#define S3C2410_UDC_INTE_EP3           (1<<3) // R/W
+#define S3C2410_UDC_INTE_EP2           (1<<2) // R/W
+#define S3C2410_UDC_INTE_EP1           (1<<1) // R/W
+#define S3C2410_UDC_INTE_EP0           (1<<0) // R/W
+
+#define S3C2410_UDC_USBINTE_RESET      (1<<2) // R/W
+#define S3C2410_UDC_USBINTE_SUSPEND    (1<<0) // R/W
+
+
+#define S3C2410_UDC_INDEX_EP0          (0x00)
+#define S3C2410_UDC_INDEX_EP1          (0x01) // ??
+#define S3C2410_UDC_INDEX_EP2          (0x02) // ??
+#define S3C2410_UDC_INDEX_EP3          (0x03) // ??
+#define S3C2410_UDC_INDEX_EP4          (0x04) // ??
+
+#define S3C2410_UDC_ICSR1_CLRDT                (1<<6) // R/W
+#define S3C2410_UDC_ICSR1_SENTSTL      (1<<5) // R/W (clear only)
+#define S3C2410_UDC_ICSR1_SENDSTL      (1<<4) // R/W
+#define S3C2410_UDC_ICSR1_FFLUSH       (1<<3) // W   (set only)
+#define S3C2410_UDC_ICSR1_UNDRUN       (1<<2) // R/W (clear only)
+#define S3C2410_UDC_ICSR1_PKTRDY       (1<<0) // R/W (set only)
+
+#define S3C2410_UDC_ICSR2_AUTOSET      (1<<7) // R/W
+#define S3C2410_UDC_ICSR2_ISO          (1<<6) // R/W
+#define S3C2410_UDC_ICSR2_MODEIN       (1<<5) // R/W
+#define S3C2410_UDC_ICSR2_DMAIEN       (1<<4) // R/W
+
+#define S3C2410_UDC_OCSR1_CLRDT                (1<<7) // R/W
+#define S3C2410_UDC_OCSR1_SENTSTL      (1<<6) // R/W (clear only)
+#define S3C2410_UDC_OCSR1_SENDSTL      (1<<5) // R/W
+#define S3C2410_UDC_OCSR1_FFLUSH       (1<<4) // R/W
+#define S3C2410_UDC_OCSR1_DERROR       (1<<3) // R
+#define S3C2410_UDC_OCSR1_OVRRUN       (1<<2) // R/W (clear only)
+#define S3C2410_UDC_OCSR1_PKTRDY       (1<<0) // R/W (clear only)
+
+#define S3C2410_UDC_OCSR2_AUTOCLR      (1<<7) // R/W
+#define S3C2410_UDC_OCSR2_ISO          (1<<6) // R/W
+#define S3C2410_UDC_OCSR2_DMAIEN       (1<<5) // R/W
+
+#define S3C2410_UDC_SETIX(x)       \
+       __raw_writel(S3C2410_UDC_INDEX_ ## x, S3C2410_UDC_INDEX_REG);
+
+
+#define S3C2410_UDC_EP0_CSR_OPKRDY     (1<<0)
+#define S3C2410_UDC_EP0_CSR_IPKRDY     (1<<1)
+#define S3C2410_UDC_EP0_CSR_SENTSTL    (1<<2)
+#define S3C2410_UDC_EP0_CSR_DE         (1<<3)
+#define S3C2410_UDC_EP0_CSR_SE         (1<<4)
+#define S3C2410_UDC_EP0_CSR_SENDSTL    (1<<5)
+#define S3C2410_UDC_EP0_CSR_SOPKTRDY   (1<<6)
+#define S3C2410_UDC_EP0_CSR_SSE        (1<<7)
+
+#define S3C2410_UDC_MAXP_8             (1<<0)
+#define S3C2410_UDC_MAXP_16            (1<<1)
+#define S3C2410_UDC_MAXP_32            (1<<2)
+#define S3C2410_UDC_MAXP_64            (1<<3)
+
+
+#endif
diff --git a/include/asm-arm/arch-s3c2410/usb-control.h b/include/asm-arm/arch-s3c2410/usb-control.h
new file mode 100644 (file)
index 0000000..1cc85a0
--- /dev/null
@@ -0,0 +1,45 @@
+/* linux/include/asm-arm/arch-s3c2410/usb-control.h
+ *
+ * (c) 2004 Simtec Electronics
+ *  Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - usb port information
+ *
+ * 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:
+ *  11-Sep-2004 BJD  Created file
+ *  21-Sep-2004 BJD  Updated port info
+*/
+
+#ifndef __ASM_ARCH_USBCONTROL_H
+#define __ASM_ARCH_USBCONTROL_H "include/asm-arm/arch-s3c2410/usb-control.h"
+
+#define S3C_HCDFLG_USED        (1)
+
+struct s3c2410_hcd_port {
+       unsigned char   flags;
+       unsigned char   power;
+       unsigned char   oc_status;
+       unsigned char   oc_changed;
+};
+
+struct s3c2410_hcd_info {
+       struct usb_hcd          *hcd;
+       struct s3c2410_hcd_port port[2];
+
+       void            (*power_control)(int port, int to);
+       void            (*enable_oc)(struct s3c2410_hcd_info *, int on);
+       void            (*report_oc)(struct s3c2410_hcd_info *, int ports);
+};
+
+static void inline s3c2410_report_oc(struct s3c2410_hcd_info *info, int ports)
+{
+       if (info->report_oc != NULL) {
+               (info->report_oc)(info, ports);
+       }
+}
+
+#endif /*__ASM_ARCH_USBCONTROL_H */
diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h
new file mode 100644 (file)
index 0000000..65436fe
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel.
+ *
+ * David A Rusling
+ *
+ * Copyright (C) 2001 ARM Limited
+ *
+ * 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/config.h>
+#include <linux/fb.h>
+
+/*
+ * CLCD Controller Internal Register addresses
+ */
+#define CLCD_TIM0              0x00000000
+#define CLCD_TIM1              0x00000004
+#define CLCD_TIM2              0x00000008
+#define CLCD_TIM3              0x0000000c
+#define CLCD_UBAS              0x00000010
+#define CLCD_LBAS              0x00000014
+
+#ifndef CONFIG_ARCH_VERSATILE_PB
+#define CLCD_IENB              0x00000018
+#define CLCD_CNTL              0x0000001c
+#else
+/*
+ * Someone rearranged these two registers on the Versatile
+ * platform...
+ */
+#define CLCD_IENB              0x0000001c
+#define CLCD_CNTL              0x00000018
+#endif
+
+#define CLCD_STAT              0x00000020
+#define CLCD_INTR              0x00000024
+#define CLCD_UCUR              0x00000028
+#define CLCD_LCUR              0x0000002C
+#define CLCD_PALL              0x00000200
+#define CLCD_PALETTE           0x00000200
+
+#define TIM2_CLKSEL            (1 << 5)
+#define TIM2_IVS               (1 << 11)
+#define TIM2_IHS               (1 << 12)
+#define TIM2_IPC               (1 << 13)
+#define TIM2_IOE               (1 << 14)
+#define TIM2_BCD               (1 << 26)
+
+#define CNTL_LCDEN             (1 << 0)
+#define CNTL_LCDBPP1           (0 << 1)
+#define CNTL_LCDBPP2           (1 << 1)
+#define CNTL_LCDBPP4           (2 << 1)
+#define CNTL_LCDBPP8           (3 << 1)
+#define CNTL_LCDBPP16          (4 << 1)
+#define CNTL_LCDBPP24          (5 << 1)
+#define CNTL_LCDBW             (1 << 4)
+#define CNTL_LCDTFT            (1 << 5)
+#define CNTL_LCDMONO8          (1 << 6)
+#define CNTL_LCDDUAL           (1 << 7)
+#define CNTL_BGR               (1 << 8)
+#define CNTL_BEBO              (1 << 9)
+#define CNTL_BEPO              (1 << 10)
+#define CNTL_LCDPWR            (1 << 11)
+#define CNTL_LCDVCOMP(x)       ((x) << 12)
+#define CNTL_LDMAFIFOTIME      (1 << 15)
+#define CNTL_WATERMARK         (1 << 16)
+
+struct clcd_panel {
+       struct fb_videomode     mode;
+       signed short            width;  /* width in mm */
+       signed short            height; /* height in mm */
+       u32                     tim2;
+       u32                     tim3;
+       u32                     cntl;
+       unsigned int            bpp:8,
+                               fixedtimings:1,
+                               grayscale:1;
+       unsigned int            connector;
+};
+
+struct clcd_regs {
+       u32                     tim0;
+       u32                     tim1;
+       u32                     tim2;
+       u32                     tim3;
+       u32                     cntl;
+       unsigned long           pixclock;
+};
+
+struct clcd_fb;
+
+/*
+ * the board-type specific routines
+ */
+struct clcd_board {
+       const char *name;
+
+       /*
+        * Optional.  Check whether the var structure is acceptable
+        * for this display.
+        */
+       int     (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
+
+       /*
+        * Compulsary.  Decode fb->fb.var into regs->*.  In the case of
+        * fixed timing, set regs->* to the register values required.
+        */
+       void    (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
+
+       /*
+        * Optional.  Disable any extra display hardware.
+        */
+       void    (*disable)(struct clcd_fb *);
+
+       /*
+        * Optional.  Enable any extra display hardware.
+        */
+       void    (*enable)(struct clcd_fb *);
+
+       /*
+        * Setup platform specific parts of CLCD driver
+        */
+       int     (*setup)(struct clcd_fb *);
+
+       /*
+        * Remove platform specific parts of CLCD driver
+        */
+       void    (*remove)(struct clcd_fb *);
+};
+
+struct amba_device;
+struct clk;
+
+/* this data structure describes each frame buffer device we find */
+struct clcd_fb {
+       struct fb_info          fb;
+       struct amba_device      *dev;
+       struct clk              *clk;
+       struct clcd_panel       *panel;
+       struct clcd_board       *board;
+       void                    *board_data;
+       void                    *regs;
+       u32                     clcd_cntl;
+       u32                     cmap[16];
+};
+
+static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
+{
+       u32 val;
+
+       /*
+        * Program the CLCD controller registers and start the CLCD
+        */
+       val = ((fb->fb.var.xres / 16) - 1) << 2;
+       val |= (fb->fb.var.hsync_len - 1) << 8;
+       val |= (fb->fb.var.right_margin - 1) << 16;
+       val |= (fb->fb.var.left_margin - 1) << 24;
+       regs->tim0 = val;
+
+       val = fb->fb.var.yres - 1;
+       val |= (fb->fb.var.vsync_len - 1) << 10;
+       val |= fb->fb.var.lower_margin << 16;
+       val |= fb->fb.var.upper_margin << 24;
+       regs->tim1 = val;
+
+       val = fb->panel->tim2;
+       val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
+       val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
+
+       if (fb->panel->cntl & CNTL_LCDTFT)
+               val |= (fb->fb.var.xres_virtual - 1) << 16;
+       else if (fb->panel->cntl & CNTL_LCDBW)
+               printk("what value for CPL for stnmono panels?");
+       else
+               val |= ((fb->fb.var.xres_virtual * 8 / 3) - 1) << 16;
+       regs->tim2 = val;
+
+       regs->tim3 = fb->panel->tim3;
+
+       val = fb->panel->cntl;
+       if (fb->fb.var.grayscale)
+               val |= CNTL_LCDBW;
+
+       switch (fb->fb.var.bits_per_pixel) {
+       case 1:
+               val |= CNTL_LCDBPP1;
+               break;
+       case 2:
+               val |= CNTL_LCDBPP2;
+               break;
+       case 4:
+               val |= CNTL_LCDBPP4;
+               break;
+       case 8:
+               val |= CNTL_LCDBPP8;
+               break;
+       case 16:
+               val |= CNTL_LCDBPP16;
+               break;
+       case 24:
+               val |= CNTL_LCDBPP24;
+               break;
+       }
+
+       regs->cntl = val;
+       regs->pixclock = fb->fb.var.pixclock;
+}
+
+static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
+{
+       var->xres_virtual = var->xres = (var->xres + 7) & ~7;
+       var->yres_virtual = var->yres;
+
+#define CHECK(e,l,h) (var->e < l || var->e > h)
+       if (CHECK(right_margin, (5+1), 256) ||  /* back porch */
+           CHECK(left_margin, (5+1), 256) ||   /* front porch */
+           CHECK(hsync_len, (5+1), 256) ||
+           var->xres > 4096 ||
+           var->lower_margin > 255 ||          /* back porch */
+           var->upper_margin > 255 ||          /* front porch */
+           var->vsync_len > 32 ||
+           var->yres > 1024)
+               return -EINVAL;
+#undef CHECK
+
+       /* single panel mode: PCD = max(PCD, 1) */
+       /* dual panel mode: PCD = max(PCD, 5) */
+
+       /*
+        * You can't change the grayscale setting, and
+        * we can only do non-interlaced video.
+        */
+       if (var->grayscale != fb->fb.var.grayscale ||
+           (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+               return -EINVAL;
+
+#define CHECK(e) (var->e != fb->fb.var.e)
+       if (fb->panel->fixedtimings &&
+           (CHECK(xres)                ||
+            CHECK(yres)                ||
+            CHECK(bits_per_pixel)      ||
+            CHECK(pixclock)            ||
+            CHECK(left_margin)         ||
+            CHECK(right_margin)        ||
+            CHECK(upper_margin)        ||
+            CHECK(lower_margin)        ||
+            CHECK(hsync_len)           ||
+            CHECK(vsync_len)           ||
+            CHECK(sync)))
+               return -EINVAL;
+#undef CHECK
+
+       var->nonstd = 0;
+       var->accel_flags = 0;
+
+       return 0;
+}
diff --git a/include/asm-arm/hardware/icst307.h b/include/asm-arm/hardware/icst307.h
new file mode 100644 (file)
index 0000000..ff8618a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  linux/include/asm-arm/hardware/icst307.h
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Support functions for calculating clocks/divisors for the ICS307
+ *  clock generators.  See http://www.icst.com/ for more information
+ *  on these devices.
+ *
+ *  This file is similar to the icst525.h file
+ */
+#ifndef ASMARM_HARDWARE_ICST307_H
+#define ASMARM_HARDWARE_ICST307_H
+
+struct icst307_params {
+       unsigned long   ref;
+       unsigned long   vco_max;        /* inclusive */
+       unsigned short  vd_min;         /* inclusive */
+       unsigned short  vd_max;         /* inclusive */
+       unsigned char   rd_min;         /* inclusive */
+       unsigned char   rd_max;         /* inclusive */
+};
+
+struct icst307_vco {
+       unsigned short  v;
+       unsigned char   r;
+       unsigned char   s;
+};
+
+unsigned long icst307_khz(const struct icst307_params *p, struct icst307_vco vco);
+struct icst307_vco icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq);
+struct icst307_vco icst307_ps_to_vco(const struct icst307_params *p, unsigned long period);
+
+#endif
diff --git a/include/asm-arm/mach/irda.h b/include/asm-arm/mach/irda.h
new file mode 100644 (file)
index 0000000..58984d9
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  linux/include/asm-arm/mach/irda.h
+ *
+ *  Copyright (C) 2004 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_MACH_IRDA_H
+#define __ASM_ARM_MACH_IRDA_H
+
+struct irda_platform_data {
+       int (*startup)(struct device *);
+       void (*shutdown)(struct device *);
+       int (*set_power)(struct device *, unsigned int state);
+       void (*set_speed)(struct device *, unsigned int speed);
+};
+
+#endif
diff --git a/include/asm-arm/mach/mmc.h b/include/asm-arm/mach/mmc.h
new file mode 100644 (file)
index 0000000..41a946e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  linux/include/asm-arm/mach/mmc.h
+ */
+#ifndef ASMARM_MACH_MMC_H
+#define ASMARM_MACH_MMC_H
+
+#include <linux/mmc/protocol.h>
+
+struct mmc_platform_data {
+       unsigned int mclk;                      /* mmc base clock rate */
+       unsigned int ocr_mask;                  /* available voltages */
+       u32 (*translate_vdd)(struct device *, unsigned int);
+       unsigned int (*status)(struct device *);
+};
+
+#endif
diff --git a/include/asm-arm/rtc.h b/include/asm-arm/rtc.h
new file mode 100644 (file)
index 0000000..c3e330d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  linux/include/asm-arm/rtc.h
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions Ltd.
+ *
+ * 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 ASMARM_RTC_H
+#define ASMARM_RTC_H
+
+struct module;
+
+struct rtc_ops {
+       struct module   *owner;
+       int             (*open)(void);
+       void            (*release)(void);
+       int             (*ioctl)(unsigned int, unsigned long);
+
+       void            (*read_time)(struct rtc_time *);
+       int             (*set_time)(struct rtc_time *);
+       void            (*read_alarm)(struct rtc_wkalrm *);
+       int             (*set_alarm)(struct rtc_wkalrm *);
+       int             (*proc)(char *buf);
+};
+
+void rtc_time_to_tm(unsigned long, struct rtc_time *);
+int rtc_tm_to_time(struct rtc_time *, unsigned long *);
+void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
+void rtc_update(unsigned long, unsigned long);
+int register_rtc(struct rtc_ops *);
+void unregister_rtc(struct rtc_ops *);
+
+static inline int rtc_periodic_alarm(struct rtc_time *tm)
+{
+       return  (tm->tm_year == -1) ||
+               ((unsigned)tm->tm_mon >= 12) ||
+               ((unsigned)(tm->tm_mday - 1) >= 31) ||
+               ((unsigned)tm->tm_hour > 23) ||
+               ((unsigned)tm->tm_min > 59) ||
+               ((unsigned)tm->tm_sec > 59);
+}
+
+#endif
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
new file mode 100644 (file)
index 0000000..e5913c3
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _ASM_GENERIC_BUG_H
+#define _ASM_GENERIC_BUG_H
+
+#include <linux/compiler.h>
+#include <linux/config.h>
+
+#ifndef HAVE_ARCH_BUG
+#define BUG() do { \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+       panic("BUG!"); \
+} while (0)
+#endif
+
+#ifndef HAVE_ARCH_PAGE_BUG
+#define PAGE_BUG(page) do { \
+       printk("page BUG for page at %p\n", page); \
+       BUG(); \
+} while (0)
+#endif
+
+#ifndef HAVE_ARCH_BUG_ON
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#endif
+
+#ifndef HAVE_ARCH_WARN_ON
+#define WARN_ON(condition) do { \
+       if (unlikely((condition)!=0)) { \
+               printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
+               dump_stack(); \
+       } \
+} while (0)
+#endif
+
+#endif
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
new file mode 100644 (file)
index 0000000..4991543
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef __GENERIC_IO_H
+#define __GENERIC_IO_H
+
+#include <linux/linkage.h>
+
+/*
+ * These are the "generic" interfaces for doing new-style
+ * memory-mapped or PIO accesses. Architectures may do
+ * their own arch-optimized versions, these just act as
+ * wrappers around the old-style IO register access functions:
+ * read[bwl]/write[bwl]/in[bwl]/out[bwl]
+ *
+ * Don't include this directly, include it from <asm/io.h>.
+ */
+
+/*
+ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
+ * access or a MMIO access, these functions don't care. The info is
+ * encoded in the hardware mapping set up by the mapping functions
+ * (or the cookie itself, depending on implementation and hw).
+ *
+ * The generic routines just encode the PIO/MMIO as part of the
+ * cookie, and coldly assume that the MMIO IO mappings are not
+ * in the low address range. Architectures for which this is not
+ * true can't use this generic implementation.
+ */
+extern unsigned int fastcall ioread8(void __iomem *);
+extern unsigned int fastcall ioread16(void __iomem *);
+extern unsigned int fastcall ioread32(void __iomem *);
+
+extern void fastcall iowrite8(u8, void __iomem *);
+extern void fastcall iowrite16(u16, void __iomem *);
+extern void fastcall iowrite32(u32, void __iomem *);
+
+/*
+ * "string" versions of the above. Note that they
+ * use native byte ordering for the accesses (on
+ * the assumption that IO and memory agree on a
+ * byte order, and CPU byteorder is irrelevant).
+ *
+ * They do _not_ update the port address. If you
+ * want MMIO that copies stuff laid out in MMIO
+ * memory across multiple ports, use "memcpy_toio()"
+ * and friends.
+ */
+extern void fastcall ioread8_rep(void __iomem *port, void *buf, unsigned long count);
+extern void fastcall ioread16_rep(void __iomem *port, void *buf, unsigned long count);
+extern void fastcall ioread32_rep(void __iomem *port, void *buf, unsigned long count);
+
+extern void fastcall iowrite8_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void fastcall iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void fastcall iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);
+
+/* Create a virtual mapping cookie for an IO port range */
+extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+extern void ioport_unmap(void __iomem *);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+struct pci_dev;
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+
+#endif
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
new file mode 100644 (file)
index 0000000..549cb3a
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _ASM_GENERIC_UACCESS_H_
+#define _ASM_GENERIC_UACCESS_H_
+
+/*
+ * This macro should be used instead of __get_user() when accessing
+ * values at locations that are not known to be aligned.
+ */
+#define __get_user_unaligned(x, ptr)                                   \
+({                                                                     \
+       __typeof__ (*(ptr)) __x;                                        \
+       __copy_from_user(&__x, (ptr), sizeof(*(ptr))) ? -EFAULT : 0;    \
+       (x) = __x;                                                      \
+})
+
+
+/*
+ * This macro should be used instead of __put_user() when accessing
+ * values at locations that are not known to be aligned.
+ */
+#define __put_user_unaligned(x, ptr)                                   \
+({                                                                     \
+       __typeof__ (*(ptr)) __x = (x);                                  \
+       __copy_to_user((ptr), &__x, sizeof(*(ptr))) ? -EFAULT : 0;      \
+})
+
+#endif /* _ASM_GENERIC_UACCESS_H */
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
new file mode 100644 (file)
index 0000000..de6498b
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _I386_KDEBUG_H
+#define _I386_KDEBUG_H 1
+
+/*
+ * Aug-05 2004 Ported by Prasanna S Panchamukhi <prasanna@in.ibm.com>
+ * from x86_64 architecture.
+ */
+#include <linux/notifier.h>
+
+struct pt_regs;
+
+struct die_args {
+       struct pt_regs *regs;
+       const char *str;
+       long err;
+       int trapnr;
+       int signr;
+};
+
+/* 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.
+  */
+int register_die_notifier(struct notifier_block *nb);
+extern struct notifier_block *i386die_chain;
+
+
+/* Grossly misnamed. */
+enum die_val {
+       DIE_OOPS = 1,
+       DIE_INT3,
+       DIE_DEBUG,
+       DIE_PANIC,
+       DIE_NMI,
+       DIE_DIE,
+       DIE_NMIWATCHDOG,
+       DIE_KERNELDEBUG,
+       DIE_TRAP,
+       DIE_GPF,
+       DIE_CALL,
+       DIE_NMI_IPI,
+       DIE_PAGE_FAULT,
+};
+
+static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig)
+{
+       struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig };
+       return notifier_call_chain(&i386die_chain, val, &args);
+}
+
+#endif
diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h
new file mode 100644 (file)
index 0000000..566e34a
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _ASM_KPROBES_H
+#define _ASM_KPROBES_H
+/*
+ *  Kernel Probes (KProbes)
+ *  include/asm-i386/kprobes.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ *
+ * 2002-Oct    Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
+ *             Probes initial implementation ( includes suggestions from
+ *             Rusty Russell).
+ */
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+struct pt_regs;
+
+typedef u8 kprobe_opcode_t;
+#define BREAKPOINT_INSTRUCTION 0xcc
+#define MAX_INSN_SIZE 16
+#define MAX_STACK_SIZE 64
+#define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
+       (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) \
+       ? (MAX_STACK_SIZE) \
+       : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
+
+/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
+ * if necessary, before executing the original int3/1 (trap) handler.
+ */
+static inline void restore_interrupts(struct pt_regs *regs)
+{
+       if (regs->eflags & IF_MASK)
+               local_irq_enable();
+}
+
+#ifdef CONFIG_KPROBES
+extern int kprobe_exceptions_notify(struct notifier_block *self,
+                                   unsigned long val, void *data);
+#else                          /* !CONFIG_KPROBES */
+static inline int kprobe_exceptions_notify(struct notifier_block *self,
+                                          unsigned long val, void *data)
+{
+       return 0;
+}
+#endif
+#endif                         /* _ASM_KPROBES_H */
diff --git a/include/asm-i386/pci-direct.h b/include/asm-i386/pci-direct.h
new file mode 100644 (file)
index 0000000..4f6738b
--- /dev/null
@@ -0,0 +1 @@
+#include "asm-x86_64/pci-direct.h"
diff --git a/include/asm-ia64/sn/l1.h b/include/asm-ia64/sn/l1.h
new file mode 100644 (file)
index 0000000..d5dbd55
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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) 1992-1997,2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#ifndef _ASM_IA64_SN_L1_H
+#define _ASM_IA64_SN_L1_H
+
+/* brick type response codes */
+#define L1_BRICKTYPE_PX         0x23            /* # */
+#define L1_BRICKTYPE_PE         0x25            /* % */
+#define L1_BRICKTYPE_N_p0       0x26            /* & */
+#define L1_BRICKTYPE_IP45       0x34            /* 4 */
+#define L1_BRICKTYPE_IP41       0x35            /* 5 */
+#define L1_BRICKTYPE_TWISTER    0x36            /* 6 */ /* IP53 & ROUTER */
+#define L1_BRICKTYPE_IX         0x3d            /* = */
+#define L1_BRICKTYPE_IP34       0x61            /* a */
+#define L1_BRICKTYPE_GA                0x62            /* b */
+#define L1_BRICKTYPE_C          0x63            /* c */
+#define L1_BRICKTYPE_OPUS_TIO  0x66            /* f */
+#define L1_BRICKTYPE_I          0x69            /* i */
+#define L1_BRICKTYPE_N          0x6e            /* n */
+#define L1_BRICKTYPE_OPUS       0x6f           /* o */
+#define L1_BRICKTYPE_P          0x70            /* p */
+#define L1_BRICKTYPE_R          0x72            /* r */
+#define L1_BRICKTYPE_CHI_CG     0x76            /* v */
+#define L1_BRICKTYPE_X          0x78            /* x */
+#define L1_BRICKTYPE_X2         0x79            /* y */
+#define L1_BRICKTYPE_SA                0x5e            /* ^ */ /* TIO bringup brick */
+#define L1_BRICKTYPE_PA                0x6a            /* j */
+#define L1_BRICKTYPE_IA                0x6b            /* k */
+
+#endif /* _ASM_IA64_SN_L1_H */
diff --git a/include/asm-ia64/sn/sn2/sn_hwperf.h b/include/asm-ia64/sn/sn2/sn_hwperf.h
new file mode 100644 (file)
index 0000000..2036382
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * 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 Silicon Graphics, Inc. All rights reserved.
+ *
+ * Data types used by the SN_SAL_HWPERF_OP SAL call for monitoring
+ * SGI Altix node and router hardware
+ *
+ * Mark Goodwin <markgw@sgi.com> Mon Aug 30 12:23:46 EST 2004
+ */
+
+#ifndef SN_HWPERF_H
+#define SN_HWPERF_H
+
+/*
+ * object structure. SN_HWPERF_ENUM_OBJECTS and SN_HWPERF_GET_CPU_INFO
+ * return an array of these. Do not change this without also
+ * changing the corresponding SAL code.
+ */
+#define SN_HWPERF_MAXSTRING            128
+struct sn_hwperf_object_info {
+       u32 id;
+       union {
+               struct {
+                       u64 this_part:1;
+                       u64 is_shared:1;
+               } fields;
+               struct {
+                       u64 flags;
+                       u64 reserved;
+               } b;
+       } f;
+       char name[SN_HWPERF_MAXSTRING];
+       char location[SN_HWPERF_MAXSTRING];
+       u32 ports;
+};
+
+#define sn_hwp_this_part       f.fields.this_part
+#define sn_hwp_is_shared       f.fields.is_shared
+#define sn_hwp_flags           f.b.flags
+
+#define SN_HWPERF_FOREIGN(x)   (!(x)->sn_hwp_this_part && !(x)->sn_hwp_is_shared)
+
+/* numa port structure, SN_HWPERF_ENUM_PORTS returns an array of these */
+struct sn_hwperf_port_info {
+       u32 port;
+       u32 conn_id;
+       u32 conn_port;
+};
+
+/* for HWPERF_{GET,SET}_MMRS */
+struct sn_hwperf_data {
+       u64 addr;
+       u64 data;
+};
+
+/* user ioctl() argument, see below */
+struct sn_hwperf_ioctl_args {
+        u64 arg;               /* argument, usually an object id */
+        u64 sz;                 /* size of transfer */
+        void *ptr;              /* pointer to source/target */
+        u32 v0;                        /* second return value */
+};
+
+/*
+ * For SN_HWPERF_{GET,SET}_MMRS and SN_HWPERF_OBJECT_DISTANCE,
+ * sn_hwperf_ioctl_args.arg can be used to specify a CPU on which
+ * to call SAL, and whether to use an interprocessor interrupt
+ * or task migration in order to do so. If the CPU specified is
+ * SN_HWPERF_ARG_ANY_CPU, then the current CPU will be used.
+ */
+#define SN_HWPERF_ARG_ANY_CPU          0x7fffffffUL
+#define SN_HWPERF_ARG_CPU_MASK         0x7fffffff00000000ULL
+#define SN_HWPERF_ARG_USE_IPI_MASK     0x8000000000000000ULL
+#define SN_HWPERF_ARG_OBJID_MASK       0x00000000ffffffffULL
+
+/* 
+ * ioctl requests on the "sn_hwperf" misc device that call SAL.
+ */
+#define SN_HWPERF_OP_MEM_COPYIN                0x1000
+#define SN_HWPERF_OP_MEM_COPYOUT       0x2000
+#define SN_HWPERF_OP_MASK              0x0fff
+
+/*
+ * Determine mem requirement.
+ * arg don't care
+ * sz  8
+ * p   pointer to u64 integer
+ */
+#define        SN_HWPERF_GET_HEAPSIZE          1
+
+/*
+ * Install mem for SAL drvr
+ * arg don't care
+ * sz  sizeof buffer pointed to by p
+ * p   pointer to buffer for scratch area
+ */
+#define SN_HWPERF_INSTALL_HEAP         2
+
+/*
+ * Determine number of objects
+ * arg don't care
+ * sz  8
+ * p   pointer to u64 integer
+ */
+#define SN_HWPERF_OBJECT_COUNT         (10|SN_HWPERF_OP_MEM_COPYOUT)
+
+/*
+ * Determine object "distance", relative to a cpu. This operation can
+ * execute on a designated logical cpu number, using either an IPI or
+ * via task migration. If the cpu number is SN_HWPERF_ANY_CPU, then
+ * the current CPU is used. See the SN_HWPERF_ARG_* macros above.
+ *
+ * arg bitmap of IPI flag, cpu number and object id
+ * sz  8
+ * p   pointer to u64 integer
+ */
+#define SN_HWPERF_OBJECT_DISTANCE      (11|SN_HWPERF_OP_MEM_COPYOUT)
+
+/*
+ * Enumerate objects. Special case if sz == 8, returns the required
+ * buffer size.
+ * arg don't care
+ * sz  sizeof buffer pointed to by p
+ * p   pointer to array of struct sn_hwperf_object_info
+ */
+#define SN_HWPERF_ENUM_OBJECTS         (12|SN_HWPERF_OP_MEM_COPYOUT)
+
+/*
+ * Enumerate NumaLink ports for an object. Special case if sz == 8,
+ * returns the required buffer size.
+ * arg object id
+ * sz  sizeof buffer pointed to by p
+ * p   pointer to array of struct sn_hwperf_port_info
+ */
+#define SN_HWPERF_ENUM_PORTS           (13|SN_HWPERF_OP_MEM_COPYOUT)
+
+/*
+ * SET/GET memory mapped registers. These operations can execute
+ * on a designated logical cpu number, using either an IPI or via
+ * task migration. If the cpu number is SN_HWPERF_ANY_CPU, then
+ * the current CPU is used. See the SN_HWPERF_ARG_* macros above.
+ *
+ * arg bitmap of ipi flag, cpu number and object id
+ * sz  sizeof buffer pointed to by p
+ * p   pointer to array of struct sn_hwperf_data
+ */
+#define SN_HWPERF_SET_MMRS             (14|SN_HWPERF_OP_MEM_COPYIN)
+#define SN_HWPERF_GET_MMRS             (15|SN_HWPERF_OP_MEM_COPYOUT| \
+                                           SN_HWPERF_OP_MEM_COPYIN)
+/*
+ * Lock a shared object
+ * arg object id
+ * sz  don't care
+ * p   don't care
+ */
+#define SN_HWPERF_ACQUIRE              16
+
+/*
+ * Unlock a shared object
+ * arg object id
+ * sz  don't care
+ * p   don't care
+ */
+#define SN_HWPERF_RELEASE              17
+
+/*
+ * Break a lock on a shared object
+ * arg object id
+ * sz  don't care
+ * p   don't care
+ */
+#define SN_HWPERF_FORCE_RELEASE                18
+
+/*
+ * ioctl requests on "sn_hwperf" that do not call SAL
+ */
+
+/*
+ * get cpu info as an array of hwperf_object_info_t. 
+ * id is logical CPU number, name is description, location
+ * is geoid (e.g. 001c04#1c). Special case if sz == 8,
+ * returns the required buffer size.
+ *
+ * arg don't care
+ * sz  sizeof buffer pointed to by p
+ * p   pointer to array of struct sn_hwperf_object_info
+ */
+#define SN_HWPERF_GET_CPU_INFO         (100|SN_HWPERF_OP_MEM_COPYOUT)
+
+/*
+ * Given an object id, return it's node number (aka cnode).
+ * arg object id
+ * sz  8
+ * p   pointer to u64 integer
+ */
+#define SN_HWPERF_GET_OBJ_NODE         (101|SN_HWPERF_OP_MEM_COPYOUT)
+
+/*
+ * Given a node number (cnode), return it's nasid.
+ * arg ordinal node number (aka cnodeid)
+ * sz  8
+ * p   pointer to u64 integer
+ */
+#define SN_HWPERF_GET_NODE_NASID       (102|SN_HWPERF_OP_MEM_COPYOUT)
+
+/* return codes */
+#define SN_HWPERF_OP_OK                        0
+#define SN_HWPERF_OP_NOMEM             1
+#define SN_HWPERF_OP_NO_PERM           2
+#define SN_HWPERF_OP_IO_ERROR          3
+#define SN_HWPERF_OP_BUSY              4
+#define SN_HWPERF_OP_RECONFIGURE       253
+#define SN_HWPERF_OP_INVAL             254
+
+#endif                         /* SN_HWPERF_H */
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h
new file mode 100644 (file)
index 0000000..4619ba5
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _ASM_M32R_A_OUT_H
+#define _ASM_M32R_A_OUT_H
+
+/* orig : i386 2.4.18 */
+
+struct exec
+{
+  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
+  unsigned a_text;             /* length of text, in bytes */
+  unsigned a_data;             /* length of data, in bytes */
+  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;             /* length of symbol table data in file, in bytes */
+  unsigned a_entry;            /* start address */
+  unsigned a_trsize;           /* length of relocation info for text, in bytes */
+  unsigned a_drsize;           /* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)    ((a).a_trsize)
+#define N_DRSIZE(a)    ((a).a_drsize)
+#define N_SYMSIZE(a)   ((a).a_syms)
+
+#ifdef __KERNEL__
+
+#define STACK_TOP      TASK_SIZE
+
+#endif
+
+#endif /* _ASM_M32R_A_OUT_H */
diff --git a/include/asm-m32r/addrspace.h b/include/asm-m32r/addrspace.h
new file mode 100644 (file)
index 0000000..06a83dc
--- /dev/null
@@ -0,0 +1,58 @@
+/* $Id$ */
+/*
+ * 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 by Hiroyuki Kondo
+ *
+ * Defitions for the address spaces of the M32R CPUs.
+ */
+#ifndef __ASM_M32R_ADDRSPACE_H
+#define __ASM_M32R_ADDRSPACE_H
+
+/*
+ * Memory segments (32bit kernel mode addresses)
+ */
+#define KUSEG                   0x00000000
+#define KSEG0                   0x80000000
+#define KSEG1                   0xa0000000
+#define KSEG2                   0xc0000000
+#define KSEG3                   0xe0000000
+
+#define K0BASE  KSEG0
+
+/*
+ * Returns the kernel segment base of a given address
+ */
+#ifndef __ASSEMBLY__
+#define KSEGX(a)                (((unsigned long)(a)) & 0xe0000000)
+#else
+#define KSEGX(a)                ((a) & 0xe0000000)
+#endif
+
+/*
+ * Returns the physical address of a KSEG0/KSEG1 address
+ */
+#ifndef __ASSEMBLY__
+#define PHYSADDR(a)            (((unsigned long)(a)) & 0x1fffffff)
+#else
+#define PHYSADDR(a)            ((a) & 0x1fffffff)
+#endif
+
+/*
+ * Map an address to a certain kernel segment
+ */
+#ifndef __ASSEMBLY__
+#define KSEG0ADDR(a)           ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG0))
+#define KSEG1ADDR(a)           ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG1))
+#define KSEG2ADDR(a)           ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG2))
+#define KSEG3ADDR(a)           ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | KSEG3))
+#else
+#define KSEG0ADDR(a)           (((a) & 0x1fffffff) | KSEG0)
+#define KSEG1ADDR(a)           (((a) & 0x1fffffff) | KSEG1)
+#define KSEG2ADDR(a)           (((a) & 0x1fffffff) | KSEG2)
+#define KSEG3ADDR(a)           (((a) & 0x1fffffff) | KSEG3)
+#endif
+
+#endif /* __ASM_M32R_ADDRSPACE_H */
diff --git a/include/asm-m32r/assembler.h b/include/asm-m32r/assembler.h
new file mode 100644 (file)
index 0000000..bdb52a5
--- /dev/null
@@ -0,0 +1,212 @@
+#ifndef _ASM_M32R_ASSEMBLER_H
+#define _ASM_M32R_ASSEMBLER_H
+
+/* $Id$ */
+
+/*
+ * linux/asm-m32r/assembler.h
+ *
+ * This file contains M32R architecture specific defines.
+ *
+ * Do not include any C declarations in this file - it is included by
+ * assembler source.
+ */
+
+#include <linux/config.h>
+
+
+#undef ENTRY
+#define ENTRY(name) ENTRY_M name
+       .macro  ENTRY_M name
+       .global \name
+       ALIGN
+\name:
+       .endm
+
+/*
+ * LDIMM: load immediate value
+ *
+ * STI: enable interruption
+ * CLI: disable interruption
+ */
+
+#ifdef __ASSEMBLY__
+
+#define LDIMM(reg,x) LDIMM reg x
+       .macro LDIMM reg x
+       seth    \reg, #high(\x)
+       or3     \reg, \reg, #low(\x)
+       .endm
+
+#if !defined(CONFIG_CHIP_M32102)
+#define STI(reg) STI_M reg
+       .macro STI_M reg
+       setpsw  #0x40       ->  nop
+       ; WORKAROUND: "-> nop" is a workaround for the M32700(TS1).
+       .endm
+
+#define CLI(reg) CLI_M reg
+       .macro CLI_M reg
+       clrpsw  #0x40       ->  nop
+       ; WORKAROUND: "-> nop" is a workaround for the M32700(TS1).
+       .endm
+#else  /* CONFIG_CHIP_M32102 */
+#define STI(reg) STI_M reg
+       .macro STI_M reg
+       mvfc    \reg, psw
+       or3     \reg, \reg, #0x0040
+       mvtc    \reg, psw
+       .endm
+
+#define CLI(reg) CLI_M reg
+       .macro CLI_M reg
+       mvfc    \reg, psw
+       and3    \reg, \reg, #0xffbf
+       mvtc    \reg, psw
+       .endm
+#endif /* CONFIG_CHIP_M32102 */
+
+       .macro  SAVE_ALL
+       push    r0              ; orig_r0
+       push    sp              ; spi (r15)
+       push    lr              ; r14
+       push    r13
+       mvfc    r13, cr3        ; spu
+       push    r13
+       mvfc    r13, bbpc
+       push    r13
+       mvfc    r13, bbpsw
+       push    r13
+       mvfc    r13, bpc
+       push    r13
+       mvfc    r13, psw
+       push    r13
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       mvfaclo r13, a1
+       push    r13
+       mvfachi r13, a1
+       push    r13
+       mvfaclo r13, a0
+       push    r13
+       mvfachi r13, a0
+       push    r13
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       mvfaclo r13
+       push    r13
+       mvfachi r13
+       push    r13
+#else
+#error unknown isa configuration
+#endif
+       ldi     r13, #-1
+       push    r13             ; syscall_nr (default: -1)
+       push    r12
+       push    r11
+       push    r10
+       push    r9
+       push    r8
+       push    r7
+       push    r3
+       push    r2
+       push    r1
+       push    r0
+       addi    sp, #-4         ; room for implicit pt_regs parameter
+       push    r6
+       push    r5
+       push    r4
+       .endm
+
+       .macro  RESTORE_ALL
+       pop     r4
+       pop     r5
+       pop     r6
+       addi    sp, #4
+       pop     r0
+       pop     r1
+       pop     r2
+       pop     r3
+       pop     r7
+       pop     r8
+       pop     r9
+       pop     r10
+       pop     r11
+       pop     r12
+       addi    r15, #4         ; Skip syscall number
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       pop     r13
+       mvtachi r13, a0
+       pop     r13
+       mvtaclo r13, a0
+       pop     r13
+       mvtachi r13, a1
+       pop     r13
+       mvtaclo r13, a1
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       pop     r13
+       mvtachi r13
+       pop     r13
+       mvtaclo r13
+#else
+#error unknown isa configuration
+#endif
+       pop     r14
+       mvtc    r14, psw
+       pop     r14
+       mvtc    r14, bpc
+       addi    sp, #8          ; Skip bbpsw, bbpc
+       pop     r14
+       mvtc    r14, cr3        ; spu
+       pop     r13
+       pop     lr              ; r14
+       pop     sp              ; spi (r15)
+       addi    sp, #4          ; Skip orig_r0
+       .fillinsn
+1:     rte
+       .section .fixup,"ax"
+2:     bl      do_exit
+       .previous
+       .section __ex_table,"a"
+       ALIGN
+       .long   1b, 2b
+       .previous
+       .endm
+
+#define GET_CURRENT(reg)  get_current reg
+       .macro get_current reg
+       ldi  \reg, #-8192
+       and  \reg, sp
+       .endm
+
+#if !defined(CONFIG_CHIP_M32102)
+       .macro  SWITCH_TO_KERNEL_STACK
+       ; switch to kernel stack (spi)
+       clrpsw  #0x80       ->  nop
+       .endm
+#else  /* CONFIG_CHIP_M32102 */
+       .macro  SWITCH_TO_KERNEL_STACK
+       push    r0              ; save r0 for working
+       mvfc    r0, psw
+       and3    r0, r0, #0x00ff7f
+       mvtc    r0, psw
+       slli    r0, #16
+       bltz    r0, 1f          ; check BSM-bit
+;
+       ;; called from kernel context: previous stack = spi
+       pop     r0              ; retrieve r0
+       bra     2f
+       .fillinsn
+1:
+       ;; called from user context: previous stack = spu
+       mvfc    r0, cr3         ; spu
+       addi    r0, #4
+       mvtc    r0, cr3         ; spu
+       ld      r0, @(-4,r0)    ; retrieve r0
+       .fillinsn
+2:
+       .endm
+#endif /* CONFIG_CHIP_M32102 */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_M32R_ASSEMBLER_H */
+
diff --git a/include/asm-m32r/atomic.h b/include/asm-m32r/atomic.h
new file mode 100644 (file)
index 0000000..570cc54
--- /dev/null
@@ -0,0 +1,305 @@
+#ifndef _ASM_M32R_ATOMIC_H
+#define _ASM_M32R_ATOMIC_H
+
+/*
+ *  linux/include/asm-m32r/atomic.h
+ *
+ *  M32R version:
+ *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/config.h>
+#include <asm/system.h>
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+#undef LOAD
+#undef STORE
+#ifdef CONFIG_SMP
+#define LOAD   "lock"
+#define STORE  "unlock"
+#else
+#define LOAD   "ld"
+#define STORE  "st"
+#endif
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * 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_return - add integer to atomic variable and return it
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v and return (@i + @v).
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+       unsigned long flags;
+       int result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# atomic_add_return            \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "add    %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (result)
+               : "r" (&v->counter), "r" (i)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * atomic_sub_return - subtract integer from atomic variable and return it
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and return (@v - @i).
+ */
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+       unsigned long flags;
+       int result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# atomic_sub_return            \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "sub    %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (result)
+               : "r" (&v->counter), "r" (i)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v.
+ */
+#define atomic_add(i,v) ((void) atomic_add_return((i), (v)))
+
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v.
+ */
+#define atomic_sub(i,v) ((void) atomic_sub_return((i), (v)))
+
+/**
+ * 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_return - increment atomic variable and return it
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1 and returns the result.
+ */
+static inline int atomic_inc_return(atomic_t *v)
+{
+       unsigned long flags;
+       int result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# atomic_inc_return            \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "addi   %0, #1;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (result)
+               : "r" (&v->counter)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * atomic_dec_return - decrement atomic variable and return it
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and returns the result.
+ */
+static inline int atomic_dec_return(atomic_t *v)
+{
+       unsigned long flags;
+       int result;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# atomic_dec_return            \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "addi   %0, #-1;                \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (result)
+               : "r" (&v->counter)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       return result;
+}
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+#define atomic_inc(v) ((void)atomic_inc_return(v))
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+#define atomic_dec(v) ((void)atomic_dec_return(v))
+
+/**
+ * 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_inc_return(v) == 0)
+
+/**
+ * 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_dec_return(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)
+
+static inline void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
+{
+       unsigned long flags;
+       unsigned long tmp;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# atomic_clear_mask            \n\t"
+               DCACHE_CLEAR("%0", "r5", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "and    %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (tmp)
+               : "r" (addr), "r" (~mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r5"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+static inline void atomic_set_mask(unsigned long  mask, atomic_t *addr)
+{
+       unsigned long flags;
+       unsigned long tmp;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# atomic_set_mask              \n\t"
+               DCACHE_CLEAR("%0", "r5", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "or     %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (tmp)
+               : "r" (addr), "r" (mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r5"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+/* Atomic operations are already serializing on m32r */
+#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 /* _ASM_M32R_ATOMIC_H */
+
diff --git a/include/asm-m32r/bitops.h b/include/asm-m32r/bitops.h
new file mode 100644 (file)
index 0000000..2500575
--- /dev/null
@@ -0,0 +1,716 @@
+#ifndef _ASM_M32R_BITOPS_H
+#define _ASM_M32R_BITOPS_H
+
+/*
+ *  linux/include/asm-m32r/bitops.h
+ *
+ *  Copyright 1992, Linus Torvalds.
+ *
+ *  M32R version:
+ *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/config.h>
+#include <linux/compiler.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <asm/types.h>
+
+/*
+ * These have to be done with inline assembly: that way the bit-setting
+ * is guaranteed to be atomic. All bit operations return 0 if the bit
+ * was cleared before the operation and != 0 if it was not.
+ *
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+#undef LOAD
+#undef STORE
+#ifdef CONFIG_SMP
+#define LOAD   "lock"
+#define STORE  "unlock"
+#else
+#define LOAD   "ld"
+#define STORE  "st"
+#endif
+
+/* #define ADDR (*(volatile long *) addr) */
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void set_bit(int nr, volatile void * addr)
+{
+       __u32 mask;
+       volatile __u32 *a = addr;
+       unsigned long flags;
+       unsigned long tmp;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               DCACHE_CLEAR("%0", "r6", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "or     %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (tmp)
+               : "r" (a), "r" (mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __set_bit(int nr, volatile void * addr)
+{
+       __u32 mask;
+       volatile __u32 *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+       *a |= mask;
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
+static inline void clear_bit(int nr, volatile void * addr)
+{
+       __u32 mask;
+       volatile __u32 *a = addr;
+       unsigned long flags;
+       unsigned long tmp;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       local_irq_save(flags);
+
+       __asm__ __volatile__ (
+               DCACHE_CLEAR("%0", "r6", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "and    %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (tmp)
+               : "r" (a), "r" (~mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long * addr)
+{
+       unsigned long mask;
+       volatile unsigned long *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+       *a &= ~mask;
+}
+
+#define smp_mb__before_clear_bit()     barrier()
+#define smp_mb__after_clear_bit()      barrier()
+
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static inline void __change_bit(int nr, volatile void * addr)
+{
+       __u32 mask;
+       volatile __u32 *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+       *a ^= mask;
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void change_bit(int nr, volatile void * addr)
+{
+       __u32  mask;
+       volatile __u32  *a = addr;
+       unsigned long flags;
+       unsigned long tmp;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               DCACHE_CLEAR("%0", "r6", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "xor    %0, %2;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (tmp)
+               : "r" (a), "r" (mask)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_set_bit(int nr, volatile void * addr)
+{
+       __u32 mask, oldbit;
+       volatile __u32 *a = addr;
+       unsigned long flags;
+       unsigned long tmp;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               DCACHE_CLEAR("%0", "%1", "%2")
+               LOAD"   %0, @%2;                \n\t"
+               "mv     %1, %0;                 \n\t"
+               "and    %0, %3;                 \n\t"
+               "or     %1, %3;                 \n\t"
+               STORE"  %1, @%2;                \n\t"
+               : "=&r" (oldbit), "=&r" (tmp)
+               : "r" (a), "r" (mask)
+               : "memory"
+       );
+       local_irq_restore(flags);
+
+       return (oldbit != 0);
+}
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_set_bit(int nr, volatile void * addr)
+{
+       __u32 mask, oldbit;
+       volatile __u32 *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+       oldbit = (*a & mask);
+       *a |= mask;
+
+       return (oldbit != 0);
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_clear_bit(int nr, volatile void * addr)
+{
+       __u32 mask, oldbit;
+       volatile __u32 *a = addr;
+       unsigned long flags;
+       unsigned long tmp;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       local_irq_save(flags);
+
+       __asm__ __volatile__ (
+               DCACHE_CLEAR("%0", "%1", "%3")
+               LOAD"   %0, @%3;                \n\t"
+               "mv     %1, %0; \n\t"
+               "and    %0, %2; \n\t"
+               "not    %2, %2; \n\t"
+               "and    %1, %2; \n\t"
+               STORE"  %1, @%3;                \n\t"
+               : "=&r" (oldbit), "=&r" (tmp), "+r" (mask)
+               : "r" (a)
+               : "memory"
+       );
+       local_irq_restore(flags);
+
+       return (oldbit != 0);
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static inline int __test_and_clear_bit(int nr, volatile void * addr)
+{
+       __u32 mask, oldbit;
+       volatile __u32 *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+       oldbit = (*a & mask);
+       *a &= ~mask;
+
+       return (oldbit != 0);
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static inline int __test_and_change_bit(int nr, volatile void * addr)
+{
+       __u32 mask, oldbit;
+       volatile __u32 *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+       oldbit = (*a & mask);
+       *a ^= mask;
+
+       return (oldbit != 0);
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_change_bit(int nr, volatile void * addr)
+{
+       __u32 mask, oldbit;
+       volatile __u32 *a = addr;
+       unsigned long flags;
+       unsigned long tmp;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               DCACHE_CLEAR("%0", "%1", "%2")
+               LOAD"   %0, @%2;                \n\t"
+               "mv     %1, %0;                 \n\t"
+               "and    %0, %3;                 \n\t"
+               "xor    %1, %3;                 \n\t"
+               STORE"  %1, @%2;                \n\t"
+               : "=&r" (oldbit), "=&r" (tmp)
+               : "r" (a), "r" (mask)
+               : "memory"
+       );
+       local_irq_restore(flags);
+
+       return (oldbit != 0);
+}
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet */
+/**
+ * test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static int test_bit(int nr, const volatile void * addr);
+#endif
+
+static inline int test_bit(int nr, const volatile void * addr)
+{
+       __u32 mask;
+       const volatile __u32 *a = addr;
+
+       a += (nr >> 5);
+       mask = (1 << (nr & 0x1F));
+
+       return ((*a & mask) != 0);
+}
+
+/**
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+       int k;
+
+       word = ~word;
+       k = 0;
+       if (!(word & 0x0000ffff)) { k += 16; word >>= 16; }
+       if (!(word & 0x000000ff)) { k += 8; word >>= 8; }
+       if (!(word & 0x0000000f)) { k += 4; word >>= 4; }
+       if (!(word & 0x00000003)) { k += 2; word >>= 2; }
+       if (!(word & 0x00000001)) { k += 1; }
+
+       return k;
+}
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+
+#define find_first_zero_bit(addr, size) \
+       find_next_zero_bit((addr), (size), 0)
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static inline int find_next_zero_bit(void *addr, int size, int 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) {
+               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);
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+       int k = 0;
+
+       if (!(word & 0x0000ffff)) { k += 16; word >>= 16; }
+       if (!(word & 0x000000ff)) { k += 8; word >>= 8; }
+       if (!(word & 0x0000000f)) { k += 4; word >>= 4; }
+       if (!(word & 0x00000003)) { k += 2; word >>= 2; }
+       if (!(word & 0x00000001)) { k += 1;}
+
+       return k;
+}
+
+/*
+ * fls: find last bit set.
+ */
+#define fls(x) generic_fls(x)
+
+#ifdef __KERNEL__
+
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int sched_find_first_bit(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;
+}
+
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static inline unsigned long find_next_bit(const unsigned long *addr,
+       unsigned long size, unsigned long offset)
+{
+       unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+       unsigned int result = offset & ~31UL;
+       unsigned int 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)
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+#define ffs(x) generic_ffs(x)
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+#define hweight32(x)   generic_hweight32(x)
+#define hweight16(x)   generic_hweight16(x)
+#define hweight8(x)    generic_hweight8(x)
+
+#endif /* __KERNEL__ */
+
+#ifdef __KERNEL__
+
+/*
+ * ext2_XXXX function
+ * orig: include/asm-sh/bitops.h
+ */
+
+#ifdef __LITTLE_ENDIAN__
+#define ext2_set_bit                   test_and_set_bit
+#define ext2_clear_bit                 __test_and_clear_bit
+#define ext2_test_bit                  test_bit
+#define ext2_find_first_zero_bit       find_first_zero_bit
+#define ext2_find_next_zero_bit                find_next_zero_bit
+#else
+static inline int ext2_set_bit(int nr, volatile void * addr)
+{
+       __u8 mask, oldbit;
+       volatile __u8 *a = addr;
+
+       a += (nr >> 3);
+       mask = (1 << (nr & 0x07));
+       oldbit = (*a & mask);
+       *a |= mask;
+
+       return (oldbit != 0);
+}
+
+static inline int ext2_clear_bit(int nr, volatile void * addr)
+{
+       __u8 mask, oldbit;
+       volatile __u8 *a = addr;
+
+       a += (nr >> 3);
+       mask = (1 << (nr & 0x07));
+       oldbit = (*a & mask);
+       *a &= ~mask;
+
+       return (oldbit != 0);
+}
+
+static inline int ext2_test_bit(int nr, const volatile void * addr)
+{
+       __u32 mask;
+       const volatile __u8 *a = addr;
+
+       a += (nr >> 3);
+       mask = (1 << (nr & 0x07));
+
+       return ((mask & *a) != 0);
+}
+
+#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));
+}
+#endif
+
+#define ext2_set_bit_atomic(lock, nr, addr)            \
+       ({                                              \
+               int ret;                                \
+               spin_lock(lock);                        \
+               ret = ext2_set_bit((nr), (addr));       \
+               spin_unlock(lock);                      \
+               ret;                                    \
+       })
+
+#define ext2_clear_bit_atomic(lock, nr, addr)          \
+       ({                                              \
+               int ret;                                \
+               spin_lock(lock);                        \
+               ret = ext2_clear_bit((nr), (addr));     \
+               spin_unlock(lock);                      \
+               ret;                                    \
+       })
+
+/* 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 /* _ASM_M32R_BITOPS_H */
diff --git a/include/asm-m32r/bug.h b/include/asm-m32r/bug.h
new file mode 100644 (file)
index 0000000..a6d1efe
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _M32R_BUG_H
+#define _M32R_BUG_H
+
+#define BUG()  do { \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+} while (0)
+
+#define PAGE_BUG(page) do { BUG(); } while (0)
+
+#define BUG_ON(condition) \
+       do { if (unlikely((condition)!=0)) BUG(); } while(0)
+
+#define WARN_ON(condition) do { \
+       if (unlikely((condition)!=0)) { \
+               printk("Badness in %s at %s:%d\n", __FUNCTION__, \
+               __FILE__, __LINE__); \
+               dump_stack(); \
+       } \
+} while (0)
+
+#endif /* _M32R_BUG_H */
+
diff --git a/include/asm-m32r/bugs.h b/include/asm-m32r/bugs.h
new file mode 100644 (file)
index 0000000..9a56f66
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _ASM_M32R_BUGS_H
+#define _ASM_M32R_BUGS_H
+
+/* $Id$ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *     void check_bugs(void);
+ */
+#include <asm/processor.h>
+
+static void __init check_bugs(void)
+{
+       extern unsigned long loops_per_jiffy;
+
+       current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+}
+
+#endif  /* _ASM_M32R_BUGS_H */
diff --git a/include/asm-m32r/byteorder.h b/include/asm-m32r/byteorder.h
new file mode 100644 (file)
index 0000000..3c0b9a2
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _ASM_M32R_BYTEORDER_H
+#define _ASM_M32R_BYTEORDER_H
+
+/* $Id$ */
+
+#include <asm/types.h>
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#if defined(__LITTLE_ENDIAN__)
+#  include <linux/byteorder/little_endian.h>
+#else
+#  include <linux/byteorder/big_endian.h>
+#endif
+
+#endif /* _ASM_M32R_BYTEORDER_H */
diff --git a/include/asm-m32r/cache.h b/include/asm-m32r/cache.h
new file mode 100644 (file)
index 0000000..7248205
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASM_M32R_CACHE_H
+#define _ASM_M32R_CACHE_H
+
+/* $Id$ */
+
+/* L1 cache line size */
+#define L1_CACHE_SHIFT         4
+#define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
+
+#define L1_CACHE_SHIFT_MAX     4
+
+#endif  /* _ASM_M32R_CACHE_H */
diff --git a/include/asm-m32r/cachectl.h b/include/asm-m32r/cachectl.h
new file mode 100644 (file)
index 0000000..2aab8f6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * cachectl.h -- defines for M32R cache control system calls
+ *
+ * Copyright (C) 2003 by Kazuhiro Inaoka
+ */
+#ifndef        __ASM_M32R_CACHECTL
+#define        __ASM_M32R_CACHECTL
+
+/*
+ * Options for cacheflush system call
+ *
+ * cacheflush() is currently fluch_cache_all().
+ */
+#define        ICACHE  (1<<0)          /* flush instruction cache        */
+#define        DCACHE  (1<<1)          /* writeback and flush data cache */
+#define        BCACHE  (ICACHE|DCACHE) /* flush both caches              */
+
+/*
+ * Caching modes for the cachectl(2) call
+ *
+ * cachectl(2) is currently not supported and returns ENOSYS.
+ */
+#define CACHEABLE      0       /* make pages cacheable */
+#define UNCACHEABLE    1       /* make pages uncacheable */
+
+#endif /* __ASM_M32R_CACHECTL */
diff --git a/include/asm-m32r/cacheflush.h b/include/asm-m32r/cacheflush.h
new file mode 100644 (file)
index 0000000..cf65b74
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _ASM_M32R_CACHEFLUSH_H
+#define _ASM_M32R_CACHEFLUSH_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+
+extern void _flush_cache_all(void);
+extern void _flush_cache_copyback_all(void);
+
+#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP)
+#define flush_cache_all()                      do { } while (0)
+#define flush_cache_mm(mm)                     do { } while (0)
+#define flush_cache_range(vma, start, end)     do { } while (0)
+#define flush_cache_page(vma, vmaddr)          do { } while (0)
+#define flush_dcache_page(page)                        do { } while (0)
+#define flush_dcache_mmap_lock(mapping)                do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
+#ifndef CONFIG_SMP
+#define flush_icache_range(start, end)         _flush_cache_copyback_all()
+#define flush_icache_page(vma,pg)              _flush_cache_copyback_all()
+#define flush_icache_user_range(vma,pg,adr,len)        _flush_cache_copyback_all()
+#define flush_cache_sigtramp(addr)             _flush_cache_copyback_all()
+#else  /* CONFIG_SMP */
+extern void smp_flush_cache_all(void);
+#define flush_icache_range(start, end)         smp_flush_cache_all()
+#define flush_icache_page(vma,pg)              smp_flush_cache_all()
+#define flush_icache_user_range(vma,pg,adr,len)        smp_flush_cache_all()
+#define flush_cache_sigtramp(addr)             _flush_cache_copyback_all()
+#endif /* CONFIG_SMP */
+#elif defined(CONFIG_CHIP_M32102)
+#define flush_cache_all()                      do { } while (0)
+#define flush_cache_mm(mm)                     do { } while (0)
+#define flush_cache_range(vma, start, end)     do { } while (0)
+#define flush_cache_page(vma, vmaddr)          do { } while (0)
+#define flush_dcache_page(page)                        do { } while (0)
+#define flush_dcache_mmap_lock(mapping)                do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
+#define flush_icache_range(start, end)         _flush_cache_all()
+#define flush_icache_page(vma,pg)              _flush_cache_all()
+#define flush_icache_user_range(vma,pg,adr,len)        _flush_cache_all()
+#define flush_cache_sigtramp(addr)             _flush_cache_all()
+#else
+#define flush_cache_all()                      do { } while (0)
+#define flush_cache_mm(mm)                     do { } while (0)
+#define flush_cache_range(vma, start, end)     do { } while (0)
+#define flush_cache_page(vma, vmaddr)          do { } while (0)
+#define flush_dcache_page(page)                        do { } while (0)
+#define flush_dcache_mmap_lock(mapping)                do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
+#define flush_icache_range(start, end)         do { } while (0)
+#define flush_icache_page(vma,pg)              do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
+#define flush_cache_sigtramp(addr)             do { } while (0)
+#endif /* CONFIG_CHIP_* */
+
+#define flush_cache_vmap(start, end)   do { } while (0)
+#define flush_cache_vunmap(start, end) do { } while (0)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len)     \
+do {                                                           \
+       memcpy(dst, src, len);                                  \
+       flush_icache_user_range(vma, page, vaddr, len);         \
+} while (0)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len)   \
+       memcpy(dst, src, len)
+
+#endif /* _ASM_M32R_CACHEFLUSH_H */
+
diff --git a/include/asm-m32r/checksum.h b/include/asm-m32r/checksum.h
new file mode 100644 (file)
index 0000000..433d928
--- /dev/null
@@ -0,0 +1,206 @@
+#ifdef __KERNEL__
+#ifndef _ASM_M32R_CHECKSUM_H
+#define _ASM_M32R_CHECKSUM_H
+
+/*
+ * include/asm-m32r/checksum.h
+ *
+ * IP/TCP/UDP checksum routines
+ *
+ * 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.
+ *
+ * Some code taken from mips and parisc architecture.
+ *
+ *    Copyright (C) 2001, 2002  Hiroyuki Kondo, Hirokazu Takata
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/in6.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.
+ *
+ * Here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern unsigned int csum_partial_copy_nocheck(const char *src, char *dst,
+                                              int len, unsigned int sum);
+
+/*
+ * This is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros thre rest of the buffer.
+ */
+extern unsigned int csum_partial_copy_from_user(const char __user *src,
+                                                char *dst,
+                                                int len, unsigned int sum,
+                                                int *err_ptr);
+
+/*
+ *     Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+       unsigned long tmpreg;
+       __asm__(
+               "       sll3    %1, %0, #16 \n"
+               "       cmp     %0, %0 \n"
+               "       addx    %0, %1 \n"
+               "       ldi     %1, #0 \n"
+               "       srli    %0, #16 \n"
+               "       addx    %0, %1 \n"
+               "       xor3    %0, %0, #0x0000ffff \n"
+               : "=r" (sum), "=&r" (tmpreg)
+               : "0"  (sum)
+               : "cbit"
+       );
+       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 long sum, tmpreg0, tmpreg1;
+
+       __asm__ __volatile__(
+               "       ld      %0, @%1+ \n"
+               "       addi    %2, #-4 \n"
+               "#      bgez    %2, 2f \n"
+               "       cmp     %0, %0 \n"
+               "       ld      %3, @%1+ \n"
+               "       ld      %4, @%1+ \n"
+               "       addx    %0, %3 \n"
+               "       ld      %3, @%1+ \n"
+               "       addx    %0, %4 \n"
+               "       addx    %0, %3 \n"
+               "       .fillinsn\n"
+               "1: \n"
+               "       ld      %4, @%1+ \n"
+               "       addi    %2, #-1 \n"
+               "       addx    %0, %4 \n"
+               "       bgtz    %2, 1b \n"
+               "\n"
+               "       ldi     %3, #0 \n"
+               "       addx    %0, %3 \n"
+               "       .fillinsn\n"
+               "2: \n"
+       /* Since the input registers which are loaded with iph and ipl
+          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" (tmpreg0), "=&r" (tmpreg1)
+       : "1" (iph), "2" (ihl)
+       : "cbit", "memory");
+
+       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)
+{
+#if defined(__LITTLE_ENDIAN)
+       unsigned long len_proto = (ntohs(len)<<16)+proto*256;
+#else
+       unsigned long len_proto = (proto<<16)+len;
+#endif
+       unsigned long tmpreg;
+
+       __asm__(
+               "       cmp     %0, %0 \n"
+               "       addx    %0, %2 \n"
+               "       addx    %0, %3 \n"
+               "       addx    %0, %4 \n"
+               "       ldi     %1, #0 \n"
+               "       addx    %0, %1 \n"
+               : "=r" (sum), "=&r" (tmpreg)
+               : "r" (daddr), "r" (saddr), "r" (len_proto), "0" (sum)
+               : "cbit"
+       );
+
+       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,
+                                                __u16 len,
+                                                unsigned short proto,
+                                                unsigned int sum)
+{
+       unsigned long tmpreg0, tmpreg1, tmpreg2, tmpreg3;
+       __asm__(
+               "       ld      %1, @(%5) \n"
+               "       ld      %2, @(4,%5) \n"
+               "       ld      %3, @(8,%5) \n"
+               "       ld      %4, @(12,%5) \n"
+               "       add     %0, %1 \n"
+               "       addx    %0, %2 \n"
+               "       addx    %0, %3 \n"
+               "       addx    %0, %4 \n"
+               "       ld      %1, @(%6) \n"
+               "       ld      %2, @(4,%6) \n"
+               "       ld      %3, @(8,%6) \n"
+               "       ld      %4, @(12,%6) \n"
+               "       addx    %0, %1 \n"
+               "       addx    %0, %2 \n"
+               "       addx    %0, %3 \n"
+               "       addx    %0, %4 \n"
+               "       addx    %0, %7 \n"
+               "       addx    %0, %8 \n"
+               "       ldi     %1, #0 \n"
+               "       addx    %0, %1 \n"
+               : "=&r" (sum), "=&r" (tmpreg0), "=&r" (tmpreg1),
+                 "=&r" (tmpreg2), "=&r" (tmpreg3)
+               : "r" (saddr), "r" (daddr),
+                 "r" (htonl((__u32) (len))), "r" (htonl(proto)), "0" (sum)
+               : "cbit"
+       );
+
+       return csum_fold(sum);
+}
+
+#endif /* _ASM_M32R_CHECKSUM_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-m32r/current.h b/include/asm-m32r/current.h
new file mode 100644 (file)
index 0000000..c19d927
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ASM_M32R_CURRENT_H
+#define _ASM_M32R_CURRENT_H
+
+/* $Id$ */
+
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static __inline__ struct task_struct *get_current(void)
+{
+       return current_thread_info()->task;
+}
+
+#define current        (get_current())
+
+#endif /* _ASM_M32R_CURRENT_H */
+
diff --git a/include/asm-m32r/delay.h b/include/asm-m32r/delay.h
new file mode 100644 (file)
index 0000000..f285eae
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _ASM_M32R_DELAY_H
+#define _ASM_M32R_DELAY_H
+
+/* $Id$ */
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines calling functions in arch/m32r/lib/delay.c
+ */
+
+extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
+
+extern void __udelay(unsigned long usecs);
+extern void __ndelay(unsigned long nsecs);
+extern void __const_udelay(unsigned long usecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) (__builtin_constant_p(n) ? \
+       ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c7ul)) : \
+       __udelay(n))
+
+#define ndelay(n) (__builtin_constant_p(n) ? \
+       ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
+       __ndelay(n))
+
+#endif /* _ASM_M32R_DELAY_H */
diff --git a/include/asm-m32r/div64.h b/include/asm-m32r/div64.h
new file mode 100644 (file)
index 0000000..417a51b
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _ASM_M32R_DIV64
+#define _ASM_M32R_DIV64
+
+/* $Id$ */
+
+/* unsigned long long division.
+ * Input:
+ *  unsigned long long  n
+ *  unsigned long  base
+ * Output:
+ *  n = n / base;
+ *  return value = n % base;
+ */
+#define do_div(n, base)                                                \
+({                                                             \
+       unsigned long _res, _high, _mid, _low;                  \
+                                                               \
+       _low = (n) & 0xffffffffUL;                              \
+       _high = (n) >> 32;                                      \
+       if (_high) {                                            \
+               _mid = (_high % (unsigned long)(base)) << 16;   \
+               _high = _high / (unsigned long)(base);          \
+               _mid += _low >> 16;                             \
+               _low &= 0x0000ffffUL;                           \
+               _low += (_mid % (unsigned long)(base)) << 16;   \
+               _mid = _mid / (unsigned long)(base);            \
+               _res = _low % (unsigned long)(base);            \
+               _low = _low / (unsigned long)(base);            \
+               n = _low + ((long long)_mid << 16) +            \
+                       ((long long)_high << 32);               \
+       } else {                                                \
+               _res = _low % (unsigned long)(base);            \
+               n = (_low / (unsigned long)(base));             \
+       }                                                       \
+       _res;                                                   \
+})
+
+#endif  /* _ASM_M32R_DIV64 */
diff --git a/include/asm-m32r/dma-mapping.h b/include/asm-m32r/dma-mapping.h
new file mode 100644 (file)
index 0000000..3a2db28
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _ASM_M32R_DMA_MAPPING_H
+#define _ASM_M32R_DMA_MAPPING_H
+
+/*
+ * NOTE: Do not include <asm-generic/dma-mapping.h>
+ * Because it requires PCI stuffs, but current M32R don't provide these.
+ */
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+                  int flag)
+{
+       return (void *)NULL;
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+                   dma_addr_t dma_handle)
+{
+       return;
+}
+
+#endif /* _ASM_M32R_DMA_MAPPING_H */
diff --git a/include/asm-m32r/dma.h b/include/asm-m32r/dma.h
new file mode 100644 (file)
index 0000000..7263b01
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _ASM_M32R_DMA_H
+#define _ASM_M32R_DMA_H
+
+/* $Id$ */
+
+#include <asm/io.h>
+
+/*
+ * The maximum address that we can perform a DMA transfer
+ * to on this platform
+ */
+#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x20000000)
+
+#endif /* _ASM_M32R_DMA_H */
diff --git a/include/asm-m32r/elf.h b/include/asm-m32r/elf.h
new file mode 100644 (file)
index 0000000..f601fcb
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef _ASM_M32R__ELF_H
+#define _ASM_M32R__ELF_H
+
+/*
+ * ELF-specific definitions.
+ *
+ * Copyright (C) 1999-2004, Renesas Technology Corp.
+ *      Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include <asm/page.h>
+
+/* M32R relocation types  */
+#define        R_M32R_NONE             0
+#define        R_M32R_16               1
+#define        R_M32R_32               2
+#define        R_M32R_24               3
+#define        R_M32R_10_PCREL         4
+#define        R_M32R_18_PCREL         5
+#define        R_M32R_26_PCREL         6
+#define        R_M32R_HI16_ULO         7
+#define        R_M32R_HI16_SLO         8
+#define        R_M32R_LO16             9
+#define        R_M32R_SDA16            10
+#ifdef OLD_TYPE
+#define        R_M32R_GOT24            11
+#define        R_M32R_26_PLTREL        12
+#define        R_M32R_GOT16_HI_ULO     13
+#define        R_M32R_GOT16_HI_SLO     14
+#define        R_M32R_GOT16_LO         15
+#define        R_M32R_GOTPC24          16
+#define        R_M32R_COPY             17
+#define        R_M32R_GLOB_DAT         18
+#define        R_M32R_JMP_SLOT         19
+#define        R_M32R_RELATIVE         20
+#define        R_M32R_GNU_VTINHERIT    21
+#define        R_M32R_GNU_VTENTRY      22
+
+#define R_M32R_16_RELA         R_M32R_16
+#define R_M32R_32_RELA         R_M32R_32
+#define R_M32R_24_RELA         R_M32R_24
+#define R_M32R_10_PCREL_RELA   R_M32R_10_PCREL
+#define R_M32R_18_PCREL_RELA   R_M32R_18_PCREL
+#define R_M32R_26_PCREL_RELA   R_M32R_26_PCREL
+#define R_M32R_HI16_ULO_RELA   R_M32R_HI16_ULO
+#define R_M32R_HI16_SLO_RELA   R_M32R_HI16_SLO
+#define R_M32R_LO16_RELA       R_M32R_LO16
+#define R_M32R_SDA16_RELA      R_M32R_SDA16
+#else /* not OLD_TYPE */
+#define        R_M32R_GNU_VTINHERIT    11
+#define        R_M32R_GNU_VTENTRY      12
+
+#define        R_M32R_GOT24_SAMPLE             11 /* comflict */
+#define        R_M32R_26_PLTREL_SAMPLE 12 /* comflict */
+#define        R_M32R_GOT16_HI_ULO_SAMPLE      13
+#define        R_M32R_GOT16_HI_SLO_SAMPLE      14
+#define        R_M32R_GOT16_LO_SAMPLE          15
+#define        R_M32R_GOTPC24_SAMPLE           16
+#define        R_M32R_COPY_SAMPLE              17
+#define        R_M32R_GLOB_DAT_SAMPLE          18
+#define        R_M32R_JMP_SLOT_SAMPLE          19
+#define        R_M32R_RELATIVE_SAMPLE          20
+#define        R_M32R_GNU_VTINHERIT_SAMPLE     21
+#define        R_M32R_GNU_VTENTRY_SAMPLE       22
+
+#define R_M32R_16_RELA         33
+#define R_M32R_32_RELA         34
+#define R_M32R_24_RELA         35
+#define R_M32R_10_PCREL_RELA   36
+#define R_M32R_18_PCREL_RELA   37
+#define R_M32R_26_PCREL_RELA   38
+#define R_M32R_HI16_ULO_RELA   39
+#define R_M32R_HI16_SLO_RELA   40
+#define R_M32R_LO16_RELA       41
+#define R_M32R_SDA16_RELA      42
+#define        R_M32R_RELA_GNU_VTINHERIT       43
+#define        R_M32R_RELA_GNU_VTENTRY 44
+
+#define R_M32R_GOT24           48
+#define R_M32R_26_PLTREL       49
+#define R_M32R_COPY            50
+#define R_M32R_GLOB_DAT                51
+#define R_M32R_JMP_SLOT                52
+#define R_M32R_RELATIVE                53
+#define R_M32R_GOTOFF          54
+#define R_M32R_GOTPC24         55
+#define R_M32R_GOT16_HI_ULO    56
+#define R_M32R_GOT16_HI_SLO    57
+#define R_M32R_GOT16_LO                58
+#define R_M32R_GOTPC_HI_ULO    59
+#define R_M32R_GOTPC_HI_SLO    60
+#define R_M32R_GOTPC_LO                61
+#endif /* not OLD_TYPE */
+
+#define R_M32R_NUM             256
+
+/*
+ * ELF register definitions..
+ */
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* We have no FP mumumu.  */
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+       (((x)->e_machine == EM_M32R) || ((x)->e_machine == EM_CYGNUS_M32R))
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS      ELFCLASS32
+#if defined(__LITTLE_ENDIAN)
+#define ELF_DATA       ELFDATA2LSB
+#elif defined(__BIG_ENDIAN)
+#define ELF_DATA       ELFDATA2MSB
+#else
+#error no endian defined
+#endif
+#define ELF_ARCH       EM_M32R
+
+/* r0 is set by ld.so to 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.
+ *
+ * So that we can use the same startup file with static executables,
+ * we start programs with a value of 0 to indicate that there is no
+ * such function.
+ */
+#define ELF_PLAT_INIT(_r, load_addr)   (_r)->r0 = 0
+
+#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         (TASK_SIZE / 3 * 2)
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+   now struct_user_regs, they are different) */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)  \
+       memcpy((char *)&pr_reg, (char *)&regs, sizeof (struct pt_regs));
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this CPU supports.  */
+#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.  */
+#define ELF_PLATFORM   (NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX)
+#endif
+
+#endif  /* _ASM_M32R__ELF_H */
diff --git a/include/asm-m32r/errno.h b/include/asm-m32r/errno.h
new file mode 100644 (file)
index 0000000..7a98520
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_M32R_ERRNO_H
+#define _ASM_M32R_ERRNO_H
+
+/* $Id$ */
+
+#include <asm-generic/errno.h>
+
+#endif /* _ASM_M32R_ERRNO_H */
+
diff --git a/include/asm-m32r/fcntl.h b/include/asm-m32r/fcntl.h
new file mode 100644 (file)
index 0000000..3e30895
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _ASM_M32R_FCNTL_H
+#define _ASM_M32R_FCNTL_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_ACCMODE         0003
+#define O_RDONLY            00
+#define O_WRONLY            01
+#define O_RDWR              02
+#define O_CREAT                   0100 /* not fcntl */
+#define O_EXCL            0200 /* not fcntl */
+#define O_NOCTTY          0400 /* not fcntl */
+#define O_TRUNC                  01000 /* not fcntl */
+#define O_APPEND         02000
+#define O_NONBLOCK       04000
+#define O_NDELAY       O_NONBLOCK
+#define O_SYNC          010000
+#define FASYNC          020000 /* fcntl, for BSD compatibility */
+#define O_DIRECT        040000 /* direct disk access hint */
+#define O_LARGEFILE    0100000
+#define O_DIRECTORY    0200000 /* must be a directory */
+#define O_NOFOLLOW     0400000 /* don't follow links */
+#define O_NOATIME      01000000
+
+#define F_DUPFD                0       /* dup */
+#define F_GETFD                1       /* get close_on_exec */
+#define F_SETFD                2       /* set/clear close_on_exec */
+#define F_GETFL                3       /* get file->f_flags */
+#define F_SETFL                4       /* set file->f_flags */
+#define F_GETLK                5
+#define F_SETLK                6
+#define F_SETLKW       7
+
+#define F_SETOWN       8       /*  for sockets. */
+#define F_GETOWN       9       /*  for sockets. */
+#define F_SETSIG       10      /*  for sockets. */
+#define F_GETSIG       11      /*  for sockets. */
+
+#define F_GETLK64      12      /*  using 'struct flock64' */
+#define F_SETLK64      13
+#define F_SETLKW64     14
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC     1       /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK                0
+#define F_WRLCK                1
+#define F_UNLCK                2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK                4       /* or 3 */
+#define F_SHLCK                8       /* or 4 */
+
+/* for leases */
+#define F_INPROGRESS   16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH                1       /* shared lock */
+#define LOCK_EX                2       /* exclusive lock */
+#define LOCK_NB                4       /* or'd with one of the above to prevent
+                                  blocking */
+#define LOCK_UN                8       /* remove lock */
+
+#define LOCK_MAND      32      /* This is a mandatory flock */
+#define LOCK_READ      64      /* ... Which allows concurrent read operations */
+#define LOCK_WRITE     128     /* ... Which allows concurrent write operations */
+#define LOCK_RW                192     /* ... Which allows concurrent read & write ops */
+
+struct flock {
+       short l_type;
+       short l_whence;
+       off_t l_start;
+       off_t l_len;
+       pid_t l_pid;
+};
+
+struct flock64 {
+       short  l_type;
+       short  l_whence;
+       loff_t l_start;
+       loff_t l_len;
+       pid_t  l_pid;
+};
+
+#define F_LINUX_SPECIFIC_BASE  1024
+
+#endif  /* _ASM_M32R_FCNTL_H */
diff --git a/include/asm-m32r/flat.h b/include/asm-m32r/flat.h
new file mode 100644 (file)
index 0000000..1b285f6
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * include/asm-m32r/flat.h
+ *
+ * uClinux flat-format executables
+ *
+ * Copyright (C) 2004  Kazuhiro Inaoka
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive for
+ * more details.
+ */
+#ifndef __ASM_M32R_FLAT_H
+#define __ASM_M32R_FLAT_H
+
+#define        flat_stack_align(sp)            (*sp += (*sp & 3 ? (4 - (*sp & 3)): 0))
+#define        flat_argvp_envp_on_stack()              0
+#define        flat_old_ram_flag(flags)                (flags)
+#define        flat_reloc_valid(reloc, size)           \
+       (((reloc) - textlen_for_m32r_lo16_data) <= (size))
+#define flat_get_addr_from_rp(rp, relval, flags) \
+       m32r_flat_get_addr_from_rp(rp, relval, (text_len) )
+
+#define flat_put_addr_at_rp(rp, addr, relval) \
+       m32r_flat_put_addr_at_rp(rp, addr, relval)
+
+/* Convert a relocation entry into an address.  */
+static inline unsigned long
+flat_get_relocate_addr (unsigned long relval)
+{
+        return relval & 0x00ffffff; /* Mask out top 8-bits */
+}
+
+#define        flat_m32r_get_reloc_type(relval)        ((relval) >> 24)
+
+#define M32R_SETH_OPCODE       0xd0c00000 /* SETH instruction code */
+
+#define FLAT_M32R_32           0x00    /* 32bits reloc */
+#define FLAT_M32R_24           0x01    /* unsigned 24bits reloc */
+#define FLAT_M32R_16           0x02    /* 16bits reloc */
+#define FLAT_M32R_LO16         0x03    /* signed low 16bits reloc (low()) */
+#define FLAT_M32R_LO16_DATA    0x04    /* signed low 16bits reloc (low())
+                                          for a symbol in .data section */
+                                       /* High 16bits of an address used
+                                          when the lower 16bbits are treated
+                                          as unsigned.
+                                           To create SETH instruction only.
+                                          0x1X: X means a number of register.
+                                          0x10 - 0x3F are reserved. */
+#define FLAT_M32R_HI16_ULO     0x10    /* reloc for SETH Rn,#high(imm16) */
+                                       /* High 16bits of an address used
+                                          when the lower 16bbits are treated
+                                          as signed.
+                                           To create SETH instruction only.
+                                          0x2X: X means a number of register.
+                                          0x20 - 0x4F are reserved. */
+#define FLAT_M32R_HI16_SLO     0x20    /* reloc for SETH Rn,#shigh(imm16) */
+
+static unsigned long textlen_for_m32r_lo16_data = 0;
+
+static inline unsigned long m32r_flat_get_addr_from_rp (unsigned long *rp,
+                                                        unsigned long relval,
+                                                       unsigned long textlen)
+{
+        unsigned int reloc = flat_m32r_get_reloc_type (relval);
+       textlen_for_m32r_lo16_data = 0;
+       if (reloc & 0xf0) {
+               unsigned long addr = htonl(*rp);
+               switch (reloc & 0xf0)
+               {
+               case FLAT_M32R_HI16_ULO:
+               case FLAT_M32R_HI16_SLO:
+                       if (addr == 0) {
+                               /* put "seth Rn,#0x0" instead of 0 (addr). */
+                               *rp = (M32R_SETH_OPCODE | ((reloc & 0x0f)<<24));
+                       }
+                       return addr;
+               default:
+                       break;
+               }
+       } else {
+               switch (reloc)
+               {
+               case FLAT_M32R_LO16:
+                       return htonl(*rp) & 0xFFFF;
+               case FLAT_M32R_LO16_DATA:
+                        /* FIXME: The return value will decrease by textlen
+                          at m32r_flat_put_addr_at_rp () */
+                       textlen_for_m32r_lo16_data = textlen;
+                       return (htonl(*rp) & 0xFFFF) + textlen;
+               case FLAT_M32R_16:
+                       return htons(*(unsigned short *)rp) & 0xFFFF;
+               case FLAT_M32R_24:
+                       return htonl(*rp) & 0xFFFFFF;
+               case FLAT_M32R_32:
+                       return htonl(*rp);
+               default:
+                       break;
+               }
+       }
+       return ~0;      /* bogus value */
+}
+
+static inline void m32r_flat_put_addr_at_rp (unsigned long *rp,
+                                            unsigned long addr,
+                                             unsigned long relval)
+{
+        unsigned int reloc = flat_m32r_get_reloc_type (relval);
+       if (reloc & 0xf0) {
+               unsigned long Rn = reloc & 0x0f; /* get a number of register */
+               Rn <<= 24; /* 0x0R000000 */
+               reloc &= 0xf0;
+               switch (reloc)
+               {
+               case FLAT_M32R_HI16_ULO: /* To create SETH Rn,#high(imm16) */
+                       *rp = (M32R_SETH_OPCODE | Rn
+                              | ((addr >> 16) & 0xFFFF));
+                       break;
+               case FLAT_M32R_HI16_SLO: /* To create SETH Rn,#shigh(imm16) */
+                       *rp = (M32R_SETH_OPCODE | Rn
+                              | (((addr >> 16) + ((addr & 0x8000) ? 1 : 0))
+                                 & 0xFFFF));
+                       break;
+               }
+       } else {
+               switch (reloc) {
+               case FLAT_M32R_LO16_DATA:
+                       addr -= textlen_for_m32r_lo16_data;
+                       textlen_for_m32r_lo16_data = 0;
+               case FLAT_M32R_LO16:
+                       *rp = (htonl(*rp) & 0xFFFF0000) | (addr & 0xFFFF);
+                       break;
+               case FLAT_M32R_16:
+                       *(unsigned short *)rp = addr & 0xFFFF;
+                       break;
+               case FLAT_M32R_24:
+                       *rp = (htonl(*rp) & 0xFF000000) | (addr & 0xFFFFFF);
+                       break;
+               case FLAT_M32R_32:
+                       *rp = addr;
+                       break;
+               }
+       }
+}
+
+#endif /* __ASM_M32R_FLAT_H */
diff --git a/include/asm-m32r/hardirq.h b/include/asm-m32r/hardirq.h
new file mode 100644 (file)
index 0000000..b46a265
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+       unsigned int __softirq_pending;
+       unsigned int __syscall_count;
+       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x00ff0000
+ */
+
+#define PREEMPT_BITS   8
+#define SOFTIRQ_BITS   8
+
+#if NR_IRQS > 256
+#define HARDIRQ_BITS   9
+#else
+#define HARDIRQ_BITS   8
+#endif
+
+#define PREEMPT_SHIFT  0
+#define SOFTIRQ_SHIFT  (PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT  (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+#define irq_enter()            (preempt_count() += HARDIRQ_OFFSET)
+#define nmi_enter()            (irq_enter())
+#define nmi_exit()             (preempt_count() -= HARDIRQ_OFFSET)
+
+#define irq_exit()                                                     \
+do {                                                                   \
+               preempt_count() -= IRQ_EXIT_OFFSET;                     \
+               if (!in_interrupt() && softirq_pending(smp_processor_id())) \
+                       do_softirq();                                   \
+               preempt_enable_no_resched();                            \
+} while (0)
+
+#endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-m32r/hdreg.h b/include/asm-m32r/hdreg.h
new file mode 100644 (file)
index 0000000..7f7fd1a
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/hdreg.h>
diff --git a/include/asm-m32r/hw_irq.h b/include/asm-m32r/hw_irq.h
new file mode 100644 (file)
index 0000000..8d7e9d0
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_M32R_HW_IRQ_H
+#define _ASM_M32R_HW_IRQ_H
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+{
+       /* Nothing to do */
+}
+
+#endif /* _ASM_M32R_HW_IRQ_H */
diff --git a/include/asm-m32r/ide.h b/include/asm-m32r/ide.h
new file mode 100644 (file)
index 0000000..8389f24
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _ASM_M32R_IDE_H
+#define _ASM_M32R_IDE_H
+
+/* $Id$ */
+
+/*
+ *  linux/include/asm-m32r/ide.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the i386 architecture specific IDE code.
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
+#define MAX_HWIFS      10
+# else
+#define MAX_HWIFS      2
+# endif
+#endif
+
+#if defined(CONFIG_PLAT_M32700UT)
+#include <asm/irq.h>
+#include <asm/m32700ut/m32700ut_pld.h>
+#endif
+
+#define IDE_ARCH_OBSOLETE_DEFAULTS
+
+static __inline__ int ide_default_irq(unsigned long base)
+{
+       switch (base) {
+#if defined(CONFIG_PLAT_M32700UT)
+               case 0x1f0: return PLD_IRQ_CFIREQ;
+               default:
+                       return 0;
+#else
+               case 0x1f0: return 14;
+               case 0x170: return 15;
+               case 0x1e8: return 11;
+               case 0x168: return 10;
+               case 0x1e0: return 8;
+               case 0x160: return 12;
+               default:
+                       return 0;
+#endif
+       }
+}
+
+static __inline__ unsigned long ide_default_io_base(int index)
+{
+       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;
+       }
+}
+
+#define IDE_ARCH_OBSOLETE_INIT
+#define ide_default_io_ctl(base)       ((base) + 0x206) /* obsolete */
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#define ide_init_default_irq(base)     (0)
+#else
+#define ide_init_default_irq(base)     ide_default_irq(base)
+#endif
+
+#include <asm-generic/ide_iops.h>
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_M32R_IDE_H */
diff --git a/include/asm-m32r/io.h b/include/asm-m32r/io.h
new file mode 100644 (file)
index 0000000..97a64d3
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef _ASM_M32R_IO_H
+#define _ASM_M32R_IO_H
+
+#include <linux/string.h>
+#include <linux/compiler.h>
+#include <asm/page.h>  /* __va */
+
+#ifdef __KERNEL__
+
+#define IO_SPACE_LIMIT  0xFFFFFFFF
+
+/**
+ *     virt_to_phys    -       map virtual addresses to physical
+ *     @address: address to remap
+ *
+ *     The returned physical address is the physical (CPU) mapping for
+ *     the memory address given. It is only valid to use this function on
+ *     addresses directly mapped or allocated via kmalloc.
+ *
+ *     This function does not give bus mappings for DMA transfers. In
+ *     almost all conceivable cases a device driver should not be using
+ *     this function
+ */
+
+static inline unsigned long virt_to_phys(volatile void * address)
+{
+       return __pa(address);
+}
+
+/**
+ *     phys_to_virt    -       map physical address to virtual
+ *     @address: address to remap
+ *
+ *     The returned virtual address is a current CPU mapping for
+ *     the memory address given. It is only valid to use this function on
+ *     addresses that have a kernel mapping
+ *
+ *     This function does not handle bus mappings for DMA transfers. In
+ *     almost all conceivable cases a device driver should not be using
+ *     this function
+ */
+
+static inline void *phys_to_virt(unsigned long address)
+{
+       return __va(address);
+}
+
+extern void __iomem *
+__ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+/**
+ *     ioremap         -       map bus memory into CPU space
+ *     @offset:        bus address of the memory
+ *     @size:          size of the resource to map
+ *
+ *     ioremap performs a platform specific sequence of operations to
+ *     make bus memory CPU accessible via the readb/readw/readl/writeb/
+ *     writew/writel functions and the other mmio helpers. The returned
+ *     address is not guaranteed to be usable directly as a virtual
+ *     address.
+ */
+
+static inline void * ioremap(unsigned long offset, unsigned long size)
+{
+       return __ioremap(offset, size, 0);
+}
+
+extern void iounmap(volatile void __iomem *addr);
+#define ioremap_nocache(off,size) ioremap(off,size)
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+#define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
+#define page_to_bus    page_to_phys
+#define virt_to_bus    virt_to_phys
+
+extern unsigned char _inb(unsigned long);
+extern unsigned short _inw(unsigned long);
+extern unsigned long _inl(unsigned long);
+extern unsigned char _inb_p(unsigned long);
+extern unsigned short _inw_p(unsigned long);
+extern unsigned long _inl_p(unsigned long);
+extern void _outb(unsigned char, unsigned long);
+extern void _outw(unsigned short, unsigned long);
+extern void _outl(unsigned long, unsigned long);
+extern void _outb_p(unsigned char, unsigned long);
+extern void _outw_p(unsigned short, unsigned long);
+extern void _outl_p(unsigned long, unsigned long);
+extern void _insb(unsigned int, void *, unsigned long);
+extern void _insw(unsigned int, void *, unsigned long);
+extern void _insl(unsigned int, void *, unsigned long);
+extern void _outsb(unsigned int, const void *, unsigned long);
+extern void _outsw(unsigned int, const void *, unsigned long);
+extern void _outsl(unsigned int, const void *, unsigned long);
+
+static inline unsigned char _readb(unsigned long addr)
+{
+       return *(volatile unsigned char __force *)addr;
+}
+
+static inline unsigned short _readw(unsigned long addr)
+{
+       return *(volatile unsigned short __force *)addr;
+}
+
+static inline unsigned long _readl(unsigned long addr)
+{
+       return *(volatile unsigned long __force *)addr;
+}
+
+static inline void _writeb(unsigned char b, unsigned long addr)
+{
+       *(volatile unsigned char __force *)addr = b;
+}
+
+static inline void _writew(unsigned short w, unsigned long addr)
+{
+       *(volatile unsigned short __force *)addr = w;
+}
+
+static inline void _writel(unsigned long l, unsigned long addr)
+{
+       *(volatile unsigned long __force *)addr = l;
+}
+
+#define inb     _inb
+#define inw     _inw
+#define inl     _inl
+#define outb    _outb
+#define outw    _outw
+#define outl    _outl
+
+#define inb_p   _inb_p
+#define inw_p   _inw_p
+#define inl_p   _inl_p
+#define outb_p  _outb_p
+#define outw_p  _outw_p
+#define outl_p  _outl_p
+
+#define insb    _insb
+#define insw    _insw
+#define insl    _insl
+#define outsb   _outsb
+#define outsw   _outsw
+#define outsl   _outsl
+
+#define readb(addr)   _readb((unsigned long)(addr))
+#define readw(addr)   _readw((unsigned long)(addr))
+#define readl(addr)   _readl((unsigned long)(addr))
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+
+#define writeb(val, addr)  _writeb((val), (unsigned long)(addr))
+#define writew(val, addr)  _writew((val), (unsigned long)(addr))
+#define writel(val, addr)  _writel((val), (unsigned long)(addr))
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+
+#define flush_write_buffers() do { } while (0)  /* M32R_FIXME */
+
+/**
+ *     isa_check_signature             -       find BIOS signatures
+ *     @io_addr: mmio address to check
+ *     @signature:  signature block
+ *     @length: length of signature
+ *
+ *     Perform a signature comparison with the ISA mmio address io_addr.
+ *     Returns 1 on a match.
+ *
+ *     This function is deprecated. New drivers should use ioremap and
+ *     check_signature.
+ */
+
+static inline int isa_check_signature(unsigned long io_addr,
+        const unsigned char *signature, int length)
+{
+        int retval = 0;
+#if 0
+printk("isa_check_signature\n");
+        do {
+                if (isa_readb(io_addr) != *signature)
+                        goto out;
+                io_addr++;
+                signature++;
+                length--;
+        } while (length);
+        retval = 1;
+out:
+#endif
+        return retval;
+}
+
+static inline void
+memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+       memset((void __force *) addr, val, count);
+}
+
+static inline void
+memcpy_fromio(void *dst, volatile void __iomem *src, int count)
+{
+       memcpy(dst, (void __force *) src, count);
+}
+
+static inline void
+memcpy_toio(volatile void __iomem *dst, const void *src, int count)
+{
+       memcpy((void __force *) dst, src, count);
+}
+
+#endif  /* __KERNEL__ */
+
+#endif  /* _ASM_M32R_IO_H */
diff --git a/include/asm-m32r/ioctl.h b/include/asm-m32r/ioctl.h
new file mode 100644 (file)
index 0000000..87d8f7d
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _ASM_M32R_IOCTL_H
+#define _ASM_M32R_IOCTL_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * linux/ioctl.h for Linux by H.H. Bergman.
+ */
+
+/* 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 /* _ASM_M32R_IOCTL_H */
diff --git a/include/asm-m32r/ioctls.h b/include/asm-m32r/ioctls.h
new file mode 100644 (file)
index 0000000..b350829
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef __ARCH_M32R_IOCTLS_H__
+#define __ARCH_M32R_IOCTLS_H__
+
+/* $Id$ */
+
+/* orig : i386 2.5.67 */
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS         0x5401
+#define TCSETS         0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TCSETSW                0x5403
+#define TCSETSF                0x5404
+#define TCGETA         0x5405
+#define TCSETA         0x5406
+#define TCSETAW                0x5407
+#define TCSETAF                0x5408
+#define TCSBRK         0x5409
+#define TCXONC         0x540A
+#define TCFLSH         0x540B
+#define TIOCEXCL       0x540C
+#define TIOCNXCL       0x540D
+#define TIOCSCTTY      0x540E
+#define TIOCGPGRP      0x540F
+#define TIOCSPGRP      0x5410
+#define TIOCOUTQ       0x5411
+#define TIOCSTI                0x5412
+#define TIOCGWINSZ     0x5413
+#define TIOCSWINSZ     0x5414
+#define TIOCMGET       0x5415
+#define TIOCMBIS       0x5416
+#define TIOCMBIC       0x5417
+#define TIOCMSET       0x5418
+#define TIOCGSOFTCAR   0x5419
+#define TIOCSSOFTCAR   0x541A
+#define FIONREAD       0x541B
+#define TIOCINQ                FIONREAD
+#define TIOCLINUX      0x541C
+#define TIOCCONS       0x541D
+#define TIOCGSERIAL    0x541E
+#define TIOCSSERIAL    0x541F
+#define TIOCPKT                0x5420
+#define FIONBIO                0x5421
+#define TIOCNOTTY      0x5422
+#define TIOCSETD       0x5423
+#define TIOCGETD       0x5424
+#define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
+/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCGSID       0x5429  /* 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 FIONCLEX       0x5450
+#define FIOCLEX                0x5451
+#define FIOASYNC       0x5452
+#define TIOCSERCONFIG  0x5453
+#define TIOCSERGWILD   0x5454
+#define TIOCSERSWILD   0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT     0x545C  /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
+#define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE       0x5460
+
+/* Used for packet mode */
+#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 TIOCSER_TEMT    0x01   /* Transmitter physically empty */
+
+#endif /* __ARCH_M32R_IOCTLS_H__ */
+
diff --git a/include/asm-m32r/ipc.h b/include/asm-m32r/ipc.h
new file mode 100644 (file)
index 0000000..03aac66
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __M32R_IPC_H__
+#define __M32R_IPC_H__
+
+/* orig : i386/ipc.h 2.6.0-test3 */
+
+/*
+ * These are used to wrap system calls on x86.
+ *
+ * See arch/i386/kernel/sys_i386.c for ugly details..
+ */
+struct ipc_kludge {
+       struct msgbuf __user *msgp;
+       long msgtyp;
+};
+
+#define SEMOP           1
+#define SEMGET          2
+#define SEMCTL          3
+#define SEMTIMEDOP      4
+#define MSGSND         11
+#define MSGRCV         12
+#define MSGGET         13
+#define MSGCTL         14
+#define SHMAT          21
+#define SHMDT          22
+#define SHMGET         23
+#define SHMCTL         24
+
+/* Used by the DIPC package, try and avoid reusing it */
+#define DIPC            25
+
+#define IPCCALL(version,op)    ((version)<<16 | (op))
+
+#endif /* __M32R_IPC_H__ */
+
diff --git a/include/asm-m32r/ipcbuf.h b/include/asm-m32r/ipcbuf.h
new file mode 100644 (file)
index 0000000..7c77fb0
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _ASM_M32R_IPCBUF_H
+#define _ASM_M32R_IPCBUF_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * The ipc64_perm structure for m32r architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+       __kernel_key_t          key;
+       __kernel_uid32_t        uid;
+       __kernel_gid32_t        gid;
+       __kernel_uid32_t        cuid;
+       __kernel_gid32_t        cgid;
+       __kernel_mode_t         mode;
+       unsigned short          __pad1;
+       unsigned short          seq;
+       unsigned short          __pad2;
+       unsigned long           __unused1;
+       unsigned long           __unused2;
+};
+
+#endif /* _ASM_M32R_IPCBUF_H */
diff --git a/include/asm-m32r/irq.h b/include/asm-m32r/irq.h
new file mode 100644 (file)
index 0000000..f83e59f
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef _ASM_M32R_IRQ_H
+#define _ASM_M32R_IRQ_H
+
+/* $Id$ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_USRV)
+/*
+ * IRQ definitions for M32700UT
+ *  M32700 Chip: 64 interrupts
+ *  ICU of M32700UT-on-board PLD: 32 interrupts cascaded to INT1# chip pin
+ */
+#define        M32700UT_NUM_CPU_IRQ    (64)
+#define M32700UT_NUM_PLD_IRQ   (32)
+#define M32700UT_IRQ_BASE      0
+#define M32700UT_CPU_IRQ_BASE  M32700UT_IRQ_BASE
+#define M32700UT_PLD_IRQ_BASE  (M32700UT_CPU_IRQ_BASE + M32700UT_NUM_CPU_IRQ)
+
+#define NR_IRQS        (M32700UT_NUM_CPU_IRQ + M32700UT_NUM_PLD_IRQ)
+#elif defined(CONFIG_PLAT_M32700UT)
+/*
+ * IRQ definitions for M32700UT(Rev.C) + M32R-LAN
+ *  M32700 Chip: 64 interrupts
+ *  ICU of M32700UT-on-board PLD: 32 interrupts cascaded to INT1# chip pin
+ *  ICU of M32R-LCD-on-board PLD: 32 interrupts cascaded to INT2# chip pin
+ *  ICU of M32R-LAN-on-board PLD: 32 interrupts cascaded to INT0# chip pin
+ */
+#define M32700UT_NUM_CPU_IRQ           (64)
+#define M32700UT_NUM_PLD_IRQ           (32)
+#define M32700UT_NUM_LCD_PLD_IRQ       (32)
+#define M32700UT_NUM_LAN_PLD_IRQ       (32)
+#define M32700UT_IRQ_BASE              0
+#define M32700UT_CPU_IRQ_BASE          (M32700UT_IRQ_BASE)
+#define M32700UT_PLD_IRQ_BASE \
+       (M32700UT_CPU_IRQ_BASE + M32700UT_NUM_CPU_IRQ)
+#define M32700UT_LCD_PLD_IRQ_BASE \
+       (M32700UT_PLD_IRQ_BASE + M32700UT_NUM_PLD_IRQ)
+#define M32700UT_LAN_PLD_IRQ_BASE \
+       (M32700UT_LCD_PLD_IRQ_BASE + M32700UT_NUM_LCD_PLD_IRQ)
+
+#define NR_IRQS \
+       (M32700UT_NUM_CPU_IRQ + M32700UT_NUM_PLD_IRQ \
+       + M32700UT_NUM_LCD_PLD_IRQ + M32700UT_NUM_LAN_PLD_IRQ)
+#elif defined(CONFIG_PLAT_OPSPUT)
+/*
+ * IRQ definitions for OPSPUT + M32R-LAN
+ *  OPSP Chip: 64 interrupts
+ *  ICU of OPSPUT-on-board PLD: 32 interrupts cascaded to INT1# chip pin
+ *  ICU of M32R-LCD-on-board PLD: 32 interrupts cascaded to INT2# chip pin
+ *  ICU of M32R-LAN-on-board PLD: 32 interrupts cascaded to INT0# chip pin
+ */
+#define OPSPUT_NUM_CPU_IRQ             (64)
+#define OPSPUT_NUM_PLD_IRQ             (32)
+#define OPSPUT_NUM_LCD_PLD_IRQ (32)
+#define OPSPUT_NUM_LAN_PLD_IRQ (32)
+#define OPSPUT_IRQ_BASE                0
+#define OPSPUT_CPU_IRQ_BASE            (OPSPUT_IRQ_BASE)
+#define OPSPUT_PLD_IRQ_BASE \
+       (OPSPUT_CPU_IRQ_BASE + OPSPUT_NUM_CPU_IRQ)
+#define OPSPUT_LCD_PLD_IRQ_BASE \
+       (OPSPUT_PLD_IRQ_BASE + OPSPUT_NUM_PLD_IRQ)
+#define OPSPUT_LAN_PLD_IRQ_BASE \
+       (OPSPUT_LCD_PLD_IRQ_BASE + OPSPUT_NUM_LCD_PLD_IRQ)
+
+#define NR_IRQS \
+       (OPSPUT_NUM_CPU_IRQ + OPSPUT_NUM_PLD_IRQ \
+       + OPSPUT_NUM_LCD_PLD_IRQ + OPSPUT_NUM_LAN_PLD_IRQ)
+#else
+#define NR_IRQS        64
+#endif
+
+#define irq_canonicalize(irq)  (irq)
+
+#ifndef __ASSEMBLY__
+extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
+extern void enable_irq(unsigned int);
+
+struct irqaction;
+struct pt_regs;
+int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+#endif
+
+#endif /* _ASM_M32R_IRQ_H */
+
diff --git a/include/asm-m32r/kmap_types.h b/include/asm-m32r/kmap_types.h
new file mode 100644 (file)
index 0000000..7429591
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __M32R_KMAP_TYPES_H
+#define __M32R_KMAP_TYPES_H
+
+/* Dummy header just to define km_type. */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+# define D(n) __KM_FENCE_##n ,
+#else
+# define D(n)
+#endif
+
+enum km_type {
+D(0)   KM_BOUNCE_READ,
+D(1)   KM_SKB_SUNRPC_DATA,
+D(2)   KM_SKB_DATA_SOFTIRQ,
+D(3)   KM_USER0,
+D(4)   KM_USER1,
+D(5)   KM_BIO_SRC_IRQ,
+D(6)   KM_BIO_DST_IRQ,
+D(7)   KM_PTE0,
+D(8)   KM_PTE1,
+D(9)   KM_IRQ0,
+D(10)  KM_IRQ1,
+D(11)  KM_SOFTIRQ0,
+D(12)  KM_SOFTIRQ1,
+D(13)  KM_TYPE_NR
+};
+
+#undef D
+
+#endif /* __M32R_KMAP_TYPES_H */
+
diff --git a/include/asm-m32r/linkage.h b/include/asm-m32r/linkage.h
new file mode 100644 (file)
index 0000000..a9fb151
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+#define __ALIGN                .balign 4
+#define __ALIGN_STR    ".balign 4"
+
+#endif /* __ASM_LINKAGE_H */
diff --git a/include/asm-m32r/local.h b/include/asm-m32r/local.h
new file mode 100644 (file)
index 0000000..def29d0
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __M32R_LOCAL_H
+#define __M32R_LOCAL_H
+
+#include <asm-generic/local.h>
+
+#endif /* __M32R_LOCAL_H */
diff --git a/include/asm-m32r/m32102.h b/include/asm-m32r/m32102.h
new file mode 100644 (file)
index 0000000..38e3a73
--- /dev/null
@@ -0,0 +1,266 @@
+#ifndef _M32102_H_
+#define _M32102_H_
+
+/*
+ * Renesas M32R 32102 group
+ *
+ * Copyright (c) 2001  Hitoshi Yamamoto
+ * Copyright (c) 2003, 2004  Renesas Technology Corp.
+ */
+
+/*======================================================================*
+ * Special Function Register
+ *======================================================================*/
+#define M32R_SFR_OFFSET  (0x00E00000)  /* 0x00E00000-0x00EFFFFF 1[MB] */
+
+/*
+ * Clock and Power Management registers.
+ */
+#define M32R_CPM_OFFSET          (0x000F4000+M32R_SFR_OFFSET)
+
+#define M32R_CPM_CPUCLKCR_PORTL  (0x00+M32R_CPM_OFFSET)
+#define M32R_CPM_CLKMOD_PORTL    (0x04+M32R_CPM_OFFSET)
+#define M32R_CPM_PLLCR_PORTL     (0x08+M32R_CPM_OFFSET)
+
+/*
+ * Multi Function Timer registers.
+ */
+#define M32R_MFT_OFFSET        (0x000FC000+M32R_SFR_OFFSET)
+
+#define M32R_MFTCR_PORTL       (0x000+M32R_MFT_OFFSET)  /* MFT control */
+#define M32R_MFTRPR_PORTL      (0x004+M32R_MFT_OFFSET)  /* MFT real port */
+
+#define M32R_MFT0_OFFSET       (0x100+M32R_MFT_OFFSET)
+#define M32R_MFT0MOD_PORTL     (0x00+M32R_MFT0_OFFSET)  /* MFT0 mode */
+#define M32R_MFT0BOS_PORTL     (0x04+M32R_MFT0_OFFSET)  /* MFT0 b-port output status */
+#define M32R_MFT0CUT_PORTL     (0x08+M32R_MFT0_OFFSET)  /* MFT0 count */
+#define M32R_MFT0RLD_PORTL     (0x0C+M32R_MFT0_OFFSET)  /* MFT0 reload */
+#define M32R_MFT0CMPRLD_PORTL  (0x10+M32R_MFT0_OFFSET)  /* MFT0 compare reload */
+
+#define M32R_MFT1_OFFSET       (0x200+M32R_MFT_OFFSET)
+#define M32R_MFT1MOD_PORTL     (0x00+M32R_MFT1_OFFSET)  /* MFT1 mode */
+#define M32R_MFT1BOS_PORTL     (0x04+M32R_MFT1_OFFSET)  /* MFT1 b-port output status */
+#define M32R_MFT1CUT_PORTL     (0x08+M32R_MFT1_OFFSET)  /* MFT1 count */
+#define M32R_MFT1RLD_PORTL     (0x0C+M32R_MFT1_OFFSET)  /* MFT1 reload */
+#define M32R_MFT1CMPRLD_PORTL  (0x10+M32R_MFT1_OFFSET)  /* MFT1 compare reload */
+
+#define M32R_MFT2_OFFSET       (0x300+M32R_MFT_OFFSET)
+#define M32R_MFT2MOD_PORTL     (0x00+M32R_MFT2_OFFSET)  /* MFT2 mode */
+#define M32R_MFT2BOS_PORTL     (0x04+M32R_MFT2_OFFSET)  /* MFT2 b-port output status */
+#define M32R_MFT2CUT_PORTL     (0x08+M32R_MFT2_OFFSET)  /* MFT2 count */
+#define M32R_MFT2RLD_PORTL     (0x0C+M32R_MFT2_OFFSET)  /* MFT2 reload */
+#define M32R_MFT2CMPRLD_PORTL  (0x10+M32R_MFT2_OFFSET)  /* MFT2 compare reload */
+
+#define M32R_MFT3_OFFSET       (0x400+M32R_MFT_OFFSET)
+#define M32R_MFT3MOD_PORTL     (0x00+M32R_MFT3_OFFSET)  /* MFT3 mode */
+#define M32R_MFT3BOS_PORTL     (0x04+M32R_MFT3_OFFSET)  /* MFT3 b-port output status */
+#define M32R_MFT3CUT_PORTL     (0x08+M32R_MFT3_OFFSET)  /* MFT3 count */
+#define M32R_MFT3RLD_PORTL     (0x0C+M32R_MFT3_OFFSET)  /* MFT3 reload */
+#define M32R_MFT3CMPRLD_PORTL  (0x10+M32R_MFT3_OFFSET)  /* MFT3 compare reload */
+
+#define M32R_MFT4_OFFSET       (0x500+M32R_MFT_OFFSET)
+#define M32R_MFT4MOD_PORTL     (0x00+M32R_MFT4_OFFSET)  /* MFT4 mode */
+#define M32R_MFT4BOS_PORTL     (0x04+M32R_MFT4_OFFSET)  /* MFT4 b-port output status */
+#define M32R_MFT4CUT_PORTL     (0x08+M32R_MFT4_OFFSET)  /* MFT4 count */
+#define M32R_MFT4RLD_PORTL     (0x0C+M32R_MFT4_OFFSET)  /* MFT4 reload */
+#define M32R_MFT4CMPRLD_PORTL  (0x10+M32R_MFT4_OFFSET)  /* MFT4 compare reload */
+
+#define M32R_MFT5_OFFSET       (0x600+M32R_MFT_OFFSET)
+#define M32R_MFT5MOD_PORTL     (0x00+M32R_MFT5_OFFSET)  /* MFT4 mode */
+#define M32R_MFT5BOS_PORTL     (0x04+M32R_MFT5_OFFSET)  /* MFT4 b-port output status */
+#define M32R_MFT5CUT_PORTL     (0x08+M32R_MFT5_OFFSET)  /* MFT4 count */
+#define M32R_MFT5RLD_PORTL     (0x0C+M32R_MFT5_OFFSET)  /* MFT4 reload */
+#define M32R_MFT5CMPRLD_PORTL  (0x10+M32R_MFT5_OFFSET)  /* MFT4 compare reload */
+
+#ifdef CONFIG_CHIP_M32700
+#define M32R_MFTCR_MFT0MSK  (1UL<<31)  /* b0 */
+#define M32R_MFTCR_MFT1MSK  (1UL<<30)  /* b1 */
+#define M32R_MFTCR_MFT2MSK  (1UL<<29)  /* b2 */
+#define M32R_MFTCR_MFT3MSK  (1UL<<28)  /* b3 */
+#define M32R_MFTCR_MFT4MSK  (1UL<<27)  /* b4 */
+#define M32R_MFTCR_MFT5MSK  (1UL<<26)  /* b5 */
+#define M32R_MFTCR_MFT0EN   (1UL<<23)  /* b8 */
+#define M32R_MFTCR_MFT1EN   (1UL<<22)  /* b9 */
+#define M32R_MFTCR_MFT2EN   (1UL<<21)  /* b10 */
+#define M32R_MFTCR_MFT3EN   (1UL<<20)  /* b11 */
+#define M32R_MFTCR_MFT4EN   (1UL<<19)  /* b12 */
+#define M32R_MFTCR_MFT5EN   (1UL<<18)  /* b13 */
+#else  /* not CONFIG_CHIP_M32700 */
+#define M32R_MFTCR_MFT0MSK  (1UL<<15)  /* b16 */
+#define M32R_MFTCR_MFT1MSK  (1UL<<14)  /* b17 */
+#define M32R_MFTCR_MFT2MSK  (1UL<<13)  /* b18 */
+#define M32R_MFTCR_MFT3MSK  (1UL<<12)  /* b19 */
+#define M32R_MFTCR_MFT4MSK  (1UL<<11)  /* b20 */
+#define M32R_MFTCR_MFT5MSK  (1UL<<10)  /* b21 */
+#define M32R_MFTCR_MFT0EN   (1UL<<7)   /* b24 */
+#define M32R_MFTCR_MFT1EN   (1UL<<6)   /* b25 */
+#define M32R_MFTCR_MFT2EN   (1UL<<5)   /* b26 */
+#define M32R_MFTCR_MFT3EN   (1UL<<4)   /* b27 */
+#define M32R_MFTCR_MFT4EN   (1UL<<3)   /* b28 */
+#define M32R_MFTCR_MFT5EN   (1UL<<2)   /* b29 */
+#endif /* not CONFIG_CHIP_M32700 */
+
+#define M32R_MFTMOD_CC_MASK    (1UL<<15)  /* b16 */
+#define M32R_MFTMOD_TCCR       (1UL<<13)  /* b18 */
+#define M32R_MFTMOD_GTSEL000   (0UL<<8)   /* b21-23 : 000 */
+#define M32R_MFTMOD_GTSEL001   (1UL<<8)   /* b21-23 : 001 */
+#define M32R_MFTMOD_GTSEL010   (2UL<<8)   /* b21-23 : 010 */
+#define M32R_MFTMOD_GTSEL011   (3UL<<8)   /* b21-23 : 011 */
+#define M32R_MFTMOD_GTSEL110   (6UL<<8)   /* b21-23 : 110 */
+#define M32R_MFTMOD_GTSEL111   (7UL<<8)   /* b21-23 : 111 */
+#define M32R_MFTMOD_CMSEL      (1UL<<3)   /* b28 */
+#define M32R_MFTMOD_CSSEL000   (0UL<<0)   /* b29-b31 : 000 */
+#define M32R_MFTMOD_CSSEL001   (1UL<<0)   /* b29-b31 : 001 */
+#define M32R_MFTMOD_CSSEL010   (2UL<<0)   /* b29-b31 : 010 */
+#define M32R_MFTMOD_CSSEL011   (3UL<<0)   /* b29-b31 : 011 */
+#define M32R_MFTMOD_CSSEL100   (4UL<<0)   /* b29-b31 : 100 */
+#define M32R_MFTMOD_CSSEL110   (6UL<<0)   /* b29-b31 : 110 */
+
+/*
+ * Serial I/O registers.
+ */
+#define M32R_SIO_OFFSET  (0x000FD000+M32R_SFR_OFFSET)
+
+#define M32R_SIO0_CR_PORTL     (0x000+M32R_SIO_OFFSET)
+#define M32R_SIO0_MOD0_PORTL   (0x004+M32R_SIO_OFFSET)
+#define M32R_SIO0_MOD1_PORTL   (0x008+M32R_SIO_OFFSET)
+#define M32R_SIO0_STS_PORTL    (0x00C+M32R_SIO_OFFSET)
+#define M32R_SIO0_TRCR_PORTL   (0x010+M32R_SIO_OFFSET)
+#define M32R_SIO0_BAUR_PORTL   (0x014+M32R_SIO_OFFSET)
+#define M32R_SIO0_RBAUR_PORTL  (0x018+M32R_SIO_OFFSET)
+#define M32R_SIO0_TXB_PORTL    (0x01C+M32R_SIO_OFFSET)
+#define M32R_SIO0_RXB_PORTL    (0x020+M32R_SIO_OFFSET)
+
+/*
+ * Interrupt Control Unit registers.
+ */
+#define M32R_ICU_OFFSET       (0x000FF000+M32R_SFR_OFFSET)
+#define M32R_ICU_ISTS_PORTL   (0x004+M32R_ICU_OFFSET)
+#define M32R_ICU_IREQ0_PORTL  (0x008+M32R_ICU_OFFSET)
+#define M32R_ICU_IREQ1_PORTL  (0x00C+M32R_ICU_OFFSET)
+#define M32R_ICU_SBICR_PORTL  (0x018+M32R_ICU_OFFSET)
+#define M32R_ICU_IMASK_PORTL  (0x01C+M32R_ICU_OFFSET)
+#define M32R_ICU_CR1_PORTL    (0x200+M32R_ICU_OFFSET)  /* INT0 */
+#define M32R_ICU_CR2_PORTL    (0x204+M32R_ICU_OFFSET)  /* INT1 */
+#define M32R_ICU_CR3_PORTL    (0x208+M32R_ICU_OFFSET)  /* INT2 */
+#define M32R_ICU_CR4_PORTL    (0x20C+M32R_ICU_OFFSET)  /* INT3 */
+#define M32R_ICU_CR5_PORTL    (0x210+M32R_ICU_OFFSET)  /* INT4 */
+#define M32R_ICU_CR6_PORTL    (0x214+M32R_ICU_OFFSET)  /* INT5 */
+#define M32R_ICU_CR7_PORTL    (0x218+M32R_ICU_OFFSET)  /* INT6 */
+#define M32R_ICU_CR16_PORTL   (0x23C+M32R_ICU_OFFSET)  /* MFT0 */
+#define M32R_ICU_CR17_PORTL   (0x240+M32R_ICU_OFFSET)  /* MFT1 */
+#define M32R_ICU_CR18_PORTL   (0x244+M32R_ICU_OFFSET)  /* MFT2 */
+#define M32R_ICU_CR19_PORTL   (0x248+M32R_ICU_OFFSET)  /* MFT3 */
+#define M32R_ICU_CR20_PORTL   (0x24C+M32R_ICU_OFFSET)  /* MFT4 */
+#define M32R_ICU_CR21_PORTL   (0x250+M32R_ICU_OFFSET)  /* MFT5 */
+#define M32R_ICU_CR32_PORTL   (0x27C+M32R_ICU_OFFSET)  /* DMA0 */
+#define M32R_ICU_CR33_PORTL   (0x280+M32R_ICU_OFFSET)  /* DMA1 */
+#define M32R_ICU_CR48_PORTL   (0x2BC+M32R_ICU_OFFSET)  /* SIO0 */
+#define M32R_ICU_CR49_PORTL   (0x2C0+M32R_ICU_OFFSET)  /* SIO0 */
+#define M32R_ICU_CR50_PORTL   (0x2C4+M32R_ICU_OFFSET)  /* SIO1 */
+#define M32R_ICU_CR51_PORTL   (0x2C8+M32R_ICU_OFFSET)  /* SIO1 */
+#define M32R_ICU_CR52_PORTL   (0x2CC+M32R_ICU_OFFSET)  /* SIO2 */
+#define M32R_ICU_CR53_PORTL   (0x2D0+M32R_ICU_OFFSET)  /* SIO2 */
+#define M32R_ICU_CR54_PORTL   (0x2D4+M32R_ICU_OFFSET)  /* SIO3 */
+#define M32R_ICU_CR55_PORTL   (0x2D8+M32R_ICU_OFFSET)  /* SIO3 */
+#define M32R_ICU_CR56_PORTL   (0x2DC+M32R_ICU_OFFSET)  /* SIO4 */
+#define M32R_ICU_CR57_PORTL   (0x2E0+M32R_ICU_OFFSET)  /* SIO4 */
+
+#ifdef CONFIG_SMP
+#define M32R_ICU_IPICR0_PORTL (0x2dc+M32R_ICU_OFFSET)  /* IPI0 */
+#define M32R_ICU_IPICR1_PORTL (0x2e0+M32R_ICU_OFFSET)  /* IPI1 */
+#define M32R_ICU_IPICR2_PORTL (0x2e4+M32R_ICU_OFFSET)  /* IPI2 */
+#define M32R_ICU_IPICR3_PORTL (0x2e8+M32R_ICU_OFFSET)  /* IPI3 */
+#define M32R_ICU_IPICR4_PORTL (0x2ec+M32R_ICU_OFFSET)  /* IPI4 */
+#define M32R_ICU_IPICR5_PORTL (0x2f0+M32R_ICU_OFFSET)  /* IPI5 */
+#define M32R_ICU_IPICR6_PORTL (0x2f4+M32R_ICU_OFFSET)  /* IPI6 */
+#define M32R_ICU_IPICR7_PORTL (0x2f8+M32R_ICU_OFFSET)  /* IPI7 */
+#endif /* CONFIG_SMP */
+
+#define M32R_ICUIMASK_IMSK0  (0UL<<16)  /* b13-b15: Disable interrupt */
+#define M32R_ICUIMASK_IMSK1  (1UL<<16)  /* b13-b15: Enable level 0 interrupt */
+#define M32R_ICUIMASK_IMSK2  (2UL<<16)  /* b13-b15: Enable level 0,1 interrupt */
+#define M32R_ICUIMASK_IMSK3  (3UL<<16)  /* b13-b15: Enable level 0-2 interrupt */
+#define M32R_ICUIMASK_IMSK4  (4UL<<16)  /* b13-b15: Enable level 0-3 interrupt */
+#define M32R_ICUIMASK_IMSK5  (5UL<<16)  /* b13-b15: Enable level 0-4 interrupt */
+#define M32R_ICUIMASK_IMSK6  (6UL<<16)  /* b13-b15: Enable level 0-5 interrupt */
+#define M32R_ICUIMASK_IMSK7  (7UL<<16)  /* b13-b15: Enable level 0-6 interrupt */
+
+#define M32R_ICUCR_IEN      (1UL<<12)  /* b19: Interrupt enable */
+#define M32R_ICUCR_IRQ      (1UL<<8)   /* b23: Interrupt request */
+#define M32R_ICUCR_ISMOD00  (0UL<<4)   /* b26-b27: Interrupt sense mode Edge HtoL */
+#define M32R_ICUCR_ISMOD01  (1UL<<4)   /* b26-b27: Interrupt sense mode Level L */
+#define M32R_ICUCR_ISMOD10  (2UL<<4)   /* b26-b27: Interrupt sense mode Edge LtoH*/
+#define M32R_ICUCR_ISMOD11  (3UL<<4)   /* b26-b27: Interrupt sense mode Level H */
+#define M32R_ICUCR_ILEVEL0  (0UL<<0)   /* b29-b31: Interrupt priority level 0 */
+#define M32R_ICUCR_ILEVEL1  (1UL<<0)   /* b29-b31: Interrupt priority level 1 */
+#define M32R_ICUCR_ILEVEL2  (2UL<<0)   /* b29-b31: Interrupt priority level 2 */
+#define M32R_ICUCR_ILEVEL3  (3UL<<0)   /* b29-b31: Interrupt priority level 3 */
+#define M32R_ICUCR_ILEVEL4  (4UL<<0)   /* b29-b31: Interrupt priority level 4 */
+#define M32R_ICUCR_ILEVEL5  (5UL<<0)   /* b29-b31: Interrupt priority level 5 */
+#define M32R_ICUCR_ILEVEL6  (6UL<<0)   /* b29-b31: Interrupt priority level 6 */
+#define M32R_ICUCR_ILEVEL7  (7UL<<0)   /* b29-b31: Disable interrupt */
+
+#define  M32R_IRQ_INT0    (1)   /* INT0 */
+#define  M32R_IRQ_INT1    (2)   /* INT1 */
+#define  M32R_IRQ_INT2    (3)   /* INT2 */
+#define  M32R_IRQ_INT3    (4)   /* INT3 */
+#define  M32R_IRQ_INT4    (5)   /* INT4 */
+#define  M32R_IRQ_INT5    (6)   /* INT5 */
+#define  M32R_IRQ_INT6    (7)   /* INT6 */
+#define  M32R_IRQ_MFT0    (16)  /* MFT0 */
+#define  M32R_IRQ_MFT1    (17)  /* MFT1 */
+#define  M32R_IRQ_MFT2    (18)  /* MFT2 */
+#define  M32R_IRQ_MFT3    (19)  /* MFT3 */
+#define  M32R_IRQ_MFT4    (20)  /* MFT4 */
+#define  M32R_IRQ_MFT5    (21)  /* MFT5 */
+#define  M32R_IRQ_DMA0    (32)  /* DMA0 */
+#define  M32R_IRQ_DMA1    (33)  /* DMA1 */
+#define  M32R_IRQ_SIO0_R  (48)  /* SIO0 send    */
+#define  M32R_IRQ_SIO0_S  (49)  /* SIO0 receive */
+#define  M32R_IRQ_SIO1_R  (50)  /* SIO1 send    */
+#define  M32R_IRQ_SIO1_S  (51)  /* SIO1 receive */
+#define  M32R_IRQ_SIO2_R  (52)  /* SIO2 send    */
+#define  M32R_IRQ_SIO2_S  (53)  /* SIO2 receive */
+#define  M32R_IRQ_SIO3_R  (54)  /* SIO3 send    */
+#define  M32R_IRQ_SIO3_S  (55)  /* SIO3 receive */
+#define  M32R_IRQ_SIO4_R  (56)  /* SIO4 send    */
+#define  M32R_IRQ_SIO4_S  (57)  /* SIO4 receive */
+
+#ifdef CONFIG_SMP
+#define M32R_IRQ_IPI0 (56)
+#define M32R_IRQ_IPI1 (57)
+#define M32R_IRQ_IPI2 (58)
+#define M32R_IRQ_IPI3 (59)
+#define M32R_IRQ_IPI4 (60)
+#define M32R_IRQ_IPI5 (61)
+#define M32R_IRQ_IPI6 (62)
+#define M32R_IRQ_IPI7 (63)
+#define M32R_CPUID_PORTL (0xffffffe0)
+
+#define M32R_FPGA_TOP (0x000F0000+M32R_SFR_OFFSET)
+
+#define M32R_FPGA_NUM_OF_CPUS_PORTL (0x00+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME0_PORTL   (0x10+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME1_PORTL   (0x14+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME2_PORTL   (0x18+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME3_PORTL   (0x1c+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID0_PORTL   (0x20+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID1_PORTL   (0x24+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID2_PORTL   (0x28+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID3_PORTL   (0x2c+M32R_FPGA_TOP)
+#define M32R_FPGA_VERSION0_PORTL    (0x30+M32R_FPGA_TOP)
+#define M32R_FPGA_VERSION1_PORTL    (0x34+M32R_FPGA_TOP)
+
+#ifndef __ASSEMBLY__
+/* For NETDEV WATCHDOG */
+typedef struct {
+       unsigned long icucr;    /* ICU Control Register */
+} icu_data_t;
+
+extern icu_data_t icu_data[];
+#endif
+
+#endif /* CONFIG_SMP */
+
+#endif /* _M32102_H_ */
diff --git a/include/asm-m32r/m32102peri.h b/include/asm-m32r/m32102peri.h
new file mode 100644 (file)
index 0000000..3c12955
--- /dev/null
@@ -0,0 +1,468 @@
+/* $Id$
+ *
+ * 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) 2000,2001 by Hiroyuki Kondo
+ */
+
+#ifndef __ASSEMBLY__
+
+typedef        void    V;
+typedef        char    B;
+typedef        short   S;
+typedef        int             W;
+typedef        long    L;
+typedef        float   F;
+typedef        double  D;
+typedef        unsigned char   UB;
+typedef        unsigned short  US;
+typedef        unsigned int    UW;
+typedef        unsigned long   UL;
+typedef        const unsigned int      CUW;
+
+/*********************************
+
+M32102 ICU
+
+*********************************/
+#define                ICUISTS         (UW *)0xa0EFF004
+#define                ICUIREQ0        (UW *)0xa0EFF008
+#define                ICUIREQ1        (UW *)0xa0EFF00C
+
+#define                ICUSBICR        (UW *)0xa0EFF018
+#define                ICUIMASK        (UW *)0xa0EFF01C
+
+#define                ICUCR1          (UW *)0xa0EFF200        /* INT0 */
+#define                ICUCR2          (UW *)0xa0EFF204        /* INT1 */
+#define                ICUCR3          (UW *)0xa0EFF208        /* INT2 */
+#define                ICUCR4          (UW *)0xa0EFF20C        /* INT3 */
+#define                ICUCR5          (UW *)0xa0EFF210        /* INT4 */
+#define                ICUCR6          (UW *)0xa0EFF214        /* INT5 */
+#define                ICUCR7          (UW *)0xa0EFF218        /* INT6 */
+
+#define                ICUCR16         (UW *)0xa0EFF23C        /* MFT0 */
+#define                ICUCR17         (UW *)0xa0EFF240        /* MFT1 */
+#define                ICUCR18         (UW *)0xa0EFF244        /* MFT2 */
+#define                ICUCR19         (UW *)0xa0EFF248        /* MFT3 */
+#define                ICUCR20         (UW *)0xa0EFF24C        /* MFT4 */
+#define                ICUCR21         (UW *)0xa0EFF250        /* MFT5 */
+
+#define                ICUCR32         (UW *)0xa0EFF27C        /* DMA0 */
+#define                ICUCR33         (UW *)0xa0EFF280        /* DMA1 */
+
+#define                ICUCR48         (UW *)0xa0EFF2BC        /* SIO0R */
+#define                ICUCR49         (UW *)0xa0EFF2C0        /* SIO0S */
+#define                ICUCR50         (UW *)0xa0EFF2C4        /* SIO1R */
+#define                ICUCR51         (UW *)0xa0EFF2C8        /* SIO1S */
+#define                ICUCR52         (UW *)0xa0EFF2CC        /* SIO2R */
+#define                ICUCR53         (UW *)0xa0EFF2D0        /* SIO2S */
+#define                ICUCR54         (UW *)0xa0EFF2D4        /* SIO3R */
+#define                ICUCR55         (UW *)0xa0EFF2D8        /* SIO3S */
+#define                ICUCR56         (UW *)0xa0EFF2DC        /* SIO4R */
+#define                ICUCR57         (UW *)0xa0EFF2E0        /* SIO4S */
+
+/*********************************
+
+M32102 MFT
+
+*********************************/
+#define                MFTCR           (US *)0xa0EFC002
+#define                MFTRPR          (UB *)0xa0EFC006
+
+#define                MFT0MOD         (US *)0xa0EFC102
+#define                MFT0BOS         (US *)0xa0EFC106
+#define                MFT0CUT         (US *)0xa0EFC10A
+#define                MFT0RLD         (US *)0xa0EFC10E
+#define                MFT0CRLD        (US *)0xa0EFC112
+
+#define                MFT1MOD         (US *)0xa0EFC202
+#define                MFT1BOS         (US *)0xa0EFC206
+#define                MFT1CUT         (US *)0xa0EFC20A
+#define                MFT1RLD         (US *)0xa0EFC20E
+#define                MFT1CRLD        (US *)0xa0EFC212
+
+#define                MFT2MOD         (US *)0xa0EFC302
+#define                MFT2BOS         (US *)0xa0EFC306
+#define                MFT2CUT         (US *)0xa0EFC30A
+#define                MFT2RLD         (US *)0xa0EFC30E
+#define                MFT2CRLD        (US *)0xa0EFC312
+
+#define                MFT3MOD         (US *)0xa0EFC402
+#define                MFT3CUT         (US *)0xa0EFC40A
+#define                MFT3RLD         (US *)0xa0EFC40E
+#define                MFT3CRLD        (US *)0xa0EFC412
+
+#define                MFT4MOD         (US *)0xa0EFC502
+#define                MFT4CUT         (US *)0xa0EFC50A
+#define                MFT4RLD         (US *)0xa0EFC50E
+#define                MFT4CRLD        (US *)0xa0EFC512
+
+#define                MFT5MOD         (US *)0xa0EFC602
+#define                MFT5CUT         (US *)0xa0EFC60A
+#define                MFT5RLD         (US *)0xa0EFC60E
+#define                MFT5CRLD        (US *)0xa0EFC612
+
+/*********************************
+
+M32102 SIO
+
+*********************************/
+
+#define SIO0CR     (volatile int *)0xa0efd000
+#define SIO0MOD0   (volatile int *)0xa0efd004
+#define SIO0MOD1   (volatile int *)0xa0efd008
+#define SIO0STS    (volatile int *)0xa0efd00c
+#define SIO0IMASK  (volatile int *)0xa0efd010
+#define SIO0BAUR   (volatile int *)0xa0efd014
+#define SIO0RBAUR  (volatile int *)0xa0efd018
+#define SIO0TXB    (volatile int *)0xa0efd01c
+#define SIO0RXB    (volatile int *)0xa0efd020
+
+#define SIO1CR     (volatile int *)0xa0efd100
+#define SIO1MOD0   (volatile int *)0xa0efd104
+#define SIO1MOD1   (volatile int *)0xa0efd108
+#define SIO1STS    (volatile int *)0xa0efd10c
+#define SIO1IMASK  (volatile int *)0xa0efd110
+#define SIO1BAUR   (volatile int *)0xa0efd114
+#define SIO1RBAUR  (volatile int *)0xa0efd118
+#define SIO1TXB    (volatile int *)0xa0efd11c
+#define SIO1RXB    (volatile int *)0xa0efd120
+/*********************************
+
+M32102 PORT
+
+*********************************/
+#define                PIEN            (UB *)0xa0EF1003        /* input enable */
+
+#define                P0DATA          (UB *)0xa0EF1020        /* data */
+#define                P1DATA          (UB *)0xa0EF1021
+#define                P2DATA          (UB *)0xa0EF1022
+#define                P3DATA          (UB *)0xa0EF1023
+#define                P4DATA          (UB *)0xa0EF1024
+#define                P5DATA          (UB *)0xa0EF1025
+#define                P6DATA          (UB *)0xa0EF1026
+#define                P7DATA          (UB *)0xa0EF1027
+
+#define                P0DIR           (UB *)0xa0EF1040        /* direction */
+#define                P1DIR           (UB *)0xa0EF1041
+#define                P2DIR           (UB *)0xa0EF1042
+#define                P3DIR           (UB *)0xa0EF1043
+#define                P4DIR           (UB *)0xa0EF1044
+#define                P5DIR           (UB *)0xa0EF1045
+#define                P6DIR           (UB *)0xa0EF1046
+#define                P7DIR           (UB *)0xa0EF1047
+
+#define                P0MOD           (US *)0xa0EF1060        /* mode control */
+#define                P1MOD           (US *)0xa0EF1062
+#define                P2MOD           (US *)0xa0EF1064
+#define                P3MOD           (US *)0xa0EF1066
+#define                P4MOD           (US *)0xa0EF1068
+#define                P5MOD           (US *)0xa0EF106A
+#define                P6MOD           (US *)0xa0EF106C
+#define                P7MOD           (US *)0xa0EF106E
+
+#define                P0ODCR          (UB *)0xa0EF1080        /* open-drain control */
+#define                P1ODCR          (UB *)0xa0EF1081
+#define                P2ODCR          (UB *)0xa0EF1082
+#define                P3ODCR          (UB *)0xa0EF1083
+#define                P4ODCR          (UB *)0xa0EF1084
+#define                P5ODCR          (UB *)0xa0EF1085
+#define                P6ODCR          (UB *)0xa0EF1086
+#define                P7ODCR          (UB *)0xa0EF1087
+
+/*********************************
+
+M32102 Cache
+
+********************************/
+
+#define                MCCR    (US *)0xFFFFFFFE
+
+
+#else  /* __ASSEMBLY__ */
+
+;;
+;; PIO     0x80ef1000
+;;
+
+#define PIEN          0xa0ef1000
+
+#define P0DATA        0xa0ef1020
+#define P1DATA        0xa0ef1021
+#define P2DATA        0xa0ef1022
+#define P3DATA        0xa0ef1023
+#define P4DATA        0xa0ef1024
+#define P5DATA        0xa0ef1025
+#define P6DATA        0xa0ef1026
+#define P7DATA        0xa0ef1027
+
+#define P0DIR         0xa0ef1040
+#define P1DIR         0xa0ef1041
+#define P2DIR         0xa0ef1042
+#define P3DIR         0xa0ef1043
+#define P4DIR         0xa0ef1044
+#define P5DIR         0xa0ef1045
+#define P6DIR         0xa0ef1046
+#define P7DIR         0xa0ef1047
+
+#define P0MOD         0xa0ef1060
+#define P1MOD         0xa0ef1062
+#define P2MOD         0xa0ef1064
+#define P3MOD         0xa0ef1066
+#define P4MOD         0xa0ef1068
+#define P5MOD         0xa0ef106a
+#define P6MOD         0xa0ef106c
+#define P7MOD         0xa0ef106e
+;
+#define P0ODCR        0xa0ef1080
+#define P1ODCR        0xa0ef1081
+#define P2ODCR        0xa0ef1082
+#define P3ODCR        0xa0ef1083
+#define P4ODCR        0xa0ef1084
+#define P5ODCR        0xa0ef1085
+#define P6ODCR        0xa0ef1086
+#define P7ODCR        0xa0ef1087
+
+;;
+;; WDT     0xa0ef2000
+;;
+
+#define WDTCR         0xa0ef2000
+
+
+;;
+;; CLK     0xa0ef4000
+;;
+
+#define CPUCLKCR      0xa0ef4000
+#define CLKMOD        0xa0ef4004
+#define PLLCR         0xa0ef4008
+
+
+;;
+;; BSEL    0xa0ef5000
+;;
+
+#define BSEL0CR       0xa0ef5000
+#define BSEL1CR       0xa0ef5004
+#define BSEL2CR       0xa0ef5008
+#define BSEL3CR       0xa0ef500c
+#define BSEL4CR       0xa0ef5010
+#define BSEL5CR       0xa0ef5014
+
+
+;;
+;; SDRAMC  0xa0ef6000
+;;
+
+#define SDRF0         0xa0ef6000
+#define SDRF1         0xa0ef6004
+#define SDIR0         0xa0ef6008
+#define SDIR1         0xa0ef600c
+#define SDBR          0xa0ef6010
+
+;; CH0
+#define SD0ADR        0xa0ef6020
+#define SD0SZ         0xa0ef6022
+#define SD0ER         0xa0ef6024
+#define SD0TR         0xa0ef6028
+#define SD0MOD        0xa0ef602c
+
+;; CH1
+#define SD1ADR        0xa0ef6040
+#define SD1SZ         0xa0ef6042
+#define SD1ER         0xa0ef6044
+#define SD1TR         0xa0ef6048
+#define SD1MOD        0xa0ef604c
+
+
+;;
+;; DMAC    0xa0ef8000
+;;
+
+#define DMAEN         0xa0ef8000
+#define DMAISTS       0xa0ef8004
+#define DMAEDET       0xa0ef8008
+#define DMAASTS       0xa0ef800c
+
+;; CH0
+#define DMA0CR0       0xa0ef8100
+#define DMA0CR1       0xa0ef8104
+#define DMA0CSA       0xa0ef8108
+#define DMA0RSA       0xa0ef810c
+#define DMA0CDA       0xa0ef8110
+#define DMA0RDA       0xa0ef8114
+#define DMA0CBCUT     0xa0ef8118
+#define DMA0RBCUT     0xa0ef811c
+
+;; CH1
+#define DMA1CR0       0xa0ef8200
+#define DMA1CR1       0xa0ef8204
+#define DMA1CSA       0xa0ef8208
+#define DMA1RSA       0xa0ef820c
+#define DMA1CDA       0xa0ef8210
+#define DMA1RDA       0xa0ef8214
+#define DMA1CBCUT     0xa0ef8218
+#define DMA1RBCUT     0xa0ef821c
+
+
+;;
+;; MFT     0xa0efc000
+;;
+
+#define MFTCR        0xa0efc000
+#define MFTRPR       0xa0efc004
+
+;; CH0
+#define MFT0MOD      0xa0efc100
+#define MFT0BOS      0xa0efc104
+#define MFT0CUT      0xa0efc108
+#define MFT0RLD      0xa0efc10c
+#define MFT0CMPRLD   0xa0efc110
+
+;; CH1
+#define MFT1MOD      0xa0efc200
+#define MFT1BOS      0xa0efc204
+#define MFT1CUT      0xa0efc208
+#define MFT1RLD      0xa0efc20c
+#define MFT1CMPRLD   0xa0efc210
+
+;; CH2
+#define MFT2MOD      0xa0efc300
+#define MFT2BOS      0xa0efc304
+#define MFT2CUT      0xa0efc308
+#define MFT2RLD      0xa0efc30c
+#define MFT2CMPRLD   0xa0efc310
+
+;; CH3
+#define MFT3MOD      0xa0efc400
+#define MFT3BOS      0xa0efc404
+#define MFT3CUT      0xa0efc408
+#define MFT3RLD      0xa0efc40c
+#define MFT3CMPRLD   0xa0efc410
+
+;; CH4
+#define MFT4MOD      0xa0efc500
+#define MFT4BOS      0xa0efc504
+#define MFT4CUT      0xa0efc508
+#define MFT4RLD      0xa0efc50c
+#define MFT4CMPRLD   0xa0efc510
+
+;; CH5
+#define MFT5MOD      0xa0efc600
+#define MFT5BOS      0xa0efc604
+#define MFT5CUT      0xa0efc608
+#define MFT5RLD      0xa0efc60c
+#define MFT5CMPRLD   0xa0efc610
+
+
+;;
+;; SIO     0xa0efd000
+;;
+
+;; CH0
+#define SIO0CR        0xa0efd000
+#define SIO0MOD0      0xa0efd004
+#define SIO0MOD1      0xa0efd008
+#define SIO0STS       0xa0efd00c
+#define SIO0IMASK     0xa0efd010
+#define SIO0BAUR      0xa0efd014
+#define SIO0RBAUR     0xa0efd018
+#define SIO0TXB       0xa0efd01c
+#define SIO0RXB       0xa0efd020
+
+;; CH1
+#define SIO1CR        0xa0efd100
+#define SIO1MOD0      0xa0efd104
+#define SIO1MOD1      0xa0efd108
+#define SIO1STS       0xa0efd10c
+#define SIO1IMASK     0xa0efd110
+#define SIO1BAUR      0xa0efd114
+#define SIO1RBAUR     0xa0efd118
+#define SIO1TXB       0xa0efd11c
+#define SIO1RXB       0xa0efd120
+
+;; CH2
+#define SIO2CR        0xa0efd200
+#define SIO2MOD0      0xa0efd204
+#define SIO2MOD1      0xa0efd208
+#define SIO2STS       0xa0efd20c
+#define SIO2IMASK     0xa0efd210
+#define SIO2BAUR      0xa0efd214
+#define SIO2RBAUR     0xa0efd218
+#define SIO2TXB       0xa0efd21c
+#define SIO2RXB       0xa0efd220
+
+;; CH3
+#define SIO3CR        0xa0efd300
+#define SIO3MOD0      0xa0efd304
+#define SIO3MOD1      0xa0efd308
+#define SIO3STS       0xa0efd30c
+#define SIO3IMASK     0xa0efd310
+#define SIO3BAUR      0xa0efd314
+#define SIO3RBAUR     0xa0efd318
+#define SIO3TXB       0xa0efd31c
+#define SIO3RXB       0xa0efd320
+
+;; CH4
+#define SIO4CR        0xa0efd400
+#define SIO4MOD0      0xa0efd404
+#define SIO4MOD1      0xa0efd408
+#define SIO4STS       0xa0efd40c
+#define SIO4IMASK     0xa0efd410
+#define SIO4BAUR      0xa0efd414
+#define SIO4RBAUR     0xa0efd418
+#define SIO4TXB       0xa0efd41c
+#define SIO4RXB       0xa0efd420
+
+
+;;
+;; ICU     0xa0eff000
+;;
+
+#define ICUISTS       0xa0eff004
+#define ICUIREQ0      0xa0eff008
+#define ICUIREQ1      0xa0eff00c
+
+#define ICUSBICR      0xa0eff018
+#define ICUIMASK      0xa0eff01c
+
+#define ICUCR1        0xa0eff200
+#define ICUCR2        0xa0eff204
+#define ICUCR3        0xa0eff208
+#define ICUCR4        0xa0eff20c
+#define ICUCR5        0xa0eff210
+#define ICUCR6        0xa0eff214
+#define ICUCR7        0xa0eff218
+
+#define ICUCR16       0xa0eff23c
+#define ICUCR17       0xa0eff240
+#define ICUCR18       0xa0eff244
+#define ICUCR19       0xa0eff248
+#define ICUCR20       0xa0eff24c
+#define ICUCR21       0xa0eff250
+
+#define ICUCR32       0xa0eff27c
+#define ICUCR33       0xa0eff280
+
+#define ICUCR48       0xa0eff2bc
+#define ICUCR49       0xa0eff2c0
+#define ICUCR50       0xa0eff2c4
+#define ICUCR51       0xa0eff2c8
+#define ICUCR52       0xa0eff2cc
+#define ICUCR53       0xa0eff2d0
+#define ICUCR54       0xa0eff2d4
+#define ICUCR55       0xa0eff2d8
+#define ICUCR56       0xa0eff2dc
+#define ICUCR57       0xa0eff2e0
+
+;;
+;; CACHE
+;;
+
+#define MCCR             0xfffffffc
+
+
+#endif  /* __ASSEMBLY__ */
diff --git a/include/asm-m32r/m32700ut/m32700ut_lan.h b/include/asm-m32r/m32700ut/m32700ut_lan.h
new file mode 100644 (file)
index 0000000..50545ec
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * include/asm/m32700ut_lan.h
+ *
+ * M32700UT-LAN board
+ *
+ * Copyright (c) 2002  Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#ifndef _M32700UT_M32700UT_LAN_H
+#define _M32700UT_M32700UT_LAN_H
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * C functions use non-cache address.
+ */
+#define M32700UT_LAN_BASE      (0x10000000 /* + NONCACHE_OFFSET */)
+#else
+#define M32700UT_LAN_BASE      (0x10000000 + NONCACHE_OFFSET)
+#endif /* __ASSEMBLY__ */
+
+/* ICU
+ *  ICUISTS:   status register
+ *  ICUIREQ0:  request register
+ *  ICUIREQ1:  request register
+ *  ICUCR3:    control register for CFIREQ# interrupt
+ *  ICUCR4:    control register for CFC Card insert interrupt
+ *  ICUCR5:    control register for CFC Card eject interrupt
+ *  ICUCR6:    control register for external interrupt
+ *  ICUCR11:   control register for MMC Card insert/eject interrupt
+ *  ICUCR13:   control register for SC error interrupt
+ *  ICUCR14:   control register for SC receive interrupt
+ *  ICUCR15:   control register for SC send interrupt
+ *  ICUCR16:   control register for SIO0 receive interrupt
+ *  ICUCR17:   control register for SIO0 send interrupt
+ */
+#define M32700UT_LAN_IRQ_LAN   (M32700UT_LAN_PLD_IRQ_BASE + 1) /* LAN */
+#define M32700UT_LAN_IRQ_I2C   (M32700UT_LAN_PLD_IRQ_BASE + 3) /* I2C */
+
+#define M32700UT_LAN_ICUISTS   __reg16(M32700UT_LAN_BASE + 0xc0002)
+#define M32700UT_LAN_ICUISTS_VECB_MASK (0xf000)
+#define M32700UT_LAN_VECB(x)   ((x) & M32700UT_LAN_ICUISTS_VECB_MASK)
+#define M32700UT_LAN_ICUISTS_ISN_MASK  (0x07c0)
+#define M32700UT_LAN_ICUISTS_ISN(x)    ((x) & M32700UT_LAN_ICUISTS_ISN_MASK)
+#define M32700UT_LAN_ICUIREQ0  __reg16(M32700UT_LAN_BASE + 0xc0004)
+#define M32700UT_LAN_ICUCR1    __reg16(M32700UT_LAN_BASE + 0xc0010)
+#define M32700UT_LAN_ICUCR3    __reg16(M32700UT_LAN_BASE + 0xc0014)
+
+/*
+ * AR register on PLD
+ */
+#define ARVCR0         __reg32(M32700UT_LAN_BASE + 0x40000)
+#define ARVCR0_VDS             0x00080000
+#define ARVCR0_RST             0x00010000
+#define ARVCR1         __reg32(M32700UT_LAN_BASE + 0x40004)
+#define ARVCR1_QVGA            0x02000000
+#define ARVCR1_NORMAL          0x01000000
+#define ARVCR1_HIEN            0x00010000
+#define ARVHCOUNT      __reg32(M32700UT_LAN_BASE + 0x40008)
+#define ARDATA         __reg32(M32700UT_LAN_BASE + 0x40010)
+#define ARINTSEL       __reg32(M32700UT_LAN_BASE + 0x40014)
+#define ARINTSEL_INT3          0x10000000      /* CPU INT3 */
+#define ARDATA32       __reg32(M32700UT_LAN_BASE + 0x04040010) // Block 5
+/*
+#define ARINTSEL_SEL2          0x00002000
+#define ARINTSEL_SEL3          0x00001000
+#define ARINTSEL_SEL6          0x00000200
+#define ARINTSEL_SEL7          0x00000100
+#define ARINTSEL_SEL9          0x00000040
+#define ARINTSEL_SEL10         0x00000020
+#define ARINTSEL_SEL11         0x00000010
+#define ARINTSEL_SEL12         0x00000008
+*/
+
+/*
+ * I2C register on PLD
+ */
+#define PLDI2CCR       __reg32(M32700UT_LAN_BASE + 0x40040)
+#define        PLDI2CCR_ES0            0x00000001      /* enable I2C interface */
+#define PLDI2CMOD      __reg32(M32700UT_LAN_BASE + 0x40044)
+#define PLDI2CMOD_ACKCLK       0x00000200
+#define PLDI2CMOD_DTWD         0x00000100
+#define PLDI2CMOD_10BT         0x00000004
+#define PLDI2CMOD_ATM_NORMAL   0x00000000
+#define PLDI2CMOD_ATM_AUTO     0x00000003
+#define PLDI2CACK      __reg32(M32700UT_LAN_BASE + 0x40048)
+#define PLDI2CACK_ACK          0x00000001
+#define PLDI2CFREQ     __reg32(M32700UT_LAN_BASE + 0x4004c)
+#define PLDI2CCND      __reg32(M32700UT_LAN_BASE + 0x40050)
+#define PLDI2CCND_START                0x00000001
+#define PLDI2CCND_STOP         0x00000002
+#define PLDI2CSTEN     __reg32(M32700UT_LAN_BASE + 0x40054)
+#define PLDI2CSTEN_STEN                0x00000001
+#define PLDI2CDATA     __reg32(M32700UT_LAN_BASE + 0x40060)
+#define PLDI2CSTS      __reg32(M32700UT_LAN_BASE + 0x40064)
+#define PLDI2CSTS_TRX          0x00000020
+#define PLDI2CSTS_BB           0x00000010
+#define PLDI2CSTS_NOACK                0x00000001      /* 0:ack, 1:noack */
+
+#endif /* _M32700UT_M32700UT_LAN_H */
diff --git a/include/asm-m32r/m32700ut/m32700ut_lcd.h b/include/asm-m32r/m32700ut/m32700ut_lcd.h
new file mode 100644 (file)
index 0000000..ede6c77
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * include/asm/m32700ut_lcd.h
+ *
+ * M32700UT-LCD board
+ *
+ * Copyright (c) 2002  Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#ifndef _M32700UT_M32700UT_LCD_H
+#define _M32700UT_M32700UT_LCD_H
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * C functions use non-cache address.
+ */
+#define M32700UT_LCD_BASE      (0x10000000 /* + NONCACHE_OFFSET */)
+#else
+#define M32700UT_LCD_BASE      (0x10000000 + NONCACHE_OFFSET)
+#endif /* __ASSEMBLY__ */
+
+/*
+ * ICU
+ */
+#define M32700UT_LCD_IRQ_BAT_INT       (M32700UT_LCD_PLD_IRQ_BASE + 1)
+#define M32700UT_LCD_IRQ_USB_INT1      (M32700UT_LCD_PLD_IRQ_BASE + 2)
+#define M32700UT_LCD_IRQ_AUDT0         (M32700UT_LCD_PLD_IRQ_BASE + 3)
+#define M32700UT_LCD_IRQ_AUDT2         (M32700UT_LCD_PLD_IRQ_BASE + 4)
+#define M32700UT_LCD_IRQ_BATSIO_RCV    (M32700UT_LCD_PLD_IRQ_BASE + 16)
+#define M32700UT_LCD_IRQ_BATSIO_SND    (M32700UT_LCD_PLD_IRQ_BASE + 17)
+#define M32700UT_LCD_IRQ_ASNDSIO_RCV   (M32700UT_LCD_PLD_IRQ_BASE + 18)
+#define M32700UT_LCD_IRQ_ASNDSIO_SND   (M32700UT_LCD_PLD_IRQ_BASE + 19)
+#define M32700UT_LCD_IRQ_ACNLSIO_SND   (M32700UT_LCD_PLD_IRQ_BASE + 21)
+
+#define M32700UT_LCD_ICUISTS   __reg16(M32700UT_LCD_BASE + 0x300002)
+#define M32700UT_LCD_ICUISTS_VECB_MASK (0xf000)
+#define M32700UT_LCD_VECB(x)   ((x) & M32700UT_LCD_ICUISTS_VECB_MASK)
+#define M32700UT_LCD_ICUISTS_ISN_MASK  (0x07c0)
+#define M32700UT_LCD_ICUISTS_ISN(x)    ((x) & M32700UT_LCD_ICUISTS_ISN_MASK)
+#define M32700UT_LCD_ICUIREQ0  __reg16(M32700UT_LCD_BASE + 0x300004)
+#define M32700UT_LCD_ICUIREQ1  __reg16(M32700UT_LCD_BASE + 0x300006)
+#define M32700UT_LCD_ICUCR1    __reg16(M32700UT_LCD_BASE + 0x300020)
+#define M32700UT_LCD_ICUCR2    __reg16(M32700UT_LCD_BASE + 0x300022)
+#define M32700UT_LCD_ICUCR3    __reg16(M32700UT_LCD_BASE + 0x300024)
+#define M32700UT_LCD_ICUCR4    __reg16(M32700UT_LCD_BASE + 0x300026)
+#define M32700UT_LCD_ICUCR16   __reg16(M32700UT_LCD_BASE + 0x300030)
+#define M32700UT_LCD_ICUCR17   __reg16(M32700UT_LCD_BASE + 0x300032)
+#define M32700UT_LCD_ICUCR18   __reg16(M32700UT_LCD_BASE + 0x300034)
+#define M32700UT_LCD_ICUCR19   __reg16(M32700UT_LCD_BASE + 0x300036)
+#define M32700UT_LCD_ICUCR21   __reg16(M32700UT_LCD_BASE + 0x30003a)
+
+#endif /* _M32700UT_M32700UT_LCD_H */
diff --git a/include/asm-m32r/m32700ut/m32700ut_pld.h b/include/asm-m32r/m32700ut/m32700ut_pld.h
new file mode 100644 (file)
index 0000000..f5e4794
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * include/asm/m32700ut/m32700ut_pld.h
+ *
+ * Definitions for Programable Logic Device(PLD) on M32700UT board.
+ *
+ * Copyright (c) 2002  Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#ifndef _M32700UT_M32700UT_PLD_H
+#define _M32700UT_M32700UT_PLD_H
+
+#include <linux/config.h>
+
+#if defined(CONFIG_PLAT_M32700UT_Alpha)
+#define PLD_PLAT_BASE          0x08c00000
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV)
+#define PLD_PLAT_BASE          0x04c00000
+#else
+#error "no platform configuration"
+#endif
+
+#ifndef __ASSEMBLY__
+/*
+ * C functions use non-cache address.
+ */
+#define PLD_BASE               (PLD_PLAT_BASE /* + NONCACHE_OFFSET */)
+#define __reg8                 (volatile unsigned char *)
+#define __reg16                        (volatile unsigned short *)
+#define __reg32                        (volatile unsigned int *)
+#else
+#define PLD_BASE               (PLD_PLAT_BASE + NONCACHE_OFFSET)
+#define __reg8
+#define __reg16
+#define __reg32
+#endif /* __ASSEMBLY__ */
+
+/* CFC */
+#define        PLD_CFRSTCR             __reg16(PLD_BASE + 0x0000)
+#define PLD_CFSTS              __reg16(PLD_BASE + 0x0002)
+#define PLD_CFIMASK            __reg16(PLD_BASE + 0x0004)
+#define PLD_CFBUFCR            __reg16(PLD_BASE + 0x0006)
+#define PLD_CFVENCR            __reg16(PLD_BASE + 0x0008)
+#define PLD_CFCR0              __reg16(PLD_BASE + 0x000a)
+#define PLD_CFCR1              __reg16(PLD_BASE + 0x000c)
+#define PLD_IDERSTCR           __reg16(PLD_BASE + 0x0010)
+
+/* MMC */
+#define PLD_MMCCR              __reg16(PLD_BASE + 0x4000)
+#define PLD_MMCMOD             __reg16(PLD_BASE + 0x4002)
+#define PLD_MMCSTS             __reg16(PLD_BASE + 0x4006)
+#define PLD_MMCBAUR            __reg16(PLD_BASE + 0x400a)
+#define PLD_MMCCMDBCUT         __reg16(PLD_BASE + 0x400c)
+#define PLD_MMCCDTBCUT         __reg16(PLD_BASE + 0x400e)
+#define PLD_MMCDET             __reg16(PLD_BASE + 0x4010)
+#define PLD_MMCWP              __reg16(PLD_BASE + 0x4012)
+#define PLD_MMCWDATA           __reg16(PLD_BASE + 0x5000)
+#define PLD_MMCRDATA           __reg16(PLD_BASE + 0x6000)
+#define PLD_MMCCMDDATA         __reg16(PLD_BASE + 0x7000)
+#define PLD_MMCRSPDATA         __reg16(PLD_BASE + 0x7006)
+
+/* ICU
+ *  ICUISTS:   status register
+ *  ICUIREQ0:  request register
+ *  ICUIREQ1:  request register
+ *  ICUCR3:    control register for CFIREQ# interrupt
+ *  ICUCR4:    control register for CFC Card insert interrupt
+ *  ICUCR5:    control register for CFC Card eject interrupt
+ *  ICUCR6:    control register for external interrupt
+ *  ICUCR11:   control register for MMC Card insert/eject interrupt
+ *  ICUCR13:   control register for SC error interrupt
+ *  ICUCR14:   control register for SC receive interrupt
+ *  ICUCR15:   control register for SC send interrupt
+ *  ICUCR16:   control register for SIO0 receive interrupt
+ *  ICUCR17:   control register for SIO0 send interrupt
+ */
+#if !defined(CONFIG_PLAT_USRV)
+#define PLD_IRQ_INT0           (M32700UT_PLD_IRQ_BASE + 0)     /* None */
+#define PLD_IRQ_INT1           (M32700UT_PLD_IRQ_BASE + 1)     /* reserved */
+#define PLD_IRQ_INT2           (M32700UT_PLD_IRQ_BASE + 2)     /* reserved */
+#define PLD_IRQ_CFIREQ         (M32700UT_PLD_IRQ_BASE + 3)     /* CF IREQ */
+#define PLD_IRQ_CFC_INSERT     (M32700UT_PLD_IRQ_BASE + 4)     /* CF Insert */
+#define PLD_IRQ_CFC_EJECT      (M32700UT_PLD_IRQ_BASE + 5)     /* CF Eject */
+#define PLD_IRQ_EXINT          (M32700UT_PLD_IRQ_BASE + 6)     /* EXINT */
+#define PLD_IRQ_INT7           (M32700UT_PLD_IRQ_BASE + 7)     /* reserved */
+#define PLD_IRQ_INT8           (M32700UT_PLD_IRQ_BASE + 8)     /* reserved */
+#define PLD_IRQ_INT9           (M32700UT_PLD_IRQ_BASE + 9)     /* reserved */
+#define PLD_IRQ_INT10          (M32700UT_PLD_IRQ_BASE + 10)    /* reserved */
+#define PLD_IRQ_MMCCARD                (M32700UT_PLD_IRQ_BASE + 11)    /* MMC Insert/Eject */
+#define PLD_IRQ_INT12          (M32700UT_PLD_IRQ_BASE + 12)    /* reserved */
+#define PLD_IRQ_SC_ERROR       (M32700UT_PLD_IRQ_BASE + 13)    /* SC error */
+#define PLD_IRQ_SC_RCV         (M32700UT_PLD_IRQ_BASE + 14)    /* SC receive */
+#define PLD_IRQ_SC_SND         (M32700UT_PLD_IRQ_BASE + 15)    /* SC send */
+#define PLD_IRQ_SIO0_RCV       (M32700UT_PLD_IRQ_BASE + 16)    /* SIO receive */
+#define PLD_IRQ_SIO0_SND       (M32700UT_PLD_IRQ_BASE + 17)    /* SIO send */
+#define PLD_IRQ_INT18          (M32700UT_PLD_IRQ_BASE + 18)    /* reserved */
+#define PLD_IRQ_INT19          (M32700UT_PLD_IRQ_BASE + 19)    /* reserved */
+#define PLD_IRQ_INT20          (M32700UT_PLD_IRQ_BASE + 20)    /* reserved */
+#define PLD_IRQ_INT21          (M32700UT_PLD_IRQ_BASE + 21)    /* reserved */
+#define PLD_IRQ_INT22          (M32700UT_PLD_IRQ_BASE + 22)    /* reserved */
+#define PLD_IRQ_INT23          (M32700UT_PLD_IRQ_BASE + 23)    /* reserved */
+#define PLD_IRQ_INT24          (M32700UT_PLD_IRQ_BASE + 24)    /* reserved */
+#define PLD_IRQ_INT25          (M32700UT_PLD_IRQ_BASE + 25)    /* reserved */
+#define PLD_IRQ_INT26          (M32700UT_PLD_IRQ_BASE + 26)    /* reserved */
+#define PLD_IRQ_INT27          (M32700UT_PLD_IRQ_BASE + 27)    /* reserved */
+#define PLD_IRQ_INT28          (M32700UT_PLD_IRQ_BASE + 28)    /* reserved */
+#define PLD_IRQ_INT29          (M32700UT_PLD_IRQ_BASE + 29)    /* reserved */
+#define PLD_IRQ_INT30          (M32700UT_PLD_IRQ_BASE + 30)    /* reserved */
+#define PLD_IRQ_INT31          (M32700UT_PLD_IRQ_BASE + 31)    /* reserved */
+
+#else  /* CONFIG_PLAT_USRV */
+
+#define PLD_IRQ_INT0           (M32700UT_PLD_IRQ_BASE + 0)     /* None */
+#define PLD_IRQ_INT1           (M32700UT_PLD_IRQ_BASE + 1)     /* reserved */
+#define PLD_IRQ_INT2           (M32700UT_PLD_IRQ_BASE + 2)     /* reserved */
+#define PLD_IRQ_CF0            (M32700UT_PLD_IRQ_BASE + 3)     /* CF0# */
+#define PLD_IRQ_CF1            (M32700UT_PLD_IRQ_BASE + 4)     /* CF1# */
+#define PLD_IRQ_CF2            (M32700UT_PLD_IRQ_BASE + 5)     /* CF2# */
+#define PLD_IRQ_CF3            (M32700UT_PLD_IRQ_BASE + 6)     /* CF3# */
+#define PLD_IRQ_CF4            (M32700UT_PLD_IRQ_BASE + 7)     /* CF4# */
+#define PLD_IRQ_INT8           (M32700UT_PLD_IRQ_BASE + 8)     /* reserved */
+#define PLD_IRQ_INT9           (M32700UT_PLD_IRQ_BASE + 9)     /* reserved */
+#define PLD_IRQ_INT10          (M32700UT_PLD_IRQ_BASE + 10)    /* reserved */
+#define PLD_IRQ_INT11          (M32700UT_PLD_IRQ_BASE + 11)    /* reserved */
+#define PLD_IRQ_UART0          (M32700UT_PLD_IRQ_BASE + 12)    /* UARTIRQ0 */
+#define PLD_IRQ_UART1          (M32700UT_PLD_IRQ_BASE + 13)    /* UARTIRQ1 */
+#define PLD_IRQ_INT14          (M32700UT_PLD_IRQ_BASE + 14)    /* reserved */
+#define PLD_IRQ_INT15          (M32700UT_PLD_IRQ_BASE + 15)    /* reserved */
+#define PLD_IRQ_SNDINT         (M32700UT_PLD_IRQ_BASE + 16)    /* SNDINT# */
+#define PLD_IRQ_INT17          (M32700UT_PLD_IRQ_BASE + 17)    /* reserved */
+#define PLD_IRQ_INT18          (M32700UT_PLD_IRQ_BASE + 18)    /* reserved */
+#define PLD_IRQ_INT19          (M32700UT_PLD_IRQ_BASE + 19)    /* reserved */
+#define PLD_IRQ_INT20          (M32700UT_PLD_IRQ_BASE + 20)    /* reserved */
+#define PLD_IRQ_INT21          (M32700UT_PLD_IRQ_BASE + 21)    /* reserved */
+#define PLD_IRQ_INT22          (M32700UT_PLD_IRQ_BASE + 22)    /* reserved */
+#define PLD_IRQ_INT23          (M32700UT_PLD_IRQ_BASE + 23)    /* reserved */
+#define PLD_IRQ_INT24          (M32700UT_PLD_IRQ_BASE + 24)    /* reserved */
+#define PLD_IRQ_INT25          (M32700UT_PLD_IRQ_BASE + 25)    /* reserved */
+#define PLD_IRQ_INT26          (M32700UT_PLD_IRQ_BASE + 26)    /* reserved */
+#define PLD_IRQ_INT27          (M32700UT_PLD_IRQ_BASE + 27)    /* reserved */
+#define PLD_IRQ_INT28          (M32700UT_PLD_IRQ_BASE + 28)    /* reserved */
+#define PLD_IRQ_INT29          (M32700UT_PLD_IRQ_BASE + 29)    /* reserved */
+#define PLD_IRQ_INT30          (M32700UT_PLD_IRQ_BASE + 30)    /* reserved */
+
+#endif /* CONFIG_PLAT_USRV */
+
+#define PLD_ICUISTS            __reg16(PLD_BASE + 0x8002)
+#define PLD_ICUISTS_VECB_MASK  (0xf000)
+#define PLD_ICUISTS_VECB(x)    ((x) & PLD_ICUISTS_VECB_MASK)
+#define PLD_ICUISTS_ISN_MASK   (0x07c0)
+#define PLD_ICUISTS_ISN(x)     ((x) & PLD_ICUISTS_ISN_MASK)
+#define PLD_ICUIREQ0           __reg16(PLD_BASE + 0x8004)
+#define PLD_ICUIREQ1           __reg16(PLD_BASE + 0x8006)
+#define PLD_ICUCR1             __reg16(PLD_BASE + 0x8100)
+#define PLD_ICUCR2             __reg16(PLD_BASE + 0x8102)
+#define PLD_ICUCR3             __reg16(PLD_BASE + 0x8104)
+#define PLD_ICUCR4             __reg16(PLD_BASE + 0x8106)
+#define PLD_ICUCR5             __reg16(PLD_BASE + 0x8108)
+#define PLD_ICUCR6             __reg16(PLD_BASE + 0x810a)
+#define PLD_ICUCR7             __reg16(PLD_BASE + 0x810c)
+#define PLD_ICUCR8             __reg16(PLD_BASE + 0x810e)
+#define PLD_ICUCR9             __reg16(PLD_BASE + 0x8110)
+#define PLD_ICUCR10            __reg16(PLD_BASE + 0x8112)
+#define PLD_ICUCR11            __reg16(PLD_BASE + 0x8114)
+#define PLD_ICUCR12            __reg16(PLD_BASE + 0x8116)
+#define PLD_ICUCR13            __reg16(PLD_BASE + 0x8118)
+#define PLD_ICUCR14            __reg16(PLD_BASE + 0x811a)
+#define PLD_ICUCR15            __reg16(PLD_BASE + 0x811c)
+#define PLD_ICUCR16            __reg16(PLD_BASE + 0x811e)
+#define PLD_ICUCR17            __reg16(PLD_BASE + 0x8120)
+#define PLD_ICUCR_IEN          (0x1000)
+#define PLD_ICUCR_IREQ         (0x0100)
+#define PLD_ICUCR_ISMOD00      (0x0000)        /* Low edge */
+#define PLD_ICUCR_ISMOD01      (0x0010)        /* Low level */
+#define PLD_ICUCR_ISMOD02      (0x0020)        /* High edge */
+#define PLD_ICUCR_ISMOD03      (0x0030)        /* High level */
+#define PLD_ICUCR_ILEVEL0      (0x0000)
+#define PLD_ICUCR_ILEVEL1      (0x0001)
+#define PLD_ICUCR_ILEVEL2      (0x0002)
+#define PLD_ICUCR_ILEVEL3      (0x0003)
+#define PLD_ICUCR_ILEVEL4      (0x0004)
+#define PLD_ICUCR_ILEVEL5      (0x0005)
+#define PLD_ICUCR_ILEVEL6      (0x0006)
+#define PLD_ICUCR_ILEVEL7      (0x0007)
+
+/* Power Control of MMC and CF */
+#define PLD_CPCR               __reg16(PLD_BASE + 0x14000)
+#define PLD_CPCR_CF            0x0001
+#define PLD_CPCR_MMC           0x0002
+
+/* LED Control
+ *
+ * 1: DIP swich side
+ * 2: Reset switch side
+ */
+#define PLD_IOLEDCR            __reg16(PLD_BASE + 0x14002)
+#define PLD_IOLED_1_ON         0x001
+#define PLD_IOLED_1_OFF                0x000
+#define PLD_IOLED_2_ON         0x002
+#define PLD_IOLED_2_OFF                0x000
+
+/* DIP Switch
+ *  0: Write-protect of Flash Memory (0:protected, 1:non-protected)
+ *  1: -
+ *  2: -
+ *  3: -
+ */
+#define PLD_IOSWSTS            __reg16(PLD_BASE + 0x14004)
+#define        PLD_IOSWSTS_IOSW2       0x0200
+#define        PLD_IOSWSTS_IOSW1       0x0100
+#define        PLD_IOSWSTS_IOWP0       0x0001
+
+/* CRC */
+#define PLD_CRC7DATA           __reg16(PLD_BASE + 0x18000)
+#define PLD_CRC7INDATA         __reg16(PLD_BASE + 0x18002)
+#define PLD_CRC16DATA          __reg16(PLD_BASE + 0x18004)
+#define PLD_CRC16INDATA                __reg16(PLD_BASE + 0x18006)
+#define PLD_CRC16ADATA         __reg16(PLD_BASE + 0x18008)
+#define PLD_CRC16AINDATA       __reg16(PLD_BASE + 0x1800a)
+
+/* RTC */
+#define PLD_RTCCR              __reg16(PLD_BASE + 0x1c000)
+#define PLD_RTCBAUR            __reg16(PLD_BASE + 0x1c002)
+#define PLD_RTCWRDATA          __reg16(PLD_BASE + 0x1c004)
+#define PLD_RTCRDDATA          __reg16(PLD_BASE + 0x1c006)
+#define PLD_RTCRSTODT          __reg16(PLD_BASE + 0x1c008)
+
+/* SIO0 */
+#define PLD_ESIO0CR            __reg16(PLD_BASE + 0x20000)
+#define        PLD_ESIO0CR_TXEN        0x0001
+#define        PLD_ESIO0CR_RXEN        0x0002
+#define PLD_ESIO0MOD0          __reg16(PLD_BASE + 0x20002)
+#define        PLD_ESIO0MOD0_CTSS      0x0040
+#define        PLD_ESIO0MOD0_RTSS      0x0080
+#define PLD_ESIO0MOD1          __reg16(PLD_BASE + 0x20004)
+#define        PLD_ESIO0MOD1_LMFS      0x0010
+#define PLD_ESIO0STS           __reg16(PLD_BASE + 0x20006)
+#define        PLD_ESIO0STS_TEMP       0x0001
+#define        PLD_ESIO0STS_TXCP       0x0002
+#define        PLD_ESIO0STS_RXCP       0x0004
+#define        PLD_ESIO0STS_TXSC       0x0100
+#define        PLD_ESIO0STS_RXSC       0x0200
+#define PLD_ESIO0STS_TXREADY   (PLD_ESIO0STS_TXCP | PLD_ESIO0STS_TEMP)
+#define PLD_ESIO0INTCR         __reg16(PLD_BASE + 0x20008)
+#define        PLD_ESIO0INTCR_TXIEN    0x0002
+#define        PLD_ESIO0INTCR_RXCEN    0x0004
+#define PLD_ESIO0BAUR          __reg16(PLD_BASE + 0x2000a)
+#define PLD_ESIO0TXB           __reg16(PLD_BASE + 0x2000c)
+#define PLD_ESIO0RXB           __reg16(PLD_BASE + 0x2000e)
+
+/* SIM Card */
+#define PLD_SCCR               __reg16(PLD_BASE + 0x38000)
+#define PLD_SCMOD              __reg16(PLD_BASE + 0x38004)
+#define PLD_SCSTS              __reg16(PLD_BASE + 0x38006)
+#define PLD_SCINTCR            __reg16(PLD_BASE + 0x38008)
+#define PLD_SCBAUR             __reg16(PLD_BASE + 0x3800a)
+#define PLD_SCTXB              __reg16(PLD_BASE + 0x3800c)
+#define PLD_SCRXB              __reg16(PLD_BASE + 0x3800e)
+
+#endif /* _M32700UT_M32700UT_PLD.H */
diff --git a/include/asm-m32r/m32r.h b/include/asm-m32r/m32r.h
new file mode 100644 (file)
index 0000000..f116649
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef _ASM_M32R_M32R_H_
+#define _ASM_M32R_M32R_H_
+
+/*
+ * Renesas M32R processor
+ *
+ * Copyright (C) 2003, 2004  Renesas Technology Corp.
+ */
+
+#include <linux/config.h>
+
+/* Chip type */
+#if defined(CONFIG_CHIP_XNUX_MP) || defined(CONFIG_CHIP_XNUX2_MP)
+#include <asm/m32r_mp_fpga.h>
+#elif defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_XNUX2) \
+       || defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32102) \
+        || defined(CONFIG_CHIP_OPSP)
+#include <asm/m32102.h>
+#include <asm/m32102peri.h>
+#endif
+
+/* Platform type */
+#if defined(CONFIG_PLAT_M32700UT)
+#include <asm/m32700ut/m32700ut_pld.h>
+#include <asm/m32700ut/m32700ut_lan.h>
+#include <asm/m32700ut/m32700ut_lcd.h>
+#endif  /* CONFIG_PLAT_M32700UT */
+
+#if defined(CONFIG_PLAT_OPSPUT)
+#include <asm/opsput/opsput_pld.h>
+#include <asm/opsput/opsput_lan.h>
+#include <asm/opsput/opsput_lcd.h>
+#endif  /* CONFIG_PLAT_OPSPUT */
+
+#if defined(CONFIG_PLAT_MAPPI2)
+#include <asm/mappi2/mappi2_pld.h>
+#endif /* CONFIG_PLAT_MAPPI2 */
+
+#if defined(CONFIG_PLAT_USRV)
+#include <asm/m32700ut/m32700ut_pld.h>
+#endif
+
+/*
+ * M32R Register
+ */
+
+/*
+ * MMU Register
+ */
+
+#define MMU_REG_BASE   (0xffff0000)
+#define ITLB_BASE      (0xfe000000)
+#define DTLB_BASE      (0xfe000800)
+
+#define NR_TLB_ENTRIES CONFIG_TLB_ENTRIES
+
+#define MATM   MMU_REG_BASE            /* MMU Address Translation Mode
+                                          Register */
+#define MPSZ   (0x04 + MMU_REG_BASE)   /* MMU Page Size Designation Register */
+#define MASID  (0x08 + MMU_REG_BASE)   /* MMU Address Space ID Register */
+#define MESTS  (0x0c + MMU_REG_BASE)   /* MMU Exception Status Register */
+#define MDEVA  (0x10 + MMU_REG_BASE)   /* MMU Operand Exception Virtual
+                                          Address Register */
+#define MDEVP  (0x14 + MMU_REG_BASE)   /* MMU Operand Exception Virtual Page
+                                          Number Register */
+#define MPTB   (0x18 + MMU_REG_BASE)   /* MMU Page Table Base Register */
+#define MSVA   (0x20 + MMU_REG_BASE)   /* MMU Search Virtual Address
+                                          Register */
+#define MTOP   (0x24 + MMU_REG_BASE)   /* MMU TLB Operation Register */
+#define MIDXI  (0x28 + MMU_REG_BASE)   /* MMU Index Register for
+                                          Instruciton */
+#define MIDXD  (0x2c + MMU_REG_BASE)   /* MMU Index Register for Operand */
+
+#define MATM_offset    (MATM - MMU_REG_BASE)
+#define MPSZ_offset    (MPSZ - MMU_REG_BASE)
+#define MASID_offset   (MASID - MMU_REG_BASE)
+#define MESTS_offset   (MESTS - MMU_REG_BASE)
+#define MDEVA_offset   (MDEVA - MMU_REG_BASE)
+#define MDEVP_offset   (MDEVP - MMU_REG_BASE)
+#define MPTB_offset    (MPTB - MMU_REG_BASE)
+#define MSVA_offset    (MSVA - MMU_REG_BASE)
+#define MTOP_offset    (MTOP - MMU_REG_BASE)
+#define MIDXI_offset   (MIDXI - MMU_REG_BASE)
+#define MIDXD_offset   (MIDXD - MMU_REG_BASE)
+
+#define MESTS_IT       (1 << 0)        /* Instruction TLB miss */
+#define MESTS_IA       (1 << 1)        /* Instruction Access Exception */
+#define MESTS_DT       (1 << 4)        /* Operand TLB miss */
+#define MESTS_DA       (1 << 5)        /* Operand Access Exception */
+#define MESTS_DRW      (1 << 6)        /* Operand Write Exception Flag */
+
+/*
+ * PSW (Processor Status Word)
+ */
+
+/* PSW bit */
+#define M32R_PSW_BIT_SM   (7)    /* Stack Mode */
+#define M32R_PSW_BIT_IE   (6)    /* Interrupt Enable */
+#define M32R_PSW_BIT_PM   (3)    /* Processor Mode [0:Supervisor,1:User] */
+#define M32R_PSW_BIT_C    (0)    /* Condition */
+#define M32R_PSW_BIT_BSM  (7+8)  /* Backup Stack Mode */
+#define M32R_PSW_BIT_BIE  (6+8)  /* Backup Interrupt Enable */
+#define M32R_PSW_BIT_BPM  (3+8)  /* Backup Processor Mode */
+#define M32R_PSW_BIT_BC   (0+8)  /* Backup Condition */
+
+/* PSW bit map */
+#define M32R_PSW_SM   (1UL<< M32R_PSW_BIT_SM)   /* Stack Mode */
+#define M32R_PSW_IE   (1UL<< M32R_PSW_BIT_IE)   /* Interrupt Enable */
+#define M32R_PSW_PM   (1UL<< M32R_PSW_BIT_PM)   /* Processor Mode */
+#define M32R_PSW_C    (1UL<< M32R_PSW_BIT_C)    /* Condition */
+#define M32R_PSW_BSM  (1UL<< M32R_PSW_BIT_BSM)  /* Backup Stack Mode */
+#define M32R_PSW_BIE  (1UL<< M32R_PSW_BIT_BIE)  /* Backup Interrupt Enable */
+#define M32R_PSW_BPM  (1UL<< M32R_PSW_BIT_BPM)  /* Backup Processor Mode */
+#define M32R_PSW_BC   (1UL<< M32R_PSW_BIT_BC)   /* Backup Condition */
+
+/*
+ * Direct address to SFR
+ */
+
+#include <asm/page.h>
+#ifdef CONFIG_MMU
+#define NONCACHE_OFFSET  __PAGE_OFFSET+0x20000000
+#else
+#define NONCACHE_OFFSET  __PAGE_OFFSET
+#endif /* CONFIG_MMU */
+
+#define M32R_ICU_ISTS_ADDR  M32R_ICU_ISTS_PORTL+NONCACHE_OFFSET
+#define M32R_ICU_IPICR_ADDR  M32R_ICU_IPICR0_PORTL+NONCACHE_OFFSET
+#define M32R_ICU_IMASK_ADDR  M32R_ICU_IMASK_PORTL+NONCACHE_OFFSET
+#define M32R_FPGA_CPU_NAME_ADDR  M32R_FPGA_CPU_NAME0_PORTL+NONCACHE_OFFSET
+#define M32R_FPGA_MODEL_ID_ADDR  M32R_FPGA_MODEL_ID0_PORTL+NONCACHE_OFFSET
+#define M32R_FPGA_VERSION_ADDR   M32R_FPGA_VERSION0_PORTL+NONCACHE_OFFSET
+
+#endif /* _ASM_M32R_M32R_H_ */
diff --git a/include/asm-m32r/m32r_mp_fpga.h b/include/asm-m32r/m32r_mp_fpga.h
new file mode 100644 (file)
index 0000000..976d2b9
--- /dev/null
@@ -0,0 +1,313 @@
+#ifndef _ASM_M32R_M32R_MP_FPGA_
+#define _ASM_M32R_M32R_MP_FPGA_
+
+/*
+ * Renesas M32R-MP-FPGA
+ *
+ * Copyright (c) 2002  Hitoshi Yamamoto
+ * Copyright (c) 2003, 2004  Renesas Technology Corp.
+ */
+
+/*
+ * ========================================================
+ * M32R-MP-FPGA Memory Map
+ * ========================================================
+ * 0x00000000 : Block#0 : 64[MB]
+ *              0x03E00000 : SFR
+ *                           0x03E00000 : reserved
+ *                           0x03EF0000 : FPGA
+ *                           0x03EF1000 : reserved
+ *                           0x03EF4000 : CKM
+ *                           0x03EF4000 : BSELC
+ *                           0x03EF5000 : reserved
+ *                           0x03EFC000 : MFT
+ *                           0x03EFD000 : SIO
+ *                           0x03EFE000 : reserved
+ *                           0x03EFF000 : ICU
+ *              0x03F00000 : Internal SRAM 64[KB]
+ *              0x03F10000 : reserved
+ * --------------------------------------------------------
+ * 0x04000000 : Block#1 : 64[MB]
+ *              0x04000000 : Debug board SRAM 4[MB]
+ *              0x04400000 : reserved
+ * --------------------------------------------------------
+ * 0x08000000 : Block#2 : 64[MB]
+ * --------------------------------------------------------
+ * 0x0C000000 : Block#3 : 64[MB]
+ * --------------------------------------------------------
+ * 0x10000000 : Block#4 : 64[MB]
+ * --------------------------------------------------------
+ * 0x14000000 : Block#5 : 64[MB]
+ * --------------------------------------------------------
+ * 0x18000000 : Block#6 : 64[MB]
+ * --------------------------------------------------------
+ * 0x1C000000 : Block#7 : 64[MB]
+ * --------------------------------------------------------
+ * 0xFE000000 : TLB
+ *              0xFE000000 : ITLB
+ *              0xFE000080 : reserved
+ *              0xFE000800 : DTLB
+ *              0xFE000880 : reserved
+ * --------------------------------------------------------
+ * 0xFF000000 : System area
+ *              0xFFFF0000 : MMU
+ *              0xFFFF0030 : reserved
+ *              0xFFFF8000 : Debug function
+ *              0xFFFFA000 : reserved
+ *              0xFFFFC000 : CPU control
+ * 0xFFFFFFFF
+ * ========================================================
+ */
+
+/*======================================================================*
+ * Special Function Register
+ *======================================================================*/
+#define M32R_SFR_OFFSET  (0x00E00000)  /* 0x03E00000-0x03EFFFFF 1[MB] */
+
+/*
+ * FPGA registers.
+ */
+#define M32R_FPGA_TOP  (0x000F0000+M32R_SFR_OFFSET)
+
+#define M32R_FPGA_NUM_OF_CPUS_PORTL  (0x00+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME0_PORTL    (0x10+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME1_PORTL    (0x14+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME2_PORTL    (0x18+M32R_FPGA_TOP)
+#define M32R_FPGA_CPU_NAME3_PORTL    (0x1C+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID0_PORTL    (0x20+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID1_PORTL    (0x24+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID2_PORTL    (0x28+M32R_FPGA_TOP)
+#define M32R_FPGA_MODEL_ID3_PORTL    (0x2C+M32R_FPGA_TOP)
+#define M32R_FPGA_VERSION0_PORTL     (0x30+M32R_FPGA_TOP)
+#define M32R_FPGA_VERSION1_PORTL     (0x34+M32R_FPGA_TOP)
+
+/*
+ * Clock and Power Manager registers.
+ */
+#define M32R_CPM_OFFSET  (0x000F4000+M32R_SFR_OFFSET)
+
+#define M32R_CPM_CPUCLKCR_PORTL  (0x00+M32R_CPM_OFFSET)
+#define M32R_CPM_CLKMOD_PORTL    (0x04+M32R_CPM_OFFSET)
+#define M32R_CPM_PLLCR_PORTL     (0x08+M32R_CPM_OFFSET)
+
+/*
+ * Block SELect Controller registers.
+ */
+#define M32R_BSELC_OFFSET  (0x000F5000+M32R_SFR_OFFSET)
+
+#define M32R_BSEL0_CR0_PORTL  (0x000+M32R_BSELC_OFFSET)
+#define M32R_BSEL0_CR1_PORTL  (0x004+M32R_BSELC_OFFSET)
+#define M32R_BSEL1_CR0_PORTL  (0x100+M32R_BSELC_OFFSET)
+#define M32R_BSEL1_CR1_PORTL  (0x104+M32R_BSELC_OFFSET)
+#define M32R_BSEL2_CR0_PORTL  (0x200+M32R_BSELC_OFFSET)
+#define M32R_BSEL2_CR1_PORTL  (0x204+M32R_BSELC_OFFSET)
+#define M32R_BSEL3_CR0_PORTL  (0x300+M32R_BSELC_OFFSET)
+#define M32R_BSEL3_CR1_PORTL  (0x304+M32R_BSELC_OFFSET)
+#define M32R_BSEL4_CR0_PORTL  (0x400+M32R_BSELC_OFFSET)
+#define M32R_BSEL4_CR1_PORTL  (0x404+M32R_BSELC_OFFSET)
+#define M32R_BSEL5_CR0_PORTL  (0x500+M32R_BSELC_OFFSET)
+#define M32R_BSEL5_CR1_PORTL  (0x504+M32R_BSELC_OFFSET)
+#define M32R_BSEL6_CR0_PORTL  (0x600+M32R_BSELC_OFFSET)
+#define M32R_BSEL6_CR1_PORTL  (0x604+M32R_BSELC_OFFSET)
+#define M32R_BSEL7_CR0_PORTL  (0x700+M32R_BSELC_OFFSET)
+#define M32R_BSEL7_CR1_PORTL  (0x704+M32R_BSELC_OFFSET)
+
+/*
+ * Multi Function Timer registers.
+ */
+#define M32R_MFT_OFFSET        (0x000FC000+M32R_SFR_OFFSET)
+
+#define M32R_MFTCR_PORTL       (0x000+M32R_MFT_OFFSET)  /* MFT control */
+#define M32R_MFTRPR_PORTL      (0x004+M32R_MFT_OFFSET)  /* MFT real port */
+
+#define M32R_MFT0_OFFSET       (0x100+M32R_MFT_OFFSET)
+#define M32R_MFT0MOD_PORTL     (0x00+M32R_MFT0_OFFSET)  /* MFT0 mode */
+#define M32R_MFT0BOS_PORTL     (0x04+M32R_MFT0_OFFSET)  /* MFT0 b-port output status */
+#define M32R_MFT0CUT_PORTL     (0x08+M32R_MFT0_OFFSET)  /* MFT0 count */
+#define M32R_MFT0RLD_PORTL     (0x0C+M32R_MFT0_OFFSET)  /* MFT0 reload */
+#define M32R_MFT0CMPRLD_PORTL  (0x10+M32R_MFT0_OFFSET)  /* MFT0 compare reload */
+
+#define M32R_MFT1_OFFSET       (0x200+M32R_MFT_OFFSET)
+#define M32R_MFT1MOD_PORTL     (0x00+M32R_MFT1_OFFSET)  /* MFT1 mode */
+#define M32R_MFT1BOS_PORTL     (0x04+M32R_MFT1_OFFSET)  /* MFT1 b-port output status */
+#define M32R_MFT1CUT_PORTL     (0x08+M32R_MFT1_OFFSET)  /* MFT1 count */
+#define M32R_MFT1RLD_PORTL     (0x0C+M32R_MFT1_OFFSET)  /* MFT1 reload */
+#define M32R_MFT1CMPRLD_PORTL  (0x10+M32R_MFT1_OFFSET)  /* MFT1 compare reload */
+
+#define M32R_MFT2_OFFSET       (0x300+M32R_MFT_OFFSET)
+#define M32R_MFT2MOD_PORTL     (0x00+M32R_MFT2_OFFSET)  /* MFT2 mode */
+#define M32R_MFT2BOS_PORTL     (0x04+M32R_MFT2_OFFSET)  /* MFT2 b-port output status */
+#define M32R_MFT2CUT_PORTL     (0x08+M32R_MFT2_OFFSET)  /* MFT2 count */
+#define M32R_MFT2RLD_PORTL     (0x0C+M32R_MFT2_OFFSET)  /* MFT2 reload */
+#define M32R_MFT2CMPRLD_PORTL  (0x10+M32R_MFT2_OFFSET)  /* MFT2 compare reload */
+
+#define M32R_MFT3_OFFSET       (0x400+M32R_MFT_OFFSET)
+#define M32R_MFT3MOD_PORTL     (0x00+M32R_MFT3_OFFSET)  /* MFT3 mode */
+#define M32R_MFT3BOS_PORTL     (0x04+M32R_MFT3_OFFSET)  /* MFT3 b-port output status */
+#define M32R_MFT3CUT_PORTL     (0x08+M32R_MFT3_OFFSET)  /* MFT3 count */
+#define M32R_MFT3RLD_PORTL     (0x0C+M32R_MFT3_OFFSET)  /* MFT3 reload */
+#define M32R_MFT3CMPRLD_PORTL  (0x10+M32R_MFT3_OFFSET)  /* MFT3 compare reload */
+
+#define M32R_MFT4_OFFSET       (0x500+M32R_MFT_OFFSET)
+#define M32R_MFT4MOD_PORTL     (0x00+M32R_MFT4_OFFSET)  /* MFT4 mode */
+#define M32R_MFT4BOS_PORTL     (0x04+M32R_MFT4_OFFSET)  /* MFT4 b-port output status */
+#define M32R_MFT4CUT_PORTL     (0x08+M32R_MFT4_OFFSET)  /* MFT4 count */
+#define M32R_MFT4RLD_PORTL     (0x0C+M32R_MFT4_OFFSET)  /* MFT4 reload */
+#define M32R_MFT4CMPRLD_PORTL  (0x10+M32R_MFT4_OFFSET)  /* MFT4 compare reload */
+
+#define M32R_MFT5_OFFSET       (0x600+M32R_MFT_OFFSET)
+#define M32R_MFT5MOD_PORTL     (0x00+M32R_MFT5_OFFSET)  /* MFT4 mode */
+#define M32R_MFT5BOS_PORTL     (0x04+M32R_MFT5_OFFSET)  /* MFT4 b-port output status */
+#define M32R_MFT5CUT_PORTL     (0x08+M32R_MFT5_OFFSET)  /* MFT4 count */
+#define M32R_MFT5RLD_PORTL     (0x0C+M32R_MFT5_OFFSET)  /* MFT4 reload */
+#define M32R_MFT5CMPRLD_PORTL  (0x10+M32R_MFT5_OFFSET)  /* MFT4 compare reload */
+
+#define M32R_MFTCR_MFT0MSK  (1UL<<15)  /* b16 */
+#define M32R_MFTCR_MFT1MSK  (1UL<<14)  /* b17 */
+#define M32R_MFTCR_MFT2MSK  (1UL<<13)  /* b18 */
+#define M32R_MFTCR_MFT3MSK  (1UL<<12)  /* b19 */
+#define M32R_MFTCR_MFT4MSK  (1UL<<11)  /* b20 */
+#define M32R_MFTCR_MFT5MSK  (1UL<<10)  /* b21 */
+#define M32R_MFTCR_MFT0EN   (1UL<<7)   /* b24 */
+#define M32R_MFTCR_MFT1EN   (1UL<<6)   /* b25 */
+#define M32R_MFTCR_MFT2EN   (1UL<<5)   /* b26 */
+#define M32R_MFTCR_MFT3EN   (1UL<<4)   /* b27 */
+#define M32R_MFTCR_MFT4EN   (1UL<<3)   /* b28 */
+#define M32R_MFTCR_MFT5EN   (1UL<<2)   /* b29 */
+
+#define M32R_MFTMOD_CC_MASK    (1UL<<15)  /* b16 */
+#define M32R_MFTMOD_TCCR       (1UL<<13)  /* b18 */
+#define M32R_MFTMOD_GTSEL000   (0UL<<8)   /* b21-23 : 000 */
+#define M32R_MFTMOD_GTSEL001   (1UL<<8)   /* b21-23 : 001 */
+#define M32R_MFTMOD_GTSEL010   (2UL<<8)   /* b21-23 : 010 */
+#define M32R_MFTMOD_GTSEL011   (3UL<<8)   /* b21-23 : 011 */
+#define M32R_MFTMOD_GTSEL110   (6UL<<8)   /* b21-23 : 110 */
+#define M32R_MFTMOD_GTSEL111   (7UL<<8)   /* b21-23 : 111 */
+#define M32R_MFTMOD_CMSEL      (1UL<<3)   /* b28 */
+#define M32R_MFTMOD_CSSEL000   (0UL<<0)   /* b29-b31 : 000 */
+#define M32R_MFTMOD_CSSEL001   (1UL<<0)   /* b29-b31 : 001 */
+#define M32R_MFTMOD_CSSEL010   (2UL<<0)   /* b29-b31 : 010 */
+#define M32R_MFTMOD_CSSEL011   (3UL<<0)   /* b29-b31 : 011 */
+#define M32R_MFTMOD_CSSEL100   (4UL<<0)   /* b29-b31 : 100 */
+#define M32R_MFTMOD_CSSEL110   (6UL<<0)   /* b29-b31 : 110 */
+
+/*
+ * Serial I/O registers.
+ */
+#define M32R_SIO_OFFSET  (0x000FD000+M32R_SFR_OFFSET)
+
+#define M32R_SIO0_CR_PORTL     (0x000+M32R_SIO_OFFSET)
+#define M32R_SIO0_MOD0_PORTL   (0x004+M32R_SIO_OFFSET)
+#define M32R_SIO0_MOD1_PORTL   (0x008+M32R_SIO_OFFSET)
+#define M32R_SIO0_STS_PORTL    (0x00C+M32R_SIO_OFFSET)
+#define M32R_SIO0_TRCR_PORTL   (0x010+M32R_SIO_OFFSET)
+#define M32R_SIO0_BAUR_PORTL   (0x014+M32R_SIO_OFFSET)
+#define M32R_SIO0_RBAUR_PORTL  (0x018+M32R_SIO_OFFSET)
+#define M32R_SIO0_TXB_PORTL    (0x01C+M32R_SIO_OFFSET)
+#define M32R_SIO0_RXB_PORTL    (0x020+M32R_SIO_OFFSET)
+
+/*
+ * Interrupt Control Unit registers.
+ */
+#define M32R_ICU_OFFSET  (0x000FF000+M32R_SFR_OFFSET)
+
+#define M32R_ICU_ISTS_PORTL     (0x004+M32R_ICU_OFFSET)
+#define M32R_ICU_IREQ0_PORTL    (0x008+M32R_ICU_OFFSET)
+#define M32R_ICU_IREQ1_PORTL    (0x00C+M32R_ICU_OFFSET)
+#define M32R_ICU_SBICR_PORTL    (0x018+M32R_ICU_OFFSET)
+#define M32R_ICU_IMASK_PORTL    (0x01C+M32R_ICU_OFFSET)
+#define M32R_ICU_CR1_PORTL      (0x200+M32R_ICU_OFFSET)  /* INT0 */
+#define M32R_ICU_CR2_PORTL      (0x204+M32R_ICU_OFFSET)  /* INT1 */
+#define M32R_ICU_CR3_PORTL      (0x208+M32R_ICU_OFFSET)  /* INT2 */
+#define M32R_ICU_CR4_PORTL      (0x20C+M32R_ICU_OFFSET)  /* INT3 */
+#define M32R_ICU_CR5_PORTL      (0x210+M32R_ICU_OFFSET)  /* INT4 */
+#define M32R_ICU_CR6_PORTL      (0x214+M32R_ICU_OFFSET)  /* INT5 */
+#define M32R_ICU_CR7_PORTL      (0x218+M32R_ICU_OFFSET)  /* INT6 */
+#define M32R_ICU_CR8_PORTL      (0x218+M32R_ICU_OFFSET)  /* INT7 */
+#define M32R_ICU_CR32_PORTL     (0x27C+M32R_ICU_OFFSET)  /* SIO0 RX */
+#define M32R_ICU_CR33_PORTL     (0x280+M32R_ICU_OFFSET)  /* SIO0 TX */
+#define M32R_ICU_CR40_PORTL     (0x29C+M32R_ICU_OFFSET)  /* DMAC0 */
+#define M32R_ICU_CR41_PORTL     (0x2A0+M32R_ICU_OFFSET)  /* DMAC1 */
+#define M32R_ICU_CR48_PORTL     (0x2BC+M32R_ICU_OFFSET)  /* MFT0 */
+#define M32R_ICU_CR49_PORTL     (0x2C0+M32R_ICU_OFFSET)  /* MFT1 */
+#define M32R_ICU_CR50_PORTL     (0x2C4+M32R_ICU_OFFSET)  /* MFT2 */
+#define M32R_ICU_CR51_PORTL     (0x2C8+M32R_ICU_OFFSET)  /* MFT3 */
+#define M32R_ICU_CR52_PORTL     (0x2CC+M32R_ICU_OFFSET)  /* MFT4 */
+#define M32R_ICU_CR53_PORTL     (0x2D0+M32R_ICU_OFFSET)  /* MFT5 */
+#define M32R_ICU_IPICR0_PORTL   (0x2DC+M32R_ICU_OFFSET)  /* IPI0 */
+#define M32R_ICU_IPICR1_PORTL   (0x2E0+M32R_ICU_OFFSET)  /* IPI1 */
+#define M32R_ICU_IPICR2_PORTL   (0x2E4+M32R_ICU_OFFSET)  /* IPI2 */
+#define M32R_ICU_IPICR3_PORTL   (0x2E8+M32R_ICU_OFFSET)  /* IPI3 */
+#define M32R_ICU_IPICR4_PORTL   (0x2EC+M32R_ICU_OFFSET)  /* IPI4 */
+#define M32R_ICU_IPICR5_PORTL   (0x2F0+M32R_ICU_OFFSET)  /* IPI5 */
+#define M32R_ICU_IPICR6_PORTL   (0x2F4+M32R_ICU_OFFSET)  /* IPI6 */
+#define M32R_ICU_IPICR7_PORTL   (0x2FC+M32R_ICU_OFFSET)  /* IPI7 */
+
+#define M32R_ICUISTS_VECB(val)  ((val>>28) & 0xF)
+#define M32R_ICUISTS_ISN(val)   ((val>>22) & 0x3F)
+#define M32R_ICUISTS_PIML(val)  ((val>>16) & 0x7)
+
+#define M32R_ICUIMASK_IMSK0  (0UL<<16)  /* b13-b15: Disable interrupt */
+#define M32R_ICUIMASK_IMSK1  (1UL<<16)  /* b13-b15: Enable level 0 interrupt */
+#define M32R_ICUIMASK_IMSK2  (2UL<<16)  /* b13-b15: Enable level 0,1 interrupt */
+#define M32R_ICUIMASK_IMSK3  (3UL<<16)  /* b13-b15: Enable level 0-2 interrupt */
+#define M32R_ICUIMASK_IMSK4  (4UL<<16)  /* b13-b15: Enable level 0-3 interrupt */
+#define M32R_ICUIMASK_IMSK5  (5UL<<16)  /* b13-b15: Enable level 0-4 interrupt */
+#define M32R_ICUIMASK_IMSK6  (6UL<<16)  /* b13-b15: Enable level 0-5 interrupt */
+#define M32R_ICUIMASK_IMSK7  (7UL<<16)  /* b13-b15: Enable level 0-6 interrupt */
+
+#define M32R_ICUCR_IEN      (1UL<<12)  /* b19: Interrupt enable */
+#define M32R_ICUCR_IRQ      (1UL<<8)   /* b23: Interrupt request */
+#define M32R_ICUCR_ISMOD00  (0UL<<4)   /* b26-b27: Interrupt sense mode Edge HtoL */
+#define M32R_ICUCR_ISMOD01  (1UL<<4)   /* b26-b27: Interrupt sense mode Level L */
+#define M32R_ICUCR_ISMOD10  (2UL<<4)   /* b26-b27: Interrupt sense mode Edge LtoH*/
+#define M32R_ICUCR_ISMOD11  (3UL<<4)   /* b26-b27: Interrupt sense mode Level H */
+#define M32R_ICUCR_ILEVEL0  (0UL<<0)   /* b29-b31: Interrupt priority level 0 */
+#define M32R_ICUCR_ILEVEL1  (1UL<<0)   /* b29-b31: Interrupt priority level 1 */
+#define M32R_ICUCR_ILEVEL2  (2UL<<0)   /* b29-b31: Interrupt priority level 2 */
+#define M32R_ICUCR_ILEVEL3  (3UL<<0)   /* b29-b31: Interrupt priority level 3 */
+#define M32R_ICUCR_ILEVEL4  (4UL<<0)   /* b29-b31: Interrupt priority level 4 */
+#define M32R_ICUCR_ILEVEL5  (5UL<<0)   /* b29-b31: Interrupt priority level 5 */
+#define M32R_ICUCR_ILEVEL6  (6UL<<0)   /* b29-b31: Interrupt priority level 6 */
+#define M32R_ICUCR_ILEVEL7  (7UL<<0)   /* b29-b31: Disable interrupt */
+#define M32R_ICUCR_ILEVEL_MASK  (7UL)
+
+#define M32R_IRQ_INT0    (1)   /* INT0 */
+#define M32R_IRQ_INT1    (2)   /* INT1 */
+#define M32R_IRQ_INT2    (3)   /* INT2 */
+#define M32R_IRQ_INT3    (4)   /* INT3 */
+#define M32R_IRQ_INT4    (5)   /* INT4 */
+#define M32R_IRQ_INT5    (6)   /* INT5 */
+#define M32R_IRQ_INT6    (7)   /* INT6 */
+#define M32R_IRQ_INT7    (8)   /* INT7 */
+#define M32R_IRQ_MFT0    (16)  /* MFT0 */
+#define M32R_IRQ_MFT1    (17)  /* MFT1 */
+#define M32R_IRQ_MFT2    (18)  /* MFT2 */
+#define M32R_IRQ_MFT3    (19)  /* MFT3 */
+#define M32R_IRQ_MFT4    (20)  /* MFT4 */
+#define M32R_IRQ_MFT5    (21)  /* MFT5 */
+#define M32R_IRQ_DMAC0   (32)  /* DMAC0 */
+#define M32R_IRQ_DMAC1   (33)  /* DMAC1 */
+#define M32R_IRQ_SIO0_R  (48)  /* SIO0 receive */
+#define M32R_IRQ_SIO0_S  (49)  /* SIO0 send    */
+#define M32R_IRQ_SIO1_R  (50)  /* SIO1 send    */
+#define M32R_IRQ_SIO1_S  (51)  /* SIO1 receive */
+#define M32R_IRQ_IPI0    (56)  /* IPI0 */
+#define M32R_IRQ_IPI1    (57)  /* IPI1 */
+#define M32R_IRQ_IPI2    (58)  /* IPI2 */
+#define M32R_IRQ_IPI3    (59)  /* IPI3 */
+#define M32R_IRQ_IPI4    (60)  /* IPI4 */
+#define M32R_IRQ_IPI5    (61)  /* IPI5 */
+#define M32R_IRQ_IPI6    (62)  /* IPI6 */
+#define M32R_IRQ_IPI7    (63)  /* IPI7 */
+
+/*======================================================================*
+ * CPU
+ *======================================================================*/
+
+#define M32R_CPUID_PORTL   (0xFFFFFFE0)
+#define M32R_MCICAR_PORTL  (0xFFFFFFF0)
+#define M32R_MCDCAR_PORTL  (0xFFFFFFF4)
+#define M32R_MCCR_PORTL    (0xFFFFFFFC)
+
+#endif  /* _ASM_M32R_M32R_MP_FPGA_ */
diff --git a/include/asm-m32r/mappi2/mappi2_pld.h b/include/asm-m32r/mappi2/mappi2_pld.h
new file mode 100644 (file)
index 0000000..01dcdd1
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * include/asm/mappi2/mappi2_pld.h
+ *
+ * Definitions for Extended IO Logic on MAPPI2 board.
+ *  based on m32700ut_pld.h by
+ *
+ * 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 _MAPPI2_PLD_H
+#define _MAPPI2_PLD_H
+
+#ifndef __ASSEMBLY__
+/* FIXME:
+ * Some C functions use non-cache address, so can't define non-cache address.
+ */
+#define PLD_BASE               (0x10c00000 /* + NONCACHE_OFFSET */)
+#define __reg8                 (volatile unsigned char *)
+#define __reg16                        (volatile unsigned short *)
+#define __reg32                        (volatile unsigned int *)
+#else
+#define PLD_BASE               (0x10c00000 + NONCACHE_OFFSET)
+#define __reg8
+#define __reg16
+#define __reg32
+#endif /* __ASSEMBLY__ */
+
+/* CFC */
+#define        PLD_CFRSTCR             __reg16(PLD_BASE + 0x0000)
+#define PLD_CFSTS              __reg16(PLD_BASE + 0x0002)
+#define PLD_CFIMASK            __reg16(PLD_BASE + 0x0004)
+#define PLD_CFBUFCR            __reg16(PLD_BASE + 0x0006)
+#define PLD_CFCR0              __reg16(PLD_BASE + 0x000a)
+#define PLD_CFCR1              __reg16(PLD_BASE + 0x000c)
+
+/* MMC */
+#define PLD_MMCCR              __reg16(PLD_BASE + 0x4000)
+#define PLD_MMCMOD             __reg16(PLD_BASE + 0x4002)
+#define PLD_MMCSTS             __reg16(PLD_BASE + 0x4006)
+#define PLD_MMCBAUR            __reg16(PLD_BASE + 0x400a)
+#define PLD_MMCCMDBCUT         __reg16(PLD_BASE + 0x400c)
+#define PLD_MMCCDTBCUT         __reg16(PLD_BASE + 0x400e)
+#define PLD_MMCDET             __reg16(PLD_BASE + 0x4010)
+#define PLD_MMCWP              __reg16(PLD_BASE + 0x4012)
+#define PLD_MMCWDATA           __reg16(PLD_BASE + 0x5000)
+#define PLD_MMCRDATA           __reg16(PLD_BASE + 0x6000)
+#define PLD_MMCCMDDATA         __reg16(PLD_BASE + 0x7000)
+#define PLD_MMCRSPDATA         __reg16(PLD_BASE + 0x7006)
+
+/* Power Control of MMC and CF */
+#define PLD_CPCR               __reg16(PLD_BASE + 0x14000)
+
+
+/*==== ICU ====*/
+#define  M32R_IRQ_PC104        (5)   /* INT4(PC/104) */
+#define  M32R_IRQ_I2C          (28)  /* I2C-BUS     */
+#if 1
+#define  PLD_IRQ_CFIREQ       (40)  /* CFC Card Interrupt */
+#define  PLD_IRQ_CFC_INSERT   (41)  /* CFC Card Insert */
+#define  PLD_IRQ_CFC_EJECT    (42)  /* CFC Card Eject */
+#define  PLD_IRQ_MMCCARD      (43)  /* MMC Card Insert */
+#define  PLD_IRQ_MMCIRQ       (44)  /* MMC Transfer Done */
+#else
+#define  PLD_IRQ_CFIREQ       (34)  /* CFC Card Interrupt */
+#define  PLD_IRQ_CFC_INSERT   (35)  /* CFC Card Insert */
+#define  PLD_IRQ_CFC_EJECT    (36)  /* CFC Card Eject */
+#define  PLD_IRQ_MMCCARD      (37)  /* MMC Card Insert */
+#define  PLD_IRQ_MMCIRQ       (38)  /* MMC Transfer Done */
+#endif
+
+
+#if 0
+/* LED Control
+ *
+ * 1: DIP swich side
+ * 2: Reset switch side
+ */
+#define PLD_IOLEDCR            __reg16(PLD_BASE + 0x14002)
+#define PLD_IOLED_1_ON         0x001
+#define PLD_IOLED_1_OFF                0x000
+#define PLD_IOLED_2_ON         0x002
+#define PLD_IOLED_2_OFF                0x000
+
+/* DIP Switch
+ *  0: Write-protect of Flash Memory (0:protected, 1:non-protected)
+ *  1: -
+ *  2: -
+ *  3: -
+ */
+#define PLD_IOSWSTS            __reg16(PLD_BASE + 0x14004)
+#define        PLD_IOSWSTS_IOSW2       0x0200
+#define        PLD_IOSWSTS_IOSW1       0x0100
+#define        PLD_IOSWSTS_IOWP0       0x0001
+
+#endif
+
+/* CRC */
+#define PLD_CRC7DATA           __reg16(PLD_BASE + 0x18000)
+#define PLD_CRC7INDATA         __reg16(PLD_BASE + 0x18002)
+#define PLD_CRC16DATA          __reg16(PLD_BASE + 0x18004)
+#define PLD_CRC16INDATA                __reg16(PLD_BASE + 0x18006)
+#define PLD_CRC16ADATA         __reg16(PLD_BASE + 0x18008)
+#define PLD_CRC16AINDATA       __reg16(PLD_BASE + 0x1800a)
+
+
+#if 0
+/* RTC */
+#define PLD_RTCCR              __reg16(PLD_BASE + 0x1c000)
+#define PLD_RTCBAUR            __reg16(PLD_BASE + 0x1c002)
+#define PLD_RTCWRDATA          __reg16(PLD_BASE + 0x1c004)
+#define PLD_RTCRDDATA          __reg16(PLD_BASE + 0x1c006)
+#define PLD_RTCRSTODT          __reg16(PLD_BASE + 0x1c008)
+
+/* SIO0 */
+#define PLD_ESIO0CR            __reg16(PLD_BASE + 0x20000)
+#define        PLD_ESIO0CR_TXEN        0x0001
+#define        PLD_ESIO0CR_RXEN        0x0002
+#define PLD_ESIO0MOD0          __reg16(PLD_BASE + 0x20002)
+#define        PLD_ESIO0MOD0_CTSS      0x0040
+#define        PLD_ESIO0MOD0_RTSS      0x0080
+#define PLD_ESIO0MOD1          __reg16(PLD_BASE + 0x20004)
+#define        PLD_ESIO0MOD1_LMFS      0x0010
+#define PLD_ESIO0STS           __reg16(PLD_BASE + 0x20006)
+#define        PLD_ESIO0STS_TEMP       0x0001
+#define        PLD_ESIO0STS_TXCP       0x0002
+#define        PLD_ESIO0STS_RXCP       0x0004
+#define        PLD_ESIO0STS_TXSC       0x0100
+#define        PLD_ESIO0STS_RXSC       0x0200
+#define PLD_ESIO0STS_TXREADY   (PLD_ESIO0STS_TXCP | PLD_ESIO0STS_TEMP)
+#define PLD_ESIO0INTCR         __reg16(PLD_BASE + 0x20008)
+#define        PLD_ESIO0INTCR_TXIEN    0x0002
+#define        PLD_ESIO0INTCR_RXCEN    0x0004
+#define PLD_ESIO0BAUR          __reg16(PLD_BASE + 0x2000a)
+#define PLD_ESIO0TXB           __reg16(PLD_BASE + 0x2000c)
+#define PLD_ESIO0RXB           __reg16(PLD_BASE + 0x2000e)
+
+/* SIM Card */
+#define PLD_SCCR               __reg16(PLD_BASE + 0x38000)
+#define PLD_SCMOD              __reg16(PLD_BASE + 0x38004)
+#define PLD_SCSTS              __reg16(PLD_BASE + 0x38006)
+#define PLD_SCINTCR            __reg16(PLD_BASE + 0x38008)
+#define PLD_SCBAUR             __reg16(PLD_BASE + 0x3800a)
+#define PLD_SCTXB              __reg16(PLD_BASE + 0x3800c)
+#define PLD_SCRXB              __reg16(PLD_BASE + 0x3800e)
+
+#endif
+
+#endif /* _MAPPI2_PLD.H */
diff --git a/include/asm-m32r/mc146818rtc.h b/include/asm-m32r/mc146818rtc.h
new file mode 100644 (file)
index 0000000..755601d
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <asm/io.h>
+
+#ifndef RTC_PORT
+// #define RTC_PORT(x) (0x70 + (x))
+#define RTC_PORT(x)    ((x))
+#define RTC_ALWAYS_BCD 1       /* RTC operates in binary mode */
+#endif
+
+/*
+ * The yet supported machines all access the RTC index register via
+ * an ISA port access but the way to access the date register differs ...
+ */
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+
+#define RTC_IRQ 8
+#if 0
+#endif
+
+#endif /* _ASM_MC146818RTC_H */
diff --git a/include/asm-m32r/mman.h b/include/asm-m32r/mman.h
new file mode 100644 (file)
index 0000000..011f6d9
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __M32R_MMAN_H__
+#define __M32R_MMAN_H__
+
+/* orig : i386 2.6.0-test6 */
+
+#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       0x8             /* page may be used for atomic ops */
+#define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED     0x01            /* Share changes */
+#define MAP_PRIVATE    0x02            /* Changes are private */
+#define MAP_TYPE       0x0f            /* Mask for type of mapping */
+#define MAP_FIXED      0x10            /* Interpret addr exactly */
+#define MAP_ANONYMOUS  0x20            /* don't use a file */
+
+#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
+#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
+#define MAP_LOCKED     0x2000          /* pages are locked */
+#define MAP_NORESERVE  0x4000          /* don't check for reservations */
+#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
+#define MAP_NONBLOCK   0x10000         /* do not block on IO */
+
+#define MS_ASYNC       1               /* sync memory asynchronously */
+#define MS_INVALIDATE  2               /* invalidate the caches */
+#define MS_SYNC                4               /* synchronous memory sync */
+
+#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 /* __M32R_MMAN_H__ */
diff --git a/include/asm-m32r/mmu.h b/include/asm-m32r/mmu.h
new file mode 100644 (file)
index 0000000..930093a
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _ASM_M32R_MMU_H
+#define _ASM_M32R_MMU_H
+
+/* $Id$ */
+
+#include <linux/config.h>
+
+#if !defined(CONFIG_MMU)
+struct mm_rblock_struct {
+  int     size;
+  int     refcount;
+  void    *kblock;
+};
+
+struct mm_tblock_struct {
+  struct mm_rblock_struct *rblock;
+  struct mm_tblock_struct *next;
+};
+
+typedef struct {
+  struct mm_tblock_struct tblock;
+  unsigned long           end_brk;
+} mm_context_t;
+#else
+
+/* Default "unsigned long" context */
+#ifndef CONFIG_SMP
+typedef unsigned long mm_context_t;
+#else
+typedef unsigned long mm_context_t[NR_CPUS];
+#endif
+
+#endif  /* CONFIG_MMU */
+#endif  /* _ASM_M32R_MMU_H */
+
diff --git a/include/asm-m32r/mmu_context.h b/include/asm-m32r/mmu_context.h
new file mode 100644 (file)
index 0000000..c16f81c
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef _ASM_M32R_MMU_CONTEXT_H
+#define _ASM_M32R_MMU_CONTEXT_H
+
+/* $Id */
+
+#include <linux/config.h>
+
+#include <asm/m32r.h>
+
+#define MMU_CONTEXT_ASID_MASK      (0x000000FF)
+#define MMU_CONTEXT_VERSION_MASK   (0xFFFFFF00)
+#define MMU_CONTEXT_FIRST_VERSION  (0x00000100)
+#define NO_CONTEXT                 (0x00000000)
+
+
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <asm/atomic.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu.h>
+#include <asm/tlbflush.h>
+
+/*
+ * Cache of MMU context last used.
+ */
+#ifndef CONFIG_SMP
+extern unsigned long mmu_context_cache_dat;
+#define mmu_context_cache      mmu_context_cache_dat
+#define mm_context(mm)         mm->context
+#else /* not CONFIG_SMP */
+extern unsigned long mmu_context_cache_dat[];
+#define mmu_context_cache      mmu_context_cache_dat[smp_processor_id()]
+#define mm_context(mm)         mm->context[smp_processor_id()]
+#endif /* not CONFIG_SMP */
+
+#define set_tlb_tag(entry, tag)        (*entry = (tag & PAGE_MASK)|get_asid())
+#define set_tlb_data(entry, data)      (*entry = (data | _PAGE_PRESENT))
+
+#ifdef CONFIG_MMU
+#define enter_lazy_tlb(mm, tsk)        do { } while (0)
+
+static __inline__ void get_new_mmu_context(struct mm_struct *mm)
+{
+       unsigned long mc = ++mmu_context_cache;
+
+       if (!(mc & MMU_CONTEXT_ASID_MASK)) {
+               /* We exhaust ASID of this version.
+                  Flush all TLB and start new cycle. */
+               local_flush_tlb_all();
+               /* Fix version if needed.
+                  Note that we avoid version #0 to distingush NO_CONTEXT. */
+               if (!mc)
+                       mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
+       }
+       mm_context(mm) = mc;
+}
+
+/*
+ * Get MMU context if needed.
+ */
+static __inline__ void get_mmu_context(struct mm_struct *mm)
+{
+       if (mm) {
+               unsigned long mc = mmu_context_cache;
+
+               /* Check if we have old version of context.
+                  If it's old, we need to get new context with new version. */
+               if ((mm_context(mm) ^ mc) & MMU_CONTEXT_VERSION_MASK)
+                       get_new_mmu_context(mm);
+       }
+}
+
+/*
+ * Initialize the context related info for a new mm_struct
+ * instance.
+ */
+static __inline__ int init_new_context(struct task_struct *tsk,
+       struct mm_struct *mm)
+{
+#ifndef CONFIG_SMP
+       mm->context = NO_CONTEXT;
+#else /* CONFIG_SMP */
+       int num_cpus = num_online_cpus();
+       int i;
+
+       for (i = 0 ; i < num_cpus ; i++)
+               mm->context[i] = NO_CONTEXT;
+#endif /* CONFIG_SMP */
+
+       return 0;
+}
+
+/*
+ * Destroy context related info for an mm_struct that is about
+ * to be put to rest.
+ */
+#define destroy_context(mm)    do { } while (0)
+
+static __inline__ void set_asid(unsigned long asid)
+{
+       *(volatile unsigned long *)MASID = (asid & MMU_CONTEXT_ASID_MASK);
+}
+
+static __inline__ unsigned long get_asid(void)
+{
+       unsigned long asid;
+
+       asid = *(volatile long *)MASID;
+       asid &= MMU_CONTEXT_ASID_MASK;
+
+       return asid;
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+static __inline__ void activate_context(struct mm_struct *mm)
+{
+       get_mmu_context(mm);
+       set_asid(mm_context(mm) & MMU_CONTEXT_ASID_MASK);
+}
+
+static __inline__ void switch_mm(struct mm_struct *prev,
+       struct mm_struct *next, struct task_struct *tsk)
+{
+#ifdef CONFIG_SMP
+       int cpu = smp_processor_id();
+#endif /* CONFIG_SMP */
+
+       if (prev != next) {
+#ifdef CONFIG_SMP
+               cpu_set(cpu, next->cpu_vm_mask);
+#endif /* CONFIG_SMP */
+               /* Set MPTB = next->pgd */
+               *(volatile unsigned long *)MPTB = (unsigned long)next->pgd;
+               activate_context(next);
+       }
+#ifdef CONFIG_SMP
+       else
+               if (!cpu_test_and_set(cpu, next->cpu_vm_mask))
+                       activate_context(next);
+#endif /* CONFIG_SMP */
+}
+
+#define deactivate_mm(tsk, mm) do { } while (0)
+
+#define activate_mm(prev, next)        \
+       switch_mm((prev), (next), NULL)
+
+#else
+#define get_mmu_context(mm)             do { } while (0)
+#define init_new_context(tsk,mm)        (0)
+#define destroy_context(mm)             do { } while (0)
+#define set_asid(asid)                  do { } while (0)
+#define get_asid()                      (0)
+#define activate_context(mm)            do { } while (0)
+#define switch_mm(prev,next,tsk)        do { } while (0)
+#define deactivate_mm(mm,tsk)           do { } while (0)
+#define activate_mm(prev,next)          do { } while (0)
+#define enter_lazy_tlb(mm,tsk)          do { } while (0)
+#endif /* CONFIG_MMU */
+
+
+#endif /* not __ASSEMBLY__ */
+
+#endif /* _ASM_M32R_MMU_CONTEXT_H */
+
diff --git a/include/asm-m32r/mmzone.h b/include/asm-m32r/mmzone.h
new file mode 100644 (file)
index 0000000..ebf0228
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Written by Pat Gaughen (gone@us.ibm.com) Mar 2002
+ *
+ */
+
+#ifndef _ASM_MMZONE_H_
+#define _ASM_MMZONE_H_
+
+#include <asm/smp.h>
+
+#ifdef CONFIG_DISCONTIGMEM
+
+extern struct pglist_data *node_data[];
+#define NODE_DATA(nid)         (node_data[nid])
+
+#define node_localnr(pfn, nid) ((pfn) - NODE_DATA(nid)->node_start_pfn)
+#define node_mem_map(nid)      (NODE_DATA(nid)->node_mem_map)
+#define node_start_pfn(nid)    (NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid)                                              \
+({                                                                     \
+       pg_data_t *__pgdat = NODE_DATA(nid);                            \
+       __pgdat->node_start_pfn + __pgdat->node_spanned_pages - 1;      \
+})
+
+#define local_mapnr(kvaddr)                                            \
+({                                                                     \
+       unsigned long __pfn = __pa(kvaddr) >> PAGE_SHIFT;               \
+       (__pfn - node_start_pfn(pfn_to_nid(__pfn)));                    \
+})
+
+#define pfn_to_page(pfn)                                               \
+({                                                                     \
+       unsigned long __pfn = pfn;                                      \
+       int __node  = pfn_to_nid(__pfn);                                \
+       &node_mem_map(__node)[node_localnr(__pfn,__node)];              \
+})
+
+#define page_to_pfn(pg)                                                        \
+({                                                                     \
+       struct page *__page = pg;                                       \
+       struct zone *__zone = page_zone(__page);                        \
+       (unsigned long)(__page - __zone->zone_mem_map)                  \
+               + __zone->zone_start_pfn;                               \
+})
+#define pmd_page(pmd)          (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+/*
+ * pfn_valid should be made as fast as possible, and the current definition
+ * is valid for machines that are NUMA, but still contiguous, which is what
+ * is currently supported. A more generalised, but slower definition would
+ * be something like this - mbligh:
+ * ( pfn_to_pgdat(pfn) && ((pfn) < node_end_pfn(pfn_to_nid(pfn))) )
+ */
+#if 1  /* M32R_FIXME */
+#define pfn_valid(pfn) (1)
+#else
+#define pfn_valid(pfn) ((pfn) < num_physpages)
+#endif
+
+/*
+ * generic node memory support, the following assumptions apply:
+ */
+
+static __inline__ int pfn_to_nid(unsigned long pfn)
+{
+       int node;
+
+       for (node = 0 ; node < MAX_NUMNODES ; node++)
+               if (pfn >= node_start_pfn(node) && pfn <= node_end_pfn(node))
+                       break;
+
+       return node;
+}
+
+static __inline__ struct pglist_data *pfn_to_pgdat(unsigned long pfn)
+{
+       return(NODE_DATA(pfn_to_nid(pfn)));
+}
+
+#endif /* CONFIG_DISCONTIGMEM */
+#endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-m32r/module.h b/include/asm-m32r/module.h
new file mode 100644 (file)
index 0000000..3f2541c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _ASM_M32R_MODULE_H
+#define _ASM_M32R_MODULE_H
+
+/* $Id$ */
+
+struct mod_arch_specific { };
+
+#define Elf_Shdr       Elf32_Shdr
+#define Elf_Sym                Elf32_Sym
+#define Elf_Ehdr       Elf32_Ehdr
+
+#endif /* _ASM_M32R_MODULE_H */
+
diff --git a/include/asm-m32r/msgbuf.h b/include/asm-m32r/msgbuf.h
new file mode 100644 (file)
index 0000000..852ff52
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _ASM_M32R_MSGBUF_H
+#define _ASM_M32R_MSGBUF_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * The msqid64_ds structure for m32r architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+       struct ipc64_perm msg_perm;
+       __kernel_time_t msg_stime;      /* last msgsnd time */
+       unsigned long   __unused1;
+       __kernel_time_t msg_rtime;      /* last msgrcv time */
+       unsigned long   __unused2;
+       __kernel_time_t msg_ctime;      /* last change time */
+       unsigned long   __unused3;
+       unsigned long  msg_cbytes;      /* current number of bytes on queue */
+       unsigned long  msg_qnum;        /* number of messages in queue */
+       unsigned long  msg_qbytes;      /* max number of bytes on queue */
+       __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
+       __kernel_pid_t msg_lrpid;       /* last receive pid */
+       unsigned long  __unused4;
+       unsigned long  __unused5;
+};
+
+#endif /* _ASM_M32R_MSGBUF_H */
diff --git a/include/asm-m32r/namei.h b/include/asm-m32r/namei.h
new file mode 100644 (file)
index 0000000..7172d3d
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _ASM_M32R_NAMEI_H
+#define _ASM_M32R_NAMEI_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * linux/include/asm-m32r/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+/* 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 /* _ASM_M32R_NAMEI_H */
diff --git a/include/asm-m32r/numnodes.h b/include/asm-m32r/numnodes.h
new file mode 100644 (file)
index 0000000..479a39d
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _ASM_NUMNODES_H_
+#define _ASM_NUMNODES_H_
+
+#include <linux/config.h>
+
+#ifdef CONFIG_DISCONTIGMEM
+
+#if defined(CONFIG_CHIP_M32700)
+#define        NODES_SHIFT     1       /* Max 2 Nodes */
+#endif /* CONFIG_CHIP_M32700 */
+
+#endif /* CONFIG_DISCONTIGMEM */
+
+#endif /* _ASM_NUMNODES_H_ */
+
diff --git a/include/asm-m32r/opsput/opsput_lan.h b/include/asm-m32r/opsput/opsput_lan.h
new file mode 100644 (file)
index 0000000..7a2a839
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * include/asm/opsput_lan.h
+ *
+ * OPSPUT-LAN board
+ *
+ * Copyright (c) 2002-2004     Takeo Takahashi, Mamoru Sakugawa
+ *
+ * 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.
+ *
+ * $Id: opsput_lan.h,v 1.1 2004/07/27 06:54:20 sakugawa Exp $
+ */
+
+#ifndef _OPSPUT_OPSPUT_LAN_H
+#define _OPSPUT_OPSPUT_LAN_H
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * C functions use non-cache address.
+ */
+#define OPSPUT_LAN_BASE        (0x10000000 /* + NONCACHE_OFFSET */)
+#else
+#define OPSPUT_LAN_BASE        (0x10000000 + NONCACHE_OFFSET)
+#endif /* __ASSEMBLY__ */
+
+/* ICU
+ *  ICUISTS:   status register
+ *  ICUIREQ0:  request register
+ *  ICUIREQ1:  request register
+ *  ICUCR3:    control register for CFIREQ# interrupt
+ *  ICUCR4:    control register for CFC Card insert interrupt
+ *  ICUCR5:    control register for CFC Card eject interrupt
+ *  ICUCR6:    control register for external interrupt
+ *  ICUCR11:   control register for MMC Card insert/eject interrupt
+ *  ICUCR13:   control register for SC error interrupt
+ *  ICUCR14:   control register for SC receive interrupt
+ *  ICUCR15:   control register for SC send interrupt
+ *  ICUCR16:   control register for SIO0 receive interrupt
+ *  ICUCR17:   control register for SIO0 send interrupt
+ */
+#define OPSPUT_LAN_IRQ_LAN     (OPSPUT_LAN_PLD_IRQ_BASE + 1)   /* LAN */
+#define OPSPUT_LAN_IRQ_I2C     (OPSPUT_LAN_PLD_IRQ_BASE + 3)   /* I2C */
+
+#define OPSPUT_LAN_ICUISTS     __reg16(OPSPUT_LAN_BASE + 0xc0002)
+#define OPSPUT_LAN_ICUISTS_VECB_MASK   (0xf000)
+#define OPSPUT_LAN_VECB(x)     ((x) & OPSPUT_LAN_ICUISTS_VECB_MASK)
+#define OPSPUT_LAN_ICUISTS_ISN_MASK    (0x07c0)
+#define OPSPUT_LAN_ICUISTS_ISN(x)      ((x) & OPSPUT_LAN_ICUISTS_ISN_MASK)
+#define OPSPUT_LAN_ICUIREQ0    __reg16(OPSPUT_LAN_BASE + 0xc0004)
+#define OPSPUT_LAN_ICUCR1      __reg16(OPSPUT_LAN_BASE + 0xc0010)
+#define OPSPUT_LAN_ICUCR3      __reg16(OPSPUT_LAN_BASE + 0xc0014)
+
+#endif /* _OPSPUT_OPSPUT_LAN_H */
diff --git a/include/asm-m32r/opsput/opsput_lcd.h b/include/asm-m32r/opsput/opsput_lcd.h
new file mode 100644 (file)
index 0000000..3a883e3
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * include/asm/opsput_lcd.h
+ *
+ * OPSPUT-LCD board
+ *
+ * Copyright (c) 2002  Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id: opsput_lcd.h,v 1.1 2004/07/27 06:54:20 sakugawa Exp $
+ */
+
+#ifndef _OPSPUT_OPSPUT_LCD_H
+#define _OPSPUT_OPSPUT_LCD_H
+
+#include <linux/config.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * C functions use non-cache address.
+ */
+#define OPSPUT_LCD_BASE        (0x10000000 /* + NONCACHE_OFFSET */)
+#else
+#define OPSPUT_LCD_BASE        (0x10000000 + NONCACHE_OFFSET)
+#endif /* __ASSEMBLY__ */
+
+/*
+ * ICU
+ */
+#define OPSPUT_LCD_IRQ_BAT_INT (OPSPUT_LCD_PLD_IRQ_BASE + 1)
+#define OPSPUT_LCD_IRQ_USB_INT1        (OPSPUT_LCD_PLD_IRQ_BASE + 2)
+#define OPSPUT_LCD_IRQ_AUDT0           (OPSPUT_LCD_PLD_IRQ_BASE + 3)
+#define OPSPUT_LCD_IRQ_AUDT2           (OPSPUT_LCD_PLD_IRQ_BASE + 4)
+#define OPSPUT_LCD_IRQ_BATSIO_RCV      (OPSPUT_LCD_PLD_IRQ_BASE + 16)
+#define OPSPUT_LCD_IRQ_BATSIO_SND      (OPSPUT_LCD_PLD_IRQ_BASE + 17)
+#define OPSPUT_LCD_IRQ_ASNDSIO_RCV     (OPSPUT_LCD_PLD_IRQ_BASE + 18)
+#define OPSPUT_LCD_IRQ_ASNDSIO_SND     (OPSPUT_LCD_PLD_IRQ_BASE + 19)
+#define OPSPUT_LCD_IRQ_ACNLSIO_SND     (OPSPUT_LCD_PLD_IRQ_BASE + 21)
+
+#define OPSPUT_LCD_ICUISTS     __reg16(OPSPUT_LCD_BASE + 0x300002)
+#define OPSPUT_LCD_ICUISTS_VECB_MASK   (0xf000)
+#define OPSPUT_LCD_VECB(x)     ((x) & OPSPUT_LCD_ICUISTS_VECB_MASK)
+#define OPSPUT_LCD_ICUISTS_ISN_MASK    (0x07c0)
+#define OPSPUT_LCD_ICUISTS_ISN(x)      ((x) & OPSPUT_LCD_ICUISTS_ISN_MASK)
+#define OPSPUT_LCD_ICUIREQ0    __reg16(OPSPUT_LCD_BASE + 0x300004)
+#define OPSPUT_LCD_ICUIREQ1    __reg16(OPSPUT_LCD_BASE + 0x300006)
+#define OPSPUT_LCD_ICUCR1      __reg16(OPSPUT_LCD_BASE + 0x300020)
+#define OPSPUT_LCD_ICUCR2      __reg16(OPSPUT_LCD_BASE + 0x300022)
+#define OPSPUT_LCD_ICUCR3      __reg16(OPSPUT_LCD_BASE + 0x300024)
+#define OPSPUT_LCD_ICUCR4      __reg16(OPSPUT_LCD_BASE + 0x300026)
+#define OPSPUT_LCD_ICUCR16     __reg16(OPSPUT_LCD_BASE + 0x300030)
+#define OPSPUT_LCD_ICUCR17     __reg16(OPSPUT_LCD_BASE + 0x300032)
+#define OPSPUT_LCD_ICUCR18     __reg16(OPSPUT_LCD_BASE + 0x300034)
+#define OPSPUT_LCD_ICUCR19     __reg16(OPSPUT_LCD_BASE + 0x300036)
+#define OPSPUT_LCD_ICUCR21     __reg16(OPSPUT_LCD_BASE + 0x30003a)
+
+#endif /* _OPSPUT_OPSPUT_LCD_H */
diff --git a/include/asm-m32r/opsput/opsput_pld.h b/include/asm-m32r/opsput/opsput_pld.h
new file mode 100644 (file)
index 0000000..2018e69
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * include/asm/opsput/opsput_pld.h
+ *
+ * Definitions for Programable Logic Device(PLD) on OPSPUT board.
+ *
+ * Copyright (c) 2002  Takeo Takahashi
+ *
+ * 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.
+ *
+ * $Id: opsput_pld.h,v 1.1 2004/07/27 06:54:20 sakugawa Exp $
+ */
+
+#ifndef _OPSPUT_OPSPUT_PLD_H
+#define _OPSPUT_OPSPUT_PLD_H
+
+#include <linux/config.h>
+
+#define PLD_PLAT_BASE          0x1cc00000
+
+#ifndef __ASSEMBLY__
+/*
+ * C functions use non-cache address.
+ */
+#define PLD_BASE               (PLD_PLAT_BASE /* + NONCACHE_OFFSET */)
+#define __reg8                 (volatile unsigned char *)
+#define __reg16                        (volatile unsigned short *)
+#define __reg32                        (volatile unsigned int *)
+#else
+#define PLD_BASE               (PLD_PLAT_BASE + NONCACHE_OFFSET)
+#define __reg8
+#define __reg16
+#define __reg32
+#endif /* __ASSEMBLY__ */
+
+/* CFC */
+#define        PLD_CFRSTCR             __reg16(PLD_BASE + 0x0000)
+#define PLD_CFSTS              __reg16(PLD_BASE + 0x0002)
+#define PLD_CFIMASK            __reg16(PLD_BASE + 0x0004)
+#define PLD_CFBUFCR            __reg16(PLD_BASE + 0x0006)
+#define PLD_CFVENCR            __reg16(PLD_BASE + 0x0008)
+#define PLD_CFCR0              __reg16(PLD_BASE + 0x000a)
+#define PLD_CFCR1              __reg16(PLD_BASE + 0x000c)
+#define PLD_IDERSTCR           __reg16(PLD_BASE + 0x0010)
+
+/* MMC */
+#define PLD_MMCCR              __reg16(PLD_BASE + 0x4000)
+#define PLD_MMCMOD             __reg16(PLD_BASE + 0x4002)
+#define PLD_MMCSTS             __reg16(PLD_BASE + 0x4006)
+#define PLD_MMCBAUR            __reg16(PLD_BASE + 0x400a)
+#define PLD_MMCCMDBCUT         __reg16(PLD_BASE + 0x400c)
+#define PLD_MMCCDTBCUT         __reg16(PLD_BASE + 0x400e)
+#define PLD_MMCDET             __reg16(PLD_BASE + 0x4010)
+#define PLD_MMCWP              __reg16(PLD_BASE + 0x4012)
+#define PLD_MMCWDATA           __reg16(PLD_BASE + 0x5000)
+#define PLD_MMCRDATA           __reg16(PLD_BASE + 0x6000)
+#define PLD_MMCCMDDATA         __reg16(PLD_BASE + 0x7000)
+#define PLD_MMCRSPDATA         __reg16(PLD_BASE + 0x7006)
+
+/* ICU
+ *  ICUISTS:   status register
+ *  ICUIREQ0:  request register
+ *  ICUIREQ1:  request register
+ *  ICUCR3:    control register for CFIREQ# interrupt
+ *  ICUCR4:    control register for CFC Card insert interrupt
+ *  ICUCR5:    control register for CFC Card eject interrupt
+ *  ICUCR6:    control register for external interrupt
+ *  ICUCR11:   control register for MMC Card insert/eject interrupt
+ *  ICUCR13:   control register for SC error interrupt
+ *  ICUCR14:   control register for SC receive interrupt
+ *  ICUCR15:   control register for SC send interrupt
+ *  ICUCR16:   control register for SIO0 receive interrupt
+ *  ICUCR17:   control register for SIO0 send interrupt
+ */
+#if !defined(CONFIG_PLAT_USRV)
+#define PLD_IRQ_INT0           (OPSPUT_PLD_IRQ_BASE + 0)       /* None */
+#define PLD_IRQ_INT1           (OPSPUT_PLD_IRQ_BASE + 1)       /* reserved */
+#define PLD_IRQ_INT2           (OPSPUT_PLD_IRQ_BASE + 2)       /* reserved */
+#define PLD_IRQ_CFIREQ         (OPSPUT_PLD_IRQ_BASE + 3)       /* CF IREQ */
+#define PLD_IRQ_CFC_INSERT     (OPSPUT_PLD_IRQ_BASE + 4)       /* CF Insert */
+#define PLD_IRQ_CFC_EJECT      (OPSPUT_PLD_IRQ_BASE + 5)       /* CF Eject */
+#define PLD_IRQ_EXINT          (OPSPUT_PLD_IRQ_BASE + 6)       /* EXINT */
+#define PLD_IRQ_INT7           (OPSPUT_PLD_IRQ_BASE + 7)       /* reserved */
+#define PLD_IRQ_INT8           (OPSPUT_PLD_IRQ_BASE + 8)       /* reserved */
+#define PLD_IRQ_INT9           (OPSPUT_PLD_IRQ_BASE + 9)       /* reserved */
+#define PLD_IRQ_INT10          (OPSPUT_PLD_IRQ_BASE + 10)      /* reserved */
+#define PLD_IRQ_MMCCARD                (OPSPUT_PLD_IRQ_BASE + 11)      /* MMC Insert/Eject */
+#define PLD_IRQ_INT12          (OPSPUT_PLD_IRQ_BASE + 12)      /* reserved */
+#define PLD_IRQ_SC_ERROR       (OPSPUT_PLD_IRQ_BASE + 13)      /* SC error */
+#define PLD_IRQ_SC_RCV         (OPSPUT_PLD_IRQ_BASE + 14)      /* SC receive */
+#define PLD_IRQ_SC_SND         (OPSPUT_PLD_IRQ_BASE + 15)      /* SC send */
+#define PLD_IRQ_SIO0_RCV       (OPSPUT_PLD_IRQ_BASE + 16)      /* SIO receive */
+#define PLD_IRQ_SIO0_SND       (OPSPUT_PLD_IRQ_BASE + 17)      /* SIO send */
+#define PLD_IRQ_INT18          (OPSPUT_PLD_IRQ_BASE + 18)      /* reserved */
+#define PLD_IRQ_INT19          (OPSPUT_PLD_IRQ_BASE + 19)      /* reserved */
+#define PLD_IRQ_INT20          (OPSPUT_PLD_IRQ_BASE + 20)      /* reserved */
+#define PLD_IRQ_INT21          (OPSPUT_PLD_IRQ_BASE + 21)      /* reserved */
+#define PLD_IRQ_INT22          (OPSPUT_PLD_IRQ_BASE + 22)      /* reserved */
+#define PLD_IRQ_INT23          (OPSPUT_PLD_IRQ_BASE + 23)      /* reserved */
+#define PLD_IRQ_INT24          (OPSPUT_PLD_IRQ_BASE + 24)      /* reserved */
+#define PLD_IRQ_INT25          (OPSPUT_PLD_IRQ_BASE + 25)      /* reserved */
+#define PLD_IRQ_INT26          (OPSPUT_PLD_IRQ_BASE + 26)      /* reserved */
+#define PLD_IRQ_INT27          (OPSPUT_PLD_IRQ_BASE + 27)      /* reserved */
+#define PLD_IRQ_INT28          (OPSPUT_PLD_IRQ_BASE + 28)      /* reserved */
+#define PLD_IRQ_INT29          (OPSPUT_PLD_IRQ_BASE + 29)      /* reserved */
+#define PLD_IRQ_INT30          (OPSPUT_PLD_IRQ_BASE + 30)      /* reserved */
+#define PLD_IRQ_INT31          (OPSPUT_PLD_IRQ_BASE + 31)      /* reserved */
+
+#else  /* CONFIG_PLAT_USRV */
+
+#define PLD_IRQ_INT0           (OPSPUT_PLD_IRQ_BASE + 0)       /* None */
+#define PLD_IRQ_INT1           (OPSPUT_PLD_IRQ_BASE + 1)       /* reserved */
+#define PLD_IRQ_INT2           (OPSPUT_PLD_IRQ_BASE + 2)       /* reserved */
+#define PLD_IRQ_CF0            (OPSPUT_PLD_IRQ_BASE + 3)       /* CF0# */
+#define PLD_IRQ_CF1            (OPSPUT_PLD_IRQ_BASE + 4)       /* CF1# */
+#define PLD_IRQ_CF2            (OPSPUT_PLD_IRQ_BASE + 5)       /* CF2# */
+#define PLD_IRQ_CF3            (OPSPUT_PLD_IRQ_BASE + 6)       /* CF3# */
+#define PLD_IRQ_CF4            (OPSPUT_PLD_IRQ_BASE + 7)       /* CF4# */
+#define PLD_IRQ_INT8           (OPSPUT_PLD_IRQ_BASE + 8)       /* reserved */
+#define PLD_IRQ_INT9           (OPSPUT_PLD_IRQ_BASE + 9)       /* reserved */
+#define PLD_IRQ_INT10          (OPSPUT_PLD_IRQ_BASE + 10)      /* reserved */
+#define PLD_IRQ_INT11          (OPSPUT_PLD_IRQ_BASE + 11)      /* reserved */
+#define PLD_IRQ_UART0          (OPSPUT_PLD_IRQ_BASE + 12)      /* UARTIRQ0 */
+#define PLD_IRQ_UART1          (OPSPUT_PLD_IRQ_BASE + 13)      /* UARTIRQ1 */
+#define PLD_IRQ_INT14          (OPSPUT_PLD_IRQ_BASE + 14)      /* reserved */
+#define PLD_IRQ_INT15          (OPSPUT_PLD_IRQ_BASE + 15)      /* reserved */
+#define PLD_IRQ_SNDINT         (OPSPUT_PLD_IRQ_BASE + 16)      /* SNDINT# */
+#define PLD_IRQ_INT17          (OPSPUT_PLD_IRQ_BASE + 17)      /* reserved */
+#define PLD_IRQ_INT18          (OPSPUT_PLD_IRQ_BASE + 18)      /* reserved */
+#define PLD_IRQ_INT19          (OPSPUT_PLD_IRQ_BASE + 19)      /* reserved */
+#define PLD_IRQ_INT20          (OPSPUT_PLD_IRQ_BASE + 20)      /* reserved */
+#define PLD_IRQ_INT21          (OPSPUT_PLD_IRQ_BASE + 21)      /* reserved */
+#define PLD_IRQ_INT22          (OPSPUT_PLD_IRQ_BASE + 22)      /* reserved */
+#define PLD_IRQ_INT23          (OPSPUT_PLD_IRQ_BASE + 23)      /* reserved */
+#define PLD_IRQ_INT24          (OPSPUT_PLD_IRQ_BASE + 24)      /* reserved */
+#define PLD_IRQ_INT25          (OPSPUT_PLD_IRQ_BASE + 25)      /* reserved */
+#define PLD_IRQ_INT26          (OPSPUT_PLD_IRQ_BASE + 26)      /* reserved */
+#define PLD_IRQ_INT27          (OPSPUT_PLD_IRQ_BASE + 27)      /* reserved */
+#define PLD_IRQ_INT28          (OPSPUT_PLD_IRQ_BASE + 28)      /* reserved */
+#define PLD_IRQ_INT29          (OPSPUT_PLD_IRQ_BASE + 29)      /* reserved */
+#define PLD_IRQ_INT30          (OPSPUT_PLD_IRQ_BASE + 30)      /* reserved */
+
+#endif /* CONFIG_PLAT_USRV */
+
+#define PLD_ICUISTS            __reg16(PLD_BASE + 0x8002)
+#define PLD_ICUISTS_VECB_MASK  (0xf000)
+#define PLD_ICUISTS_VECB(x)    ((x) & PLD_ICUISTS_VECB_MASK)
+#define PLD_ICUISTS_ISN_MASK   (0x07c0)
+#define PLD_ICUISTS_ISN(x)     ((x) & PLD_ICUISTS_ISN_MASK)
+#define PLD_ICUIREQ0           __reg16(PLD_BASE + 0x8004)
+#define PLD_ICUIREQ1           __reg16(PLD_BASE + 0x8006)
+#define PLD_ICUCR1             __reg16(PLD_BASE + 0x8100)
+#define PLD_ICUCR2             __reg16(PLD_BASE + 0x8102)
+#define PLD_ICUCR3             __reg16(PLD_BASE + 0x8104)
+#define PLD_ICUCR4             __reg16(PLD_BASE + 0x8106)
+#define PLD_ICUCR5             __reg16(PLD_BASE + 0x8108)
+#define PLD_ICUCR6             __reg16(PLD_BASE + 0x810a)
+#define PLD_ICUCR7             __reg16(PLD_BASE + 0x810c)
+#define PLD_ICUCR8             __reg16(PLD_BASE + 0x810e)
+#define PLD_ICUCR9             __reg16(PLD_BASE + 0x8110)
+#define PLD_ICUCR10            __reg16(PLD_BASE + 0x8112)
+#define PLD_ICUCR11            __reg16(PLD_BASE + 0x8114)
+#define PLD_ICUCR12            __reg16(PLD_BASE + 0x8116)
+#define PLD_ICUCR13            __reg16(PLD_BASE + 0x8118)
+#define PLD_ICUCR14            __reg16(PLD_BASE + 0x811a)
+#define PLD_ICUCR15            __reg16(PLD_BASE + 0x811c)
+#define PLD_ICUCR16            __reg16(PLD_BASE + 0x811e)
+#define PLD_ICUCR17            __reg16(PLD_BASE + 0x8120)
+#define PLD_ICUCR_IEN          (0x1000)
+#define PLD_ICUCR_IREQ         (0x0100)
+#define PLD_ICUCR_ISMOD00      (0x0000)        /* Low edge */
+#define PLD_ICUCR_ISMOD01      (0x0010)        /* Low level */
+#define PLD_ICUCR_ISMOD02      (0x0020)        /* High edge */
+#define PLD_ICUCR_ISMOD03      (0x0030)        /* High level */
+#define PLD_ICUCR_ILEVEL0      (0x0000)
+#define PLD_ICUCR_ILEVEL1      (0x0001)
+#define PLD_ICUCR_ILEVEL2      (0x0002)
+#define PLD_ICUCR_ILEVEL3      (0x0003)
+#define PLD_ICUCR_ILEVEL4      (0x0004)
+#define PLD_ICUCR_ILEVEL5      (0x0005)
+#define PLD_ICUCR_ILEVEL6      (0x0006)
+#define PLD_ICUCR_ILEVEL7      (0x0007)
+
+/* Power Control of MMC and CF */
+#define PLD_CPCR               __reg16(PLD_BASE + 0x14000)
+#define PLD_CPCR_CF            0x0001
+#define PLD_CPCR_MMC           0x0002
+
+/* LED Control
+ *
+ * 1: DIP swich side
+ * 2: Reset switch side
+ */
+#define PLD_IOLEDCR            __reg16(PLD_BASE + 0x14002)
+#define PLD_IOLED_1_ON         0x001
+#define PLD_IOLED_1_OFF                0x000
+#define PLD_IOLED_2_ON         0x002
+#define PLD_IOLED_2_OFF                0x000
+
+/* DIP Switch
+ *  0: Write-protect of Flash Memory (0:protected, 1:non-protected)
+ *  1: -
+ *  2: -
+ *  3: -
+ */
+#define PLD_IOSWSTS            __reg16(PLD_BASE + 0x14004)
+#define        PLD_IOSWSTS_IOSW2       0x0200
+#define        PLD_IOSWSTS_IOSW1       0x0100
+#define        PLD_IOSWSTS_IOWP0       0x0001
+
+/* CRC */
+#define PLD_CRC7DATA           __reg16(PLD_BASE + 0x18000)
+#define PLD_CRC7INDATA         __reg16(PLD_BASE + 0x18002)
+#define PLD_CRC16DATA          __reg16(PLD_BASE + 0x18004)
+#define PLD_CRC16INDATA                __reg16(PLD_BASE + 0x18006)
+#define PLD_CRC16ADATA         __reg16(PLD_BASE + 0x18008)
+#define PLD_CRC16AINDATA       __reg16(PLD_BASE + 0x1800a)
+
+/* RTC */
+#define PLD_RTCCR              __reg16(PLD_BASE + 0x1c000)
+#define PLD_RTCBAUR            __reg16(PLD_BASE + 0x1c002)
+#define PLD_RTCWRDATA          __reg16(PLD_BASE + 0x1c004)
+#define PLD_RTCRDDATA          __reg16(PLD_BASE + 0x1c006)
+#define PLD_RTCRSTODT          __reg16(PLD_BASE + 0x1c008)
+
+/* SIO0 */
+#define PLD_ESIO0CR            __reg16(PLD_BASE + 0x20000)
+#define        PLD_ESIO0CR_TXEN        0x0001
+#define        PLD_ESIO0CR_RXEN        0x0002
+#define PLD_ESIO0MOD0          __reg16(PLD_BASE + 0x20002)
+#define        PLD_ESIO0MOD0_CTSS      0x0040
+#define        PLD_ESIO0MOD0_RTSS      0x0080
+#define PLD_ESIO0MOD1          __reg16(PLD_BASE + 0x20004)
+#define        PLD_ESIO0MOD1_LMFS      0x0010
+#define PLD_ESIO0STS           __reg16(PLD_BASE + 0x20006)
+#define        PLD_ESIO0STS_TEMP       0x0001
+#define        PLD_ESIO0STS_TXCP       0x0002
+#define        PLD_ESIO0STS_RXCP       0x0004
+#define        PLD_ESIO0STS_TXSC       0x0100
+#define        PLD_ESIO0STS_RXSC       0x0200
+#define PLD_ESIO0STS_TXREADY   (PLD_ESIO0STS_TXCP | PLD_ESIO0STS_TEMP)
+#define PLD_ESIO0INTCR         __reg16(PLD_BASE + 0x20008)
+#define        PLD_ESIO0INTCR_TXIEN    0x0002
+#define        PLD_ESIO0INTCR_RXCEN    0x0004
+#define PLD_ESIO0BAUR          __reg16(PLD_BASE + 0x2000a)
+#define PLD_ESIO0TXB           __reg16(PLD_BASE + 0x2000c)
+#define PLD_ESIO0RXB           __reg16(PLD_BASE + 0x2000e)
+
+/* SIM Card */
+#define PLD_SCCR               __reg16(PLD_BASE + 0x38000)
+#define PLD_SCMOD              __reg16(PLD_BASE + 0x38004)
+#define PLD_SCSTS              __reg16(PLD_BASE + 0x38006)
+#define PLD_SCINTCR            __reg16(PLD_BASE + 0x38008)
+#define PLD_SCBAUR             __reg16(PLD_BASE + 0x3800a)
+#define PLD_SCTXB              __reg16(PLD_BASE + 0x3800c)
+#define PLD_SCRXB              __reg16(PLD_BASE + 0x3800e)
+
+#endif /* _OPSPUT_OPSPUT_PLD.H */
diff --git a/include/asm-m32r/page.h b/include/asm-m32r/page.h
new file mode 100644 (file)
index 0000000..ea2d1f9
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef _ASM_M32R_PAGE_H
+#define _ASM_M32R_PAGE_H
+
+#include <linux/config.h>
+
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT     12
+#define PAGE_SIZE      (1UL << PAGE_SHIFT)
+#define PAGE_MASK      (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+extern void clear_page(void *to);
+extern void copy_page(void *to, void *from);
+
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+#define pte_val(x)     ((x).pte)
+#define PTE_MASK       PAGE_MASK
+
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#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) } )
+
+#endif /* !__ASSEMBLY__ */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)       (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
+
+/*
+ * This handles the memory map.. We could make this a config
+ * option, but too many people screw it up, and too few need
+ * it.
+ *
+ * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
+ * a virtual address space of one gigabyte, which limits the
+ * amount of physical memory you can use to about 950MB.
+ *
+ * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
+ * and CONFIG_HIGHMEM64G options in the kernel configuration.
+ */
+
+
+/* This handles the memory map.. */
+
+#ifndef __ASSEMBLY__
+
+/* Pure 2^n version of get_order */
+static __inline__ int get_order(unsigned long size)
+{
+       int order;
+
+       size = (size - 1) >> (PAGE_SHIFT - 1);
+       order = -1;
+       do {
+               size >>= 1;
+               order++;
+       } while (size);
+
+       return order;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#define __MEMORY_START  CONFIG_MEMORY_START
+#define __MEMORY_SIZE   CONFIG_MEMORY_SIZE
+
+#ifdef CONFIG_MMU
+#define __PAGE_OFFSET  (0x80000000)
+#else
+#define __PAGE_OFFSET  (0x00000000)
+#endif
+
+#define PAGE_OFFSET            ((unsigned long)__PAGE_OFFSET)
+#define __pa(x)                        ((unsigned long)(x) - PAGE_OFFSET)
+#define __va(x)                        ((void *)((unsigned long)(x) + PAGE_OFFSET))
+
+#ifndef CONFIG_DISCONTIGMEM
+#define PFN_BASE               (CONFIG_MEMORY_START >> PAGE_SHIFT)
+#define pfn_to_page(pfn)       (mem_map + ((pfn) - PFN_BASE))
+#define page_to_pfn(page)      \
+       ((unsigned long)((page) - mem_map) + PFN_BASE)
+#define pfn_valid(pfn)         (((pfn) - PFN_BASE) < max_mapnr)
+#endif  /* !CONFIG_DISCONTIGMEM */
+
+#define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC )
+
+#define devmem_is_allowed(x) 1
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_M32R_PAGE_H */
+
diff --git a/include/asm-m32r/param.h b/include/asm-m32r/param.h
new file mode 100644 (file)
index 0000000..750b938
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _ASM_M32R_PARAM_H
+#define _ASM_M32R_PARAM_H
+
+/* $Id$ */
+
+/* orig : i386 2.5.67 */
+
+#ifdef __KERNEL__
+# define HZ            100             /* Internal kernel timer frequency */
+# define USER_HZ       100             /* .. some user interfaces are in "ticks" */
+# define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
+#endif
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE  4096
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#endif /* _ASM_M32R_PARAM_H */
+
diff --git a/include/asm-m32r/pci.h b/include/asm-m32r/pci.h
new file mode 100644 (file)
index 0000000..00d7b6f
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _ASM_M32R_PCI_H
+#define _ASM_M32R_PCI_H
+
+/* $Id$ */
+
+#include <asm-generic/pci.h>
+
+#define PCI_DMA_BUS_IS_PHYS    (1)
+
+#endif /* _ASM_M32R_PCI_H */
diff --git a/include/asm-m32r/percpu.h b/include/asm-m32r/percpu.h
new file mode 100644 (file)
index 0000000..e316930
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ARCH_M32R_PERCPU__
+#define __ARCH_M32R_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_M32R_PERCPU__ */
diff --git a/include/asm-m32r/pgalloc.h b/include/asm-m32r/pgalloc.h
new file mode 100644 (file)
index 0000000..8d5a444
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef _ASM_M32R_PGALLOC_H
+#define _ASM_M32R_PGALLOC_H
+
+/* $Id$ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+#define pmd_populate_kernel(mm, pmd, pte)      \
+       set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
+
+static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+       struct page *pte)
+{
+       set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
+}
+
+/*
+ * Allocate and free page tables.
+ */
+static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+       pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+       if (pgd)
+               clear_page(pgd);
+
+       return pgd;
+}
+
+static __inline__ void pgd_free(pgd_t *pgd)
+{
+       free_page((unsigned long)pgd);
+}
+
+static __inline__ pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+       unsigned long address)
+{
+       pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL);
+
+       if (pte)
+               clear_page(pte);
+
+       return pte;
+}
+
+static __inline__ struct page *pte_alloc_one(struct mm_struct *mm,
+       unsigned long address)
+{
+       struct page *pte = alloc_page(GFP_KERNEL);
+
+       if (pte)
+               clear_page(page_address(pte));
+
+       return pte;
+}
+
+static __inline__ void pte_free_kernel(pte_t *pte)
+{
+       free_page((unsigned long)pte);
+}
+
+static __inline__ void pte_free(struct page *pte)
+{
+       __free_page(pte);
+}
+
+#define __pte_free_tlb(tlb, pte)       pte_free((pte))
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ * (In the PAE case we free the pmds as part of the pgd.)
+ */
+
+#define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *)2); })
+#define pmd_free(x)                    do { } while (0)
+#define __pmd_free_tlb(tlb, x)         do { } while (0)
+#define pgd_populate(mm, pmd, pte)     BUG()
+
+#define check_pgt_cache()      do { } while (0)
+
+#endif /* _ASM_M32R_PGALLOC_H */
+
diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h
new file mode 100644 (file)
index 0000000..7755c2b
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _ASM_M32R_PGTABLE_2LEVEL_H
+#define _ASM_M32R_PGTABLE_2LEVEL_H
+
+/* $Id$ */
+
+#include <linux/config.h>
+
+/*
+ * traditional M32R two-level paging structure:
+ */
+
+#define PGDIR_SHIFT    22
+#define PTRS_PER_PGD   1024
+
+/*
+ * the M32R is two-level, so we don't really have any
+ * PMD directory physically.
+ */
+#define PMD_SHIFT      22
+#define PTRS_PER_PMD   1
+
+#define PTRS_PER_PTE   1024
+
+#define pte_ERROR(e) \
+       printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+       printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+       printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+static __inline__ int pgd_none(pgd_t pgd)      { return 0; }
+static __inline__ int pgd_bad(pgd_t pgd)       { return 0; }
+static __inline__ int pgd_present(pgd_t pgd)   { return 1; }
+#define pgd_clear(xp)                          do { } while (0)
+
+/*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
+/*
+ * (pmds are folded into pgds so this doesnt get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
+#define pgd_page(pgd) \
+((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
+
+static __inline__ pmd_t *pmd_offset(pgd_t * dir, unsigned long address)
+{
+       return (pmd_t *) dir;
+}
+
+#define ptep_get_and_clear(xp) __pte(xchg(&(xp)->pte, 0))
+#define pte_same(a, b)         (pte_val(a) == pte_val(b))
+#define pte_page(x)            pfn_to_page(pte_pfn(x))
+#define pte_none(x)            (!pte_val(x))
+#define pte_pfn(x)             (pte_val(x) >> PAGE_SHIFT)
+#define pfn_pte(pfn, prot)     __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot)     __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+/* M32R_FIXME : PTE_FILE_MAX_BITS, pte_to_pgoff, pgoff_to_pte */
+#define PTE_FILE_MAX_BITS      31
+#define pte_to_pgoff(pte)      (pte_val(pte) >> 1)
+#define pgoff_to_pte(off)      ((pte_t) { ((off) << 1) | _PAGE_FILE })
+
+#endif /* _ASM_M32R_PGTABLE_2LEVEL_H */
+
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
new file mode 100644 (file)
index 0000000..8894d84
--- /dev/null
@@ -0,0 +1,422 @@
+#ifndef _ASM_M32R_PGTABLE_H
+#define _ASM_M32R_PGTABLE_H
+
+/* $Id$ */
+
+/*
+ * The Linux memory management assumes a three-level page table setup. On
+ * the M32R, we use that, but "fold" the mid level into the top-level page
+ * table, so that we physically have the same two-level page table as the
+ * M32R mmu expects.
+ *
+ * This file contains the functions and defines necessary to modify and use
+ * the M32R page table tree.
+ */
+
+/* CAUTION!: If you change macro definitions in this file, you might have to
+ * change arch/m32r/mmu.S manually.
+ */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/addrspace.h>
+#include <asm/bitops.h>
+#include <asm/page.h>
+
+extern pgd_t swapper_pg_dir[1024];
+extern void paging_init(void);
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr)       (virt_to_page(empty_zero_page))
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * The Linux x86 paging architecture is 'compile-time dual-mode', it
+ * implements both the traditional 2-level x86 page tables and the
+ * newer 3-level PAE-mode page tables.
+ */
+#ifndef __ASSEMBLY__
+#include <asm/pgtable-2level.h>
+#endif
+
+#define pgtable_cache_init()   do { } while (0)
+
+#define PMD_SIZE       (1UL << PMD_SHIFT)
+#define PMD_MASK       (~(PMD_SIZE - 1))
+#define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK     (~(PGDIR_SIZE - 1))
+
+#define USER_PTRS_PER_PGD      (TASK_SIZE / PGDIR_SIZE)
+#define FIRST_USER_PGD_NR      0
+
+#ifndef __ASSEMBLY__
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_START          KSEG2
+#define VMALLOC_END            KSEG3
+
+/*
+ * The 4MB page is guessing..  Detailed in the infamous "Chapter H"
+ * of the Pentium details, but assuming intel did the straightforward
+ * thing, this bit set in the page directory entry just means that
+ * the page directory entry points directly to a 4MB-aligned block of
+ * memory.
+ */
+
+/*
+ *     M32R TLB format
+ *
+ *     [0]    [1:19]           [20:23]       [24:31]
+ *     +-----------------------+----+-------------+
+ *     |          VPN          |0000|    ASID     |
+ *     +-----------------------+----+-------------+
+ *     +-+---------------------+----+-+---+-+-+-+-+
+ *     |0         PPN          |0000|N|AC |L|G|V| |
+ *     +-+---------------------+----+-+---+-+-+-+-+
+ *                                     RWX
+ */
+
+#define _PAGE_BIT_DIRTY                0       /* software */
+#define _PAGE_BIT_FILE         0       /* when !present: nonlinear file
+                                          mapping */
+#define _PAGE_BIT_PRESENT      1       /* Valid */
+#define _PAGE_BIT_GLOBAL       2       /* Global */
+#define _PAGE_BIT_LARGE                3       /* Large */
+#define _PAGE_BIT_EXEC         4       /* Execute */
+#define _PAGE_BIT_WRITE                5       /* Write */
+#define _PAGE_BIT_READ         6       /* Read */
+#define _PAGE_BIT_NONCACHABLE  7       /* Non cachable */
+#define _PAGE_BIT_USER         8       /* software */
+#define _PAGE_BIT_ACCESSED     9       /* software */
+
+#define _PAGE_DIRTY    \
+       (1UL << _PAGE_BIT_DIRTY)        /* software : page changed */
+#define _PAGE_FILE     \
+       (1UL << _PAGE_BIT_FILE)         /* when !present: nonlinear file
+                                          mapping */
+#define _PAGE_PRESENT  \
+       (1UL << _PAGE_BIT_PRESENT)      /* Valid : Page is Valid */
+#define _PAGE_GLOBAL   \
+       (1UL << _PAGE_BIT_GLOBAL)       /* Global */
+#define _PAGE_LARGE    \
+       (1UL << _PAGE_BIT_LARGE)        /* Large */
+#define _PAGE_EXEC     \
+       (1UL << _PAGE_BIT_EXEC)         /* Execute */
+#define _PAGE_WRITE    \
+       (1UL << _PAGE_BIT_WRITE)        /* Write */
+#define _PAGE_READ     \
+       (1UL << _PAGE_BIT_READ)         /* Read */
+#define _PAGE_NONCACHABLE      \
+       (1UL<<_PAGE_BIT_NONCACHABLE)    /* Non cachable */
+#define _PAGE_USER     \
+       (1UL << _PAGE_BIT_USER)         /* software : user space access
+                                          allowed */
+#define _PAGE_ACCESSED \
+       (1UL << _PAGE_BIT_ACCESSED)     /* software : page referenced */
+
+#define _PAGE_TABLE    \
+       ( _PAGE_PRESENT | _PAGE_WRITE | _PAGE_READ | _PAGE_USER \
+       | _PAGE_ACCESSED | _PAGE_DIRTY )
+#define _KERNPG_TABLE  \
+       ( _PAGE_PRESENT | _PAGE_WRITE | _PAGE_READ | _PAGE_ACCESSED \
+       | _PAGE_DIRTY )
+#define _PAGE_CHG_MASK \
+       ( PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY )
+
+#ifdef CONFIG_MMU
+#define PAGE_NONE      \
+       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_SHARED    \
+       __pgprot(_PAGE_PRESENT | _PAGE_WRITE | _PAGE_READ | _PAGE_USER \
+               | _PAGE_ACCESSED)
+#define PAGE_SHARED_X  \
+       __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_WRITE | _PAGE_READ \
+               | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY      \
+       __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_USER \
+               | _PAGE_ACCESSED)
+#define PAGE_COPY_X    \
+       __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_USER \
+               | _PAGE_ACCESSED)
+#define PAGE_READONLY  \
+       __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY_X        \
+       __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_USER \
+               | _PAGE_ACCESSED)
+
+#define __PAGE_KERNEL  \
+       ( _PAGE_PRESENT | _PAGE_EXEC | _PAGE_WRITE | _PAGE_READ | _PAGE_DIRTY \
+       | _PAGE_ACCESSED )
+#define __PAGE_KERNEL_RO       ( __PAGE_KERNEL & ~_PAGE_WRITE )
+#define __PAGE_KERNEL_NOCACHE  ( __PAGE_KERNEL | _PAGE_NONCACHABLE)
+
+#define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
+
+#define PAGE_KERNEL            MAKE_GLOBAL(__PAGE_KERNEL)
+#define PAGE_KERNEL_RO         MAKE_GLOBAL(__PAGE_KERNEL_RO)
+#define PAGE_KERNEL_NOCACHE    MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
+
+#else
+#define PAGE_NONE               __pgprot(0)
+#define PAGE_SHARED             __pgprot(0)
+#define PAGE_SHARED_X           __pgprot(0)
+#define PAGE_COPY               __pgprot(0)
+#define PAGE_COPY_X             __pgprot(0)
+#define PAGE_READONLY           __pgprot(0)
+#define PAGE_READONLY_X         __pgprot(0)
+
+#define PAGE_KERNEL             __pgprot(0)
+#define PAGE_KERNEL_RO          __pgprot(0)
+#define PAGE_KERNEL_NOCACHE     __pgprot(0)
+#endif /* CONFIG_MMU */
+
+/*
+ * The i386 can't do page protection for execute, and considers that
+ * the same are read. Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ */
+       /* rwx */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY_X
+#define __P010 PAGE_COPY_X
+#define __P011 PAGE_COPY_X
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY_X
+#define __P110 PAGE_COPY_X
+#define __P111 PAGE_COPY_X
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY_X
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED_X
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY_X
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED_X
+
+/* page table for 0-4MB for everybody */
+
+#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
+#define pte_clear(xp)  do { set_pte(xp, __pte(0)); } while (0)
+
+#define pmd_none(x)    (!pmd_val(x))
+#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
+#define pmd_clear(xp)  do { set_pmd(xp, __pmd(0)); } while (0)
+#define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) \
+       != _KERNPG_TABLE)
+
+#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT))
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static __inline__ int pte_user(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_USER;
+}
+
+static __inline__ int pte_read(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_READ;
+}
+
+static __inline__ int pte_exec(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_EXEC;
+}
+
+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_write(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_WRITE;
+}
+
+/*
+ * The following only works if pte_present() is not true.
+ */
+static __inline__ int pte_file(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_FILE;
+}
+
+static __inline__ pte_t pte_rdprotect(pte_t pte)
+{
+       pte_val(pte) &= ~_PAGE_READ;
+       return pte;
+}
+
+static __inline__ pte_t pte_exprotect(pte_t pte)
+{
+       pte_val(pte) &= ~_PAGE_EXEC;
+       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_wrprotect(pte_t pte)
+{
+       pte_val(pte) &= ~_PAGE_WRITE;
+       return pte;
+}
+
+static __inline__ pte_t pte_mkread(pte_t pte)
+{
+       pte_val(pte) |= _PAGE_READ;
+       return pte;
+}
+
+static __inline__ pte_t pte_mkexec(pte_t pte)
+{
+       pte_val(pte) |= _PAGE_EXEC;
+       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_WRITE;
+       return pte;
+}
+
+static __inline__  int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+       return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
+}
+
+static __inline__  int ptep_test_and_clear_young(pte_t *ptep)
+{
+       return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
+}
+
+static __inline__ void ptep_set_wrprotect(pte_t *ptep)
+{
+       clear_bit(_PAGE_BIT_WRITE, ptep);
+}
+
+static __inline__ void ptep_mkdirty(pte_t *ptep)
+{
+       set_bit(_PAGE_BIT_DIRTY, ptep);
+}
+
+/*
+ * 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 mk_pte(page, pgprot)   pfn_pte(page_to_pfn(page), pgprot)
+
+static __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+       set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) \
+               | pgprot_val(newprot)));
+
+       return pte;
+}
+
+#define page_pte(page) page_pte_prot(page, __pgprot(0))
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+static __inline__ void pmd_set(pmd_t * pmdp, pte_t * ptep)
+{
+       pmd_val(*pmdp) = (((unsigned long) ptep) & PAGE_MASK);
+}
+
+#define pmd_page_kernel(pmd)   \
+       ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
+#ifndef CONFIG_DISCONTIGMEM
+#define pmd_page(pmd)  (mem_map + ((pmd_val(pmd) >> PAGE_SHIFT) - PFN_BASE))
+#endif /* !CONFIG_DISCONTIGMEM */
+
+/* to find an entry in a page-table-directory. */
+#define pgd_index(address)     \
+       (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+
+#define pgd_offset(mm, address)        ((mm)->pgd + pgd_index(address))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address)  pgd_offset(&init_mm, address)
+
+#define pmd_index(address)     \
+       (((address) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
+
+#define pte_index(address)     \
+       (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, address)        \
+       ((pte_t *)pmd_page_kernel(*(dir)) + pte_index(address))
+#define pte_offset_map(dir, address)   \
+       ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
+#define pte_offset_map_nested(dir, address)    pte_offset_map(dir, address)
+#define pte_unmap(pte)         do { } while (0)
+#define pte_unmap_nested(pte)  do { } while (0)
+
+/* Encode and de-code a swap entry */
+#define __swp_type(x)                  (((x).val >> 1) & 0x3f)
+#define __swp_offset(x)                        ((x).val >> 8)
+#define __swp_entry(type, offset)      \
+       ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define __pte_to_swp_entry(pte)                ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)          ((pte_t) { (x).val })
+
+#endif /* !__ASSEMBLY__ */
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define kern_addr_valid(addr)  (1)
+
+#define io_remap_page_range    remap_page_range
+
+#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 /* _ASM_M32R_PGTABLE_H */
+
diff --git a/include/asm-m32r/poll.h b/include/asm-m32r/poll.h
new file mode 100644 (file)
index 0000000..43b7acf
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _ASM_M32R_POLL_H
+#define _ASM_M32R_POLL_H
+
+/*
+ * poll(2) bit definitions.  Based on <asm-i386/poll.h>.
+ *
+ * Modified 2004
+ *      Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#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     0x0100
+#define POLLWRBAND     0x0200
+#define POLLMSG                0x0400
+#define POLLREMOVE     0x1000
+
+struct pollfd {
+       int fd;
+       short events;
+       short revents;
+};
+
+#endif  /* _ASM_M32R_POLL_H */
diff --git a/include/asm-m32r/posix_types.h b/include/asm-m32r/posix_types.h
new file mode 100644 (file)
index 0000000..47e7e85
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef _ASM_M32R_POSIX_TYPES_H
+#define _ASM_M32R_POSIX_TYPES_H
+
+/* $Id$ */
+
+/* orig : i386, sh 2.4.18 */
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned long  __kernel_ino_t;
+typedef unsigned short __kernel_mode_t;
+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 short __kernel_uid_t;
+typedef unsigned short __kernel_gid_t;
+typedef unsigned int   __kernel_size_t;
+typedef int            __kernel_ssize_t;
+typedef int            __kernel_ptrdiff_t;
+typedef long           __kernel_time_t;
+typedef long           __kernel_suseconds_t;
+typedef long           __kernel_clock_t;
+typedef int            __kernel_timer_t;
+typedef int            __kernel_clockid_t;
+typedef int            __kernel_daddr_t;
+typedef char *         __kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+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 {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+       int     val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+       int     __val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       __fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
+}
+
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
+{
+       unsigned long __tmp = __fd / __NFDBITS;
+       unsigned long __rem = __fd % __NFDBITS;
+       return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
+{
+       unsigned long *__tmp = __p->fds_bits;
+       int __i;
+
+       if (__builtin_constant_p(__FDSET_LONGS)) {
+               switch (__FDSET_LONGS) {
+               case 16:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       __tmp[ 4] = 0; __tmp[ 5] = 0;
+                       __tmp[ 6] = 0; __tmp[ 7] = 0;
+                       __tmp[ 8] = 0; __tmp[ 9] = 0;
+                       __tmp[10] = 0; __tmp[11] = 0;
+                       __tmp[12] = 0; __tmp[13] = 0;
+                       __tmp[14] = 0; __tmp[15] = 0;
+                       return;
+
+               case 8:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       __tmp[ 4] = 0; __tmp[ 5] = 0;
+                       __tmp[ 6] = 0; __tmp[ 7] = 0;
+                       return;
+
+               case 4:
+                       __tmp[ 0] = 0; __tmp[ 1] = 0;
+                       __tmp[ 2] = 0; __tmp[ 3] = 0;
+                       return;
+               }
+       }
+       __i = __FDSET_LONGS;
+       while (__i) {
+               __i--;
+               *__tmp = 0;
+               __tmp++;
+       }
+}
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
+#endif  /* _ASM_M32R_POSIX_TYPES_H */
diff --git a/include/asm-m32r/processor.h b/include/asm-m32r/processor.h
new file mode 100644 (file)
index 0000000..24caabe
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef _ASM_M32R_PROCESSOR_H
+#define _ASM_M32R_PROCESSOR_H
+
+/* $Id$ */
+
+/*
+ * 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  by Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ */
+
+/*
+ * include/asm-m32r/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <asm/cache.h>
+#include <asm/ptrace.h>  /* pt_regs */
+
+#include <asm/cachectl.h>
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l; })
+
+/*
+ *  CPU type and hardware bug flags. Kept separately for each CPU.
+ *  Members of this structure are referenced in head.S, so think twice
+ *  before touching them. [mj]
+ */
+
+struct cpuinfo_m32r {
+       unsigned long pgtable_cache_sz;
+       unsigned long cpu_clock;
+       unsigned long bus_clock;
+       unsigned long timer_divide;
+       unsigned long loops_per_jiffy;
+};
+
+/*
+ * capabilities of CPUs
+ */
+
+extern struct cpuinfo_m32r boot_cpu_data;
+
+#ifdef CONFIG_SMP
+extern struct cpuinfo_m32r cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else
+#define cpu_data &boot_cpu_data
+#define current_cpu_data boot_cpu_data
+#endif
+
+/*
+ * User space process size: 2GB (default).
+ */
+#ifdef CONFIG_MMU
+#define TASK_SIZE  (0x80000000UL)
+#else
+#define TASK_SIZE  (0x00400000UL)
+#endif
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE     PAGE_ALIGN(TASK_SIZE / 3)
+
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
+
+struct debug_trap {
+       int nr_trap;
+       unsigned long   addr;
+       unsigned long   insn;
+};
+
+struct thread_struct {
+       unsigned long address;
+       unsigned long trap_no;          /* Trap number  */
+       unsigned long error_code;       /* Error code of trap */
+       unsigned long lr;               /* saved pc */
+       unsigned long sp;               /* user stack pointer */
+       struct debug_trap debug_trap;
+};
+
+#define INIT_SP        (sizeof(init_stack) + (unsigned long) &init_stack)
+
+#define INIT_THREAD    {       \
+       .sp = INIT_SP,          \
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+
+/* User process Backup PSW */
+#define USERPS_BPSW (M32R_PSW_BSM|M32R_PSW_BIE|M32R_PSW_BPM)
+
+#define start_thread(regs, new_pc, new_spu)                            \
+       do {                                                            \
+               set_fs(USER_DS);                                        \
+               regs->psw = (regs->psw | USERPS_BPSW) & 0x0000FFFFUL;   \
+               regs->bpc = new_pc;                                     \
+               regs->spu = new_spu;                                    \
+       } while (0)
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+struct mm_struct;
+
+/* Free all resources held by a thread. */
+extern void release_thread(struct task_struct *);
+
+#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 */
+extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
+extern void release_segments(struct mm_struct * mm);
+
+extern unsigned long thread_saved_pc(struct task_struct *);
+
+/* 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)
+
+unsigned long get_wchan(struct task_struct *p);
+#define KSTK_EIP(tsk)  ((tsk)->thread.lr)
+#define KSTK_ESP(tsk)  ((tsk)->thread.sp)
+
+#define THREAD_SIZE (2*PAGE_SIZE)
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static __inline__ void rep_nop(void)
+{
+       __asm__ __volatile__(
+               "nop \n\t"
+               "nop \n\t"
+               :
+               :
+               : "memory");
+}
+
+#define cpu_relax()     rep_nop()
+
+#endif /* _ASM_M32R_PROCESSOR_H */
diff --git a/include/asm-m32r/ptrace.h b/include/asm-m32r/ptrace.h
new file mode 100644 (file)
index 0000000..9764171
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef _ASM_M32R_PTRACE_H
+#define _ASM_M32R_PTRACE_H
+
+/*
+ * linux/include/asm-m32r/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.
+ *
+ * M32R version:
+ *   Copyright (C) 2001-2002, 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>          /* M32R_PSW_BSM, M32R_PSW_BPM */
+
+/* 0 - 13 are integer registers (general purpose registers).  */
+#define PT_R4          0
+#define PT_R5          1
+#define PT_R6          2
+#define PT_REGS        3
+#define PT_R0          4
+#define PT_R1          5
+#define PT_R2          6
+#define PT_R3          7
+#define PT_R7          8
+#define PT_R8          9
+#define PT_R9          10
+#define PT_R10         11
+#define PT_R11         12
+#define PT_R12         13
+#define PT_SYSCNR      14
+#define PT_R13         PT_FP
+#define PT_R14         PT_LR
+#define PT_R15         PT_SP
+
+/* processor status and miscellaneous context registers.  */
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+#define PT_ACC0H       15
+#define PT_ACC0L       16
+#define PT_ACC1H       17
+#define PT_ACC1L       18
+#define PT_ACCH                PT_ACC0H
+#define PT_ACCL                PT_ACC0L
+#define PT_PSW         19
+#define PT_BPC         20
+#define PT_BBPSW       21
+#define PT_BBPC                22
+#define PT_SPU         23
+#define PT_FP          24
+#define PT_LR          25
+#define PT_SPI         26
+#define PT_ORIGR0      27
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+#define PT_ACCH                15
+#define PT_ACCL                16
+#define PT_PSW         17
+#define PT_BPC         18
+#define PT_BBPSW       19
+#define PT_BBPC                20
+#define PT_SPU         21
+#define PT_FP          22
+#define PT_LR          23
+#define PT_SPI         24
+#define PT_ORIGR0      25
+#else
+#error unknown isa conifiguration
+#endif
+
+/* virtual pt_reg entry for gdb */
+#define PT_PC          30
+#define PT_CBR         31
+#define PT_EVB         32
+
+
+/* Control registers.  */
+#define SPR_CR0 PT_PSW
+#define SPR_CR1 PT_CBR         /* read only */
+#define SPR_CR2 PT_SPI
+#define SPR_CR3 PT_SPU
+#define SPR_CR4
+#define SPR_CR5 PT_EVB         /* part of M32R/E, M32R/I core only */
+#define SPR_CR6 PT_BPC
+#define SPR_CR7
+#define SPR_CR8 PT_BBPSW
+#define SPR_CR9
+#define SPR_CR10
+#define SPR_CR11
+#define SPR_CR12
+#define SPR_CR13 PT_WR
+#define SPR_CR14 PT_BBPC
+#define SPR_CR15
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+struct pt_regs {
+       /* Saved main processor registers. */
+       unsigned long r4;
+       unsigned long r5;
+       unsigned long r6;
+       struct pt_regs *pt_regs;
+       unsigned long r0;
+       unsigned long r1;
+       unsigned long r2;
+       unsigned long r3;
+       unsigned long r7;
+       unsigned long r8;
+       unsigned long r9;
+       unsigned long r10;
+       unsigned long r11;
+       unsigned long r12;
+       long syscall_nr;
+
+       /* Saved main processor status and miscellaneous context registers. */
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       unsigned long acc0h;
+       unsigned long acc0l;
+       unsigned long acc1h;
+       unsigned long acc1l;
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       unsigned long acch;
+       unsigned long accl;
+#else
+#error unknown isa configuration
+#endif
+       unsigned long psw;
+       unsigned long bpc;              /* saved PC for TRAP syscalls */
+       unsigned long bbpsw;
+       unsigned long bbpc;
+       unsigned long spu;              /* saved user stack */
+       unsigned long fp;
+       unsigned long lr;               /* saved PC for JL syscalls */
+       unsigned long spi;              /* saved kernel stack */
+       unsigned long orig_r0;
+};
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS         12
+#define PTRACE_SETREGS         13
+
+#define PTRACE_OLDSETOPTIONS   21
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD  0x00000001
+
+#ifdef __KERNEL__
+#if defined(CONFIG_ISA_M32R2) || defined(CONFIG_CHIP_VDEC2)
+#define user_mode(regs) ((M32R_PSW_BPM & (regs)->psw) != 0)
+#elif defined(CONFIG_ISA_M32R)
+#define user_mode(regs) ((M32R_PSW_BSM & (regs)->psw) != 0)
+#else
+#error unknown isa configuration
+#endif
+
+#define instruction_pointer(regs) ((regs)->bpc)
+#define profile_pc(regs) instruction_pointer(regs)
+
+extern void show_regs(struct pt_regs *);
+
+extern void withdraw_debug_trap(struct pt_regs *regs);
+
+#endif /* __KERNEL */
+
+#endif /* _ASM_M32R_PTRACE_H */
diff --git a/include/asm-m32r/resource.h b/include/asm-m32r/resource.h
new file mode 100644 (file)
index 0000000..69ece06
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _ASM_M32R_RESOURCE_H
+#define _ASM_M32R_RESOURCE_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * Resource limits
+ */
+
+#define RLIMIT_CPU     0               /* CPU time in ms */
+#define RLIMIT_FSIZE   1               /* Maximum filesize */
+#define RLIMIT_DATA    2               /* max data size */
+#define RLIMIT_STACK   3               /* max stack size */
+#define RLIMIT_CORE    4               /* max core file size */
+#define RLIMIT_RSS     5               /* max resident set size */
+#define RLIMIT_NPROC   6               /* max number of processes */
+#define RLIMIT_NOFILE  7               /* max number of open files */
+#define RLIMIT_MEMLOCK 8               /* max locked-in-memory address space */
+#define RLIMIT_AS      9               /* address space limit */
+#define RLIMIT_LOCKS   10              /* maximum file locks held */
+#define RLIMIT_SIGPENDING 11           /* max number of pending signals */
+#define RLIMIT_MSGQUEUE        12              /* maximum bytes in POSIX mqueues */
+
+#define RLIM_NLIMITS   13
+
+/*
+ * SuS says limits have to be unsigned.
+ * Which makes a ton more sense anyway.
+ */
+#define RLIM_INFINITY  (~0UL)
+
+#ifdef __KERNEL__
+
+#define INIT_RLIMITS                                   \
+{                                                      \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       {      _STK_LIM, RLIM_INFINITY },               \
+       {             0, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       {             0,             0 },               \
+       {      INR_OPEN,     INR_OPEN  },               \
+       { MLOCK_LIMIT,   MLOCK_LIMIT   },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { RLIM_INFINITY, RLIM_INFINITY },               \
+       { MAX_SIGPENDING, MAX_SIGPENDING },             \
+       { MQ_BYTES_MAX, MQ_BYTES_MAX },                 \
+}
+
+#endif /* __KERNEL__ */
+
+#endif  /* _ASM_M32R_RESOURCE_H */
diff --git a/include/asm-m32r/rtc.h b/include/asm-m32r/rtc.h
new file mode 100644 (file)
index 0000000..3696bb1
--- /dev/null
@@ -0,0 +1,70 @@
+/* $Id: rtc.h,v 1.1.1.1 2004/03/25 04:29:22 hitoshiy Exp $ */
+
+#ifndef __RTC_H__
+#define __RTC_H__
+
+
+#include <linux/config.h>
+
+   /* Dallas DS1302 clock/calendar register numbers. */
+#  define RTC_SECONDS      0
+#  define RTC_MINUTES      1
+#  define RTC_HOURS        2
+#  define RTC_DAY_OF_MONTH 3
+#  define RTC_MONTH        4
+#  define RTC_WEEKDAY      5
+#  define RTC_YEAR         6
+#  define RTC_CONTROL      7
+
+   /* Bits in CONTROL register. */
+#  define RTC_CONTROL_WRITEPROTECT     0x80
+#  define RTC_TRICKLECHARGER           8
+
+  /* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS. */
+#  define RTC_TCR_PATTERN      0xA0    /* 1010xxxx */
+#  define RTC_TCR_1DIOD        0x04    /* xxxx01xx */
+#  define RTC_TCR_2DIOD        0x08    /* xxxx10xx */
+#  define RTC_TCR_DISABLED     0x00    /* xxxxxx00 Disabled */
+#  define RTC_TCR_2KOHM        0x01    /* xxxxxx01 2KOhm */
+#  define RTC_TCR_4KOHM        0x02    /* xxxxxx10 4kOhm */
+#  define RTC_TCR_8KOHM        0x03    /* xxxxxx11 8kOhm */
+
+#ifdef CONFIG_M32700UT_DS1302
+extern unsigned char ds1302_readreg(int reg);
+extern void ds1302_writereg(int reg, unsigned char val);
+extern int ds1302_init(void);
+#  define CMOS_READ(x) ds1302_readreg(x)
+#  define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
+#  define RTC_INIT() ds1302_init()
+#else
+  /* No RTC configured so we shouldn't try to access any. */
+#  define CMOS_READ(x) 42
+#  define CMOS_WRITE(x,y)
+#  define RTC_INIT() (-1)
+#endif
+
+/*
+ * The struct used to pass data via the following ioctl. Similar to the
+ * struct tm in <time.h>, but it needs to be here so that the kernel
+ * source is self contained, allowing cross-compiles, etc. etc.
+ */
+struct rtc_time {
+       int tm_sec;
+       int tm_min;
+       int tm_hour;
+       int tm_mday;
+       int tm_mon;
+       int tm_year;
+       int tm_wday;
+       int tm_yday;
+       int tm_isdst;
+};
+
+/* ioctl() calls that are permitted to the /dev/rtc interface. */
+#define RTC_MAGIC 'p'
+#define RTC_RD_TIME            _IOR(RTC_MAGIC, 0x09, struct rtc_time)  /* Read RTC time. */
+#define RTC_SET_TIME           _IOW(RTC_MAGIC, 0x0a, struct rtc_time)  /* Set RTC time. */
+#define RTC_SET_CHARGE         _IOW(RTC_MAGIC, 0x0b, int)
+#define RTC_MAX_IOCTL 0x0b
+
+#endif /* __RTC_H__ */
diff --git a/include/asm-m32r/scatterlist.h b/include/asm-m32r/scatterlist.h
new file mode 100644 (file)
index 0000000..09a10e4
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _ASM_M32R_SCATTERLIST_H
+#define _ASM_M32R_SCATTERLIST_H
+
+/* $Id$ */
+
+struct scatterlist {
+    char *  address;    /* Location data is to be transferred to, NULL for
+                         * highmem page */
+    struct page * page; /* Location for highmem page, if any */
+    unsigned int offset;/* for highmem, page offset */
+
+    dma_addr_t dma_address;
+    unsigned int length;
+};
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* _ASM_M32R_SCATTERLIST_H */
diff --git a/include/asm-m32r/sections.h b/include/asm-m32r/sections.h
new file mode 100644 (file)
index 0000000..6b969e5
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _M32R_SECTIONS_H
+#define _M32R_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+#endif /* _M32R_SECTIONS_H */
+
diff --git a/include/asm-m32r/segment.h b/include/asm-m32r/segment.h
new file mode 100644 (file)
index 0000000..e45db68
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _ASM_M32R_SEGMENT_H
+#define _ASM_M32R_SEGMENT_H
+
+/* $Id$ */
+
+/* orig : i386 (2.4.18) */
+
+#define __KERNEL_CS    0x10
+#define __KERNEL_DS    0x18
+
+#define __USER_CS      0x23
+#define __USER_DS      0x2B
+
+#endif  /* _ASM_M32R_SEGMENT_H */
diff --git a/include/asm-m32r/semaphore.h b/include/asm-m32r/semaphore.h
new file mode 100644 (file)
index 0000000..5aca12f
--- /dev/null
@@ -0,0 +1,214 @@
+#ifndef _ASM_M32R_SEMAPHORE_H
+#define _ASM_M32R_SEMAPHORE_H
+
+#include <linux/linkage.h>
+
+#ifdef __KERNEL__
+
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * Copyright (C) 1996  Linus Torvalds
+ * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/config.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+#undef LOAD
+#undef STORE
+#ifdef CONFIG_SMP
+#define LOAD   "lock"
+#define STORE  "unlock"
+#else
+#define LOAD   "ld"
+#define STORE  "st"
+#endif
+
+struct semaphore {
+       atomic_t count;
+       int sleepers;
+       wait_queue_head_t wait;
+};
+
+#define __SEMAPHORE_INITIALIZER(name, n)                               \
+{                                                                      \
+       .count          = ATOMIC_INIT(n),                               \
+       .sleepers       = 0,                                            \
+       .wait           = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)    \
+}
+
+#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)
+
+static 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);
+       sem->sleepers = 0;
+       init_waitqueue_head(&sem->wait);
+}
+
+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_failed(void /* special register calling convention */);
+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
+asmlinkage void __up_wakeup(void /* special register calling convention */);
+
+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);
+
+/*
+ * Atomically decrement the semaphore's count.  If it goes negative,
+ * block the calling thread in the TASK_UNINTERRUPTIBLE state.
+ */
+static inline void down(struct semaphore * sem)
+{
+       unsigned long flags;
+       long count;
+
+       might_sleep();
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# down                         \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "addi   %0, #-1;                \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (count)
+               : "r" (&sem->count)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       if (unlikely(count < 0))
+               __down(sem);
+}
+
+/*
+ * Interruptible try to acquire a semaphore.  If we obtained
+ * it, return zero.  If we were interrupted, returns -EINTR
+ */
+static inline int down_interruptible(struct semaphore * sem)
+{
+       unsigned long flags;
+       long count;
+       int result = 0;
+
+       might_sleep();
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# down_interruptible           \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "addi   %0, #-1;                \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (count)
+               : "r" (&sem->count)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       if (unlikely(count < 0))
+               result = __down_interruptible(sem);
+
+       return result;
+}
+
+/*
+ * Non-blockingly attempt to down() a semaphore.
+ * Returns zero if we acquired it
+ */
+static inline int down_trylock(struct semaphore * sem)
+{
+       unsigned long flags;
+       long count;
+       int result = 0;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# down_trylock                 \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "addi   %0, #-1;                \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (count)
+               : "r" (&sem->count)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       if (unlikely(count < 0))
+               result = __down_trylock(sem);
+
+       return result;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+static inline void up(struct semaphore * sem)
+{
+       unsigned long flags;
+       long count;
+
+       local_irq_save(flags);
+       __asm__ __volatile__ (
+               "# up                           \n\t"
+               DCACHE_CLEAR("%0", "r4", "%1")
+               LOAD"   %0, @%1;                \n\t"
+               "addi   %0, #1;                 \n\t"
+               STORE"  %0, @%1;                \n\t"
+               : "=&r" (count)
+               : "r" (&sem->count)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+       local_irq_restore(flags);
+
+       if (unlikely(count <= 0))
+               __up(sem);
+}
+
+#endif  /* __KERNEL__ */
+
+#endif  /* _ASM_M32R_SEMAPHORE_H */
diff --git a/include/asm-m32r/sembuf.h b/include/asm-m32r/sembuf.h
new file mode 100644 (file)
index 0000000..e69018e
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _ASM_M32R_SEMBUF_H
+#define _ASM_M32R_SEMBUF_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * The semid64_ds structure for m32r architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+       struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
+       __kernel_time_t sem_otime;              /* last semop time */
+       unsigned long   __unused1;
+       __kernel_time_t sem_ctime;              /* last change time */
+       unsigned long   __unused2;
+       unsigned long   sem_nsems;              /* no. of semaphores in array */
+       unsigned long   __unused3;
+       unsigned long   __unused4;
+};
+
+#endif /* _ASM_M32R_SEMBUF_H */
diff --git a/include/asm-m32r/serial.h b/include/asm-m32r/serial.h
new file mode 100644 (file)
index 0000000..bf14299
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef _ASM_M32R_SERIAL_H
+#define _ASM_M32R_SERIAL_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * include/asm-m32r/serial.h
+ */
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#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
+
+#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                  \
+       /* 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
+
+#ifndef CONFIG_PLAT_USRV
+#define SERIAL_PORT_DFNS               \
+       STD_SERIAL_PORT_DEFNS           \
+       EXTRA_SERIAL_PORT_DEFNS         \
+       HUB6_SERIAL_PORT_DFNS           \
+       MCA_SERIAL_PORT_DFNS
+
+#else  /* CONFIG_PLAT_USRV */
+
+#define SERIAL_PORT_DFNS               \
+       /* UART CLK   PORT IRQ     FLAGS        */                      \
+       { 0, BASE_BAUD, 0x3F8, PLD_IRQ_UART0, STD_COM_FLAGS },  /* ttyS0 */     \
+       { 0, BASE_BAUD, 0x2F8, PLD_IRQ_UART1, STD_COM_FLAGS },  /* ttyS1 */
+#endif /* CONFIG_PLAT_USRV */
+
+#endif  /* _ASM_M32R_SERIAL_H */
diff --git a/include/asm-m32r/setup.h b/include/asm-m32r/setup.h
new file mode 100644 (file)
index 0000000..5f028dc
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM                  ((unsigned char *)empty_zero_page)
+
+#define MOUNT_ROOT_RDONLY      (*(unsigned long *) (PARAM+0x000))
+#define RAMDISK_FLAGS          (*(unsigned long *) (PARAM+0x004))
+#define ORIG_ROOT_DEV          (*(unsigned long *) (PARAM+0x008))
+#define LOADER_TYPE            (*(unsigned long *) (PARAM+0x00c))
+#define INITRD_START           (*(unsigned long *) (PARAM+0x010))
+#define INITRD_SIZE            (*(unsigned long *) (PARAM+0x014))
+
+#define M32R_CPUCLK            (*(unsigned long *) (PARAM+0x018))
+#define M32R_BUSCLK            (*(unsigned long *) (PARAM+0x01c))
+#define M32R_TIMER_DIVIDE      (*(unsigned long *) (PARAM+0x020))
+
+#define COMMAND_LINE           ((char *) (PARAM+0x100))
+
+#define SCREEN_INFO            (*(struct screen_info *) (PARAM+0x200))
+
+#define COMMAND_LINE_SIZE      (512)
+
+#define RAMDISK_IMAGE_START_MASK       (0x07FF)
+#define RAMDISK_PROMPT_FLAG            (0x8000)
+#define RAMDISK_LOAD_FLAG              (0x4000)
+
+#define PFN_UP(x)      (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)    ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)    ((x) << PAGE_SHIFT)
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
diff --git a/include/asm-m32r/shmbuf.h b/include/asm-m32r/shmbuf.h
new file mode 100644 (file)
index 0000000..b84e897
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _ASM_M32R_SHMBUF_H
+#define _ASM_M32R_SHMBUF_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+/*
+ * The shmid64_ds structure for M32R architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+       struct ipc64_perm       shm_perm;       /* operation perms */
+       size_t                  shm_segsz;      /* size of segment (bytes) */
+       __kernel_time_t         shm_atime;      /* last attach time */
+       unsigned long           __unused1;
+       __kernel_time_t         shm_dtime;      /* last detach time */
+       unsigned long           __unused2;
+       __kernel_time_t         shm_ctime;      /* last change time */
+       unsigned long           __unused3;
+       __kernel_pid_t          shm_cpid;       /* pid of creator */
+       __kernel_pid_t          shm_lpid;       /* pid of last operator */
+       unsigned long           shm_nattch;     /* no. of current attaches */
+       unsigned long           __unused4;
+       unsigned long           __unused5;
+};
+
+struct shminfo64 {
+       unsigned long   shmmax;
+       unsigned long   shmmin;
+       unsigned long   shmmni;
+       unsigned long   shmseg;
+       unsigned long   shmall;
+       unsigned long   __unused1;
+       unsigned long   __unused2;
+       unsigned long   __unused3;
+       unsigned long   __unused4;
+};
+
+#endif /* _ASM_M32R_SHMBUF_H */
diff --git a/include/asm-m32r/shmparam.h b/include/asm-m32r/shmparam.h
new file mode 100644 (file)
index 0000000..db0019b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_M32R_SHMPARAM_H
+#define _ASM_M32R_SHMPARAM_H
+
+/* $Id$ */
+
+#define        SHMLBA PAGE_SIZE                 /* attach addr a multiple of this */
+
+#endif /* _ASM_M32R_SHMPARAM_H */
diff --git a/include/asm-m32r/sigcontext.h b/include/asm-m32r/sigcontext.h
new file mode 100644 (file)
index 0000000..c233e2d
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _ASM_M32R_SIGCONTEXT_H
+#define _ASM_M32R_SIGCONTEXT_H
+
+/* $Id$ */
+
+#include <linux/config.h>
+
+struct sigcontext {
+       /* CPU registers */
+       /* Saved main processor registers. */
+       unsigned long sc_r4;
+       unsigned long sc_r5;
+       unsigned long sc_r6;
+       struct pt_regs *sc_pt_regs;
+       unsigned long sc_r0;
+       unsigned long sc_r1;
+       unsigned long sc_r2;
+       unsigned long sc_r3;
+       unsigned long sc_r7;
+       unsigned long sc_r8;
+       unsigned long sc_r9;
+       unsigned long sc_r10;
+       unsigned long sc_r11;
+       unsigned long sc_r12;
+
+       /* Saved main processor status and miscellaneous context registers. */
+#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
+       unsigned long sc_acc0h;
+       unsigned long sc_acc0l;
+       unsigned long sc_acc1h;
+       unsigned long sc_acc1l;
+#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
+       unsigned long sc_acch;
+       unsigned long sc_accl;
+#else
+#error unknown isa configuration
+#endif
+       unsigned long sc_psw;
+       unsigned long sc_bpc;           /* saved PC for TRAP syscalls */
+       unsigned long sc_bbpsw;
+       unsigned long sc_bbpc;
+       unsigned long sc_spu;           /* saved user stack */
+       unsigned long sc_fp;
+       unsigned long sc_lr;            /* saved PC for JL syscalls */
+       unsigned long sc_spi;           /* saved kernel stack */
+
+       unsigned long   oldmask;
+};
+
+#endif  /* _ASM_M32R_SIGCONTEXT_H */
diff --git a/include/asm-m32r/siginfo.h b/include/asm-m32r/siginfo.h
new file mode 100644 (file)
index 0000000..482202f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _M32R_SIGINFO_H
+#define _M32R_SIGINFO_H
+
+/* $Id$ */
+
+#include <asm-generic/siginfo.h>
+
+#endif /* _M32R_SIGINFO_H */
diff --git a/include/asm-m32r/signal.h b/include/asm-m32r/signal.h
new file mode 100644 (file)
index 0000000..ce46eae
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef _ASM_M32R_SIGNAL_H
+#define _ASM_M32R_SIGNAL_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+#include <linux/types.h>
+#include <linux/linkage.h>
+#include <linux/time.h>
+#include <linux/compiler.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+#define _NSIG          64
+#define _NSIG_BPW      32
+#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t;            /* at least 32 bits */
+
+typedef struct {
+       unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG           32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/*
+#define SIGLOST                29
+*/
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#define SIGRTMAX       _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_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   0x00000001u
+#define SA_NOCLDWAIT   0x00000002u
+#define SA_SIGINFO     0x00000004u
+#define SA_ONSTACK     0x08000000u
+#define SA_RESTART     0x10000000u
+#define SA_NODEFER     0x40000000u
+#define SA_RESETHAND   0x80000000u
+
+#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
+
+#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 __signalfn_t(int);
+typedef __signalfn_t __user *__sighandler_t;
+
+typedef void __restorefn_t(void);
+typedef __restorefn_t __user *__sigrestore_t;
+
+#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;
+       __sigrestore_t sa_restorer;
+};
+
+struct sigaction {
+       __sighandler_t sa_handler;
+       unsigned long sa_flags;
+       __sigrestore_t sa_restorer;
+       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 __user *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+
+#undef __HAVE_ARCH_SIG_BITOPS
+
+struct pt_regs;
+extern int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+
+#define ptrace_signal_deliver(regs, cookie)    do { } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif  /* _ASM_M32R_SIGNAL_H */
diff --git a/include/asm-m32r/smp.h b/include/asm-m32r/smp.h
new file mode 100644 (file)
index 0000000..7857c8b
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef _ASM_M32R_SMP_H
+#define _ASM_M32R_SMP_H
+
+/* $Id$ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
+#ifndef __ASSEMBLY__
+
+#include <linux/cpumask.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <asm/m32r.h>
+
+#define PHYSID_ARRAY_SIZE       1
+
+struct physid_mask
+{
+       unsigned long mask[PHYSID_ARRAY_SIZE];
+};
+
+typedef struct physid_mask physid_mask_t;
+
+#define physid_set(physid, map)                 set_bit(physid, (map).mask)
+#define physid_clear(physid, map)               clear_bit(physid, (map).mask)
+#define physid_isset(physid, map)               test_bit(physid, (map).mask)
+#define physid_test_and_set(physid, map)        test_and_set_bit(physid, (map).mask)
+
+#define physids_and(dst, src1, src2)            bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
+#define physids_or(dst, src1, src2)             bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
+#define physids_clear(map)                      bitmap_zero((map).mask, MAX_APICS)
+#define physids_complement(dst, src)            bitmap_complement((dst).mask,(src).mask, MAX_APICS)
+#define physids_empty(map)                      bitmap_empty((map).mask, MAX_APICS)
+#define physids_equal(map1, map2)               bitmap_equal((map1).mask, (map2).mask, MAX_APICS)
+#define physids_weight(map)                     bitmap_weight((map).mask, MAX_APICS)
+#define physids_shift_right(d, s, n)            bitmap_shift_right((d).mask, (s).mask, n, MAX_APICS)
+#define physids_shift_left(d, s, n)             bitmap_shift_left((d).mask, (s).mask, n, MAX_APICS)
+#define physids_coerce(map)                     ((map).mask[0])
+
+#define physids_promote(physids)                                       \
+       ({                                                              \
+               physid_mask_t __physid_mask = PHYSID_MASK_NONE;         \
+               __physid_mask.mask[0] = physids;                        \
+               __physid_mask;                                          \
+       })
+
+#define physid_mask_of_physid(physid)                                  \
+       ({                                                              \
+               physid_mask_t __physid_mask = PHYSID_MASK_NONE;         \
+               physid_set(physid, __physid_mask);                      \
+               __physid_mask;                                          \
+       })
+
+#define PHYSID_MASK_ALL         { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} }
+#define PHYSID_MASK_NONE        { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} }
+
+extern physid_mask_t phys_cpu_present_map;
+
+/*
+ * Some lowlevel functions might want to know about
+ * the real CPU ID <-> CPU # mapping.
+ */
+extern volatile int physid_2_cpu[NR_CPUS];
+extern volatile int cpu_2_physid[NR_CPUS];
+#define physid_to_cpu(physid)  physid_2_cpu[physid]
+#define cpu_to_physid(cpu_id)  cpu_2_physid[cpu_id]
+
+#define smp_processor_id()     (current_thread_info()->cpu)
+
+extern cpumask_t cpu_callout_map;
+#define cpu_possible_map cpu_callout_map
+
+static __inline__ int hard_smp_processor_id(void)
+{
+       return (int)*(volatile long *)M32R_CPUID_PORTL;
+}
+
+static __inline__ int cpu_logical_map(int cpu)
+{
+       return cpu;
+}
+
+static __inline__ int cpu_number_map(int cpu)
+{
+       return cpu;
+}
+
+static __inline__ unsigned int num_booting_cpus(void)
+{
+       return cpus_weight(cpu_callout_map);
+}
+
+extern void smp_send_timer(void);
+extern void calibrate_delay(void);
+extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
+
+#endif /* not __ASSEMBLY__ */
+
+#define NO_PROC_ID (0xff)      /* No processor magic marker */
+
+#define PROC_CHANGE_PENALTY    (15)    /* Schedule penalty */
+
+/*
+ * M32R-mp IPI
+ */
+#define RESCHEDULE_IPI         (M32R_IRQ_IPI0-M32R_IRQ_IPI0)
+#define INVALIDATE_TLB_IPI     (M32R_IRQ_IPI1-M32R_IRQ_IPI0)
+#define CALL_FUNCTION_IPI      (M32R_IRQ_IPI2-M32R_IRQ_IPI0)
+#define LOCAL_TIMER_IPI                (M32R_IRQ_IPI3-M32R_IRQ_IPI0)
+#define INVALIDATE_CACHE_IPI   (M32R_IRQ_IPI4-M32R_IRQ_IPI0)
+#define CPU_BOOT_IPI           (M32R_IRQ_IPI5-M32R_IRQ_IPI0)
+
+#define IPI_SHIFT      (0)
+#define NR_IPIS                (8)
+
+#endif /* CONFIG_SMP */
+
+#endif /* _ASM_M32R_SMP_H */
diff --git a/include/asm-m32r/socket.h b/include/asm-m32r/socket.h
new file mode 100644 (file)
index 0000000..159519d
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _ASM_M32R_SOCKET_H
+#define _ASM_M32R_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 /* _ASM_M32R_SOCKET_H */
diff --git a/include/asm-m32r/sockios.h b/include/asm-m32r/sockios.h
new file mode 100644 (file)
index 0000000..147a118
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _ASM_M32R_SOCKIOS_H
+#define _ASM_M32R_SOCKIOS_H
+
+/* $Id$ */
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN      0x8901
+#define SIOCSPGRP      0x8902
+#define FIOGETOWN      0x8903
+#define SIOCGPGRP      0x8904
+#define SIOCATMARK     0x8905
+#define SIOCGSTAMP     0x8906          /* Get stamp */
+
+#endif  /* _ASM_M32R_SOCKIOS_H */
diff --git a/include/asm-m32r/spinlock.h b/include/asm-m32r/spinlock.h
new file mode 100644 (file)
index 0000000..6fd012a
--- /dev/null
@@ -0,0 +1,382 @@
+#ifndef _ASM_M32R_SPINLOCK_H
+#define _ASM_M32R_SPINLOCK_H
+
+/*
+ *  linux/include/asm-m32r/spinlock.h
+ *
+ *  M32R version:
+ *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#include <linux/config.h>      /* CONFIG_DEBUG_SPINLOCK, CONFIG_SMP */
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+
+extern int printk(const char * fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+#define RW_LOCK_BIAS            0x01000000
+#define RW_LOCK_BIAS_STR       "0x01000000"
+
+/* It seems that people are forgetting to
+ * initialize their spinlocks properly, tsk tsk.
+ * Remember to turn this off in 2.4. -ben
+ */
+#if defined(CONFIG_DEBUG_SPINLOCK)
+#define SPINLOCK_DEBUG 1
+#else
+#define SPINLOCK_DEBUG 0
+#endif
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+       volatile int lock;
+#if SPINLOCK_DEBUG
+       unsigned magic;
+#endif
+#ifdef CONFIG_PREEMPT
+       unsigned int break_lock;
+#endif
+} spinlock_t;
+
+#define SPINLOCK_MAGIC 0xdead4ead
+
+#if SPINLOCK_DEBUG
+#define SPINLOCK_MAGIC_INIT    , SPINLOCK_MAGIC
+#else
+#define SPINLOCK_MAGIC_INIT    /* */
+#endif
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
+
+#define spin_lock_init(x)      do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define spin_is_locked(x)      (*(volatile int *)(&(x)->lock) <= 0)
+#define spin_unlock_wait(x)    do { barrier(); } while(spin_is_locked(x))
+#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
+
+/**
+ * _raw_spin_trylock - Try spin lock and return a result
+ * @lock: Pointer to the lock variable
+ *
+ * _raw_spin_trylock() tries to get the lock and returns a result.
+ * On the m32r, the result value is 1 (= Success) or 0 (= Failure).
+ */
+static inline int _raw_spin_trylock(spinlock_t *lock)
+{
+       int oldval;
+       unsigned long tmp1, tmp2;
+
+       /*
+        * lock->lock :  =1 : unlock
+        *            : <=0 : lock
+        * {
+        *   oldval = lock->lock; <--+ need atomic operation
+        *   lock->lock = 0;      <--+
+        * }
+        */
+       __asm__ __volatile__ (
+               "# spin_trylock                 \n\t"
+               "ldi    %1, #0;                 \n\t"
+               "mvfc   %2, psw;                \n\t"
+               "clrpsw #0x40 -> nop;           \n\t"
+               DCACHE_CLEAR("%0", "r6", "%3")
+               "lock   %0, @%3;                \n\t"
+               "unlock %1, @%3;                \n\t"
+               "mvtc   %2, psw;                \n\t"
+               : "=&r" (oldval), "=&r" (tmp1), "=&r" (tmp2)
+               : "r" (&lock->lock)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+
+       return (oldval > 0);
+}
+
+static inline void _raw_spin_lock(spinlock_t *lock)
+{
+       unsigned long tmp0, tmp1;
+
+#if SPINLOCK_DEBUG
+       __label__ here;
+here:
+       if (lock->magic != SPINLOCK_MAGIC) {
+               printk("eip: %p\n", &&here);
+               BUG();
+       }
+#endif
+       /*
+        * lock->lock :  =1 : unlock
+        *            : <=0 : lock
+        *
+        * for ( ; ; ) {
+        *   lock->lock -= 1;  <-- need atomic operation
+        *   if (lock->lock == 0) break;
+        *   for ( ; lock->lock <= 0 ; );
+        * }
+        */
+       __asm__ __volatile__ (
+               "# spin_lock                    \n\t"
+               ".fillinsn                      \n"
+               "1:                             \n\t"
+               "mvfc   %1, psw;                \n\t"
+               "clrpsw #0x40 -> nop;           \n\t"
+               DCACHE_CLEAR("%0", "r6", "%2")
+               "lock   %0, @%2;                \n\t"
+               "addi   %0, #-1;                \n\t"
+               "unlock %0, @%2;                \n\t"
+               "mvtc   %1, psw;                \n\t"
+               "bltz   %0, 2f;                 \n\t"
+               LOCK_SECTION_START(".balign 4 \n\t")
+               ".fillinsn                      \n"
+               "2:                             \n\t"
+               "ld     %0, @%2;                \n\t"
+               "bgtz   %0, 1b;                 \n\t"
+               "bra    2b;                     \n\t"
+               LOCK_SECTION_END
+               : "=&r" (tmp0), "=&r" (tmp1)
+               : "r" (&lock->lock)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+}
+
+static inline void _raw_spin_unlock(spinlock_t *lock)
+{
+#if SPINLOCK_DEBUG
+       BUG_ON(lock->magic != SPINLOCK_MAGIC);
+       BUG_ON(!spin_is_locked(lock));
+#endif
+       mb();
+       lock->lock = 1;
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct {
+       volatile int lock;
+#if SPINLOCK_DEBUG
+       unsigned magic;
+#endif
+#ifdef CONFIG_PREEMPT
+       unsigned int break_lock;
+#endif
+} rwlock_t;
+
+#define RWLOCK_MAGIC   0xdeaf1eed
+
+#if SPINLOCK_DEBUG
+#define RWLOCK_MAGIC_INIT      , RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT      /* */
+#endif
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
+
+#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
+#define rwlock_is_locked(x)    ((x)->lock != RW_LOCK_BIAS)
+
+/*
+ * On x86, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+ *
+ * The inline assembly is non-obvious. Think about it.
+ *
+ * Changed to use the same technique as rw semaphores.  See
+ * semaphore.h for details.  -ben
+ */
+/* the spinlock helpers are in arch/i386/kernel/semaphore.c */
+
+static inline void _raw_read_lock(rwlock_t *rw)
+{
+       unsigned long tmp0, tmp1;
+
+#if SPINLOCK_DEBUG
+       BUG_ON(rw->magic != RWLOCK_MAGIC);
+#endif
+       /*
+        * rw->lock :  >0 : unlock
+        *          : <=0 : lock
+        *
+        * for ( ; ; ) {
+        *   rw->lock -= 1;  <-- need atomic operation
+        *   if (rw->lock >= 0) break;
+        *   rw->lock += 1;  <-- need atomic operation
+        *   for ( ; rw->lock <= 0 ; );
+        * }
+        */
+       __asm__ __volatile__ (
+               "# read_lock                    \n\t"
+               ".fillinsn                      \n"
+               "1:                             \n\t"
+               "mvfc   %1, psw;                \n\t"
+               "clrpsw #0x40 -> nop;           \n\t"
+               DCACHE_CLEAR("%0", "r6", "%2")
+               "lock   %0, @%2;                \n\t"
+               "addi   %0, #-1;                \n\t"
+               "unlock %0, @%2;                \n\t"
+               "mvtc   %1, psw;                \n\t"
+               "bltz   %0, 2f;                 \n\t"
+               LOCK_SECTION_START(".balign 4 \n\t")
+               ".fillinsn                      \n"
+               "2:                             \n\t"
+               "clrpsw #0x40 -> nop;           \n\t"
+               DCACHE_CLEAR("%0", "r6", "%2")
+               "lock   %0, @%2;                \n\t"
+               "addi   %0, #1;                 \n\t"
+               "unlock %0, @%2;                \n\t"
+               "mvtc   %1, psw;                \n\t"
+               ".fillinsn                      \n"
+               "3:                             \n\t"
+               "ld     %0, @%2;                \n\t"
+               "bgtz   %0, 1b;                 \n\t"
+               "bra    3b;                     \n\t"
+               LOCK_SECTION_END
+               : "=&r" (tmp0), "=&r" (tmp1)
+               : "r" (&rw->lock)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+}
+
+static inline void _raw_write_lock(rwlock_t *rw)
+{
+       unsigned long tmp0, tmp1, tmp2;
+
+#if SPINLOCK_DEBUG
+       BUG_ON(rw->magic != RWLOCK_MAGIC);
+#endif
+       /*
+        * rw->lock :  =RW_LOCK_BIAS_STR : unlock
+        *          : !=RW_LOCK_BIAS_STR : lock
+        *
+        * for ( ; ; ) {
+        *   rw->lock -= RW_LOCK_BIAS_STR;  <-- need atomic operation
+        *   if (rw->lock == 0) break;
+        *   rw->lock += RW_LOCK_BIAS_STR;  <-- need atomic operation
+        *   for ( ; rw->lock != RW_LOCK_BIAS_STR ; ) ;
+        * }
+        */
+       __asm__ __volatile__ (
+               "# write_lock                                   \n\t"
+               "seth   %1, #high(" RW_LOCK_BIAS_STR ");        \n\t"
+               "or3    %1, %1, #low(" RW_LOCK_BIAS_STR ");     \n\t"
+               ".fillinsn                                      \n"
+               "1:                                             \n\t"
+               "mvfc   %2, psw;                                \n\t"
+               "clrpsw #0x40 -> nop;                           \n\t"
+               DCACHE_CLEAR("%0", "r7", "%3")
+               "lock   %0, @%3;                                \n\t"
+               "sub    %0, %1;                                 \n\t"
+               "unlock %0, @%3;                                \n\t"
+               "mvtc   %2, psw;                                \n\t"
+               "bnez   %0, 2f;                                 \n\t"
+               LOCK_SECTION_START(".balign 4 \n\t")
+               ".fillinsn                                      \n"
+               "2:                                             \n\t"
+               "clrpsw #0x40 -> nop;                           \n\t"
+               DCACHE_CLEAR("%0", "r7", "%3")
+               "lock   %0, @%3;                                \n\t"
+               "add    %0, %1;                                 \n\t"
+               "unlock %0, @%3;                                \n\t"
+               "mvtc   %2, psw;                                \n\t"
+               ".fillinsn                                      \n"
+               "3:                                             \n\t"
+               "ld     %0, @%3;                                \n\t"
+               "beq    %0, %1, 1b;                             \n\t"
+               "bra    3b;                                     \n\t"
+               LOCK_SECTION_END
+               : "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2)
+               : "r" (&rw->lock)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r7"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+}
+
+static inline void _raw_read_unlock(rwlock_t *rw)
+{
+       unsigned long tmp0, tmp1;
+
+       __asm__ __volatile__ (
+               "# read_unlock                  \n\t"
+               "mvfc   %1, psw;                \n\t"
+               "clrpsw #0x40 -> nop;           \n\t"
+               DCACHE_CLEAR("%0", "r6", "%2")
+               "lock   %0, @%2;                \n\t"
+               "addi   %0, #1;                 \n\t"
+               "unlock %0, @%2;                \n\t"
+               "mvtc   %1, psw;                \n\t"
+               : "=&r" (tmp0), "=&r" (tmp1)
+               : "r" (&rw->lock)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r6"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+}
+
+static inline void _raw_write_unlock(rwlock_t *rw)
+{
+       unsigned long tmp0, tmp1, tmp2;
+
+       __asm__ __volatile__ (
+               "# write_unlock                                 \n\t"
+               "seth   %1, #high(" RW_LOCK_BIAS_STR ");        \n\t"
+               "or3    %1, %1, #low(" RW_LOCK_BIAS_STR ");     \n\t"
+               "mvfc   %2, psw;                                \n\t"
+               "clrpsw #0x40 -> nop;                           \n\t"
+               DCACHE_CLEAR("%0", "r7", "%3")
+               "lock   %0, @%3;                                \n\t"
+               "add    %0, %1;                                 \n\t"
+               "unlock %0, @%3;                                \n\t"
+               "mvtc   %2, psw;                                \n\t"
+               : "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2)
+               : "r" (&rw->lock)
+               : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+               , "r7"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+       );
+}
+
+#define _raw_read_trylock(lock) generic_raw_read_trylock(lock)
+
+static inline int _raw_write_trylock(rwlock_t *lock)
+{
+       atomic_t *count = (atomic_t *)lock;
+       if (atomic_sub_and_test(RW_LOCK_BIAS, count))
+               return 1;
+       atomic_add(RW_LOCK_BIAS, count);
+       return 0;
+}
+
+#endif /* _ASM_M32R_SPINLOCK_H */
diff --git a/include/asm-m32r/stat.h b/include/asm-m32r/stat.h
new file mode 100644 (file)
index 0000000..05748fe
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef _ASM_M32R_STAT_H
+#define _ASM_M32R_STAT_H
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+#include <asm/byteorder.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 glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat64 {
+       unsigned long long      st_dev;
+       unsigned char   __pad0[4];
+#define STAT64_HAS_BROKEN_ST_INO
+       unsigned long   __st_ino;
+
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       unsigned long long      st_rdev;
+       unsigned char   __pad3[4];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+#if defined(__BIG_ENDIAN)
+       unsigned long   __pad4;         /* future possible st_blocks high bits */
+       unsigned long   st_blocks;      /* Number 512-byte blocks allocated. */
+#elif defined(__LITTLE_ENDIAN)
+       unsigned long   st_blocks;      /* Number 512-byte blocks allocated. */
+       unsigned long   __pad4;         /* future possible st_blocks high bits */
+#else
+#error no endian defined
+#endif
+       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 long      st_ino;
+};
+
+#endif  /* _ASM_M32R_STAT_H */
diff --git a/include/asm-m32r/statfs.h b/include/asm-m32r/statfs.h
new file mode 100644 (file)
index 0000000..6eb4c60
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_M32R_STATFS_H
+#define _ASM_M32R_STATFS_H
+
+#include <asm-generic/statfs.h>
+
+#endif  /* _ASM_M32R_STATFS_H */
diff --git a/include/asm-m32r/string.h b/include/asm-m32r/string.h
new file mode 100644 (file)
index 0000000..cb54bcc
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _ASM_M32R_STRING_H
+#define _ASM_M32R_STRING_H
+
+/* $Id$ */
+
+#define  __HAVE_ARCH_STRLEN
+extern size_t strlen(const char * s);
+
+#define  __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
+
+#define  __HAVE_ARCH_MEMSET
+extern void *memset(void *__s, int __c, size_t __count);
+
+#endif  /* _ASM_M32R_STRING_H */
diff --git a/include/asm-m32r/syscall.h b/include/asm-m32r/syscall.h
new file mode 100644 (file)
index 0000000..d8d4b2c
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_M32R_SYSCALL_H
+#define _ASM_M32R_SYSCALL_H
+
+/* $Id$ */
+
+/* Definitions for the system call vector.  */
+#define SYSCALL_VECTOR          "2"
+#define SYSCALL_VECTOR_ADDRESS  "0xa0"
+
+#endif /* _ASM_M32R_SYSCALL_H */
+
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
new file mode 100644 (file)
index 0000000..cca922a
--- /dev/null
@@ -0,0 +1,301 @@
+#ifndef _ASM_M32R_SYSTEM_H
+#define _ASM_M32R_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  by Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ */
+
+#include <linux/config.h>
+
+#ifdef __KERNEL__
+
+/*
+ * switch_to(prev, next) should switch from task `prev' to `next'
+ * `prev' will never be the same as `next'.
+ *
+ * `next' and `prev' should be struct task_struct, but it isn't always defined
+ */
+
+#ifndef CONFIG_SMP
+#define prepare_to_switch()  do { } while(0)
+#endif /* not CONFIG_SMP */
+
+#define switch_to(prev, next, last)  do { \
+       register unsigned long  arg0 __asm__ ("r0") = (unsigned long)prev; \
+       register unsigned long  arg1 __asm__ ("r1") = (unsigned long)next; \
+       register unsigned long  *oldsp __asm__ ("r2") = &(prev->thread.sp); \
+       register unsigned long  *newsp __asm__ ("r3") = &(next->thread.sp); \
+       register unsigned long  *oldlr __asm__ ("r4") = &(prev->thread.lr); \
+       register unsigned long  *newlr __asm__ ("r5") = &(next->thread.lr); \
+       register struct task_struct  *__last __asm__ ("r6"); \
+       __asm__ __volatile__ ( \
+               "st     r8, @-r15                                 \n\t" \
+               "st     r9, @-r15                                 \n\t" \
+               "st    r10, @-r15                                 \n\t" \
+               "st    r11, @-r15                                 \n\t" \
+               "st    r12, @-r15                                 \n\t" \
+               "st    r13, @-r15                                 \n\t" \
+               "st    r14, @-r15                                 \n\t" \
+               "seth  r14, #high(1f)                             \n\t" \
+               "or3   r14, r14, #low(1f)                         \n\t" \
+               "st    r14, @r4    ; store old LR                 \n\t" \
+               "st    r15, @r2    ; store old SP                 \n\t" \
+               "ld    r15, @r3    ; load new SP                  \n\t" \
+               "st     r0, @-r15  ; store 'prev' onto new stack  \n\t" \
+               "ld    r14, @r5    ; load new LR                  \n\t" \
+               "jmp   r14                                        \n\t" \
+               ".fillinsn                                        \n  " \
+               "1:                                               \n\t" \
+               "ld     r6, @r15+  ; load 'prev' from new stack   \n\t" \
+               "ld    r14, @r15+                                 \n\t" \
+               "ld    r13, @r15+                                 \n\t" \
+               "ld    r12, @r15+                                 \n\t" \
+               "ld    r11, @r15+                                 \n\t" \
+               "ld    r10, @r15+                                 \n\t" \
+               "ld     r9, @r15+                                 \n\t" \
+               "ld     r8, @r15+                                 \n\t" \
+               : "=&r" (__last) \
+               : "r" (arg0), "r" (arg1), "r" (oldsp), "r" (newsp), \
+                 "r" (oldlr), "r" (newlr) \
+               : "memory" \
+       ); \
+       last = __last; \
+} while(0)
+
+/* Interrupt Control */
+#if !defined(CONFIG_CHIP_M32102)
+#define local_irq_enable() \
+       __asm__ __volatile__ ("setpsw #0x40 -> nop": : :"memory")
+#define local_irq_disable() \
+       __asm__ __volatile__ ("clrpsw #0x40 -> nop": : :"memory")
+#else  /* CONFIG_CHIP_M32102 */
+static __inline__ void local_irq_enable(void)
+{
+       unsigned long tmpreg;
+       __asm__ __volatile__(
+               "mvfc   %0, psw;                \n\t"
+               "or3    %0, %0, #0x0040;        \n\t"
+               "mvtc   %0, psw;                \n\t"
+       : "=&r" (tmpreg) : : "cbit", "memory");
+}
+
+static __inline__ void local_irq_disable(void)
+{
+       unsigned long tmpreg0, tmpreg1;
+       __asm__ __volatile__(
+               "ld24   %0, #0  ; Use 32-bit insn. \n\t"
+               "mvfc   %1, psw ; No interrupt can be accepted here. \n\t"
+               "mvtc   %0, psw \n\t"
+               "and3   %0, %1, #0xffbf \n\t"
+               "mvtc   %0, psw \n\t"
+       : "=&r" (tmpreg0), "=&r" (tmpreg1) : : "cbit", "memory");
+}
+#endif /* CONFIG_CHIP_M32102 */
+
+#define local_save_flags(x) \
+       __asm__ __volatile__("mvfc %0,psw" : "=r"(x) : /* no input */)
+
+#define local_irq_restore(x) \
+       __asm__ __volatile__("mvtc %0,psw" : /* no outputs */ \
+               : "r" (x) : "cbit", "memory")
+
+#if !defined(CONFIG_CHIP_M32102)
+#define local_irq_save(x)                              \
+       __asm__ __volatile__(                           \
+               "mvfc   %0, psw;                \n\t"   \
+               "clrpsw #0x40 -> nop;           \n\t"   \
+               : "=r" (x) : /* no input */ : "memory")
+#else  /* CONFIG_CHIP_M32102 */
+#define local_irq_save(x)                              \
+       ({                                              \
+               unsigned long tmpreg;                   \
+               __asm__ __volatile__(                   \
+                       "ld24   %1, #0 \n\t"            \
+                       "mvfc   %0, psw \n\t"           \
+                       "mvtc   %1, psw \n\t"           \
+                       "and3   %1, %0, #0xffbf \n\t"   \
+                       "mvtc   %1, psw \n\t"           \
+                       : "=r" (x), "=&r" (tmpreg)      \
+                       : : "cbit", "memory");          \
+       })
+#endif /* CONFIG_CHIP_M32102 */
+
+#define irqs_disabled()                                        \
+       ({                                              \
+               unsigned long flags;                    \
+               local_save_flags(flags);                \
+               !(flags & 0x40);                        \
+       })
+
+#endif  /* __KERNEL__ */
+
+#define nop()  __asm__ __volatile__ ("nop" : : )
+
+#define xchg(ptr,x) \
+       ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+#define tas(ptr)       (xchg((ptr),1))
+
+#ifdef CONFIG_SMP
+extern void  __xchg_called_with_bad_pointer(void);
+#endif
+
+#ifdef CONFIG_CHIP_M32700_TS1
+#define DCACHE_CLEAR(reg0, reg1, addr)                         \
+       "seth   "reg1", #high(dcache_dummy);            \n\t"   \
+       "or3    "reg1", "reg1", #low(dcache_dummy);     \n\t"   \
+       "lock   "reg0", @"reg1";                        \n\t"   \
+       "add3   "reg0", "addr", #0x1000;                \n\t"   \
+       "ld     "reg0", @"reg0";                        \n\t"   \
+       "add3   "reg0", "addr", #0x2000;                \n\t"   \
+       "ld     "reg0", @"reg0";                        \n\t"   \
+       "unlock "reg0", @"reg1";                        \n\t"
+       /* FIXME: This workaround code cannot handle kenrel modules
+        * correctly under SMP environment.
+        */
+#else  /* CONFIG_CHIP_M32700_TS1 */
+#define DCACHE_CLEAR(reg0, reg1, addr)
+#endif /* CONFIG_CHIP_M32700_TS1 */
+
+static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr,
+       int size)
+{
+       unsigned long flags;
+       unsigned long tmp = 0;
+
+       local_irq_save(flags);
+
+       switch (size) {
+#ifndef CONFIG_SMP
+       case 1:
+               __asm__ __volatile__ (
+                       "ldb    %0, @%2 \n\t"
+                       "stb    %1, @%2 \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+               break;
+       case 2:
+               __asm__ __volatile__ (
+                       "ldh    %0, @%2 \n\t"
+                       "sth    %1, @%2 \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+               break;
+       case 4:
+               __asm__ __volatile__ (
+                       "ld     %0, @%2 \n\t"
+                       "st     %1, @%2 \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory");
+               break;
+#else  /* CONFIG_SMP */
+       case 4:
+               __asm__ __volatile__ (
+                       DCACHE_CLEAR("%0", "r4", "%2")
+                       "lock   %0, @%2;        \n\t"
+                       "unlock %1, @%2;        \n\t"
+                       : "=&r" (tmp) : "r" (x), "r" (ptr)
+                       : "memory"
+#ifdef CONFIG_CHIP_M32700_TS1
+                       , "r4"
+#endif /* CONFIG_CHIP_M32700_TS1 */
+               );
+               break;
+       default:
+               __xchg_called_with_bad_pointer();
+#endif  /* CONFIG_SMP */
+       }
+
+       local_irq_restore(flags);
+
+       return (tmp);
+}
+
+/*
+ * Memory barrier.
+ *
+ * mb() prevents loads and stores being reordered across this point.
+ * rmb() prevents loads being reordered across this point.
+ * wmb() prevents stores being reordered across this point.
+ */
+#if 0
+#define mb()   __asm__ __volatile__ ("push r0; \n\t pop r0;" : : : "memory")
+#else
+#define mb()   __asm__ __volatile__ ("" : : : "memory")
+#endif
+#define rmb()  mb()
+#define wmb()  mb()
+
+/**
+ * read_barrier_depends - Flush all pending reads that subsequents reads
+ * depend on.
+ *
+ * No data-dependent reads from memory-like regions are ever reordered
+ * over this barrier.  All reads preceding this primitive are guaranteed
+ * to access memory (but not necessarily other CPUs' caches) before any
+ * reads following this primitive that depend on the data return by
+ * any of the preceding reads.  This primitive is much lighter weight than
+ * rmb() on most CPUs, and is never heavier weight than is
+ * rmb().
+ *
+ * These ordering constraints are respected by both the local CPU
+ * and the compiler.
+ *
+ * Ordering is not guaranteed by anything other than these primitives,
+ * not even by data dependencies.  See the documentation for
+ * memory_barrier() for examples and URLs to more information.
+ *
+ * For example, the following code would force ordering (the initial
+ * value of "a" is zero, "b" is one, and "p" is "&a"):
+ *
+ * <programlisting>
+ *      CPU 0                           CPU 1
+ *
+ *      b = 2;
+ *      memory_barrier();
+ *      p = &b;                         q = p;
+ *                                      read_barrier_depends();
+ *                                      d = *q;
+ * </programlisting>
+ *
+ *
+ * because the read of "*q" depends on the read of "p" and these
+ * two reads are separated by a read_barrier_depends().  However,
+ * the following code, with the same initial values for "a" and "b":
+ *
+ * <programlisting>
+ *      CPU 0                           CPU 1
+ *
+ *      a = 2;
+ *      memory_barrier();
+ *      b = 3;                          y = b;
+ *                                      read_barrier_depends();
+ *                                      x = a;
+ * </programlisting>
+ *
+ * does not enforce ordering, since there is no data dependency between
+ * the read of "a" and the read of "b".  Therefore, on some CPUs, such
+ * as Alpha, "y" could be set to 3 and "x" to 0.  Use rmb()
+ * in cases like thiswhere there are no data dependencies.
+ **/
+
+#define read_barrier_depends() do { } while (0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#define smp_read_barrier_depends()     read_barrier_depends()
+#else
+#define smp_mb()       barrier()
+#define smp_rmb()      barrier()
+#define smp_wmb()      barrier()
+#define smp_read_barrier_depends()     do { } while (0)
+#endif
+
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#endif  /* _ASM_M32R_SYSTEM_H */
+
diff --git a/include/asm-m32r/termbits.h b/include/asm-m32r/termbits.h
new file mode 100644 (file)
index 0000000..aa5a829
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef _ASM_M32R_TERMBITS_H
+#define _ASM_M32R_TERMBITS_H
+
+/* $Id$ */
+
+#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  /* _ASM_M32R_TERMBITS_H */
diff --git a/include/asm-m32r/termios.h b/include/asm-m32r/termios.h
new file mode 100644 (file)
index 0000000..fc99d2e
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _M32R_TERMIOS_H
+#define _M32R_TERMIOS_H
+
+/* orig : i386 2.6.0-test5 */
+
+#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      /* synchronous PPP */
+#define N_HCI          15  /* Bluetooth HCI UART */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+
+/*     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 /* _M32R_TERMIOS_H */
diff --git a/include/asm-m32r/thread_info.h b/include/asm-m32r/thread_info.h
new file mode 100644 (file)
index 0000000..de7d3f1
--- /dev/null
@@ -0,0 +1,149 @@
+/* thread_info.h: i386 low-level thread information
+ *
+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_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:
+                                                  0-0xBFFFFFFF for user-thead
+                                                  0-0xFFFFFFFF for kernel-thread
+                                               */
+       struct restart_block    restart_block;
+
+       __u8                    supervisor_stack[0];
+};
+
+#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         0x4000000
+
+/*
+ * 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__ __volatile__ (
+               "ldi    %0, #0xffffe000;        \n\t"
+               "and    %0, sp;                 \n\t"
+               : "=r" (ti)
+       );
+
+       return ti;
+}
+
+/* thread information allocation */
+#define THREAD_SIZE (2*PAGE_SIZE)
+#define alloc_thread_info(task) \
+       ((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)   GET_THREAD_INFO reg
+       .macro GET_THREAD_INFO reg
+       ldi     \reg, #0xffffe000
+       and     \reg, sp
+       .endm
+
+#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_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) */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-m32r/timex.h b/include/asm-m32r/timex.h
new file mode 100644 (file)
index 0000000..e102aaf
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _ASM_M32R_TIMEX_H
+#define _ASM_M32R_TIMEX_H
+
+/* $Id$ */
+
+/*
+ * linux/include/asm-m32r/timex.h
+ *
+ * m32r architecture timex specifications
+ */
+
+#include <linux/config.h>
+
+#define CLOCK_TICK_RATE        (CONFIG_BUS_CLOCK / CONFIG_TIMER_DIVIDE)
+#define CLOCK_TICK_FACTOR      20      /* Factor of both 1000000 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 __KERNEL__
+/*
+ * Standard way to access the cycle counter.
+ * Currently only used on SMP.
+ */
+
+typedef unsigned long long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+static __inline__ cycles_t get_cycles (void)
+{
+       return 0;
+}
+#endif  /* __KERNEL__ */
+
+#endif  /* _ASM_M32R_TIMEX_H */
diff --git a/include/asm-m32r/tlb.h b/include/asm-m32r/tlb.h
new file mode 100644 (file)
index 0000000..c7ebd8d
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _M32R_TLB_H
+#define _M32R_TLB_H
+
+/*
+ * x86 doesn't need any special per-pte or
+ * per-vma handling..
+ */
+#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, address) do { } while (0)
+
+/*
+ * .. because we flush the whole mm when it
+ * fills up.
+ */
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#endif /* _M32R_TLB_H */
diff --git a/include/asm-m32r/tlbflush.h b/include/asm-m32r/tlbflush.h
new file mode 100644 (file)
index 0000000..bc7c407
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _ASM_M32R_TLBFLUSH_H
+#define _ASM_M32R_TLBFLUSH_H
+
+#include <linux/config.h>
+#include <asm/m32r.h>
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+extern void local_flush_tlb_all(void);
+extern void local_flush_tlb_mm(struct mm_struct *);
+extern void local_flush_tlb_page(struct vm_area_struct *, unsigned long);
+extern void local_flush_tlb_range(struct vm_area_struct *, unsigned long,
+       unsigned long);
+
+#ifndef CONFIG_SMP
+#ifdef CONFIG_MMU
+#define flush_tlb_all()                        local_flush_tlb_all()
+#define flush_tlb_mm(mm)               local_flush_tlb_mm(mm)
+#define flush_tlb_page(vma, page)      local_flush_tlb_page(vma, page)
+#define flush_tlb_range(vma, start, end)       \
+       local_flush_tlb_range(vma, start, end)
+#define flush_tlb_kernel_range(start, end)     local_flush_tlb_all()
+#else  /* CONFIG_MMU */
+#define flush_tlb_all()                        do { } while (0)
+#define flush_tlb_mm(mm)               do { } while (0)
+#define flush_tlb_page(vma, vmaddr)    do { } while (0)
+#define flush_tlb_range(vma, start, end)       do { } while (0)
+#endif /* CONFIG_MMU */
+#else  /* CONFIG_SMP */
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *);
+extern void smp_flush_tlb_page(struct vm_area_struct *, unsigned long);
+extern void smp_flush_tlb_range(struct vm_area_struct *, unsigned long,
+       unsigned long);
+
+#define flush_tlb_all()                        smp_flush_tlb_all()
+#define flush_tlb_mm(mm)               smp_flush_tlb_mm(mm)
+#define flush_tlb_page(vma, page)      smp_flush_tlb_page(vma, page)
+#define flush_tlb_range(vma, start, end)       \
+       smp_flush_tlb_range(vma, start, end)
+#define flush_tlb_kernel_range(start, end)     smp_flush_tlb_all()
+#endif /* CONFIG_SMP */
+
+static __inline__ void __flush_tlb_page(unsigned long page)
+{
+       unsigned int tmpreg0, tmpreg1, tmpreg2;
+
+       __asm__ __volatile__ (
+               "seth   %0, #high(%4)   \n\t"
+               "st     %3, @(%5, %0)   \n\t"
+               "ldi    %1, #1          \n\t"
+               "st     %1, @(%6, %0)   \n\t"
+               "add3   %1, %0, %7      \n\t"
+               ".fillinsn              \n"
+               "1:                     \n\t"
+               "ld     %2, @(%6, %0)   \n\t"
+               "bnez   %2, 1b          \n\t"
+               "ld     %0, @%1+        \n\t"
+               "ld     %1, @%1         \n\t"
+               "st     %2, @+%0        \n\t"
+               "st     %2, @+%1        \n\t"
+               : "=&r" (tmpreg0), "=&r" (tmpreg1), "=&r" (tmpreg2)
+               : "r" (page), "i" (MMU_REG_BASE), "i" (MSVA_offset),
+               "i" (MTOP_offset), "i" (MIDXI_offset)
+               : "memory"
+       );
+}
+
+static __inline__ void __flush_tlb_all(void)
+{
+       unsigned int tmpreg0, tmpreg1;
+
+       __asm__ __volatile__ (
+               "seth   %0, #high(%2)           \n\t"
+               "or3    %0, %0, #low(%2)        \n\t"
+               "ldi    %1, #0xc                \n\t"
+               "st     %1, @%0                 \n\t"
+               ".fillinsn                      \n"
+               "1:                             \n\t"
+               "ld     %1, @%0                 \n\t"
+               "bnez   %1, 1b                  \n\t"
+               : "=&r" (tmpreg0), "=&r" (tmpreg1)
+               : "i" (MTOP) : "memory"
+       );
+}
+
+#define flush_tlb_pgtables(mm, start, end)     do { } while (0)
+
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
+#endif /* _ASM_M32R_TLBFLUSH_H */
+
diff --git a/include/asm-m32r/topology.h b/include/asm-m32r/topology.h
new file mode 100644 (file)
index 0000000..b5a3ea1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * linux/include/asm-generic/topology.h
+ *
+ * Written by: Matthew Dobson, IBM Corporation
+ *
+ * Copyright (C) 2002, IBM Corp.
+ *
+ * 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 <colpatch@us.ibm.com>
+ */
+#ifndef _ASM_M32R_TOPOLOGY_H
+#define _ASM_M32R_TOPOLOGY_H
+
+/* Other architectures wishing to use this simple topology API should fill
+   in the below functions as appropriate in their own <asm/topology.h> file. */
+
+#define cpu_to_node(cpu)       (0)
+
+#ifndef parent_node
+#define parent_node(node)      (0)
+#endif
+#ifndef node_to_cpumask
+#define node_to_cpumask(node)  (cpu_online_map)
+#endif
+#ifndef node_to_first_cpu
+#define node_to_first_cpu(node)        (0)
+#endif
+#ifndef pcibus_to_cpumask
+#define pcibus_to_cpumask(bus) (cpu_online_map)
+#endif
+
+/* Cross-node load balancing interval. */
+#ifndef NODE_BALANCE_RATE
+#define NODE_BALANCE_RATE 10
+#endif
+
+#endif /* _ASM_M32R_TOPOLOGY_H */
diff --git a/include/asm-m32r/types.h b/include/asm-m32r/types.h
new file mode 100644 (file)
index 0000000..ca0a887
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _ASM_M32R_TYPES_H
+#define _ASM_M32R_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+/* $Id$ */
+
+/* orig : i386 2.4.18 */
+
+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
+#endif /* __ASSEMBLY__ */
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+#define BITS_PER_LONG 32
+
+#ifndef __ASSEMBLY__
+
+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;
+
+/* DMA addresses are 32-bits wide.  */
+
+typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
+
+typedef unsigned short kmem_bufctl_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif  /* _ASM_M32R_TYPES_H */
diff --git a/include/asm-m32r/uaccess.h b/include/asm-m32r/uaccess.h
new file mode 100644 (file)
index 0000000..58530a3
--- /dev/null
@@ -0,0 +1,752 @@
+#ifndef _ASM_M32R_UACCESS_H
+#define _ASM_M32R_UACCESS_H
+
+/*
+ *  linux/include/asm-m32r/uaccess.h
+ *
+ *  M32R version.
+ *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#undef UACCESS_DEBUG
+
+#ifdef UACCESS_DEBUG
+#define UAPRINTK(args...) printk(args)
+#else
+#define UAPRINTK(args...)
+#endif /* UACCESS_DEBUG */
+
+/*
+ * User space memory access functions
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/thread_info.h>
+#include <asm/page.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * 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, these macros are grossly misnamed.
+ */
+
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+
+#ifdef CONFIG_MMU
+#define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFF)
+#define USER_DS                MAKE_MM_SEG(PAGE_OFFSET)
+#else
+#define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFF)
+#define USER_DS                MAKE_MM_SEG(0xFFFFFFFF)
+#endif /* CONFIG_MMU */
+
+#define get_ds()       (KERNEL_DS)
+#ifdef CONFIG_MMU
+#define get_fs()       (current_thread_info()->addr_limit)
+#define set_fs(x)      (current_thread_info()->addr_limit = (x))
+#else
+static inline mm_segment_t get_fs(void)
+{
+  return USER_DS;
+}
+
+static inline void set_fs(mm_segment_t s)
+{
+}
+#endif /* CONFIG_MMU */
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
+
+#define __addr_ok(addr) \
+       ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
+
+/*
+ * Test whether a block of memory is a valid user space address.
+ * Returns 0 if the range is valid, nonzero otherwise.
+ *
+ * This is equivalent to the following test:
+ * (u33)addr + (u33)size >= (u33)current->addr_limit.seg
+ *
+ * This needs 33-bit arithmetic. We have a carry...
+ */
+#define __range_ok(addr,size) ({                                       \
+       unsigned long flag, sum;                                        \
+       __chk_user_ptr(addr);                                           \
+       asm (                                                           \
+               "       cmpu    %1, %1    ; clear cbit\n"               \
+               "       addx    %1, %3    ; set cbit if overflow\n"     \
+               "       subx    %0, %0\n"                               \
+               "       cmpu    %4, %1\n"                               \
+               "       subx    %0, %5\n"                               \
+               : "=&r"(flag), "=r"(sum)                                \
+               : "1"(addr), "r"((int)(size)),                          \
+                 "r"(current_thread_info()->addr_limit.seg), "r"(0)    \
+               : "cbit" );                                             \
+       flag; })
+
+/**
+ * access_ok: - Checks if a user space pointer is valid
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
+ *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
+ *        to write to a block, it is always safe to read from it.
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
+#ifdef CONFIG_MMU
+#define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
+#else
+static inline int access_ok(int type, const void *addr, unsigned long size)
+{
+  extern unsigned long memory_start, memory_end;
+  unsigned long val = (unsigned long)addr;
+
+  return ((val >= memory_start) && ((val + size) < memory_end));
+}
+#endif /* CONFIG_MMU */
+
+/**
+ * verify_area: - Obsolete, use access_ok()
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This function has been replaced by access_ok().
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns zero if the memory block may be valid, -EFAULT
+ * if it is definitely invalid.
+ *
+ * See access_ok() for more details.
+ */
+static inline int verify_area(int type, const void __user *addr,
+                             unsigned long size)
+{
+       return access_ok(type, addr, size) ? 0 : -EFAULT;
+}
+
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+/*
+ * 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.
+ *
+ * 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).
+ */
+
+extern void __get_user_1(void);
+extern void __get_user_2(void);
+extern void __get_user_4(void);
+
+#ifndef MODULE
+#define __get_user_x(size,ret,x,ptr)                                   \
+       __asm__ __volatile__(                                           \
+               "       mv      r0, %0\n"                               \
+               "       mv      r1, %1\n"                               \
+               "       bl __get_user_" #size "\n"                      \
+               "       mv      %0, r0\n"                               \
+               "       mv      %1, r1\n"                               \
+               : "=r"(ret), "=r"(x)                                    \
+               : "0"(ptr)                                              \
+               : "r0", "r1", "r14" )
+#else /* MODULE */
+/*
+ * Use "jl" instead of "bl" for MODULE
+ */
+#define __get_user_x(size,ret,x,ptr)                                   \
+       __asm__ __volatile__(                                           \
+               "       mv      r0, %0\n"                               \
+               "       mv      r1, %1\n"                               \
+               "       seth    lr, #high(__get_user_" #size ")\n"      \
+               "       or3     lr, lr, #low(__get_user_" #size ")\n"   \
+               "       jl      lr\n"                                   \
+               "       mv      %0, r0\n"                               \
+               "       mv      %1, r1\n"                               \
+               : "=r"(ret), "=r"(x)                                    \
+               : "0"(ptr)                                              \
+               : "r0", "r1", "r14" )
+#endif
+
+/* Careful: we have to cast the result to the type of the pointer for sign
+   reasons */
+/**
+ * get_user: - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define get_user(x,ptr)                                                        \
+({     int __ret_gu,__val_gu;                                          \
+       __chk_user_ptr(ptr);                                            \
+       switch(sizeof (*(ptr))) {                                       \
+       case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;          \
+       case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;          \
+       case 4:  __get_user_x(4,__ret_gu,__val_gu,ptr); break;          \
+       default: __get_user_x(X,__ret_gu,__val_gu,ptr); break;          \
+       }                                                               \
+       (x) = (__typeof__(*(ptr)))__val_gu;                             \
+       __ret_gu;                                                       \
+})
+
+extern void __put_user_bad(void);
+
+/**
+ * put_user: - Write a simple value into user space.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define put_user(x,ptr)                                                        \
+  __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user(x,ptr) \
+  __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define __put_user(x,ptr) \
+  __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#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)) __user *__pu_addr = (ptr);                   \
+       might_sleep();                                                  \
+       if (access_ok(VERIFY_WRITE,__pu_addr,size))                     \
+               __put_user_size((x),__pu_addr,(size),__pu_err);         \
+       __pu_err;                                                       \
+})
+
+#if defined(__LITTLE_ENDIAN__)
+#define __put_user_u64(x, addr, err)                                    \
+        __asm__ __volatile__(                                           \
+                "       .fillinsn\n"                                    \
+                "1:     st %L1,@%2\n"                                    \
+                "       .fillinsn\n"                                    \
+                "2:     st %H1,@(4,%2)\n"                                \
+                "       .fillinsn\n"                                    \
+                "3:\n"                                                  \
+                ".section .fixup,\"ax\"\n"                              \
+                "       .balign 4\n"                                    \
+                "4:     ldi %0,%3\n"                                    \
+                "       seth r14,#high(3b)\n"                           \
+                "       or3 r14,r14,#low(3b)\n"                         \
+                "       jmp r14\n"                                      \
+                ".previous\n"                                           \
+                ".section __ex_table,\"a\"\n"                           \
+                "       .balign 4\n"                                    \
+                "       .long 1b,4b\n"                                  \
+                "       .long 2b,4b\n"                                  \
+                ".previous"                                             \
+                : "=r"(err)                                             \
+                : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err)            \
+                : "r14", "memory")
+
+#elif defined(__BIG_ENDIAN__)
+#define __put_user_u64(x, addr, err)                                   \
+       __asm__ __volatile__(                                           \
+               "       .fillinsn\n"                                    \
+               "1:     st %H1,@%2\n"                                   \
+               "       .fillinsn\n"                                    \
+               "2:     st %L1,@(4,%2)\n"                               \
+               "       .fillinsn\n"                                    \
+               "3:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "4:     ldi %0,%3\n"                                    \
+               "       seth r14,#high(3b)\n"                           \
+               "       or3 r14,r14,#low(3b)\n"                         \
+               "       jmp r14\n"                                      \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 1b,4b\n"                                  \
+               "       .long 2b,4b\n"                                  \
+               ".previous"                                             \
+               : "=r"(err)                                             \
+               : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err)             \
+               : "r14", "memory")
+#else
+#error no endian defined
+#endif
+
+#define __put_user_size(x,ptr,size,retval)                             \
+do {                                                                   \
+       retval = 0;                                                     \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+         case 1: __put_user_asm(x,ptr,retval,"b"); break;              \
+         case 2: __put_user_asm(x,ptr,retval,"h"); break;              \
+         case 4: __put_user_asm(x,ptr,retval,""); break;               \
+         case 8: __put_user_u64((__typeof__(*ptr))(x),ptr,retval); break;\
+         default: __put_user_bad();                                    \
+       }                                                               \
+} while (0)
+
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, itype)                            \
+       __asm__ __volatile__(                                           \
+               "       .fillinsn\n"                                    \
+               "1:     st"itype" %1,@%2\n"                             \
+               "       .fillinsn\n"                                    \
+               "2:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "3:     ldi %0,%3\n"                                    \
+               "       seth r14,#high(2b)\n"                           \
+               "       or3 r14,r14,#low(2b)\n"                         \
+               "       jmp r14\n"                                      \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 1b,3b\n"                                  \
+               ".previous"                                             \
+               : "=r"(err)                                             \
+               : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err)             \
+               : "r14", "memory")
+
+#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;                                                       \
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval)                             \
+do {                                                                   \
+       retval = 0;                                                     \
+       __chk_user_ptr(ptr);                                            \
+       switch (size) {                                                 \
+         case 1: __get_user_asm(x,ptr,retval,"ub"); break;             \
+         case 2: __get_user_asm(x,ptr,retval,"uh"); break;             \
+         case 4: __get_user_asm(x,ptr,retval,""); break;               \
+         default: (x) = __get_user_bad();                              \
+       }                                                               \
+} while (0)
+
+#define __get_user_asm(x, addr, err, itype)                            \
+       __asm__ __volatile__(                                           \
+               "       .fillinsn\n"                                    \
+               "1:     ld"itype" %1,@%2\n"                             \
+               "       .fillinsn\n"                                    \
+               "2:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "3:     ldi %0,%3\n"                                    \
+               "       seth r14,#high(2b)\n"                           \
+               "       or3 r14,r14,#low(2b)\n"                         \
+               "       jmp r14\n"                                      \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 1b,3b\n"                                  \
+               ".previous"                                             \
+               : "=r"(err), "=&r"(x)                                   \
+               : "r"(addr), "i"(-EFAULT), "0"(err)                     \
+               : "r14", "memory")
+
+/*
+ * Here we special-case 1, 2 and 4-byte copy_*_user invocations.  On a fault
+ * we return the initial request size (1, 2 or 4), as copy_*_user should do.
+ * If a store crosses a page boundary and gets a fault, the m32r will not write
+ * anything, so this is accurate.
+ */
+
+
+/*
+ * Copy To/From Userspace
+ */
+
+/* Generic arbitrary sized copy.  */
+/* Return the number of bytes NOT copied.  */
+#define __copy_user(to,from,size)                                      \
+do {                                                                   \
+       unsigned long __dst, __src, __c;                                \
+       __asm__ __volatile__ (                                          \
+               "       mv      r14, %0\n"                              \
+               "       or      r14, %1\n"                              \
+               "       beq     %0, %1, 9f\n"                           \
+               "       beqz    %2, 9f\n"                               \
+               "       and3    r14, r14, #3\n"                         \
+               "       bnez    r14, 2f\n"                              \
+               "       and3    %2, %2, #3\n"                           \
+               "       beqz    %3, 2f\n"                               \
+               "       addi    %0, #-4         ; word_copy \n"         \
+               "       .fillinsn\n"                                    \
+               "0:     ld      r14, @%1+\n"                            \
+               "       addi    %3, #-1\n"                              \
+               "       .fillinsn\n"                                    \
+               "1:     st      r14, @+%0\n"                            \
+               "       bnez    %3, 0b\n"                               \
+               "       beqz    %2, 9f\n"                               \
+               "       addi    %0, #4\n"                               \
+               "       .fillinsn\n"                                    \
+               "2:     ldb     r14, @%1        ; byte_copy \n"         \
+               "       .fillinsn\n"                                    \
+               "3:     stb     r14, @%0\n"                             \
+               "       addi    %1, #1\n"                               \
+               "       addi    %2, #-1\n"                              \
+               "       addi    %0, #1\n"                               \
+               "       bnez    %2, 2b\n"                               \
+               "       .fillinsn\n"                                    \
+               "9:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "5:     addi    %3, #1\n"                               \
+               "       addi    %1, #-4\n"                              \
+               "       .fillinsn\n"                                    \
+               "6:     slli    %3, #2\n"                               \
+               "       add     %2, %3\n"                               \
+               "       addi    %0, #4\n"                               \
+               "       .fillinsn\n"                                    \
+               "7:     seth    r14, #high(9b)\n"                       \
+               "       or3     r14, r14, #low(9b)\n"                   \
+               "       jmp     r14\n"                                  \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 0b,6b\n"                                  \
+               "       .long 1b,5b\n"                                  \
+               "       .long 2b,9b\n"                                  \
+               "       .long 3b,9b\n"                                  \
+               ".previous\n"                                           \
+               : "=&r"(__dst), "=&r"(__src), "=&r"(size), "=&r"(__c)   \
+               : "0"(to), "1"(from), "2"(size), "3"(size / 4)          \
+               : "r14", "memory");                                     \
+} while (0)
+
+#define __copy_user_zeroing(to,from,size)                              \
+do {                                                                   \
+       unsigned long __dst, __src, __c;                                \
+       __asm__ __volatile__ (                                          \
+               "       mv      r14, %0\n"                              \
+               "       or      r14, %1\n"                              \
+               "       beq     %0, %1, 9f\n"                           \
+               "       beqz    %2, 9f\n"                               \
+               "       and3    r14, r14, #3\n"                         \
+               "       bnez    r14, 2f\n"                              \
+               "       and3    %2, %2, #3\n"                           \
+               "       beqz    %3, 2f\n"                               \
+               "       addi    %0, #-4         ; word_copy \n"         \
+               "       .fillinsn\n"                                    \
+               "0:     ld      r14, @%1+\n"                            \
+               "       addi    %3, #-1\n"                              \
+               "       .fillinsn\n"                                    \
+               "1:     st      r14, @+%0\n"                            \
+               "       bnez    %3, 0b\n"                               \
+               "       beqz    %2, 9f\n"                               \
+               "       addi    %0, #4\n"                               \
+               "       .fillinsn\n"                                    \
+               "2:     ldb     r14, @%1        ; byte_copy \n"         \
+               "       .fillinsn\n"                                    \
+               "3:     stb     r14, @%0\n"                             \
+               "       addi    %1, #1\n"                               \
+               "       addi    %2, #-1\n"                              \
+               "       addi    %0, #1\n"                               \
+               "       bnez    %2, 2b\n"                               \
+               "       .fillinsn\n"                                    \
+               "9:\n"                                                  \
+               ".section .fixup,\"ax\"\n"                              \
+               "       .balign 4\n"                                    \
+               "5:     addi    %3, #1\n"                               \
+               "       addi    %1, #-4\n"                              \
+               "       .fillinsn\n"                                    \
+               "6:     slli    %3, #2\n"                               \
+               "       add     %2, %3\n"                               \
+               "       addi    %0, #4\n"                               \
+               "       .fillinsn\n"                                    \
+               "7:     ldi     r14, #0         ; store zero \n"        \
+               "       .fillinsn\n"                                    \
+               "8:     addi    %2, #-1\n"                              \
+               "       stb     r14, @%0        ; ACE? \n"              \
+               "       addi    %0, #1\n"                               \
+               "       bnez    %2, 8b\n"                               \
+               "       seth    r14, #high(9b)\n"                       \
+               "       or3     r14, r14, #low(9b)\n"                   \
+               "       jmp     r14\n"                                  \
+               ".previous\n"                                           \
+               ".section __ex_table,\"a\"\n"                           \
+               "       .balign 4\n"                                    \
+               "       .long 0b,6b\n"                                  \
+               "       .long 1b,5b\n"                                  \
+               "       .long 2b,7b\n"                                  \
+               "       .long 3b,7b\n"                                  \
+               ".previous\n"                                           \
+               : "=&r"(__dst), "=&r"(__src), "=&r"(size), "=&r"(__c)   \
+               : "0"(to), "1"(from), "2"(size), "3"(size / 4)          \
+               : "r14", "memory");                                     \
+} while (0)
+
+
+/* We let the __ versions of copy_from/to_user inline, because they're often
+ * used in fast paths and have only a small space overhead.
+ */
+static inline unsigned long __generic_copy_from_user_nocheck(void *to,
+       const void __user *from, unsigned long n)
+{
+       __copy_user_zeroing(to,from,n);
+       return n;
+}
+
+static inline unsigned long __generic_copy_to_user_nocheck(void __user *to,
+       const void *from, unsigned long n)
+{
+       __copy_user(to,from,n);
+       return n;
+}
+
+unsigned long __generic_copy_to_user(void *, const void *, unsigned long);
+unsigned long __generic_copy_from_user(void *, const void *, unsigned long);
+
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+#define __copy_to_user(to,from,n)                      \
+       __generic_copy_to_user_nocheck((to),(from),(n))
+
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
+
+/**
+ * copy_to_user: - Copy a block of data into user space.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+#define copy_to_user(to,from,n)                                \
+({                                                     \
+       might_sleep();                                  \
+       __generic_copy_to_user((to),(from),(n));        \
+})
+
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking. * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+#define __copy_from_user(to,from,n)                    \
+       __generic_copy_from_user_nocheck((to),(from),(n))
+
+/**
+ * copy_from_user: - Copy a block of data from user space.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+#define copy_from_user(to,from,n)                      \
+({                                                     \
+       might_sleep();                                  \
+__generic_copy_from_user((to),(from),(n));     \
+})
+
+long __must_check strncpy_from_user(char *dst, const char __user *src,
+                               long count);
+long __must_check __strncpy_from_user(char *dst,
+                               const char __user *src, long count);
+
+/**
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
+unsigned long __clear_user(void __user *mem, unsigned long len);
+
+/**
+ * clear_user: - Zero a block of memory in user space.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
+unsigned long clear_user(void __user *mem, unsigned long len);
+
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+long strnlen_user(const char __user *str, long n);
+
+#endif /* _ASM_M32R_UACCESS_H */
diff --git a/include/asm-m32r/ucontext.h b/include/asm-m32r/ucontext.h
new file mode 100644 (file)
index 0000000..2de709a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _ASM_M32R_UCONTEXT_H
+#define _ASM_M32R_UCONTEXT_H
+
+/* orig : i386 2.4.18 */
+
+struct ucontext {
+       unsigned long     uc_flags;
+       struct ucontext  *uc_link;
+       stack_t           uc_stack;
+       struct sigcontext uc_mcontext;
+       sigset_t          uc_sigmask;   /* mask last for extensibility */
+};
+
+#endif /* _ASM_M32R_UCONTEXT_H */
diff --git a/include/asm-m32r/unaligned.h b/include/asm-m32r/unaligned.h
new file mode 100644 (file)
index 0000000..3aef9ac
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _ASM_M32R_UNALIGNED_H
+#define _ASM_M32R_UNALIGNED_H
+
+/* $Id$ */
+
+/* orig : generic 2.4.18 */
+
+/*
+ * For the benefit of those who are trying to port Linux to another
+ * architecture, here are some C-language equivalents.
+ */
+
+#include <asm/string.h>
+
+
+#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  /* _ASM_M32R_UNALIGNED_H */
diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h
new file mode 100644 (file)
index 0000000..a506573
--- /dev/null
@@ -0,0 +1,483 @@
+#ifndef _ASM_M32R_UNISTD_H
+#define _ASM_M32R_UNISTD_H
+
+/* $Id$ */
+
+#include <asm/syscall.h>       /* SYSCALL_* */
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_restart_syscall     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_umount             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_cacheflush                 31 /* old #define __NR_stty             31*/
+#define __NR_cachectl           32 /* old #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_umount2            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_vm86old           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_getsid            147
+#define __NR_fdatasync         148
+#define __NR__sysctl           149
+#define __NR_mlock             150
+#define __NR_munlock           151
+#define __NR_mlockall          152
+#define __NR_munlockall                153
+#define __NR_sched_setparam            154
+#define __NR_sched_getparam            155
+#define __NR_sched_setscheduler                156
+#define __NR_sched_getscheduler                157
+#define __NR_sched_yield               158
+#define __NR_sched_get_priority_max    159
+#define __NR_sched_get_priority_min    160
+#define __NR_sched_rr_get_interval     161
+#define __NR_nanosleep         162
+#define __NR_mremap            163
+#define __NR_setresuid         164
+#define __NR_getresuid         165
+#define __NR_tas               166
+#define __NR_query_module      167
+#define __NR_poll              168
+#define __NR_nfsservctl                169
+#define __NR_setresgid         170
+#define __NR_getresgid         171
+#define __NR_prctl              172
+#define __NR_rt_sigreturn      173
+#define __NR_rt_sigaction      174
+#define __NR_rt_sigprocmask    175
+#define __NR_rt_sigpending     176
+#define __NR_rt_sigtimedwait   177
+#define __NR_rt_sigqueueinfo   178
+#define __NR_rt_sigsuspend     179
+#define __NR_pread64           180
+#define __NR_pwrite64          181
+#define __NR_chown             182
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
+#define __NR_sigaltstack       186
+#define __NR_sendfile          187
+#define __NR_getpmsg           188     /* some people actually want streams */
+#define __NR_putpmsg           189     /* some people actually want streams */
+#define __NR_vfork             190
+#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_lchown32          198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_chown32           212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_pivot_root                217
+#define __NR_mincore           218
+#define __NR_madvise           219
+#define __NR_madvise1          219     /* delete when C lib stub is removed */
+#define __NR_getdents64                220
+#define __NR_fcntl64           221
+#define __NR_security           223     /* syscall for security modules */
+#define __NR_gettid             224
+#define __NR_readahead          225
+#define __NR_setxattr           226
+#define __NR_lsetxattr          227
+#define __NR_fsetxattr          228
+#define __NR_getxattr           229
+#define __NR_lgetxattr          230
+#define __NR_fgetxattr          231
+#define __NR_listxattr          232
+#define __NR_llistxattr         233
+#define __NR_flistxattr         234
+#define __NR_removexattr        235
+#define __NR_lremovexattr       236
+#define __NR_fremovexattr       237
+#define __NR_tkill             238
+#define __NR_sendfile64                239
+#define __NR_futex             240
+#define __NR_sched_setaffinity 241
+#define __NR_sched_getaffinity 242
+#define __NR_set_thread_area    243
+#define __NR_get_thread_area    244
+#define __NR_io_setup           245
+#define __NR_io_destroy         246
+#define __NR_io_getevents       247
+#define __NR_io_submit          248
+#define __NR_io_cancel          249
+#define __NR_fadvise64          250
+
+#define __NR_exit_group         252
+#define __NR_lookup_dcookie     253
+#define __NR_epoll_create       254
+#define __NR_epoll_ctl          255
+#define __NR_epoll_wait         256
+#define __NR_remap_file_pages   257
+#define __NR_set_tid_address    258
+#define __NR_timer_create       259
+#define __NR_timer_settime      (__NR_timer_create+1)
+#define __NR_timer_gettime      (__NR_timer_create+2)
+#define __NR_timer_getoverrun   (__NR_timer_create+3)
+#define __NR_timer_delete       (__NR_timer_create+4)
+#define __NR_clock_settime      (__NR_timer_create+5)
+#define __NR_clock_gettime      (__NR_timer_create+6)
+#define __NR_clock_getres       (__NR_timer_create+7)
+#define __NR_clock_nanosleep    (__NR_timer_create+8)
+#define __NR_statfs64           268
+#define __NR_fstatfs64          269
+#define __NR_tgkill             270
+#define __NR_utimes             271
+#define __NR_fadvise64_64       272
+#define __NR_vserver            273
+#define __NR_mbind              274
+#define __NR_get_mempolicy      275
+#define __NR_set_mempolicy      276
+#define __NR_mq_open            277
+#define __NR_mq_unlink          (__NR_mq_open+1)
+#define __NR_mq_timedsend       (__NR_mq_open+2)
+#define __NR_mq_timedreceive    (__NR_mq_open+3)
+#define __NR_mq_notify          (__NR_mq_open+4)
+#define __NR_mq_getsetattr      (__NR_mq_open+5)
+#define __NR_sys_kexec_load    283
+#define __NR_waitid            284
+
+#define NR_syscalls 285
+
+/* user-visible error numbers are in the range -1 - -124: see
+ * <asm-m32r/errno.h>
+ */
+
+#define __syscall_return(type, res) \
+do { \
+       if ((unsigned long)(res) >= (unsigned long)(-(124 + 1))) { \
+       /* Avoid using "res" which is declared to be in register r0; \
+          errno might expand to a function call and clobber it.  */ \
+               int __err = -(res); \
+               errno = __err; \
+               res = -1; \
+       } \
+       return (type) (res); \
+} while (0)
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+register long __scno __asm__ ("r7") = __NR_##name; \
+register long __res __asm__("r0"); \
+__asm__ __volatile__ (\
+       "trap #" SYSCALL_VECTOR \
+       : "=r" (__res) \
+       : "r" (__scno) \
+       : "memory"); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+register long __scno __asm__ ("r7") = __NR_##name; \
+register long __res __asm__ ("r0") = (long)(arg1); \
+__asm__ __volatile__ (\
+       "trap #" SYSCALL_VECTOR \
+       : "=r" (__res) \
+       : "r" (__scno), "0" (__res) \
+       : "memory"); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1,type2 arg2) \
+{ \
+register long __scno __asm__ ("r7") = __NR_##name; \
+register long __arg2 __asm__ ("r1") = (long)(arg2); \
+register long __res __asm__ ("r0") = (long)(arg1); \
+__asm__ __volatile__ (\
+       "trap #" SYSCALL_VECTOR \
+       : "=r" (__res) \
+       : "r" (__scno), "0" (__res), "r" (__arg2) \
+       : "memory"); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1,type2 arg2,type3 arg3) \
+{ \
+register long __scno __asm__ ("r7") = __NR_##name; \
+register long __arg3 __asm__ ("r2") = (long)(arg3); \
+register long __arg2 __asm__ ("r1") = (long)(arg2); \
+register long __res __asm__ ("r0") = (long)(arg1); \
+__asm__ __volatile__ (\
+       "trap #" SYSCALL_VECTOR \
+       : "=r" (__res) \
+       : "r" (__scno), "0" (__res), "r" (__arg2), \
+               "r" (__arg3) \
+       : "memory"); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
+{ \
+register long __scno __asm__ ("r7") = __NR_##name; \
+register long __arg4 __asm__ ("r3") = (long)(arg4); \
+register long __arg3 __asm__ ("r2") = (long)(arg3); \
+register long __arg2 __asm__ ("r1") = (long)(arg2); \
+register long __res __asm__ ("r0") = (long)(arg1); \
+__asm__ __volatile__ (\
+       "trap #" SYSCALL_VECTOR \
+       : "=r" (__res) \
+       : "r" (__scno), "0" (__res), "r" (__arg2), \
+               "r" (__arg3), "r" (__arg4) \
+       : "memory"); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+       type5,arg5) \
+type name(type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+register long __scno __asm__ ("r7") = __NR_##name; \
+register long __arg5 __asm__ ("r4") = (long)(arg5); \
+register long __arg4 __asm__ ("r3") = (long)(arg4); \
+register long __arg3 __asm__ ("r2") = (long)(arg3); \
+register long __arg2 __asm__ ("r1") = (long)(arg2); \
+register long __res __asm__ ("r0") = (long)(arg1); \
+__asm__ __volatile__ (\
+       "trap #" SYSCALL_VECTOR \
+       : "=r" (__res) \
+       : "r" (__scno), "0" (__res), "r" (__arg2), \
+               "r" (__arg3), "r" (__arg4), "r" (__arg5) \
+       : "memory"); \
+__syscall_return(type,__res); \
+}
+
+#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
+
+#ifdef __KERNEL_SYSCALLS__
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/linkage.h>
+#include <asm/ptrace.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.
+ */
+static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+
+asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount);
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+                         unsigned long prot, unsigned long flags,
+                         unsigned long fd, unsigned long pgoff);
+asmlinkage int sys_execve(struct pt_regs regs);
+asmlinkage int sys_clone(struct pt_regs regs);
+asmlinkage int sys_fork(struct pt_regs regs);
+asmlinkage int sys_vfork(struct pt_regs regs);
+asmlinkage int sys_pipe(unsigned long __user *fildes);
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data);
+asmlinkage long sys_iopl(unsigned long unused);
+struct sigaction;
+asmlinkage long sys_rt_sigaction(int sig,
+                                const struct sigaction __user *act,
+                                struct sigaction __user *oact,
+                                size_t sigsetsize);
+
+#endif /* __KERNEL_SYSCALLS__ */
+
+/*
+ * "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
+ */
+#ifndef cond_syscall
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#endif
+
+#endif /* _ASM_M32R_UNISTD_H */
diff --git a/include/asm-m32r/user.h b/include/asm-m32r/user.h
new file mode 100644 (file)
index 0000000..2ffd0c6
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _ASM_M32R_USER_H
+#define _ASM_M32R_USER_H
+
+/* $Id$ */
+
+/* orig : sh 2.4.18
+ * mod  : remove fpu registers
+ */
+
+#include <linux/types.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+
+/*
+ * Core file format: The core file is written in such a way that gdb
+ * can understand it and provide useful information to the user (under
+ * linux we use the `trad-core' bfd).
+ *
+ * The actual file contents are as follows:
+ * UPAGE: 1 page consisting of a user struct that tells gdb
+ *     what is present in the file.  Directly after this is a
+ *     copy of the task_struct, which is currently not used by gdb,
+ *     but it may come in handy at some point.  All of the registers
+ *     are stored as part of the upage.  The upage should always be
+ *     only one page.
+ * DATA: The data area is stored.  We use current->end_text to
+ *     current->brk to pick up all of the user variables, plus any memory
+ *     that may have been sbrk'ed.  No attempt is made to determine if a
+ *     page is demand-zero or if a page is totally unused, we just cover
+ *     the entire range.  All of the addresses are rounded in such a way
+ *     that an integral number of pages is written.
+ * STACK: We need the stack information in order to get a meaningful
+ *     backtrace.  We need to write the data from usp to
+ *     current->start_stack, so we round each of these off in order to be
+ *     able to write an integer number of pages.
+ */
+
+struct user {
+       struct pt_regs  regs;                   /* entire machine state */
+       size_t          u_tsize;                /* text size (pages) */
+       size_t          u_dsize;                /* data size (pages) */
+       size_t          u_ssize;                /* stack size (pages) */
+       unsigned long   start_code;             /* text starting address */
+       unsigned long   start_data;             /* data starting address */
+       unsigned long   start_stack;            /* stack starting address */
+       long int        signal;                 /* signal causing core dump */
+       struct regs *   u_ar0;                  /* help gdb find registers */
+       unsigned long   magic;                  /* identifies a core file */
+       char            u_comm[32];             /* user command name */
+};
+
+#define NBPG                   PAGE_SIZE
+#define UPAGES                 1
+#define HOST_TEXT_START_ADDR   (u.start_code)
+#define HOST_DATA_START_ADDR   (u.start_data)
+#define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _ASM_M32R_USER_H */
diff --git a/include/asm-m32r/vga.h b/include/asm-m32r/vga.h
new file mode 100644 (file)
index 0000000..d0f4b6e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _ASM_M32R_VGA_H
+#define _ASM_M32R_VGA_H
+
+/* $Id$ */
+
+/*
+ *     Access to VGA videoram
+ *
+ *     (c) 1998 Martin Mares <mj@ucw.cz>
+ */
+
+/*
+ *     On the PC, we can just recalculate addresses and then
+ *     access the videoram directly without any black magic.
+ */
+
+#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+
+#define vga_readb(x) (*(x))
+#define vga_writeb(x,y) (*(y) = (x))
+
+#endif  /* _ASM_M32R_VGA_H */
diff --git a/include/asm-m32r/xor.h b/include/asm-m32r/xor.h
new file mode 100644 (file)
index 0000000..fd960dc
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_M32R_XOR_H
+#define _ASM_M32R_XOR_H
+
+/* $Id$ */
+
+#include <asm-generic/xor.h>
+
+#endif  /* _ASM_M32R_XOR_H */
diff --git a/include/asm-m68k/hp300hw.h b/include/asm-m68k/hp300hw.h
new file mode 100644 (file)
index 0000000..d998ea6
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _M68K_HP300HW_H
+#define _M68K_HP300HW_H
+
+extern unsigned long hp300_model;
+
+/* This information was taken from NetBSD */
+#define        HP_320          (0)     /* 16MHz 68020+HP MMU+16K external cache */
+#define        HP_330          (1)     /* 16MHz 68020+68851 MMU */
+#define        HP_340          (2)     /* 16MHz 68030 */
+#define        HP_345          (3)     /* 50MHz 68030+32K external cache */
+#define        HP_350          (4)     /* 25MHz 68020+HP MMU+32K external cache */
+#define        HP_360          (5)     /* 25MHz 68030 */
+#define        HP_370          (6)     /* 33MHz 68030+64K external cache */
+#define        HP_375          (7)     /* 50MHz 68030+32K external cache */
+#define        HP_380          (8)     /* 25MHz 68040 */
+#define        HP_385          (9)     /* 33MHz 68040 */
+
+#define        HP_400          (10)    /* 50MHz 68030+32K external cache */
+#define        HP_425T         (11)    /* 25MHz 68040 - model 425t */
+#define        HP_425S         (12)    /* 25MHz 68040 - model 425s */
+#define HP_425E                (13)    /* 25MHz 68040 - model 425e */
+#define HP_433T                (14)    /* 33MHz 68040 - model 433t */
+#define HP_433S                (15)    /* 33MHz 68040 - model 433s */
+
+#endif /* _M68K_HP300HW_H */
diff --git a/include/asm-m68knommu/m527xsim.h b/include/asm-m68knommu/m527xsim.h
new file mode 100644 (file)
index 0000000..82a39bc
--- /dev/null
@@ -0,0 +1,38 @@
+/****************************************************************************/
+
+/*
+ *     m527xsim.h -- ColdFire 5270/5271 System Integration Module support.
+ *
+ *     (C) Copyright 2004, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/****************************************************************************/
+#ifndef        m527xsim_h
+#define        m527xsim_h
+/****************************************************************************/
+
+#include <linux/config.h>
+
+/*
+ *     Define the 5270/5271 SIM register set addresses.
+ */
+#define        MCFICM_INTC0            0x0c00          /* Base for Interrupt Ctrl 0 */
+#define        MCFICM_INTC1            0x0d00          /* Base for Interrupt Ctrl 1 */
+#define        MCFINTC_IPRH            0x00            /* Interrupt pending 32-63 */
+#define        MCFINTC_IPRL            0x04            /* Interrupt pending 1-31 */
+#define        MCFINTC_IMRH            0x08            /* Interrupt mask 32-63 */
+#define        MCFINTC_IMRL            0x0c            /* Interrupt mask 1-31 */
+#define        MCFINTC_INTFRCH         0x10            /* Interrupt force 32-63 */
+#define        MCFINTC_INTFRCL         0x14            /* Interrupt force 1-31 */
+#define        MCFINTC_IRLR            0x18            /* */
+#define        MCFINTC_IACKL           0x19            /* */
+#define        MCFINTC_ICR0            0x40            /* Base ICR register */
+
+#define        MCFINT_VECBASE          64              /* Vector base number */
+#define        MCFINT_UART0            13              /* Interrupt number for UART0 */
+#define        MCFINT_UART1            14              /* Interrupt number for UART1 */
+#define        MCFINT_UART2            15              /* Interrupt number for UART2 */
+#define        MCFINT_PIT1             36              /* Interrupt number for PIT1 */
+
+/****************************************************************************/
+#endif /* m527xsim_h */
diff --git a/include/asm-m68knommu/m528xsim.h b/include/asm-m68knommu/m528xsim.h
new file mode 100644 (file)
index 0000000..bc91a4b
--- /dev/null
@@ -0,0 +1,36 @@
+/****************************************************************************/
+
+/*
+ *     m528xsim.h -- ColdFire 5280/5282 System Integration Module support.
+ *
+ *     (C) Copyright 2003, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/****************************************************************************/
+#ifndef        m528xsim_h
+#define        m528xsim_h
+/****************************************************************************/
+
+#include <linux/config.h>
+
+/*
+ *     Define the 5280/5282 SIM register set addresses.
+ */
+#define        MCFICM_INTC0            0x0c00          /* Base for Interrupt Ctrl 0 */
+#define        MCFICM_INTC1            0x0d00          /* Base for Interrupt Ctrl 0 */
+#define        MCFINTC_IPRH            0x00            /* Interrupt pending 32-63 */
+#define        MCFINTC_IPRL            0x04            /* Interrupt pending 1-31 */
+#define        MCFINTC_IMRH            0x08            /* Interrupt mask 32-63 */
+#define        MCFINTC_IMRL            0x0c            /* Interrupt mask 1-31 */
+#define        MCFINTC_INTFRCH         0x10            /* Interrupt force 32-63 */
+#define        MCFINTC_INTFRCL         0x14            /* Interrupt force 1-31 */
+#define        MCFINTC_IRLR            0x18            /* */
+#define        MCFINTC_IACKL           0x19            /* */
+#define        MCFINTC_ICR0            0x40            /* Base ICR register */
+
+#define        MCFINT_VECBASE          64              /* Vector base number */
+#define        MCFINT_UART0            13              /* Interrupt number for UART0 */
+#define        MCFINT_PIT1             55              /* Interrupt number for PIT1 */
+
+/****************************************************************************/
+#endif /* m528xsim_h */
diff --git a/include/asm-mips/compiler.h b/include/asm-mips/compiler.h
new file mode 100644 (file)
index 0000000..169ae26
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2004  Maciej W. Rozycki
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef _ASM_COMPILER_H
+#define _ASM_COMPILER_H
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define GCC_REG_ACCUM "$0"
+#else
+#define GCC_REG_ACCUM "accum"
+#endif
+
+#endif /* _ASM_COMPILER_H */
diff --git a/include/asm-mips/cpu-info.h b/include/asm-mips/cpu-info.h
new file mode 100644 (file)
index 0000000..984277a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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 Waldorf GMBH
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Ralf Baechle
+ * Copyright (C) 1996 Paul M. Antoine
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef __ASM_CPU_INFO_H
+#define __ASM_CPU_INFO_H
+
+#include <linux/config.h>
+#include <asm/cache.h>
+
+#ifdef CONFIG_SGI_IP27
+#include <asm/sn/types.h>
+#endif
+
+/*
+ * Descriptor for a cache
+ */
+struct cache_desc {
+       unsigned short linesz;  /* Size of line in bytes */
+       unsigned short ways;    /* Number of ways */
+       unsigned short sets;    /* Number of lines per set */
+       unsigned int waysize;   /* Bytes per way */
+       unsigned int waybit;    /* Bits to select in a cache set */
+       unsigned int flags;     /* Flags describing cache properties */
+};
+
+/*
+ * Flag definitions
+ */
+#define MIPS_CACHE_NOT_PRESENT 0x00000001
+#define MIPS_CACHE_VTAG                0x00000002      /* Virtually tagged cache */
+#define MIPS_CACHE_ALIASES     0x00000004      /* Cache could have aliases */
+#define MIPS_CACHE_IC_F_DC     0x00000008      /* Ic can refill from D-cache */
+
+struct cpuinfo_mips {
+       unsigned long           udelay_val;
+       unsigned long           asid_cache;
+#if defined(CONFIG_SGI_IP27)
+//     cpuid_t         p_cpuid;        /* PROM assigned cpuid */
+       cnodeid_t       p_nodeid;       /* my node ID in compact-id-space */
+       nasid_t         p_nasid;        /* my node ID in numa-as-id-space */
+       unsigned char   p_slice;        /* Physical position on node board */
+#endif
+#if 0
+       unsigned long           loops_per_sec;
+       unsigned long           ipi_count;
+       unsigned long           irq_attempt[NR_IRQS];
+       unsigned long           smp_local_irq_count;
+       unsigned long           prof_multiplier;
+       unsigned long           prof_counter;
+#endif
+
+       /*
+        * Capability and feature descriptor structure for MIPS CPU
+        */
+       unsigned long           options;
+       unsigned int            processor_id;
+       unsigned int            fpu_id;
+       unsigned int            cputype;
+       int                     isa_level;
+       int                     tlbsize;
+       struct cache_desc       icache; /* Primary I-cache */
+       struct cache_desc       dcache; /* Primary D or combined I/D cache */
+       struct cache_desc       scache; /* Secondary cache */
+       struct cache_desc       tcache; /* Tertiary/split secondary cache */
+       void                    *data;  /* Additional data */
+} __attribute__((aligned(SMP_CACHE_BYTES)));
+
+extern struct cpuinfo_mips cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+
+extern void cpu_probe(void);
+extern void cpu_report(void);
+
+#endif /* __ASM_CPU_INFO_H */
diff --git a/include/asm-mips/dec/serial.h b/include/asm-mips/dec/serial.h
new file mode 100644 (file)
index 0000000..acad758
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *     include/asm-mips/dec/serial.h
+ *
+ *     Definitions common to all DECstation serial devices.
+ *
+ *     Copyright (C) 2004  Maciej W. Rozycki
+ *
+ *     Based on bits extracted from drivers/tc/zs.h for which
+ *     the following copyrights apply:
+ *
+ *     Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
+ *     Copyright (C) 1996  Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ *     Copyright (C)       Harald Koerfgen
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+#ifndef __ASM_MIPS_DEC_SERIAL_H
+#define __ASM_MIPS_DEC_SERIAL_H
+
+struct dec_serial_hook {
+       int (*init_channel)(void *handle);
+       void (*init_info)(void *handle);
+       void (*rx_char)(unsigned char ch, unsigned char fl);
+       int (*poll_rx_char)(void *handle);
+       int (*poll_tx_char)(void *handle, unsigned char ch);
+       unsigned int cflags;
+};
+
+extern int register_dec_serial_hook(unsigned int channel,
+                                   struct dec_serial_hook *hook);
+extern int unregister_dec_serial_hook(unsigned int channel);
+
+#endif /* __ASM_MIPS_DEC_SERIAL_H */
diff --git a/include/asm-mips/interrupt.h b/include/asm-mips/interrupt.h
new file mode 100644 (file)
index 0000000..e8357f5
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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, 95, 96, 97, 98, 99, 2003 by Ralf Baechle
+ * Copyright (C) 1996 by Paul M. Antoine
+ * Copyright (C) 1999 Silicon Graphics
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#ifndef _ASM_INTERRUPT_H
+#define _ASM_INTERRUPT_H
+
+#include <asm/hazards.h>
+
+__asm__ (
+       ".macro\tlocal_irq_enable\n\t"
+       ".set\tpush\n\t"
+       ".set\treorder\n\t"
+       ".set\tnoat\n\t"
+       "mfc0\t$1,$12\n\t"
+       "ori\t$1,0x1f\n\t"
+       "xori\t$1,0x1e\n\t"
+       "mtc0\t$1,$12\n\t"
+       "irq_enable_hazard\n\t"
+       ".set\tpop\n\t"
+       ".endm");
+
+static inline void local_irq_enable(void)
+{
+       __asm__ __volatile__(
+               "local_irq_enable"
+               : /* no outputs */
+               : /* no inputs */
+               : "memory");
+}
+
+/*
+ * For cli() we have to insert nops to make sure that the new value
+ * has actually arrived in the status register before the end of this
+ * macro.
+ * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
+ * no nops at all.
+ */
+__asm__ (
+       ".macro\tlocal_irq_disable\n\t"
+       ".set\tpush\n\t"
+       ".set\tnoat\n\t"
+       "mfc0\t$1,$12\n\t"
+       "ori\t$1,1\n\t"
+       "xori\t$1,1\n\t"
+       ".set\tnoreorder\n\t"
+       "mtc0\t$1,$12\n\t"
+       "irq_disable_hazard\n\t"
+       ".set\tpop\n\t"
+       ".endm");
+
+static inline void local_irq_disable(void)
+{
+       __asm__ __volatile__(
+               "local_irq_disable"
+               : /* no outputs */
+               : /* no inputs */
+               : "memory");
+}
+
+__asm__ (
+       ".macro\tlocal_save_flags flags\n\t"
+       ".set\tpush\n\t"
+       ".set\treorder\n\t"
+       "mfc0\t\\flags, $12\n\t"
+       ".set\tpop\n\t"
+       ".endm");
+
+#define local_save_flags(x)                                            \
+__asm__ __volatile__(                                                  \
+       "local_save_flags %0"                                           \
+       : "=r" (x))
+
+__asm__ (
+       ".macro\tlocal_irq_save result\n\t"
+       ".set\tpush\n\t"
+       ".set\treorder\n\t"
+       ".set\tnoat\n\t"
+       "mfc0\t\\result, $12\n\t"
+       "ori\t$1, \\result, 1\n\t"
+       "xori\t$1, 1\n\t"
+       ".set\tnoreorder\n\t"
+       "mtc0\t$1, $12\n\t"
+       "irq_disable_hazard\n\t"
+       ".set\tpop\n\t"
+       ".endm");
+
+#define local_irq_save(x)                                              \
+__asm__ __volatile__(                                                  \
+       "local_irq_save\t%0"                                            \
+       : "=r" (x)                                                      \
+       : /* no inputs */                                               \
+       : "memory")
+
+__asm__ (
+       ".macro\tlocal_irq_restore flags\n\t"
+       ".set\tnoreorder\n\t"
+       ".set\tnoat\n\t"
+       "mfc0\t$1, $12\n\t"
+       "andi\t\\flags, 1\n\t"
+       "ori\t$1, 1\n\t"
+       "xori\t$1, 1\n\t"
+       "or\t\\flags, $1\n\t"
+       "mtc0\t\\flags, $12\n\t"
+       "irq_disable_hazard\n\t"
+       ".set\tat\n\t"
+       ".set\treorder\n\t"
+       ".endm");
+
+#define local_irq_restore(flags)                                       \
+do {                                                                   \
+       unsigned long __tmp1;                                           \
+                                                                       \
+       __asm__ __volatile__(                                           \
+               "local_irq_restore\t%0"                                 \
+               : "=r" (__tmp1)                                         \
+               : "0" (flags)                                           \
+               : "memory");                                            \
+} while(0)
+
+#define irqs_disabled()                                                        \
+({                                                                     \
+       unsigned long flags;                                            \
+       local_save_flags(flags);                                        \
+       !(flags & 1);                                                   \
+})
+
+#endif /* _ASM_INTERRUPT_H */
diff --git a/include/asm-mips/mach-ip22/spaces.h b/include/asm-mips/mach-ip22/spaces.h
new file mode 100644 (file)
index 0000000..30d42fc
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 - 1999, 2000, 03, 04 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_MACH_IP22_SPACES_H
+#define _ASM_MACH_IP22_SPACES_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_MIPS32
+
+#define CAC_BASE               0x80000000
+#define IO_BASE                        0xa0000000
+#define UNCAC_BASE             0xa0000000
+#define MAP_BASE               0xc0000000
+
+/*
+ * This handles the memory map.
+ * We handle pages at KSEG0 for kernels with 32 bit address space.
+ */
+#define PAGE_OFFSET            0x80000000UL
+
+/*
+ * Memory above this physical address will be considered highmem.
+ */
+#ifndef HIGHMEM_START
+#define HIGHMEM_START          0x20000000UL
+#endif
+
+#endif /* CONFIG_MIPS32 */
+
+#ifdef CONFIG_MIPS64
+#define PAGE_OFFSET            0xffffffff80000000UL
+
+#ifndef HIGHMEM_START
+#define HIGHMEM_START          (1UL << 59UL)
+#endif
+
+#define CAC_BASE               0xffffffff80000000
+#define IO_BASE                        0xffffffffa0000000
+#define UNCAC_BASE             0xffffffffa0000000
+#define MAP_BASE               0xffffffffc0000000
+
+#define TO_PHYS(x)             (             ((x) & TO_PHYS_MASK))
+#define TO_CAC(x)              (CAC_BASE   | ((x) & TO_PHYS_MASK))
+#define TO_UNCAC(x)            (UNCAC_BASE | ((x) & TO_PHYS_MASK))
+
+#endif /* CONFIG_MIPS64 */
+
+#endif /* __ASM_MACH_IP22_SPACES_H */
diff --git a/include/asm-mips/mach-ip32/spaces.h b/include/asm-mips/mach-ip32/spaces.h
new file mode 100644 (file)
index 0000000..649864c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 - 1999, 2000, 03, 04 Ralf Baechle
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
+ */
+#ifndef _ASM_MACH_IP32_SPACES_H
+#define _ASM_MACH_IP32_SPACES_H
+
+#include <linux/config.h>
+
+/*
+ * This handles the memory map.
+ */
+#define PAGE_OFFSET            0xffffffff80000000
+
+/*
+ * Memory above this physical address will be considered highmem.
+ * Fixme: 59 bits is a fictive number and makes assumptions about processors
+ * in the distant future.  Nobody will care for a few years :-)
+ */
+#ifndef HIGHMEM_START
+#define HIGHMEM_START          (1UL << 59UL)
+#endif
+
+#ifdef CONFIG_DMA_NONCOHERENT
+#define CAC_BASE               0x9800000000000000
+#else
+#define CAC_BASE               0xa800000000000000
+#endif
+#define IO_BASE                        0x9000000000000000
+#define UNCAC_BASE             0x9000000000000000
+#define MAP_BASE               0xc000000000000000
+
+#define TO_PHYS(x)             (             ((x) & TO_PHYS_MASK))
+#define TO_CAC(x)              (CAC_BASE   | ((x) & TO_PHYS_MASK))
+#define TO_UNCAC(x)            (UNCAC_BASE | ((x) & TO_PHYS_MASK))
+
+#endif /* __ASM_MACH_IP32_SPACES_H */
diff --git a/include/asm-mips/mach-mips/cpu-feature-overrides.h b/include/asm-mips/mach-mips/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..2aba654
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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, 2004 Chris Dearman
+ */
+#ifndef __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * CPU feature overrides for MIPS boards
+ */
+#ifdef CONFIG_CPU_MIPS32
+#define cpu_has_tlb            1
+#define cpu_has_4kex           1
+#define cpu_has_4ktlb          1
+/* #define cpu_has_fpu         ? */
+/* #define cpu_has_32fpr       ? */
+#define cpu_has_counter                1
+/* #define cpu_has_watch       ? */
+#define cpu_has_divec          1
+#define cpu_has_vce            0
+/* #define cpu_has_cache_cdex_p        ? */
+/* #define cpu_has_cache_cdex_s        ? */
+/* #define cpu_has_prefetch    ? */
+#define cpu_has_mcheck         1
+/* #define cpu_has_ejtag       ? */
+#define cpu_has_llsc           1
+/* #define cpu_has_vtag_icache ? */
+/* #define cpu_has_dc_aliases  ? */
+/* #define cpu_has_ic_fills_f_dc ? */
+#define cpu_has_nofpuex                0
+/* #define cpu_has_64bits      ? */
+/* #define cpu_has_64bit_zero_reg ? */
+/* #define cpu_has_subset_pcaches ? */
+#endif
+
+#ifdef CONFIG_CPU_MIPS64
+#define cpu_has_tlb            1
+#define cpu_has_4kex           1
+#define cpu_has_4ktlb          1
+/* #define cpu_has_fpu         ? */
+/* #define cpu_has_32fpr       ? */
+#define cpu_has_counter                1
+/* #define cpu_has_watch       ? */
+#define cpu_has_divec          1
+#define cpu_has_vce            0
+/* #define cpu_has_cache_cdex_p        ? */
+/* #define cpu_has_cache_cdex_s        ? */
+/* #define cpu_has_prefetch    ? */
+#define cpu_has_mcheck         1
+/* #define cpu_has_ejtag       ? */
+#define cpu_has_llsc           1
+/* #define cpu_has_vtag_icache ? */
+/* #define cpu_has_dc_aliases  ? */
+/* #define cpu_has_ic_fills_f_dc ? */
+#define cpu_has_nofpuex                0
+/* #define cpu_has_64bits      ? */
+/* #define cpu_has_64bit_zero_reg ? */
+/* #define cpu_has_subset_pcaches ? */
+#endif
+
+#endif /* __ASM_MACH_MIPS_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-ocelot3/cpu-feature-overrides.h b/include/asm-mips/mach-ocelot3/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..6cebe12
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 MontaVista Software Inc.
+ * Author: Manish Lachwani, mlachwani@mvista.com
+ * Copyright (C) 2004 Ralf Baechle
+ */
+#ifndef __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * Momentum Ocelot-3 is based on Rm7900 processor which
+ * is based on the E9000 core.
+ */
+#define cpu_has_watch          1
+#define cpu_has_mips16         0
+#define cpu_has_divec          0
+#define cpu_has_vce            0
+#define cpu_has_cache_cdex_p   0
+#define cpu_has_cache_cdex_s   0
+#define cpu_has_prefetch       1
+#define cpu_has_mcheck         0
+#define cpu_has_ejtag          0
+
+#define cpu_has_llsc           1
+#define cpu_has_vtag_icache    0
+#define cpu_has_dc_aliases     0
+#define cpu_has_ic_fills_f_dc  0
+
+#define cpu_has_nofpuex        0
+#define cpu_has_64bits         1
+
+#define cpu_has_subset_pcaches 0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+#define cpu_scache_line_size() 32
+
+/*
+ * On the RM9000 we need to ensure that I-cache lines being fetches only
+ * contain valid instructions are funny things will happen.
+ */
+#define PLAT_TRAMPOLINE_STUFF_LINE     32UL
+
+#endif /* __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..5bb8b89
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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, 2004 Ralf Baechle
+ */
+#ifndef __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * Sibyte are MIPS64 processors weired to a specific configuration
+ */
+#define cpu_has_watch          1
+#define cpu_has_mips16         0
+#define cpu_has_divec          1
+#define cpu_has_vce            0
+#define cpu_has_cache_cdex_p   0
+#define cpu_has_cache_cdex_s   0
+#define cpu_has_prefetch       1
+#define cpu_has_mcheck         1
+#define cpu_has_ejtag          1
+
+#define cpu_has_llsc           1
+#define cpu_has_vtag_icache    1
+#define cpu_has_dc_aliases     0
+#define cpu_has_ic_fills_f_dc  0
+
+#define cpu_has_nofpuex                0
+#define cpu_has_64bits         1
+
+#define cpu_has_subset_pcaches 0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+#define cpu_scache_line_size() 32
+
+#endif /* __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/msc01_ic.h b/include/asm-mips/msc01_ic.h
new file mode 100644 (file)
index 0000000..64f1720
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * PCI Register definitions for the MIPS System Controller.
+ *
+ * Copyright (C) 2004 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ASM_MIPS_BOARDS_MSC01_IC_H
+#define __ASM_MIPS_BOARDS_MSC01_IC_H
+
+/*****************************************************************************
+ * Register offset addresses
+ *****************************************************************************/
+
+#define MSC01_IC_RST_OFS     0x00008    /* Software reset              */
+#define MSC01_IC_ENAL_OFS    0x00100    /* Int_in enable mask 31:0     */
+#define MSC01_IC_ENAH_OFS    0x00108    /* Int_in enable mask 63:32    */
+#define MSC01_IC_DISL_OFS    0x00120    /* Int_in disable mask 31:0    */
+#define MSC01_IC_DISH_OFS    0x00128    /* Int_in disable mask 63:32   */
+#define MSC01_IC_ISBL_OFS    0x00140    /* Raw int_in 31:0             */
+#define MSC01_IC_ISBH_OFS    0x00148    /* Raw int_in 63:32            */
+#define MSC01_IC_ISAL_OFS    0x00160    /* Masked int_in 31:0          */
+#define MSC01_IC_ISAH_OFS    0x00168    /* Masked int_in 63:32         */
+#define MSC01_IC_LVL_OFS     0x00180    /* Disable priority int_out    */
+#define MSC01_IC_RAMW_OFS    0x00180    /* Shadow set RAM (EI)        */
+#define MSC01_IC_OSB_OFS     0x00188    /* Raw int_out                 */
+#define MSC01_IC_OSA_OFS     0x00190    /* Masked int_out              */
+#define MSC01_IC_GENA_OFS    0x00198    /* Global HW int enable        */
+#define MSC01_IC_BASE_OFS    0x001a0    /* Base address of IC_VEC      */
+#define MSC01_IC_VEC_OFS     0x001b0    /* Active int's vector address */
+#define MSC01_IC_EOI_OFS     0x001c0    /* Enable lower level ints     */
+#define MSC01_IC_CFG_OFS     0x001c8    /* Configuration register      */
+#define MSC01_IC_TRLD_OFS    0x001d0    /* Interval timer reload val   */
+#define MSC01_IC_TVAL_OFS    0x001e0    /* Interval timer current val  */
+#define MSC01_IC_TCFG_OFS    0x001f0    /* Interval timer config       */
+#define MSC01_IC_SUP_OFS     0x00200    /* Set up int_in line 0        */
+#define MSC01_IC_ENA_OFS     0x00800    /* Int_in enable mask 63:0     */
+#define MSC01_IC_DIS_OFS     0x00820    /* Int_in disable mask 63:0    */
+#define MSC01_IC_ISB_OFS     0x00840    /* Raw int_in 63:0             */
+#define MSC01_IC_ISA_OFS     0x00860    /* Masked int_in 63:0          */
+
+/*****************************************************************************
+ * Register field encodings
+ *****************************************************************************/
+
+#define MSC01_IC_RST_RST_SHF      0
+#define MSC01_IC_RST_RST_MSK      0x00000001
+#define MSC01_IC_RST_RST_BIT      MSC01_IC_RST_RST_MSK
+#define MSC01_IC_LVL_LVL_SHF      0
+#define MSC01_IC_LVL_LVL_MSK      0x000000ff
+#define MSC01_IC_LVL_SPUR_SHF     16
+#define MSC01_IC_LVL_SPUR_MSK     0x00010000
+#define MSC01_IC_LVL_SPUR_BIT     MSC01_IC_LVL_SPUR_MSK
+#define MSC01_IC_RAMW_RIPL_SHF   0
+#define MSC01_IC_RAMW_RIPL_MSK   0x0000003f
+#define MSC01_IC_RAMW_DATA_SHF   6
+#define MSC01_IC_RAMW_DATA_MSK   0x00000fc0
+#define MSC01_IC_RAMW_ADDR_SHF   25
+#define MSC01_IC_RAMW_ADDR_MSK   0x7e000000
+#define MSC01_IC_RAMW_READ_SHF   31
+#define MSC01_IC_RAMW_READ_MSK   0x80000000
+#define MSC01_IC_RAMW_READ_BIT   MSC01_IC_RAMW_READ_MSK
+#define MSC01_IC_OSB_OSB_SHF      0
+#define MSC01_IC_OSB_OSB_MSK      0x000000ff
+#define MSC01_IC_OSA_OSA_SHF      0
+#define MSC01_IC_OSA_OSA_MSK      0x000000ff
+#define MSC01_IC_GENA_GENA_SHF    0
+#define MSC01_IC_GENA_GENA_MSK    0x00000001
+#define MSC01_IC_GENA_GENA_BIT    MSC01_IC_GENA_GENA_MSK
+#define MSC01_IC_CFG_DIS_SHF      0
+#define MSC01_IC_CFG_DIS_MSK      0x00000001
+#define MSC01_IC_CFG_DIS_BIT      MSC01_IC_CFG_DIS_MSK
+#define MSC01_IC_CFG_SHFT_SHF     8
+#define MSC01_IC_CFG_SHFT_MSK     0x00000f00
+#define MSC01_IC_TCFG_ENA_SHF     0
+#define MSC01_IC_TCFG_ENA_MSK     0x00000001
+#define MSC01_IC_TCFG_ENA_BIT     MSC01_IC_TCFG_ENA_MSK
+#define MSC01_IC_TCFG_INT_SHF     8
+#define MSC01_IC_TCFG_INT_MSK     0x00000100
+#define MSC01_IC_TCFG_INT_BIT     MSC01_IC_TCFG_INT_MSK
+#define MSC01_IC_TCFG_EDGE_SHF    16
+#define MSC01_IC_TCFG_EDGE_MSK    0x00010000
+#define MSC01_IC_TCFG_EDGE_BIT    MSC01_IC_TCFG_EDGE_MSK
+#define MSC01_IC_SUP_PRI_SHF      0
+#define MSC01_IC_SUP_PRI_MSK      0x00000007
+#define MSC01_IC_SUP_EDGE_SHF     8
+#define MSC01_IC_SUP_EDGE_MSK     0x00000100
+#define MSC01_IC_SUP_EDGE_BIT     MSC01_IC_SUP_EDGE_MSK
+#define MSC01_IC_SUP_STEP         8
+
+/*
+ * MIPS System controller interrupt register base.
+ *
+ * FIXME - are these macros specific to Malta and co or to the MSC?  If the
+ * latter, they should be moved elsewhere.
+ */
+#define MIPS_MSC01_IC_REG_BASE 0x1bc40000
+
+/*****************************************************************************
+ * Absolute register addresses
+ *****************************************************************************/
+
+#define MSC01_IC_RST     (MSC01_IC_REG_BASE + MSC01_IC_RST_OFS)
+#define MSC01_IC_ENAL    (MSC01_IC_REG_BASE + MSC01_IC_ENAL_OFS)
+#define MSC01_IC_ENAH    (MSC01_IC_REG_BASE + MSC01_IC_ENAH_OFS)
+#define MSC01_IC_DISL    (MSC01_IC_REG_BASE + MSC01_IC_DISL_OFS)
+#define MSC01_IC_DISH    (MSC01_IC_REG_BASE + MSC01_IC_DISH_OFS)
+#define MSC01_IC_ISBL    (MSC01_IC_REG_BASE + MSC01_IC_ISBL_OFS)
+#define MSC01_IC_ISBH    (MSC01_IC_REG_BASE + MSC01_IC_ISBH_OFS)
+#define MSC01_IC_ISAL    (MSC01_IC_REG_BASE + MSC01_IC_ISAL_OFS)
+#define MSC01_IC_ISAH    (MSC01_IC_REG_BASE + MSC01_IC_ISAH_OFS)
+#define MSC01_IC_LVL     (MSC01_IC_REG_BASE + MSC01_IC_LVL_OFS)
+#define MSC01_IC_RAMW    (MSC01_IC_REG_BASE + MSC01_IC_RAMW_OFS)
+#define MSC01_IC_OSB     (MSC01_IC_REG_BASE + MSC01_IC_OSB_OFS)
+#define MSC01_IC_OSA     (MSC01_IC_REG_BASE + MSC01_IC_OSA_OFS)
+#define MSC01_IC_GENA    (MSC01_IC_REG_BASE + MSC01_IC_GENA_OFS)
+#define MSC01_IC_BASE    (MSC01_IC_REG_BASE + MSC01_IC_BASE_OFS)
+#define MSC01_IC_VEC     (MSC01_IC_REG_BASE + MSC01_IC_VEC_OFS)
+#define MSC01_IC_EOI     (MSC01_IC_REG_BASE + MSC01_IC_EOI_OFS)
+#define MSC01_IC_CFG     (MSC01_IC_REG_BASE + MSC01_IC_CFG_OFS)
+#define MSC01_IC_TRLD    (MSC01_IC_REG_BASE + MSC01_IC_TRLD_OFS)
+#define MSC01_IC_TVAL    (MSC01_IC_REG_BASE + MSC01_IC_TVAL_OFS)
+#define MSC01_IC_TCFG    (MSC01_IC_REG_BASE + MSC01_IC_TCFG_OFS)
+#define MSC01_IC_SUP     (MSC01_IC_REG_BASE + MSC01_IC_SUP_OFS)
+#define MSC01_IC_ENA     (MSC01_IC_REG_BASE + MSC01_IC_ENA_OFS)
+#define MSC01_IC_DIS     (MSC01_IC_REG_BASE + MSC01_IC_DIS_OFS)
+#define MSC01_IC_ISB     (MSC01_IC_REG_BASE + MSC01_IC_ISB_OFS)
+#define MSC01_IC_ISA     (MSC01_IC_REG_BASE + MSC01_IC_ISA_OFS)
+
+/*
+ * Soc-it interrupts are configurable.
+ * Every board describes its IRQ mapping with this table.
+ */
+typedef struct msc_irqmap {
+       int     im_irq;
+       int     im_type;
+       int     im_lvl;
+} msc_irqmap_t;
+
+/* im_type */
+#define MSC01_IRQ_LEVEL                0
+#define MSC01_IRQ_EDGE         1
+
+extern void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq);
+extern void ll_msc_irq(struct pt_regs *regs);
+
+#endif /* __ASM_MIPS_BOARDS_MSC01_IC_H */
+
diff --git a/include/asm-mips/tx4927/smsc_fdc37m81x.h b/include/asm-mips/tx4927/smsc_fdc37m81x.h
new file mode 100644 (file)
index 0000000..5d93bab
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * linux/include/asm-mips/tx4927/smsc_fdc37m81x.h
+ *
+ * Interface for smsc fdc48m81x Super IO chip
+ *
+ * Author: MontaVista Software, Inc. source@mvista.com
+ *
+ * 2001-2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Copyright (C) 2004 MontaVista Software Inc.
+ * Manish Lachwani, mlachwani@mvista.com
+ */
+
+#ifndef _SMSC_FDC37M81X_H_
+#define _SMSC_FDC37M81X_H_
+
+/* Common Registers */
+#define SMSC_FDC37M81X_CONFIG_INDEX  0x00
+#define SMSC_FDC37M81X_CONFIG_DATA   0x01
+#define SMSC_FDC37M81X_CONF          0x02
+#define SMSC_FDC37M81X_INDEX         0x03
+#define SMSC_FDC37M81X_DNUM          0x07
+#define SMSC_FDC37M81X_DID           0x20
+#define SMSC_FDC37M81X_DREV          0x21
+#define SMSC_FDC37M81X_PCNT          0x22
+#define SMSC_FDC37M81X_PMGT          0x23
+#define SMSC_FDC37M81X_OSC           0x24
+#define SMSC_FDC37M81X_CONFPA0       0x26
+#define SMSC_FDC37M81X_CONFPA1       0x27
+#define SMSC_FDC37M81X_TEST4         0x2B
+#define SMSC_FDC37M81X_TEST5         0x2C
+#define SMSC_FDC37M81X_TEST1         0x2D
+#define SMSC_FDC37M81X_TEST2         0x2E
+#define SMSC_FDC37M81X_TEST3         0x2F
+
+/* Logical device numbers */
+#define SMSC_FDC37M81X_FDD           0x00
+#define SMSC_FDC37M81X_PARALLEL      0x03
+#define SMSC_FDC37M81X_SERIAL1       0x04
+#define SMSC_FDC37M81X_SERIAL2       0x05
+#define SMSC_FDC37M81X_KBD           0x07
+#define SMSC_FDC37M81X_AUXIO         0x08
+#define SMSC_FDC37M81X_NONE          0xff
+
+/* Logical device Config Registers */
+#define SMSC_FDC37M81X_ACTIVE        0x30
+#define SMSC_FDC37M81X_BASEADDR0     0x60
+#define SMSC_FDC37M81X_BASEADDR1     0x61
+#define SMSC_FDC37M81X_INT           0x70
+#define SMSC_FDC37M81X_INT2          0x72
+#define SMSC_FDC37M81X_LDCR_F0       0xF0
+
+/* Chip Config Values */
+#define SMSC_FDC37M81X_CONFIG_ENTER  0x55
+#define SMSC_FDC37M81X_CONFIG_EXIT   0xaa
+#define SMSC_FDC37M81X_CHIP_ID       0x4d
+
+unsigned long __init smsc_fdc37m81x_init(unsigned long port);
+
+void smsc_fdc37m81x_config_beg(void);
+
+void smsc_fdc37m81x_config_end(void);
+
+void smsc_fdc37m81x_config_set(u8 reg, u8 val);
+
+#endif
diff --git a/include/asm-ppc/8253pit.h b/include/asm-ppc/8253pit.h
new file mode 100644 (file)
index 0000000..285f784
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * 8253/8254 Programmable Interval Timer
+ */
+
+#ifndef _8253PIT_H
+#define _8253PIT_H
+
+#define PIT_TICK_RATE  1193182UL
+
+#endif
diff --git a/include/asm-ppc/xparameters.h b/include/asm-ppc/xparameters.h
new file mode 100644 (file)
index 0000000..fe4eac6
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * include/asm-ppc/xparameters.h
+ *
+ * This file includes the correct xparameters.h for the CONFIG'ed board
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2004 (c) MontaVista Software, Inc.  This file is licensed under the terms
+ * of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_XILINX_ML300)
+#include <platforms/4xx/xparameters/xparameters_ml300.h>
+#endif
diff --git a/include/asm-ppc64/8253pit.h b/include/asm-ppc64/8253pit.h
new file mode 100644 (file)
index 0000000..285f784
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * 8253/8254 Programmable Interval Timer
+ */
+
+#ifndef _8253PIT_H
+#define _8253PIT_H
+
+#define PIT_TICK_RATE  1193182UL
+
+#endif
diff --git a/include/asm-ppc64/plpar_wrappers.h b/include/asm-ppc64/plpar_wrappers.h
new file mode 100644 (file)
index 0000000..17452d3
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _PPC64_PLPAR_WRAPPERS_H
+#define _PPC64_PLPAR_WRAPPERS_H
+
+#include <asm/hvcall.h>
+
+static inline long poll_pending(void)
+{
+       unsigned long dummy;
+       return plpar_hcall(H_POLL_PENDING, 0, 0, 0, 0,
+                          &dummy, &dummy, &dummy);
+}
+
+static inline long prod_processor(void)
+{
+       plpar_hcall_norets(H_PROD);
+       return(0); 
+}
+
+static inline long cede_processor(void)
+{
+       plpar_hcall_norets(H_CEDE);
+       return(0); 
+}
+
+static inline long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa)
+{
+       plpar_hcall_norets(H_REGISTER_VPA, flags, proc, vpa);
+       return(0); 
+}
+
+static inline long plpar_pte_remove(unsigned long flags,
+                                   unsigned long ptex,
+                                   unsigned long avpn,
+                                   unsigned long *old_pteh_ret,
+                                   unsigned long *old_ptel_ret)
+{
+       unsigned long dummy;
+       return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,
+                          old_pteh_ret, old_ptel_ret, &dummy);
+}
+
+static inline long plpar_pte_read(unsigned long flags,
+                                 unsigned long ptex,
+                                 unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+       unsigned long dummy;
+       return plpar_hcall(H_READ, flags, ptex, 0, 0,
+                          old_pteh_ret, old_ptel_ret, &dummy);
+}
+
+static inline long plpar_pte_protect(unsigned long flags,
+                                    unsigned long ptex,
+                                    unsigned long avpn)
+{
+       return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
+}
+
+static inline long plpar_tce_get(unsigned long liobn,
+                                unsigned long ioba,
+                                unsigned long *tce_ret)
+{
+       unsigned long dummy;
+       return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0,
+                          tce_ret, &dummy, &dummy);
+}
+
+static inline long plpar_tce_put(unsigned long liobn,
+                                unsigned long ioba,
+                                unsigned long tceval)
+{
+       return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
+}
+
+static inline long plpar_tce_put_indirect(unsigned long liobn,
+                                         unsigned long ioba,
+                                         unsigned long page,
+                                         unsigned long count)
+{
+       return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count);
+}
+
+static inline long plpar_tce_stuff(unsigned long liobn,
+                                  unsigned long ioba,
+                                  unsigned long tceval,
+                                  unsigned long count)
+{
+       return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count);
+}
+
+static inline long plpar_get_term_char(unsigned long termno,
+                                      unsigned long *len_ret,
+                                      char *buf_ret)
+{
+       unsigned long *lbuf = (unsigned long *)buf_ret;  /* ToDo: alignment? */
+       return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0,
+                          len_ret, lbuf+0, lbuf+1);
+}
+
+static inline long plpar_put_term_char(unsigned long termno,
+                                      unsigned long len,
+                                      const char *buffer)
+{
+       unsigned long *lbuf = (unsigned long *)buffer;  /* ToDo: alignment? */
+       return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0],
+                                 lbuf[1]);
+}
+
+
+#endif /* _PPC64_PLPAR_WRAPPERS_H */
diff --git a/include/asm-ppc64/sstep.h b/include/asm-ppc64/sstep.h
new file mode 100644 (file)
index 0000000..448190d
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM
+ *
+ * This 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.
+ */
+
+struct pt_regs;
+
+/* Emulate instructions that cause a transfer of control. */
+extern int emulate_step(struct pt_regs *regs, unsigned int instr);
diff --git a/include/asm-sh/edosk7705/io.h b/include/asm-sh/edosk7705/io.h
new file mode 100644 (file)
index 0000000..a1089a6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * include/asm-sh/edosk7705/io.h
+ *
+ * Modified version of io_se.h for the EDOSK7705 specific functions.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for an Hitachi EDOSK7705 development board
+ */
+
+#ifndef __ASM_SH_EDOSK7705_IO_H
+#define __ASM_SH_EDOSK7705_IO_H
+
+#include <asm/io_generic.h>
+
+extern unsigned char sh_edosk7705_inb(unsigned long port);
+extern unsigned int sh_edosk7705_inl(unsigned long port);
+
+extern void sh_edosk7705_outb(unsigned char value, unsigned long port);
+extern void sh_edosk7705_outl(unsigned int value, unsigned long port);
+
+extern void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count);
+extern void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count);
+extern void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count);
+
+extern unsigned long sh_edosk7705_isa_port2addr(unsigned long offset);
+
+#endif /* __ASM_SH_EDOSK7705_IO_H */
diff --git a/include/asm-sh/irq-sh73180.h b/include/asm-sh/irq-sh73180.h
new file mode 100644 (file)
index 0000000..bf2e431
--- /dev/null
@@ -0,0 +1,350 @@
+#ifndef __ASM_SH_IRQ_SH73180_H
+#define __ASM_SH_IRQ_SH73180_H
+
+/*
+ * linux/include/asm-sh/irq-sh73180.h
+ *
+ * Copyright (C) 2004 Takashi SHUDO <shudo@hitachi-ul.co.jp>
+ */
+
+#undef INTC_IPRA
+#undef INTC_IPRB
+#undef INTC_IPRC
+#undef INTC_IPRD
+
+#undef DMTE0_IRQ
+#undef DMTE1_IRQ
+#undef DMTE2_IRQ
+#undef DMTE3_IRQ
+#undef DMTE4_IRQ
+#undef DMTE5_IRQ
+#undef DMTE6_IRQ
+#undef DMTE7_IRQ
+#undef DMAE_IRQ
+#undef DMA_IPR_ADDR
+#undef DMA_IPR_POS
+#undef DMA_PRIORITY
+
+#undef NR_IRQS
+
+#undef __irq_demux
+#undef irq_demux
+
+#undef INTC_IMCR0
+#undef INTC_IMCR1
+#undef INTC_IMCR2
+#undef INTC_IMCR3
+#undef INTC_IMCR4
+#undef INTC_IMCR5
+#undef INTC_IMCR6
+#undef INTC_IMCR7
+#undef INTC_IMCR8
+#undef INTC_IMCR9
+#undef INTC_IMCR10
+
+
+#define INTC_IPRA      0xA4080000UL
+#define INTC_IPRB      0xA4080004UL
+#define INTC_IPRC      0xA4080008UL
+#define INTC_IPRD      0xA408000CUL
+#define INTC_IPRE      0xA4080010UL
+#define INTC_IPRF      0xA4080014UL
+#define INTC_IPRG      0xA4080018UL
+#define INTC_IPRH      0xA408001CUL
+#define INTC_IPRI      0xA4080020UL
+#define INTC_IPRJ      0xA4080024UL
+#define INTC_IPRK      0xA4080028UL
+
+#define INTC_IMR0      0xA4080080UL
+#define INTC_IMR1      0xA4080084UL
+#define INTC_IMR2      0xA4080088UL
+#define INTC_IMR3      0xA408008CUL
+#define INTC_IMR4      0xA4080090UL
+#define INTC_IMR5      0xA4080094UL
+#define INTC_IMR6      0xA4080098UL
+#define INTC_IMR7      0xA408009CUL
+#define INTC_IMR8      0xA40800A0UL
+#define INTC_IMR9      0xA40800A4UL
+#define INTC_IMR10     0xA40800A8UL
+#define INTC_IMR11     0xA40800ACUL
+
+#define INTC_IMCR0     0xA40800C0UL
+#define INTC_IMCR1     0xA40800C4UL
+#define INTC_IMCR2     0xA40800C8UL
+#define INTC_IMCR3     0xA40800CCUL
+#define INTC_IMCR4     0xA40800D0UL
+#define INTC_IMCR5     0xA40800D4UL
+#define INTC_IMCR6     0xA40800D8UL
+#define INTC_IMCR7     0xA40800DCUL
+#define INTC_IMCR8     0xA40800E0UL
+#define INTC_IMCR9     0xA40800E4UL
+#define INTC_IMCR10    0xA40800E8UL
+#define INTC_IMCR11    0xA40800ECUL
+
+#define INTC_ICR0      0xA4140000UL
+#define INTC_ICR1      0xA414001CUL
+
+#define INTMSK0                0xa4140044
+#define INTMSKCLR0     0xa4140064
+#define INTC_INTPRI0   0xa4140010
+
+/*
+  NOTE:
+
+  *_IRQ = (INTEVT2 - 0x200)/0x20
+*/
+
+/* TMU0 */
+#define TMU0_IRQ       16
+#define TMU0_IPR_ADDR  INTC_IPRA
+#define TMU0_IPR_POS    3
+#define TMU0_PRIORITY   2
+
+#define TIMER_IRQ       16
+#define TIMER_IPR_ADDR  INTC_IPRA
+#define TIMER_IPR_POS    3
+#define TIMER_PRIORITY   2
+
+/* TMU1 */
+#define TMU1_IRQ       17
+#define TMU1_IPR_ADDR  INTC_IPRA
+#define TMU1_IPR_POS    2
+#define TMU1_PRIORITY   2
+
+/* TMU2 */
+#define TMU2_IRQ       18
+#define TMU2_IPR_ADDR  INTC_IPRA
+#define TMU2_IPR_POS    1
+#define TMU2_PRIORITY   2
+
+/* LCDC */
+#define LCDC_IRQ       28
+#define LCDC_IPR_ADDR  INTC_IPRB
+#define LCDC_IPR_POS    2
+#define LCDC_PRIORITY   2
+
+/* VIO (Video I/O) */
+#define CEU_IRQ                52
+#define BEU_IRQ                53
+#define VEU_IRQ                54
+#define VOU_IRQ                55
+#define VIO_IPR_ADDR   INTC_IPRE
+#define VIO_IPR_POS     2
+#define VIO_PRIORITY    2
+
+/* MFI (Multi Functional Interface) */
+#define MFI_IRQ                56
+#define MFI_IPR_ADDR   INTC_IPRE
+#define MFI_IPR_POS     1
+#define MFI_PRIORITY    2
+
+/* VPU (Video Processing Unit) */
+#define VPU_IRQ                60
+#define VPU_IPR_ADDR   INTC_IPRE
+#define VPU_IPR_POS     0
+#define VPU_PRIORITY    2
+
+/* 3DG */
+#define TDG_IRQ                63
+#define TDG_IPR_ADDR   INTC_IPRJ
+#define TDG_IPR_POS     2
+#define TDG_PRIORITY    2
+
+/* DMAC(1) */
+#define DMTE0_IRQ      48
+#define DMTE1_IRQ      49
+#define DMTE2_IRQ      50
+#define DMTE3_IRQ      51
+#define DMA1_IPR_ADDR  INTC_IPRE
+#define DMA1_IPR_POS   3
+#define DMA1_PRIORITY  7
+
+/* DMAC(2) */
+#define DMTE4_IRQ      76
+#define DMTE5_IRQ      77
+#define DMA2_IPR_ADDR  INTC_IPRF
+#define DMA2_IPR_POS   2
+#define DMA2_PRIORITY  7
+
+/* SCIF0 */
+#define SCIF_ERI_IRQ   80
+#define SCIF_RXI_IRQ   81
+#define SCIF_BRI_IRQ   82
+#define SCIF_TXI_IRQ   83
+#define SCIF_IPR_ADDR  INTC_IPRG
+#define SCIF_IPR_POS   3
+#define SCIF_PRIORITY  3
+
+/* SIOF0 */
+#define SIOF0_IRQ      84
+#define SIOF0_IPR_ADDR INTC_IPRH
+#define SIOF0_IPR_POS  3
+#define SIOF0_PRIORITY 3
+
+/* FLCTL (Flash Memory Controller) */
+#define FLSTE_IRQ      92
+#define FLTEND_IRQ     93
+#define FLTRQ0_IRQ     94
+#define FLTRQ1_IRQ     95
+#define FLCTL_IPR_ADDR INTC_IPRH
+#define FLCTL_IPR_POS  1
+#define FLCTL_PRIORITY 3
+
+/* IIC(0) (IIC Bus Interface) */
+#define IIC0_ALI_IRQ   96
+#define IIC0_TACKI_IRQ 97
+#define IIC0_WAITI_IRQ 98
+#define IIC0_DTEI_IRQ  99
+#define IIC0_IPR_ADDR  INTC_IPRH
+#define IIC0_IPR_POS   0
+#define IIC0_PRIORITY  3
+
+/* IIC(1) (IIC Bus Interface) */
+#define IIC1_ALI_IRQ   44
+#define IIC1_TACKI_IRQ 45
+#define IIC1_WAITI_IRQ 46
+#define IIC1_DTEI_IRQ  47
+#define IIC1_IPR_ADDR  INTC_IPRG
+#define IIC1_IPR_POS   0
+#define IIC1_PRIORITY  3
+
+/* SIO0 */
+#define SIO0_IRQ       88
+#define SIO0_IPR_ADDR  INTC_IPRI
+#define SIO0_IPR_POS   3
+#define SIO0_PRIORITY  3
+
+/* SDHI */
+#define SDHI_SDHII0_IRQ        100
+#define SDHI_SDHII1_IRQ        101
+#define SDHI_SDHII2_IRQ        102
+#define SDHI_SDHII3_IRQ        103
+#define SDHI_IPR_ADDR  INTC_IPRK
+#define SDHI_IPR_POS   0
+#define SDHI_PRIORITY  3
+
+/* SIU (Sound Interface Unit) */
+#define SIU_IRQ                108
+#define SIU_IPR_ADDR   INTC_IPRJ
+#define SIU_IPR_POS    1
+#define SIU_PRIORITY   3
+
+
+/* ONCHIP_NR_IRQS */
+#define NR_IRQS 109
+
+/* In a generic kernel, NR_IRQS is an upper bound, and we should use
+ * ACTUAL_NR_IRQS (which uses the machine vector) to get the correct value.
+ */
+#define ACTUAL_NR_IRQS NR_IRQS
+
+
+extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
+extern void enable_irq(unsigned int);
+
+/*
+ * Simple Mask Register Support
+ */
+extern void make_maskreg_irq(unsigned int irq);
+extern unsigned short *irq_mask_register;
+
+/*
+ * Function for "on chip support modules".
+ */
+extern void make_ipr_irq(unsigned int irq, unsigned int addr,
+                        int pos,  int priority);
+extern void make_imask_irq(unsigned int irq);
+
+#define PORT_PACR      0xA4050100UL
+#define PORT_PBCR      0xA4050102UL
+#define PORT_PCCR      0xA4050104UL
+#define PORT_PDCR      0xA4050106UL
+#define PORT_PECR      0xA4050108UL
+#define PORT_PFCR      0xA405010AUL
+#define PORT_PGCR      0xA405010CUL
+#define PORT_PHCR      0xA405010EUL
+#define PORT_PJCR      0xA4050110UL
+#define PORT_PKCR      0xA4050112UL
+#define PORT_PLCR      0xA4050114UL
+#define PORT_SCPCR     0xA4050116UL
+#define PORT_PMCR      0xA4050118UL
+#define PORT_PNCR      0xA405011AUL
+#define PORT_PQCR      0xA405011CUL
+#define PORT_PRCR      0xA405011EUL
+#define PORT_PTCR      0xA405014CUL
+#define PORT_PUCR      0xA405014EUL
+#define PORT_PVCR      0xA4050150UL
+
+#define PORT_PSELA     0xA4050140UL
+#define PORT_PSELB     0xA4050142UL
+#define PORT_PSELC     0xA4050144UL
+#define PORT_PSELE     0xA4050158UL
+
+#define PORT_HIZCRA    0xA4050146UL
+#define PORT_HIZCRB    0xA4050148UL
+#define PORT_DRVCR     0xA405014AUL
+
+#define PORT_PADR      0xA4050120UL
+#define PORT_PBDR      0xA4050122UL
+#define PORT_PCDR      0xA4050124UL
+#define PORT_PDDR      0xA4050126UL
+#define PORT_PEDR      0xA4050128UL
+#define PORT_PFDR      0xA405012AUL
+#define PORT_PGDR      0xA405012CUL
+#define PORT_PHDR      0xA405012EUL
+#define PORT_PJDR      0xA4050130UL
+#define PORT_PKDR      0xA4050132UL
+#define PORT_PLDR      0xA4050134UL
+#define PORT_SCPDR     0xA4050136UL
+#define PORT_PMDR      0xA4050138UL
+#define PORT_PNDR      0xA405013AUL
+#define PORT_PQDR      0xA405013CUL
+#define PORT_PRDR      0xA405013EUL
+#define PORT_PTDR      0xA405016CUL
+#define PORT_PUDR      0xA405016EUL
+#define PORT_PVDR      0xA4050170UL
+
+#define IRQ0_IRQ       32
+#define IRQ1_IRQ       33
+#define IRQ2_IRQ       34
+#define IRQ3_IRQ       35
+#define IRQ4_IRQ       36
+#define IRQ5_IRQ       37
+#define IRQ6_IRQ       38
+#define IRQ7_IRQ       39
+
+#define INTPRI00       0xA4140010UL
+
+#define IRQ0_IPR_ADDR  INTPRI00
+#define IRQ1_IPR_ADDR  INTPRI00
+#define IRQ2_IPR_ADDR  INTPRI00
+#define IRQ3_IPR_ADDR  INTPRI00
+#define IRQ4_IPR_ADDR  INTPRI00
+#define IRQ5_IPR_ADDR  INTPRI00
+#define IRQ6_IPR_ADDR  INTPRI00
+#define IRQ7_IPR_ADDR  INTPRI00
+
+#define IRQ0_IPR_POS   7
+#define IRQ1_IPR_POS   6
+#define IRQ2_IPR_POS   5
+#define IRQ3_IPR_POS   4
+#define IRQ4_IPR_POS   3
+#define IRQ5_IPR_POS   2
+#define IRQ6_IPR_POS   1
+#define IRQ7_IPR_POS   0
+
+#define IRQ0_PRIORITY  1
+#define IRQ1_PRIORITY  1
+#define IRQ2_PRIORITY  1
+#define IRQ3_PRIORITY  1
+#define IRQ4_PRIORITY  1
+#define IRQ5_PRIORITY  1
+#define IRQ6_PRIORITY  1
+#define IRQ7_PRIORITY  1
+
+extern int shmse_irq_demux(int irq);
+#define __irq_demux(irq) shmse_irq_demux(irq)
+#define irq_demux(irq) __irq_demux(irq)
+
+#endif /* __ASM_SH_IRQ_SH73180_H */
diff --git a/include/asm-sh/microdev/io.h b/include/asm-sh/microdev/io.h
new file mode 100644 (file)
index 0000000..f2ca4ac
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * linux/include/asm-sh/io_microdev.h
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ *
+ * IO functions for the SuperH SH4-202 MicroDev board.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ */
+
+
+#ifndef _ASM_SH_IO_MICRODEV_H
+#define _ASM_SH_IO_MICRODEV_H
+
+extern unsigned long microdev_isa_port2addr(unsigned long offset);
+
+extern unsigned char microdev_inb(unsigned long port);
+extern unsigned short microdev_inw(unsigned long port);
+extern unsigned int microdev_inl(unsigned long port);
+
+extern void microdev_outb(unsigned char value, unsigned long port);
+extern void microdev_outw(unsigned short value, unsigned long port);
+extern void microdev_outl(unsigned int value, unsigned long port);
+
+extern unsigned char microdev_inb_p(unsigned long port);
+extern unsigned short microdev_inw_p(unsigned long port);
+extern unsigned int microdev_inl_p(unsigned long port);
+
+extern void microdev_outb_p(unsigned char value, unsigned long port);
+extern void microdev_outw_p(unsigned short value, unsigned long port);
+extern void microdev_outl_p(unsigned int value, unsigned long port);
+
+extern void microdev_insb(unsigned long port, void *addr, unsigned long count);
+extern void microdev_insw(unsigned long port, void *addr, unsigned long count);
+extern void microdev_insl(unsigned long port, void *addr, unsigned long count);
+
+extern void microdev_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void microdev_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void microdev_outsl(unsigned long port, const void *addr, unsigned long count);
+
+#if defined(CONFIG_PCI)
+extern unsigned char  microdev_pci_inb(unsigned long port);
+extern unsigned short microdev_pci_inw(unsigned long port);
+extern unsigned long  microdev_pci_inl(unsigned long port);
+extern void           microdev_pci_outb(unsigned char  data, unsigned long port);
+extern void           microdev_pci_outw(unsigned short data, unsigned long port);
+extern void           microdev_pci_outl(unsigned long  data, unsigned long port);
+#endif
+
+#endif /* _ASM_SH_IO_MICRODEV_H */
+
diff --git a/include/asm-sh/microdev/irq.h b/include/asm-sh/microdev/irq.h
new file mode 100644 (file)
index 0000000..47f6f77
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * linux/include/asm-sh/irq_microdev.h
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ *
+ * IRQ functions for the SuperH SH4-202 MicroDev board.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ */
+
+
+#ifndef _ASM_SH_IRQ_MICRODEV_H
+#define _ASM_SH_IRQ_MICRODEV_H
+
+extern void init_microdev_irq(void);
+extern void microdev_print_fpga_intc_status(void);
+
+
+       /*
+        *      The following are useful macros for manipulating the
+        *      interrupt controller (INTC) on the CPU-board FPGA.
+        *      It should be noted that there is an INTC on the FPGA,
+        *      and a seperate INTC on the SH4-202 core - these are
+        *      two different things, both of which need to be prorammed
+        *      to correctly route - unfortunately, they have the
+        *      same name and abbreviations!
+        */
+#define        MICRODEV_FPGA_INTC_BASE         0xa6110000ul                            /* INTC base address on CPU-board FPGA */
+#define        MICRODEV_FPGA_INTENB_REG        (MICRODEV_FPGA_INTC_BASE+0ul)           /* Interrupt Enable Register on INTC on CPU-board FPGA */
+#define        MICRODEV_FPGA_INTDSB_REG        (MICRODEV_FPGA_INTC_BASE+8ul)           /* Interrupt Disable Register on INTC on CPU-board FPGA */
+#define        MICRODEV_FPGA_INTC_MASK(n)      (1ul<<(n))                              /* Interupt mask to enable/disable INTC in CPU-board FPGA */
+#define        MICRODEV_FPGA_INTPRI_REG(n)     (MICRODEV_FPGA_INTC_BASE+0x10+((n)/8)*8)/* Interrupt Priority Register on INTC on CPU-board FPGA */
+#define        MICRODEV_FPGA_INTPRI_LEVEL(n,x) ((x)<<(((n)%8)*4))                      /* MICRODEV_FPGA_INTPRI_LEVEL(int_number, int_level) */
+#define        MICRODEV_FPGA_INTPRI_MASK(n)    (MICRODEV_FPGA_INTPRI_LEVEL((n),0xful)) /* Interrupt Priority Mask on INTC on CPU-board FPGA */
+#define        MICRODEV_FPGA_INTSRC_REG        (MICRODEV_FPGA_INTC_BASE+0x30ul)        /* Interrupt Source Register on INTC on CPU-board FPGA */
+#define        MICRODEV_FPGA_INTREQ_REG        (MICRODEV_FPGA_INTC_BASE+0x38ul)        /* Interrupt Request Register on INTC on CPU-board FPGA */
+
+
+       /*
+        *      The following are the IRQ numbers for the Linux Kernel for external interrupts.
+        *      i.e. the numbers seen by 'cat /proc/interrupt'.
+        */
+#define MICRODEV_LINUX_IRQ_KEYBOARD     1      /* SuperIO Keyboard */
+#define MICRODEV_LINUX_IRQ_SERIAL1      2      /* SuperIO Serial #1 */
+#define MICRODEV_LINUX_IRQ_ETHERNET     3      /* on-board Ethnernet */
+#define MICRODEV_LINUX_IRQ_SERIAL2      4      /* SuperIO Serial #2 */
+#define MICRODEV_LINUX_IRQ_USB_HC       7      /* on-board USB HC */
+#define MICRODEV_LINUX_IRQ_MOUSE       12      /* SuperIO PS/2 Mouse */
+#define MICRODEV_LINUX_IRQ_IDE2                13      /* SuperIO IDE #2 */
+#define MICRODEV_LINUX_IRQ_IDE1                14      /* SuperIO IDE #1 */
+
+       /*
+        *      The following are the IRQ numbers for the INTC on the FPGA for external interrupts.
+        *      i.e. the bits in the INTC registers in the FPGA.
+        */
+#define MICRODEV_FPGA_IRQ_KEYBOARD      1      /* SuperIO Keyboard */
+#define MICRODEV_FPGA_IRQ_SERIAL1       3      /* SuperIO Serial #1 */
+#define MICRODEV_FPGA_IRQ_SERIAL2       4      /* SuperIO Serial #2 */
+#define MICRODEV_FPGA_IRQ_MOUSE                12      /* SuperIO PS/2 Mouse */
+#define MICRODEV_FPGA_IRQ_IDE1         14      /* SuperIO IDE #1 */
+#define MICRODEV_FPGA_IRQ_IDE2         15      /* SuperIO IDE #2 */
+#define MICRODEV_FPGA_IRQ_USB_HC       16      /* on-board USB HC */
+#define MICRODEV_FPGA_IRQ_ETHERNET     18      /* on-board Ethnernet */
+
+#define MICRODEV_IRQ_PCI_INTA           8
+#define MICRODEV_IRQ_PCI_INTB           9
+#define MICRODEV_IRQ_PCI_INTC          10
+#define MICRODEV_IRQ_PCI_INTD          11
+
+#endif /* _ASM_SH_IRQ_MICRODEV_H */
diff --git a/include/asm-sh/se73180/io.h b/include/asm-sh/se73180/io.h
new file mode 100644 (file)
index 0000000..c9cb1b9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * include/asm-sh/se73180/io.h
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Based on include/asm-sh/se7300/io.h
+ *
+ * IO functions for SH-Mobile3(SH73180) SolutionEngine
+ *
+ */
+
+#ifndef _ASM_SH_IO_73180SE_H
+#define _ASM_SH_IO_73180SE_H
+
+extern unsigned char sh73180se_inb(unsigned long port);
+extern unsigned short sh73180se_inw(unsigned long port);
+extern unsigned int sh73180se_inl(unsigned long port);
+
+extern void sh73180se_outb(unsigned char value, unsigned long port);
+extern void sh73180se_outw(unsigned short value, unsigned long port);
+extern void sh73180se_outl(unsigned int value, unsigned long port);
+
+extern unsigned char sh73180se_inb_p(unsigned long port);
+extern void sh73180se_outb_p(unsigned char value, unsigned long port);
+
+extern void sh73180se_insb(unsigned long port, void *addr, unsigned long count);
+extern void sh73180se_insw(unsigned long port, void *addr, unsigned long count);
+extern void sh73180se_insl(unsigned long port, void *addr, unsigned long count);
+extern void sh73180se_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void sh73180se_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void sh73180se_outsl(unsigned long port, const void *addr, unsigned long count);
+
+#endif /* _ASM_SH_IO_73180SE_H */
diff --git a/include/asm-sh/se73180/se73180.h b/include/asm-sh/se73180/se73180.h
new file mode 100644 (file)
index 0000000..f5b93e3
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __ASM_SH_HITACHI_SE73180_H
+#define __ASM_SH_HITACHI_SE73180_H
+
+/*
+ * include/asm-sh/se/se73180.h
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ *
+ * SH-Mobile SolutionEngine 73180 support
+ */
+
+/* Box specific addresses.  */
+
+/* Area 0 */
+#define PA_ROM         0x00000000      /* EPROM */
+#define PA_ROM_SIZE    0x00400000      /* EPROM size 4M byte(Actually 2MB) */
+#define PA_FROM                0x00400000      /* Flash ROM */
+#define PA_FROM_SIZE   0x00400000      /* Flash size 4M byte */
+#define PA_SRAM                0x00800000      /* SRAM */
+#define PA_FROM_SIZE   0x00400000      /* SRAM size 4M byte */
+/* Area 1 */
+#define PA_EXT1                0x04000000
+#define PA_EXT1_SIZE   0x04000000
+/* Area 2 */
+#define PA_EXT2                0x08000000
+#define PA_EXT2_SIZE   0x04000000
+/* Area 3 */
+#define PA_SDRAM       0x0c000000
+#define PA_SDRAM_SIZE  0x04000000
+/* Area 4 */
+#define PA_PCIC                0x10000000      /* MR-SHPC-01 PCMCIA */
+#define PA_MRSHPC       0xb03fffe0      /* MR-SHPC-01 PCMCIA controller */
+#define PA_MRSHPC_MW1   0xb0400000      /* MR-SHPC-01 memory window base */
+#define PA_MRSHPC_MW2   0xb0500000      /* MR-SHPC-01 attribute window base */
+#define PA_MRSHPC_IO    0xb0600000      /* MR-SHPC-01 I/O window base */
+#define MRSHPC_OPTION   (PA_MRSHPC + 6)
+#define MRSHPC_CSR      (PA_MRSHPC + 8)
+#define MRSHPC_ISR      (PA_MRSHPC + 10)
+#define MRSHPC_ICR      (PA_MRSHPC + 12)
+#define MRSHPC_CPWCR    (PA_MRSHPC + 14)
+#define MRSHPC_MW0CR1   (PA_MRSHPC + 16)
+#define MRSHPC_MW1CR1   (PA_MRSHPC + 18)
+#define MRSHPC_IOWCR1   (PA_MRSHPC + 20)
+#define MRSHPC_MW0CR2   (PA_MRSHPC + 22)
+#define MRSHPC_MW1CR2   (PA_MRSHPC + 24)
+#define MRSHPC_IOWCR2   (PA_MRSHPC + 26)
+#define MRSHPC_CDCR     (PA_MRSHPC + 28)
+#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+#define PA_LED         0xb0C00000      /* LED */
+#define LED_SHIFT       0
+#define PA_DIPSW       0xb0900000      /* Dip switch 31 */
+#define PA_EPLD_MODESET        0xb0a00000      /* FPGA Mode set register */
+#define PA_EPLD_ST1    0xb0a80000      /* FPGA Interrupt status register1 */
+#define PA_EPLD_ST2    0xb0ac0000      /* FPGA Interrupt status register2 */
+/* Area 5 */
+#define PA_EXT5                0x14000000
+#define PA_EXT5_SIZE   0x04000000
+/* Area 6 */
+#define PA_LCD1                0xb8000000
+#define PA_LCD2                0xb8800000
+
+#endif  /* __ASM_SH_HITACHI_SE73180_H */
diff --git a/include/asm-sh/sh03/io.h b/include/asm-sh/sh03/io.h
new file mode 100644 (file)
index 0000000..25792e9
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * include/asm-sh/sh03/io.h
+ *
+ * Copyright 2004 Interface Co.,Ltd. Saito.K
+ *
+ * IO functions for an Interface CTP/PCI-SH03
+ */
+
+#ifndef _ASM_SH_IO_SH03_H
+#define _ASM_SH_IO_SH03_H
+
+#include <linux/time.h>
+
+#define INTC_IPRD      0xffd00010UL
+
+#define IRL0_IRQ       2
+#define IRL0_IPR_ADDR  INTC_IPRD
+#define IRL0_IPR_POS   3
+#define IRL0_PRIORITY  13
+
+#define IRL1_IRQ       5
+#define IRL1_IPR_ADDR  INTC_IPRD
+#define IRL1_IPR_POS   2
+#define IRL1_PRIORITY  10
+
+#define IRL2_IRQ       8
+#define IRL2_IPR_ADDR  INTC_IPRD
+#define IRL2_IPR_POS   1
+#define IRL2_PRIORITY  7
+
+#define IRL3_IRQ       11
+#define IRL3_IPR_ADDR  INTC_IPRD
+#define IRL3_IPR_POS   0
+#define IRL3_PRIORITY  4
+
+
+extern unsigned long sh03_isa_port2addr(unsigned long offset);
+
+extern void setup_sh03(void);
+extern void init_sh03_IRQ(void);
+extern void heartbeat_sh03(void);
+
+extern void sh03_rtc_gettimeofday(struct timeval *tv);
+extern int sh03_rtc_settimeofday(const struct timeval *tv);
+
+#endif /* _ASM_SH_IO_SH03_H */
diff --git a/include/asm-sh/sh03/sh03.h b/include/asm-sh/sh03/sh03.h
new file mode 100644 (file)
index 0000000..19c40b8
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __ASM_SH_SH03_H
+#define __ASM_SH_SH03_H
+
+/*
+ * linux/include/asm-sh/sh03/sh03.h
+ *
+ * Copyright (C) 2004  Interface Co., Ltd. Saito.K
+ *
+ * Interface CTP/PCI-SH03 support
+ */
+
+#define PA_PCI_IO       (0xbe240000)    /* PCI I/O space */
+#define PA_PCI_MEM      (0xbd000000)    /* PCI MEM space */
+
+#define PCIPAR          (0xa4000cf8)    /* PCI Config address */
+#define PCIPDR          (0xa4000cfc)    /* PCI Config data    */
+
+#endif  /* __ASM_SH_SH03_H */
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
new file mode 100644 (file)
index 0000000..42b4cc6
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _SPARC64_KPROBES_H
+#define _SPARC64_KPROBES_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+typedef u32 kprobe_opcode_t;
+
+#define BREAKPOINT_INSTRUCTION   0x91d02070 /* ta 0x70 */
+#define BREAKPOINT_INSTRUCTION_2 0x91d02071 /* ta 0x71 */
+#define MAX_INSN_SIZE 2
+
+#ifdef CONFIG_KPROBES
+extern int kprobe_exceptions_notify(struct notifier_block *self,
+                                   unsigned long val, void *data);
+#else                          /* !CONFIG_KPROBES */
+static inline int kprobe_exceptions_notify(struct notifier_block *self,
+                                          unsigned long val, void *data)
+{
+       return 0;
+}
+#endif
+
+#endif /* _SPARC64_KPROBES_H */
diff --git a/include/asm-um/module-i386.h b/include/asm-um/module-i386.h
new file mode 100644 (file)
index 0000000..5ead4a0
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __UM_MODULE_I386_H
+#define __UM_MODULE_I386_H
+
+/* UML is simple */
+struct mod_arch_specific
+{
+};
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#endif
diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86_64/genapic.h
new file mode 100644 (file)
index 0000000..50b38e7
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _ASM_GENAPIC_H
+#define _ASM_GENAPIC_H 1
+
+/*
+ * Copyright 2004 James Cleverdon, IBM.
+ * Subject to the GNU Public License, v.2
+ *
+ * Generic APIC sub-arch data struct.
+ *
+ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+ * James Cleverdon.
+ */
+
+struct genapic {
+       char *name;
+       u32 int_delivery_mode;
+       u32 int_dest_mode;
+       u32 int_delivery_dest;  /* for quick IPIs */
+       int (*apic_id_registered)(void);
+       cpumask_t (*target_cpus)(void);
+       void (*init_apic_ldr)(void);
+       /* ipi */
+       void (*send_IPI_mask)(cpumask_t mask, int vector);
+       void (*send_IPI_allbutself)(int vector);
+       void (*send_IPI_all)(int vector);
+       /* */
+       unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask);
+       unsigned int (*phys_pkg_id)(int index_msb);
+};
+
+
+extern struct genapic *genapic;
+
+#endif
diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h
new file mode 100644 (file)
index 0000000..d184184
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef __ASM_IPI_H
+#define __ASM_IPI_H
+
+/*
+ * Copyright 2004 James Cleverdon, IBM.
+ * Subject to the GNU Public License, v.2
+ *
+ * Generic APIC InterProcessor Interrupt code.
+ *
+ * Moved to include file by James Cleverdon from
+ * arch/x86-64/kernel/smp.c
+ *
+ * Copyrights from kernel/smp.c:
+ *
+ * (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
+ * (c) 2002,2003 Andi Kleen, SuSE Labs.
+ * Subject to the GNU Public License, v.2
+ */
+
+#include <asm/fixmap.h>
+#include <asm/hw_irq.h>
+#include <asm/apicdef.h>
+#include <asm/genapic.h>
+
+/*
+ * the following functions deal with sending IPIs between CPUs.
+ *
+ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
+ */
+
+static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector, unsigned int dest)
+{
+       unsigned int icr =  APIC_DM_FIXED | shortcut | vector | dest;
+       if (vector == KDB_VECTOR)
+               icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI;
+       return icr;
+}
+
+static inline int __prepare_ICR2 (unsigned int mask)
+{
+       return SET_APIC_DEST_FIELD(mask);
+}
+
+static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
+{
+       /*
+        * Subtle. In the case of the 'never do double writes' workaround
+        * we have to lock out interrupts to be safe.  As we don't care
+        * of the value read we use an atomic rmw access to avoid costly
+        * cli/sti.  Otherwise we use an even cheaper single atomic write
+        * to the APIC.
+        */
+       unsigned int cfg;
+
+       /*
+        * Wait for idle.
+        */
+       apic_wait_icr_idle();
+
+       /*
+        * No need to touch the target chip field
+        */
+       cfg = __prepare_ICR(shortcut, vector, dest);
+
+       /*
+        * Send the IPI. The write to APIC_ICR fires this off.
+        */
+       apic_write_around(APIC_ICR, cfg);
+}
+
+
+static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
+{
+       unsigned long cfg, flags;
+       unsigned long query_cpu;
+
+       /*
+        * Hack. The clustered APIC addressing mode doesn't allow us to send
+        * to an arbitrary mask, so I do a unicast to each CPU instead.
+        * - mbligh
+        */
+       local_irq_save(flags);
+
+       for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
+               if (cpu_isset(query_cpu, mask)) {
+
+                       /*
+                        * Wait for idle.
+                        */
+                       apic_wait_icr_idle();
+
+                       /*
+                        * prepare target chip field
+                        */
+                       cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]);
+                       apic_write_around(APIC_ICR2, cfg);
+
+                       /*
+                        * program the ICR
+                        */
+                       cfg = __prepare_ICR(0, vector, APIC_DEST_PHYSICAL);
+
+                       /*
+                        * Send the IPI. The write to APIC_ICR fires this off.
+                        */
+                       apic_write_around(APIC_ICR, cfg);
+               }
+       }
+       local_irq_restore(flags);
+}
+
+#endif /* __ASM_IPI_H */
diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86_64/kprobes.h
new file mode 100644 (file)
index 0000000..3f82412
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _ASM_KPROBES_H
+#define _ASM_KPROBES_H
+/*
+ *  Kernel Probes (KProbes)
+ *  include/asm-x86_64/kprobes.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ *
+ * 2004-Oct    Prasanna S Panchamukhi <prasanna@in.ibm.com> and Jim Keniston
+ *             kenistoj@us.ibm.com adopted from i386.
+ */
+#include <linux/types.h>
+#include <linux/ptrace.h>
+
+struct pt_regs;
+
+typedef u8 kprobe_opcode_t;
+#define BREAKPOINT_INSTRUCTION 0xcc
+#define MAX_INSN_SIZE 15
+#define MAX_STACK_SIZE 64
+#define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \
+       (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) \
+       ? (MAX_STACK_SIZE) \
+       : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
+
+/* Architecture specific copy of original instruction*/
+struct arch_specific_insn {
+       /* copy of the original instruction */
+       kprobe_opcode_t *insn;
+};
+
+/* trap3/1 are intr gates for kprobes.  So, restore the status of IF,
+ * if necessary, before executing the original int3/1 (trap) handler.
+ */
+static inline void restore_interrupts(struct pt_regs *regs)
+{
+       if (regs->eflags & IF_MASK)
+               local_irq_enable();
+}
+
+extern int post_kprobe_handler(struct pt_regs *regs);
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
+extern int kprobe_handler(struct pt_regs *regs);
+
+extern int kprobe_exceptions_notify(struct notifier_block *self,
+                                   unsigned long val, void *data);
+#endif                         /* _ASM_KPROBES_H */
diff --git a/include/asm-x86_64/mach_apic.h b/include/asm-x86_64/mach_apic.h
new file mode 100644 (file)
index 0000000..0acea44
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __ASM_MACH_APIC_H
+#define __ASM_MACH_APIC_H
+
+/*
+ * Copyright 2004 James Cleverdon, IBM.
+ * Subject to the GNU Public License, v.2
+ *
+ * Generic APIC sub-arch defines.
+ *
+ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
+ * James Cleverdon.
+ */
+
+#include <asm/genapic.h>
+
+#define INT_DELIVERY_MODE (genapic->int_delivery_mode)
+#define INT_DEST_MODE (genapic->int_dest_mode)
+#define INT_DELIVERY_DEST (genapic->int_delivery_dest)
+#define TARGET_CPUS      (genapic->target_cpus())
+#define apic_id_registered (genapic->apic_id_registered)
+#define init_apic_ldr (genapic->init_apic_ldr)
+#define send_IPI_mask (genapic->send_IPI_mask)
+#define send_IPI_allbutself (genapic->send_IPI_allbutself)
+#define send_IPI_all (genapic->send_IPI_all)
+#define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid)
+#define phys_pkg_id    (genapic->phys_pkg_id)
+
+#endif /* __ASM_MACH_APIC_H */
diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h
new file mode 100644 (file)
index 0000000..c25270a
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _ASM_SWIOTLB_H
+#define _ASM_SWTIOLB_H 1
+
+#include <linux/config.h>
+
+/* SWIOTLB interface */
+
+extern dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size,
+                                     int dir);
+extern void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+                                 size_t size, int dir);
+extern void swiotlb_sync_single_for_cpu(struct device *hwdev,
+                                        dma_addr_t dev_addr,
+                                        size_t size, int dir);
+extern void swiotlb_sync_single_for_device(struct device *hwdev,
+                                           dma_addr_t dev_addr,
+                                           size_t size, int dir);
+extern void swiotlb_sync_sg_for_cpu(struct device *hwdev,
+                                    struct scatterlist *sg, int nelems,
+                                    int dir);
+extern void swiotlb_sync_sg_for_device(struct device *hwdev,
+                                       struct scatterlist *sg, int nelems,
+                                       int dir);
+extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
+                     int nents, int direction);
+extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg,
+                        int nents, int direction);
+extern int swiotlb_dma_mapping_error(dma_addr_t dma_addr);
+
+#ifdef CONFIG_SWIOTLB
+extern int swiotlb;
+#else
+#define swiotlb 0
+#endif
+
+#endif
diff --git a/include/linux/ckrm_events.h b/include/linux/ckrm_events.h
new file mode 100644 (file)
index 0000000..bfe7d33
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * ckrm_events.h - Class-based Kernel Resource Management (CKRM)
+ *                 event handling
+ *
+ * Copyright (C) Hubertus Franke, IBM Corp. 2003,2004
+ *           (C) Shailabh Nagar,  IBM Corp. 2003
+ *           (C) Chandra Seetharaman, IBM Corp. 2003
+ * 
+ * 
+ * Provides a base header file including macros and basic data structures.
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ * 
+ * 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.
+ *
+ */
+
+/*
+ * Changes
+ *
+ * 28 Aug 2003
+ *        Created.
+ * 06 Nov 2003
+ *        Made modifications to suit the new RBCE module.
+ * 10 Nov 2003
+ *        Added callbacks_active and surrounding logic. Added task paramter
+ *        for all CE callbacks.
+ * 19 Nov 2004
+ *        New Event callback structure
+ */
+
+#ifndef _LINUX_CKRM_EVENTS_H
+#define _LINUX_CKRM_EVENTS_H
+
+#ifdef CONFIG_CKRM
+
+/*
+ * Data structure and function to get the list of registered 
+ * resource controllers.
+ */
+
+/*
+ * CKRM defines a set of events at particular points in the kernel
+ * at which callbacks registered by various class types are called
+ */
+
+enum ckrm_event {
+       /*
+        * we distinguish these events types:
+        *
+        * (a) CKRM_LATCHABLE_EVENTS
+        *      events can be latched for event callbacks by classtypes
+        *
+        * (b) CKRM_NONLATACHBLE_EVENTS
+        *     events can not be latched but can be used to call classification
+        * 
+        * (c) event that are used for notification purposes
+        *     range: [ CKRM_EVENT_CANNOT_CLASSIFY .. )
+        */
+
+       /* events (a) */
+
+       CKRM_LATCHABLE_EVENTS,
+
+       CKRM_EVENT_NEWTASK = CKRM_LATCHABLE_EVENTS,
+       CKRM_EVENT_FORK,
+       CKRM_EVENT_EXIT,
+       CKRM_EVENT_EXEC,
+       CKRM_EVENT_UID,
+       CKRM_EVENT_GID,
+       CKRM_EVENT_LOGIN,
+       CKRM_EVENT_USERADD,
+       CKRM_EVENT_USERDEL,
+       CKRM_EVENT_LISTEN_START,
+       CKRM_EVENT_LISTEN_STOP,
+       CKRM_EVENT_APPTAG,
+
+       /* events (b) */
+
+       CKRM_NONLATCHABLE_EVENTS,
+
+       CKRM_EVENT_RECLASSIFY = CKRM_NONLATCHABLE_EVENTS,
+
+       /* events (c) */
+
+       CKRM_NOTCLASSIFY_EVENTS,
+
+       CKRM_EVENT_MANUAL = CKRM_NOTCLASSIFY_EVENTS,
+
+       CKRM_NUM_EVENTS
+};
+#endif
+
+#ifdef __KERNEL__
+#ifdef CONFIG_CKRM
+
+/*
+ * CKRM event callback specification for the classtypes or resource controllers 
+ *   typically an array is specified using CKRM_EVENT_SPEC terminated with 
+ *   CKRM_EVENT_SPEC_LAST and then that array is registered using
+ *   ckrm_register_event_set.
+ *   Individual registration of event_cb is also possible
+ */
+
+typedef void (*ckrm_event_cb) (void *arg);
+
+struct ckrm_hook_cb {
+       ckrm_event_cb fct;
+       struct ckrm_hook_cb *next;
+};
+
+struct ckrm_event_spec {
+       enum ckrm_event ev;
+       struct ckrm_hook_cb cb;
+};
+
+#define CKRM_EVENT_SPEC(EV,FCT) { CKRM_EVENT_##EV, \
+                                       { (ckrm_event_cb)FCT, NULL } }
+
+int ckrm_register_event_set(struct ckrm_event_spec especs[]);
+int ckrm_unregister_event_set(struct ckrm_event_spec especs[]);
+int ckrm_register_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb);
+int ckrm_unregister_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb);
+
+extern void ckrm_invoke_event_cb_chain(enum ckrm_event ev, void *arg);
+
+#define CKRM_DEF_CB(EV,fct)                                    \
+static inline void ckrm_cb_##fct(void)                         \
+{                                                              \
+         ckrm_invoke_event_cb_chain(CKRM_EVENT_##EV,NULL);      \
+}
+
+#define CKRM_DEF_CB_ARG(EV,fct,argtp)                                  \
+static inline void ckrm_cb_##fct(argtp arg)                            \
+{                                                                      \
+         ckrm_invoke_event_cb_chain(CKRM_EVENT_##EV,(void*)arg);       \
+}
+
+#else /* !CONFIG_CKRM */
+
+#define CKRM_DEF_CB(EV,fct)                    \
+static inline void ckrm_cb_##fct(void)  { }
+
+#define CKRM_DEF_CB_ARG(EV,fct,argtp)          \
+static inline void ckrm_cb_##fct(argtp arg) { }
+
+#endif /* CONFIG_CKRM */
+
+/*
+ *   define the CKRM event functions 
+ *               EVENT          FCT           ARG         
+ */
+
+/* forward declarations for function arguments */
+struct task_struct;
+struct sock;
+struct user_struct;
+
+CKRM_DEF_CB_ARG(FORK, fork, struct task_struct *);
+CKRM_DEF_CB_ARG(EXEC, exec, const char *);
+CKRM_DEF_CB(UID, uid);
+CKRM_DEF_CB(GID, gid);
+CKRM_DEF_CB(APPTAG, apptag);
+CKRM_DEF_CB(LOGIN, login);
+CKRM_DEF_CB_ARG(USERADD, useradd, struct user_struct *);
+CKRM_DEF_CB_ARG(USERDEL, userdel, struct user_struct *);
+CKRM_DEF_CB_ARG(LISTEN_START, listen_start, struct sock *);
+CKRM_DEF_CB_ARG(LISTEN_STOP, listen_stop, struct sock *);
+
+/* some other functions required */
+#ifdef CONFIG_CKRM
+extern void ckrm_init(void);
+extern void ckrm_cb_newtask(struct task_struct *);
+extern void ckrm_cb_exit(struct task_struct *);
+#else
+#define ckrm_init()            do { } while (0)
+#define ckrm_cb_newtask(x)     do { } while (0)
+#define ckrm_cb_exit(x)                do { } while (0)
+#endif
+
+extern int get_exe_path_name(struct task_struct *, char *, int);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_CKRM_EVENTS_H */
diff --git a/include/linux/gen_stats.h b/include/linux/gen_stats.h
new file mode 100644 (file)
index 0000000..ab631c3
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __LINUX_GEN_STATS_H
+#define __LINUX_GEN_STATS_H
+
+#include <linux/types.h>
+
+enum {
+       TCA_STATS_UNSPEC,
+       TCA_STATS_BASIC,
+       TCA_STATS_RATE_EST,
+       TCA_STATS_QUEUE,
+       TCA_STATS_APP,
+       __TCA_STATS_MAX,
+};
+#define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
+
+/**
+ * @bytes: number of seen bytes
+ * @packets: number of seen packets
+ */
+struct gnet_stats_basic
+{
+       __u64   bytes;
+       __u32   packets;
+};
+
+/**
+ * @bps: current byte rate
+ * @pps: current packet rate
+ */
+struct gnet_stats_rate_est
+{
+       __u32   bps;
+       __u32   pps;
+};
+
+/**
+ * @qlen: queue length
+ * @backlog: backlog size of queue
+ * @drops: number of dropped packets
+ * @requeues: number of requeues
+ */
+struct gnet_stats_queue
+{
+       __u32   qlen;
+       __u32   backlog;
+       __u32   drops;
+       __u32   requeues;
+       __u32   overlimits;
+};
+
+/**
+ * @interval: sampling period
+ * @ewma_log: the log of measurement window weight
+ */
+struct gnet_estimator
+{
+       signed char     interval;
+       unsigned char   ewma_log;
+};
+
+
+#endif /* __LINUX_GEN_STATS_H */
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
new file mode 100644 (file)
index 0000000..7e1aad3
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef LINUX_HARDIRQ_H
+#define LINUX_HARDIRQ_H
+
+#include <linux/config.h>
+#include <linux/smp_lock.h>
+#include <asm/hardirq.h>
+
+#define __IRQ_MASK(x)  ((1UL << (x))-1)
+
+#define PREEMPT_MASK   (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define HARDIRQ_MASK   (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define SOFTIRQ_MASK   (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+
+#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT)
+
+#define hardirq_count()        (preempt_count() & HARDIRQ_MASK)
+#define softirq_count()        (preempt_count() & SOFTIRQ_MASK)
+#define irq_count()    (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
+
+/*
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context? Interrupt context?
+ */
+#define in_irq()               (hardirq_count())
+#define in_softirq()           (softirq_count())
+#define in_interrupt()         (irq_count())
+
+#ifdef CONFIG_PREEMPT
+# define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
+# define preemptible() (preempt_count() == 0 && !irqs_disabled())
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
+#else
+# define in_atomic()   (preempt_count() != 0)
+# define preemptible() 0
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
+
+#ifdef CONFIG_SMP
+extern void synchronize_irq(unsigned int irq);
+#else
+# define synchronize_irq(irq)  barrier()
+#endif
+
+#endif /* LINUX_HARDIRQ_H */
diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h
new file mode 100644 (file)
index 0000000..941b786
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _LINUX_I2C_ALGO_PCA_H
+#define _LINUX_I2C_ALGO_PCA_H
+
+struct i2c_algo_pca_data {
+       int  (*get_own)                 (struct i2c_algo_pca_data *adap); /* Obtain own address */
+       int  (*get_clock)               (struct i2c_algo_pca_data *adap);
+       void (*write_byte)              (struct i2c_algo_pca_data *adap, int reg, int val);
+       int  (*read_byte)               (struct i2c_algo_pca_data *adap, int reg);
+       int  (*wait_for_interrupt)      (struct i2c_algo_pca_data *adap);
+};
+
+#define I2C_PCA_ADAP_MAX       16
+
+int i2c_pca_add_bus(struct i2c_adapter *);
+int i2c_pca_del_bus(struct i2c_adapter *);
+
+#endif /* _LINUX_I2C_ALGO_PCA_H */
diff --git a/include/linux/key-ui.h b/include/linux/key-ui.h
new file mode 100644 (file)
index 0000000..60cc7b7
--- /dev/null
@@ -0,0 +1,97 @@
+/* key-ui.h: key userspace interface stuff for use by keyfs
+ *
+ * Copyright (C) 2004 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.
+ */
+
+#ifndef _LINUX_KEY_UI_H
+#define _LINUX_KEY_UI_H
+
+#include <linux/key.h>
+
+/* the key tree */
+extern struct rb_root key_serial_tree;
+extern spinlock_t key_serial_lock;
+
+/* required permissions */
+#define        KEY_VIEW        0x01    /* require permission to view attributes */
+#define        KEY_READ        0x02    /* require permission to read content */
+#define        KEY_WRITE       0x04    /* require permission to update / modify */
+#define        KEY_SEARCH      0x08    /* require permission to search (keyring) or find (key) */
+#define        KEY_LINK        0x10    /* require permission to link */
+#define        KEY_ALL         0x1f    /* all the above permissions */
+
+/*
+ * the keyring payload contains a list of the keys to which the keyring is
+ * subscribed
+ */
+struct keyring_list {
+       unsigned        maxkeys;        /* max keys this list can hold */
+       unsigned        nkeys;          /* number of keys currently held */
+       struct key      *keys[0];
+};
+
+
+/*
+ * check to see whether permission is granted to use a key in the desired way
+ */
+static inline int key_permission(const struct key *key, key_perm_t perm)
+{
+       key_perm_t kperm;
+
+       if (key->uid == current->fsuid)
+               kperm = key->perm >> 16;
+       else if (key->gid != -1 &&
+                key->perm & KEY_GRP_ALL &&
+                in_group_p(key->gid)
+                )
+               kperm = key->perm >> 8;
+       else
+               kperm = key->perm;
+
+       kperm = kperm & perm & KEY_ALL;
+
+       return kperm == perm;
+}
+
+/*
+ * check to see whether permission is granted to use a key in at least one of
+ * the desired ways
+ */
+static inline int key_any_permission(const struct key *key, key_perm_t perm)
+{
+       key_perm_t kperm;
+
+       if (key->uid == current->fsuid)
+               kperm = key->perm >> 16;
+       else if (key->gid != -1 &&
+                key->perm & KEY_GRP_ALL &&
+                in_group_p(key->gid)
+                )
+               kperm = key->perm >> 8;
+       else
+               kperm = key->perm;
+
+       kperm = kperm & perm & KEY_ALL;
+
+       return kperm != 0;
+}
+
+
+extern struct key *lookup_user_key(key_serial_t id, int create, int part,
+                                  key_perm_t perm);
+
+extern long join_session_keyring(const char *name);
+
+extern struct key_type *key_type_lookup(const char *type);
+extern void key_type_put(struct key_type *ktype);
+
+#define key_negative_timeout   60      /* default timeout on a negative key's existence */
+
+
+#endif /* _LINUX_KEY_UI_H */
diff --git a/include/linux/key.h b/include/linux/key.h
new file mode 100644 (file)
index 0000000..15eaba5
--- /dev/null
@@ -0,0 +1,286 @@
+/* key.h: authentication token and access key management
+ *
+ * Copyright (C) 2004 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.
+ *
+ *
+ * See Documentation/keys.txt for information on keys/keyrings.
+ */
+
+#ifndef _LINUX_KEY_H
+#define _LINUX_KEY_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+#ifdef __KERNEL__
+
+/* key handle serial number */
+typedef int32_t key_serial_t;
+
+/* key handle permissions mask */
+typedef uint32_t key_perm_t;
+
+struct key;
+
+#ifdef CONFIG_KEYS
+
+#undef KEY_DEBUGGING
+
+#define KEY_USR_VIEW   0x00010000      /* user can view a key's attributes */
+#define KEY_USR_READ   0x00020000      /* user can read key payload / view keyring */
+#define KEY_USR_WRITE  0x00040000      /* user can update key payload / add link to keyring */
+#define KEY_USR_SEARCH 0x00080000      /* user can find a key in search / search a keyring */
+#define KEY_USR_LINK   0x00100000      /* user can create a link to a key/keyring */
+#define KEY_USR_ALL    0x001f0000
+
+#define KEY_GRP_VIEW   0x00000100      /* group permissions... */
+#define KEY_GRP_READ   0x00000200
+#define KEY_GRP_WRITE  0x00000400
+#define KEY_GRP_SEARCH 0x00000800
+#define KEY_GRP_LINK   0x00001000
+#define KEY_GRP_ALL    0x00001f00
+
+#define KEY_OTH_VIEW   0x00000001      /* third party permissions... */
+#define KEY_OTH_READ   0x00000002
+#define KEY_OTH_WRITE  0x00000004
+#define KEY_OTH_SEARCH 0x00000008
+#define KEY_OTH_LINK   0x00000010
+#define KEY_OTH_ALL    0x0000001f
+
+struct seq_file;
+struct user_struct;
+
+struct key_type;
+struct key_owner;
+struct keyring_list;
+struct keyring_name;
+
+/*****************************************************************************/
+/*
+ * authentication token / access credential / keyring
+ * - types of key include:
+ *   - keyrings
+ *   - disk encryption IDs
+ *   - Kerberos TGTs and tickets
+ */
+struct key {
+       atomic_t                usage;          /* number of references */
+       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) */
+       uid_t                   uid;
+       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 */
+
+#ifdef KEY_DEBUGGING
+       unsigned                magic;
+#define KEY_DEBUG_MAGIC                0x18273645u
+#define KEY_DEBUG_MAGIC_X      0xf8e9dacbu
+#endif
+
+       /* the description string
+        * - this is used to match a key against search criteria
+        * - this should be a printable string
+        * - eg: for krb5 AFS, this might be "afs@REDHAT.COM"
+        */
+       char                    *description;
+
+       /* type specific data
+        * - this is used by the keyring type to index the name
+        */
+       union {
+               struct list_head        link;
+       } type_data;
+
+       /* key data
+        * - this is used to hold the data actually used in cryptography or
+        *   whatever
+        */
+       union {
+               unsigned long           value;
+               void                    *data;
+               struct keyring_list     *subscriptions;
+       } payload;
+};
+
+/*****************************************************************************/
+/*
+ * kernel managed key type definition
+ */
+struct key_type {
+       /* name of the type */
+       const char *name;
+
+       /* default payload length for quota precalculation (optional)
+        * - this can be used instead of calling key_payload_reserve(), that
+        *   function only needs to be called if the real datalen is different
+        */
+       size_t def_datalen;
+
+       /* instantiate a key of this type
+        * - this method should call key_payload_reserve() to determine if the
+        *   user's quota will hold the payload
+        */
+       int (*instantiate)(struct key *key, const void *data, size_t datalen);
+
+       /* duplicate a key of this type (optional)
+        * - the source key will be locked against change
+        * - the new description will be attached
+        * - the quota will have been adjusted automatically from
+        *   source->quotalen
+        */
+       int (*duplicate)(struct key *key, const struct key *source);
+
+       /* update a key of this type (optional)
+        * - this method should call key_payload_reserve() to recalculate the
+        *   quota consumption
+        * - the key must be locked against read when modifying
+        */
+       int (*update)(struct key *key, const void *data, size_t datalen);
+
+       /* match a key against a description */
+       int (*match)(const struct key *key, const void *desc);
+
+       /* clear the data from a key (optional) */
+       void (*destroy)(struct key *key);
+
+       /* describe a key */
+       void (*describe)(const struct key *key, struct seq_file *p);
+
+       /* read a key's data (optional)
+        * - permission checks will be done by the caller
+        * - the key's semaphore will be readlocked by the caller
+        * - should return the amount of data that could be read, no matter how
+        *   much is copied into the buffer
+        * - shouldn't do the copy if the buffer is NULL
+        */
+       long (*read)(const struct key *key, char __user *buffer, size_t buflen);
+
+       /* internal fields */
+       struct list_head        link;           /* link in types list */
+};
+
+extern struct key_type key_type_keyring;
+
+extern int register_key_type(struct key_type *ktype);
+extern void unregister_key_type(struct key_type *ktype);
+
+extern struct key *key_alloc(struct key_type *type,
+                            const char *desc,
+                            uid_t uid, gid_t gid, key_perm_t perm,
+                            int not_in_quota);
+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);
+extern int key_negate_and_link(struct key *key,
+                              unsigned timeout,
+                              struct key *keyring);
+extern void key_revoke(struct key *key);
+extern void key_put(struct key *key);
+
+static inline struct key *key_get(struct key *key)
+{
+       if (key)
+               atomic_inc(&key->usage);
+       return key;
+}
+
+extern struct key *request_key(struct key_type *type,
+                              const char *description,
+                              const char *callout_info);
+
+extern int key_validate(struct key *key);
+
+extern struct key *key_create_or_update(struct key *keyring,
+                                       const char *type,
+                                       const char *description,
+                                       const void *payload,
+                                       size_t plen,
+                                       int not_in_quota);
+
+extern int key_update(struct key *key,
+                     const void *payload,
+                     size_t plen);
+
+extern int key_link(struct key *keyring,
+                   struct key *key);
+
+extern int key_unlink(struct key *keyring,
+                     struct key *key);
+
+extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
+                                int not_in_quota, struct key *dest);
+
+extern int keyring_clear(struct key *keyring);
+
+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);
+
+#define key_serial(key) ((key) ? (key)->serial : 0)
+
+/*
+ * the userspace interface
+ */
+extern struct key root_user_keyring, root_session_keyring;
+extern int alloc_uid_keyring(struct user_struct *user);
+extern void switch_uid_keyring(struct user_struct *new_user);
+extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
+extern void exit_keys(struct task_struct *tsk);
+extern int suid_keys(struct task_struct *tsk);
+extern int exec_keys(struct task_struct *tsk);
+extern void key_fsuid_changed(struct task_struct *tsk);
+extern void key_fsgid_changed(struct task_struct *tsk);
+extern void key_init(void);
+
+#else /* CONFIG_KEYS */
+
+#define key_validate(k)                        0
+#define key_serial(k)                  0
+#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 copy_keys(f,t)                 0
+#define exit_keys(t)                   do { } while(0)
+#define suid_keys(t)                   do { } while(0)
+#define exec_keys(t)                   do { } while(0)
+#define key_fsuid_changed(t)           do { } while(0)
+#define key_fsgid_changed(t)           do { } while(0)
+#define key_init()                     do { } while(0)
+
+#endif /* CONFIG_KEYS */
+#endif /* __KERNEL__ */
+#endif /* _LINUX_KEY_H */
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h
new file mode 100644 (file)
index 0000000..381dedc
--- /dev/null
@@ -0,0 +1,39 @@
+/* keyctl.h: keyctl command IDs
+ *
+ * Copyright (C) 2004 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.
+ */
+
+#ifndef _LINUX_KEYCTL_H
+#define _LINUX_KEYCTL_H
+
+/* special process keyring shortcut IDs */
+#define KEY_SPEC_THREAD_KEYRING                -1      /* - key ID for thread-specific keyring */
+#define KEY_SPEC_PROCESS_KEYRING       -2      /* - key ID for process-specific keyring */
+#define KEY_SPEC_SESSION_KEYRING       -3      /* - key ID for session-specific keyring */
+#define KEY_SPEC_USER_KEYRING          -4      /* - key ID for UID-specific keyring */
+#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 */
+
+/* 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 */
+#define KEYCTL_UPDATE                  2       /* update a key */
+#define KEYCTL_REVOKE                  3       /* revoke a key */
+#define KEYCTL_CHOWN                   4       /* set ownership of a key */
+#define KEYCTL_SETPERM                 5       /* set perms on a key */
+#define KEYCTL_DESCRIBE                        6       /* describe a key */
+#define KEYCTL_CLEAR                   7       /* clear contents of a keyring */
+#define KEYCTL_LINK                    8       /* link a key into a keyring */
+#define KEYCTL_UNLINK                  9       /* unlink a key from a keyring */
+#define KEYCTL_SEARCH                  10      /* search for a key in a keyring */
+#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 */
+
+#endif /*  _LINUX_KEYCTL_H */
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
new file mode 100644 (file)
index 0000000..0e6e972
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * A simple kernel FIFO implementation.
+ *
+ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef _LINUX_KFIFO_H
+#define _LINUX_KFIFO_H
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+struct kfifo {
+       unsigned char *buffer;  /* the buffer holding the data */
+       unsigned int size;      /* the size of the allocated buffer */
+       unsigned int in;        /* data is added at offset (in % size) */
+       unsigned int out;       /* data is extracted from off. (out % size) */
+       spinlock_t *lock;       /* protects concurrent modifications */
+};
+
+extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
+                               int gfp_mask, spinlock_t *lock);
+extern struct kfifo *kfifo_alloc(unsigned int size, int gfp_mask,
+                                spinlock_t *lock);
+extern void kfifo_free(struct kfifo *fifo);
+extern unsigned int __kfifo_put(struct kfifo *fifo,
+                               unsigned char *buffer, unsigned int len);
+extern unsigned int __kfifo_get(struct kfifo *fifo,
+                               unsigned char *buffer, unsigned int len);
+
+/*
+ * __kfifo_reset - removes the entire FIFO contents, no locking version
+ * @fifo: the fifo to be emptied.
+ */
+static inline void __kfifo_reset(struct kfifo *fifo)
+{
+       fifo->in = fifo->out = 0;
+}
+
+/*
+ * kfifo_reset - removes the entire FIFO contents
+ * @fifo: the fifo to be emptied.
+ */
+static inline void kfifo_reset(struct kfifo *fifo)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       __kfifo_reset(fifo);
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+}
+
+/*
+ * kfifo_put - puts some data into the FIFO
+ * @fifo: the fifo to be used.
+ * @buffer: the data to be added.
+ * @len: the length of the data to be added.
+ *
+ * This function copies at most 'len' bytes from the 'buffer' into
+ * the FIFO depending on the free space, and returns the number of
+ * bytes copied.
+ */
+static inline unsigned int kfifo_put(struct kfifo *fifo,
+                                    unsigned char *buffer, unsigned int len)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_put(fifo, buffer, len);
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
+/*
+ * kfifo_get - gets some data from the FIFO
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most 'len' bytes from the FIFO into the
+ * 'buffer' and returns the number of copied bytes.
+ */
+static inline unsigned int kfifo_get(struct kfifo *fifo,
+                                    unsigned char *buffer, unsigned int len)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_get(fifo, buffer, len);
+
+       /*
+        * optimization: if the FIFO is empty, set the indices to 0
+        * so we don't wrap the next time
+        */
+       if (fifo->in == fifo->out)
+               fifo->in = fifo->out = 0;
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
+/*
+ * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ */
+static inline unsigned int __kfifo_len(struct kfifo *fifo)
+{
+       return fifo->in - fifo->out;
+}
+
+/*
+ * kfifo_len - returns the number of bytes available in the FIFO
+ * @fifo: the fifo to be used.
+ */
+static inline unsigned int kfifo_len(struct kfifo *fifo)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_len(fifo);
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
+#else
+#warning "don't include kernel headers in userspace"
+#endif /* __KERNEL__ */
+#endif
diff --git a/include/linux/kobject_uevent.h b/include/linux/kobject_uevent.h
new file mode 100644 (file)
index 0000000..aa664fe
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * kobject_uevent.h - list of kobject user events that can be generated
+ *
+ * Copyright (C) 2004 IBM Corp.
+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#ifndef _KOBJECT_EVENT_H_
+#define _KOBJECT_EVENT_H_
+
+#define HOTPLUG_PATH_LEN       256
+
+/* path to the hotplug userspace helper executed on an event */
+extern char hotplug_path[];
+
+/*
+ * If you add an action here, you must also add the proper string to the
+ * lib/kobject_uevent.c file.
+ */
+typedef int __bitwise kobject_action_t;
+enum kobject_action {
+       KOBJ_ADD        = (__force kobject_action_t) 0x01,      /* add event, for hotplug */
+       KOBJ_REMOVE     = (__force kobject_action_t) 0x02,      /* remove event, for hotplug */
+       KOBJ_CHANGE     = (__force kobject_action_t) 0x03,      /* a sysfs attribute file has changed */
+       KOBJ_MOUNT      = (__force kobject_action_t) 0x04,      /* mount event for block devices */
+       KOBJ_UMOUNT     = (__force kobject_action_t) 0x05,      /* umount event for block devices */
+       KOBJ_OFFLINE    = (__force kobject_action_t) 0x06,      /* offline event for hotplug devices */
+       KOBJ_ONLINE     = (__force kobject_action_t) 0x07,      /* online event for hotplug devices */
+};
+
+
+#ifdef CONFIG_KOBJECT_UEVENT
+int kobject_uevent(struct kobject *kobj,
+                  enum kobject_action action,
+                  struct attribute *attr);
+int kobject_uevent_atomic(struct kobject *kobj,
+                         enum kobject_action action,
+                         struct attribute *attr);
+#else
+static inline int kobject_uevent(struct kobject *kobj,
+                                enum kobject_action action,
+                                struct attribute *attr)
+{
+       return 0;
+}
+static inline int kobject_uevent_atomic(struct kobject *kobj,
+                                       enum kobject_action action,
+                                       struct attribute *attr)
+{
+       return 0;
+}
+#endif
+
+#endif
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
new file mode 100644 (file)
index 0000000..172b7f4
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef _LINUX_KPROBES_H
+#define _LINUX_KPROBES_H
+/*
+ *  Kernel Probes (KProbes)
+ *  include/linux/kprobes.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ *
+ * 2002-Oct    Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
+ *             Probes initial implementation ( includes suggestions from
+ *             Rusty Russell).
+ * 2004-July   Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
+ *             interface to access function arguments.
+ */
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <asm/kprobes.h>
+
+struct kprobe;
+struct pt_regs;
+typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
+typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *);
+typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
+                                      unsigned long flags);
+typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *,
+                                      int trapnr);
+struct kprobe {
+       struct hlist_node hlist;
+
+       /* location of the probe point */
+       kprobe_opcode_t *addr;
+
+       /* Called before addr is executed. */
+       kprobe_pre_handler_t pre_handler;
+
+       /* Called after addr is executed, unless... */
+       kprobe_post_handler_t post_handler;
+
+       /* ... called if executing addr causes a fault (eg. page fault).
+        * Return 1 if it handled fault, otherwise kernel will see it. */
+       kprobe_fault_handler_t fault_handler;
+
+       /* ... called if breakpoint trap occurs in probe handler.
+        * Return 1 if it handled break, otherwise kernel will see it. */
+       kprobe_break_handler_t break_handler;
+
+       /* Saved opcode (which has been replaced with breakpoint) */
+       kprobe_opcode_t opcode;
+
+       /* copy of the original instruction */
+       kprobe_opcode_t insn[MAX_INSN_SIZE];
+};
+
+/*
+ * Special probe type that uses setjmp-longjmp type tricks to resume
+ * execution at a specified entry with a matching prototype corresponding
+ * to the probed function - a trick to enable arguments to become
+ * accessible seamlessly by probe handling logic.
+ * Note:
+ * Because of the way compilers allocate stack space for local variables
+ * etc upfront, regardless of sub-scopes within a function, this mirroring
+ * principle currently works only for probes placed on function entry points.
+ */
+struct jprobe {
+       struct kprobe kp;
+       kprobe_opcode_t *entry; /* probe handling code to jump to */
+};
+
+#ifdef CONFIG_KPROBES
+/* Locks kprobe: irq must be disabled */
+void lock_kprobes(void);
+void unlock_kprobes(void);
+
+/* kprobe running now on this CPU? */
+static inline int kprobe_running(void)
+{
+       extern unsigned int kprobe_cpu;
+       return kprobe_cpu == smp_processor_id();
+}
+
+extern void arch_prepare_kprobe(struct kprobe *p);
+extern void show_registers(struct pt_regs *regs);
+
+/* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
+struct kprobe *get_kprobe(void *addr);
+
+int register_kprobe(struct kprobe *p);
+void unregister_kprobe(struct kprobe *p);
+int setjmp_pre_handler(struct kprobe *, struct pt_regs *);
+int longjmp_break_handler(struct kprobe *, struct pt_regs *);
+int register_jprobe(struct jprobe *p);
+void unregister_jprobe(struct jprobe *p);
+void jprobe_return(void);
+
+#else
+static inline int kprobe_running(void)
+{
+       return 0;
+}
+static inline int register_kprobe(struct kprobe *p)
+{
+       return -ENOSYS;
+}
+static inline void unregister_kprobe(struct kprobe *p)
+{
+}
+static inline int register_jprobe(struct jprobe *p)
+{
+       return -ENOSYS;
+}
+static inline void unregister_jprobe(struct jprobe *p)
+{
+}
+static inline void jprobe_return(void)
+{
+}
+#endif
+#endif                         /* _LINUX_KPROBES_H */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
new file mode 100644 (file)
index 0000000..44da5ac
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  linux/include/linux/mmc/card.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.
+ *
+ *  Card driver specific definitions.
+ */
+#ifndef LINUX_MMC_CARD_H
+#define LINUX_MMC_CARD_H
+
+#include <linux/mmc/mmc.h>
+
+struct mmc_cid {
+       unsigned int            manfid;
+       char                    prod_name[8];
+       unsigned int            serial;
+       unsigned short          oemid;
+       unsigned short          year;
+       unsigned char           hwrev;
+       unsigned char           fwrev;
+       unsigned char           month;
+};
+
+struct mmc_csd {
+       unsigned char           mmca_vsn;
+       unsigned short          cmdclass;
+       unsigned short          tacc_clks;
+       unsigned int            tacc_ns;
+       unsigned int            max_dtr;
+       unsigned int            read_blkbits;
+       unsigned int            capacity;
+};
+
+struct mmc_host;
+
+/*
+ * MMC device
+ */
+struct mmc_card {
+       struct list_head        node;           /* node in hosts devices list */
+       struct mmc_host         *host;          /* the host this device belongs to */
+       struct device           dev;            /* the device */
+       unsigned int            rca;            /* relative card address of device */
+       unsigned int            state;          /* (our) card state */
+#define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
+#define MMC_STATE_DEAD         (1<<1)          /* device no longer in stack */
+#define MMC_STATE_BAD          (1<<2)          /* unrecognised device */
+       u32                     raw_cid[4];     /* raw card CID */
+       u32                     raw_csd[4];     /* raw card CSD */
+       struct mmc_cid          cid;            /* card identification */
+       struct mmc_csd          csd;            /* card specific */
+};
+
+#define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
+#define mmc_card_dead(c)       ((c)->state & MMC_STATE_DEAD)
+#define mmc_card_bad(c)                ((c)->state & MMC_STATE_BAD)
+
+#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
+#define mmc_card_set_dead(c)   ((c)->state |= MMC_STATE_DEAD)
+#define mmc_card_set_bad(c)    ((c)->state |= MMC_STATE_BAD)
+
+#define mmc_card_name(c)       ((c)->cid.prod_name)
+#define mmc_card_id(c)         ((c)->dev.bus_id)
+
+#define mmc_list_to_card(l)    container_of(l, struct mmc_card, node)
+#define mmc_get_drvdata(c)     dev_get_drvdata(&(c)->dev)
+#define mmc_set_drvdata(c,d)   dev_set_drvdata(&(c)->dev, d)
+
+/*
+ * MMC device driver (e.g., Flash card, I/O card...)
+ */
+struct mmc_driver {
+       struct device_driver drv;
+       int (*probe)(struct mmc_card *);
+       void (*remove)(struct mmc_card *);
+       int (*suspend)(struct mmc_card *, u32);
+       int (*resume)(struct mmc_card *);
+};
+
+extern int mmc_register_driver(struct mmc_driver *);
+extern void mmc_unregister_driver(struct mmc_driver *);
+
+static inline int mmc_card_claim_host(struct mmc_card *card)
+{
+       return __mmc_claim_host(card->host, card);
+}
+
+#define mmc_card_release_host(c)       mmc_release_host((c)->host)
+
+#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
new file mode 100644 (file)
index 0000000..f67686c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  linux/include/linux/mmc/host.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.
+ *
+ *  Host driver specific definitions.
+ */
+#ifndef LINUX_MMC_HOST_H
+#define LINUX_MMC_HOST_H
+
+#include <linux/mmc/mmc.h>
+
+struct mmc_ios {
+       unsigned int    clock;                  /* clock rate */
+       unsigned short  vdd;
+
+#define        MMC_VDD_150     0
+#define        MMC_VDD_155     1
+#define        MMC_VDD_160     2
+#define        MMC_VDD_165     3
+#define        MMC_VDD_170     4
+#define        MMC_VDD_180     5
+#define        MMC_VDD_190     6
+#define        MMC_VDD_200     7
+#define        MMC_VDD_210     8
+#define        MMC_VDD_220     9
+#define        MMC_VDD_230     10
+#define        MMC_VDD_240     11
+#define        MMC_VDD_250     12
+#define        MMC_VDD_260     13
+#define        MMC_VDD_270     14
+#define        MMC_VDD_280     15
+#define        MMC_VDD_290     16
+#define        MMC_VDD_300     17
+#define        MMC_VDD_310     18
+#define        MMC_VDD_320     19
+#define        MMC_VDD_330     20
+#define        MMC_VDD_340     21
+#define        MMC_VDD_350     22
+#define        MMC_VDD_360     23
+
+       unsigned char   bus_mode;               /* command output mode */
+
+#define MMC_BUSMODE_OPENDRAIN  1
+#define MMC_BUSMODE_PUSHPULL   2
+
+       unsigned char   power_mode;             /* power supply mode */
+
+#define MMC_POWER_OFF          0
+#define MMC_POWER_UP           1
+#define MMC_POWER_ON           2
+};
+
+struct mmc_host_ops {
+       void    (*request)(struct mmc_host *host, struct mmc_request *req);
+       void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
+};
+
+struct mmc_card;
+struct device;
+
+struct mmc_host {
+       struct device           *dev;
+       struct mmc_host_ops     *ops;
+       unsigned int            f_min;
+       unsigned int            f_max;
+       u32                     ocr_avail;
+       char                    host_name[8];
+
+       /* host specific block data */
+       unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
+       unsigned short          max_hw_segs;    /* see blk_queue_max_hw_segments */
+       unsigned short          max_phys_segs;  /* see blk_queue_max_phys_segments */
+       unsigned short          max_sectors;    /* see blk_queue_max_sectors */
+       unsigned short          unused;
+
+       /* private data */
+       struct mmc_ios          ios;            /* current io bus settings */
+       u32                     ocr;            /* the current OCR setting */
+
+       struct list_head        cards;          /* devices attached to this host */
+
+       wait_queue_head_t       wq;
+       spinlock_t              lock;           /* card_busy lock */
+       struct mmc_card         *card_busy;     /* the MMC card claiming host */
+       struct mmc_card         *card_selected; /* the selected MMC card */
+
+       struct work_struct      detect;
+};
+
+extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
+extern int mmc_add_host(struct mmc_host *);
+extern void mmc_remove_host(struct mmc_host *);
+extern void mmc_free_host(struct mmc_host *);
+
+#define mmc_priv(x)    ((void *)((x) + 1))
+#define mmc_dev(x)     ((x)->dev)
+
+extern int mmc_suspend_host(struct mmc_host *, u32);
+extern int mmc_resume_host(struct mmc_host *);
+
+extern void mmc_detect_change(struct mmc_host *);
+extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
+
+#endif
+
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
new file mode 100644 (file)
index 0000000..c288ae6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *  linux/include/linux/mmc/mmc.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.
+ */
+#ifndef MMC_H
+#define MMC_H
+
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+struct request;
+struct mmc_data;
+struct mmc_request;
+
+struct mmc_command {
+       u32                     opcode;
+       u32                     arg;
+       u32                     resp[4];
+       unsigned int            flags;          /* expected response type */
+#define MMC_RSP_NONE   (0 << 0)
+#define MMC_RSP_SHORT  (1 << 0)
+#define MMC_RSP_LONG   (2 << 0)
+#define MMC_RSP_MASK   (3 << 0)
+#define MMC_RSP_CRC    (1 << 3)                /* expect valid crc */
+#define MMC_RSP_BUSY   (1 << 4)                /* card may send busy */
+
+/*
+ * These are the response types, and correspond to valid bit
+ * patterns of the above flags.  One additional valid pattern
+ * is all zeros, which means we don't expect a response.
+ */
+#define MMC_RSP_R1     (MMC_RSP_SHORT|MMC_RSP_CRC)
+#define MMC_RSP_R1B    (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
+#define MMC_RSP_R2     (MMC_RSP_LONG|MMC_RSP_CRC)
+#define MMC_RSP_R3     (MMC_RSP_SHORT)
+
+       unsigned int            retries;        /* max number of retries */
+       unsigned int            error;          /* command error */
+
+#define MMC_ERR_NONE   0
+#define MMC_ERR_TIMEOUT        1
+#define MMC_ERR_BADCRC 2
+#define MMC_ERR_FIFO   3
+#define MMC_ERR_FAILED 4
+#define MMC_ERR_INVALID        5
+
+       struct mmc_data         *data;          /* data segment associated with cmd */
+       struct mmc_request      *mrq;           /* assoicated request */
+};
+
+struct mmc_data {
+       unsigned int            timeout_ns;     /* data timeout (in ns, max 80ms) */
+       unsigned int            timeout_clks;   /* data timeout (in clocks) */
+       unsigned int            blksz_bits;     /* data block size */
+       unsigned int            blocks;         /* number of blocks */
+       struct request          *req;           /* request structure */
+       unsigned int            error;          /* data error */
+       unsigned int            flags;
+
+#define MMC_DATA_WRITE (1 << 8)
+#define MMC_DATA_READ  (1 << 9)
+#define MMC_DATA_STREAM        (1 << 10)
+
+       unsigned int            bytes_xfered;
+
+       struct mmc_command      *stop;          /* stop command */
+       struct mmc_request      *mrq;           /* assoicated request */
+};
+
+struct mmc_request {
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+       struct mmc_command      *stop;
+
+       void                    *done_data;     /* completion data */
+       void                    (*done)(struct mmc_request *);/* completion function */
+};
+
+struct mmc_host;
+struct mmc_card;
+
+extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
+extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+
+extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
+
+static inline void mmc_claim_host(struct mmc_host *host)
+{
+       __mmc_claim_host(host, (struct mmc_card *)-1);
+}
+
+extern void mmc_release_host(struct mmc_host *host);
+
+#endif
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
new file mode 100644 (file)
index 0000000..5b79ed4
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2002/06/18 12:37:30 $
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
+ */
+
+#ifndef MMC_MMC_PROTOCOL_H
+#define MMC_MMC_PROTOCOL_H
+
+/* Standard MMC commands (3.1)           type  argument     response */
+   /* class 1 */
+#define        MMC_GO_IDLE_STATE         0   /* bc                          */
+#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
+#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
+#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
+#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
+#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
+#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
+#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
+#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
+#define MMC_SEND_STATUS                 13   /* ac   [31:16] RCA        R1  */
+#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
+
+  /* class 2 */
+#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
+#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
+#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+
+  /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
+
+  /* class 4 */
+#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
+#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
+#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
+
+  /* class 6 */
+#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
+#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
+#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
+
+  /* class 5 */
+#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE                37   /* ac                      R1b */
+
+  /* class 9 */
+#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
+#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
+
+  /* class 7 */
+#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
+
+  /* class 8 */
+#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
+#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
+
+/*
+  MMC status in R1
+  Type
+       e : error bit
+       s : status bit
+       r : detected and set for the actual command response
+       x : detected and set during command execution. the host must poll
+            the card by sending status command in order to read these bits.
+  Clear condition
+       a : according to the card state
+       b : always related to the previous command. Reception of
+            a valid command will clear it (with a delay of one command)
+       c : clear by read
+ */
+
+#define R1_OUT_OF_RANGE                (1 << 31)       /* er, c */
+#define R1_ADDRESS_ERROR       (1 << 30)       /* erx, c */
+#define R1_BLOCK_LEN_ERROR     (1 << 29)       /* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)      /* er, c */
+#define R1_ERASE_PARAM         (1 << 27)       /* ex, c */
+#define R1_WP_VIOLATION                (1 << 26)       /* erx, c */
+#define R1_CARD_IS_LOCKED      (1 << 25)       /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED  (1 << 24)       /* erx, c */
+#define R1_COM_CRC_ERROR       (1 << 23)       /* er, b */
+#define R1_ILLEGAL_COMMAND     (1 << 22)       /* er, b */
+#define R1_CARD_ECC_FAILED     (1 << 21)       /* ex, c */
+#define R1_CC_ERROR            (1 << 20)       /* erx, c */
+#define R1_ERROR               (1 << 19)       /* erx, c */
+#define R1_UNDERRUN            (1 << 18)       /* ex, c */
+#define R1_OVERRUN             (1 << 17)       /* ex, c */
+#define R1_CID_CSD_OVERWRITE   (1 << 16)       /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP       (1 << 15)       /* sx, c */
+#define R1_CARD_ECC_DISABLED   (1 << 14)       /* sx, a */
+#define R1_ERASE_RESET         (1 << 13)       /* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)            ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA      (1 << 8)        /* sx, a */
+#define R1_APP_CMD             (1 << 7)        /* sr, c */
+
+/* These are unpacked versions of the actual responses */
+
+struct _mmc_csd {
+       u8  csd_structure;
+       u8  spec_vers;
+       u8  taac;
+       u8  nsac;
+       u8  tran_speed;
+       u16 ccc;
+       u8  read_bl_len;
+       u8  read_bl_partial;
+       u8  write_blk_misalign;
+       u8  read_blk_misalign;
+       u8  dsr_imp;
+       u16 c_size;
+       u8  vdd_r_curr_min;
+       u8  vdd_r_curr_max;
+       u8  vdd_w_curr_min;
+       u8  vdd_w_curr_max;
+       u8  c_size_mult;
+       union {
+               struct { /* MMC system specification version 3.1 */
+                       u8  erase_grp_size;
+                       u8  erase_grp_mult;
+               } v31;
+               struct { /* MMC system specification version 2.2 */
+                       u8  sector_size;
+                       u8  erase_grp_size;
+               } v22;
+       } erase;
+       u8  wp_grp_size;
+       u8  wp_grp_enable;
+       u8  default_ecc;
+       u8  r2w_factor;
+       u8  write_bl_len;
+       u8  write_bl_partial;
+       u8  file_format_grp;
+       u8  copy;
+       u8  perm_write_protect;
+       u8  tmp_write_protect;
+       u8  file_format;
+       u8  ecc;
+};
+
+#define MMC_VDD_145_150        0x00000001      /* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155        0x00000002      /* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160        0x00000004      /* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165        0x00000008      /* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170        0x00000010      /* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18  0x00000020      /* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19  0x00000040      /* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20  0x00000080      /* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21  0x00000100      /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22  0x00000200      /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23  0x00000400      /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24  0x00000800      /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25  0x00001000      /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26  0x00002000      /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27  0x00004000      /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28  0x00008000      /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29  0x00010000      /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30  0x00020000      /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31  0x00040000      /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32  0x00080000      /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33  0x00100000      /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34  0x00200000      /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35  0x00400000      /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36  0x00800000      /* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY  0x80000000      /* Card Power up status bit */
+
+
+/*
+ * CSD field definitions
+ */
+
+#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1       */
+
+#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
+
+#endif  /* MMC_MMC_PROTOCOL_H */
+
diff --git a/include/linux/mmtimer.h b/include/linux/mmtimer.h
new file mode 100644 (file)
index 0000000..884cabf
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Intel Multimedia Timer device interface
+ *
+ * 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-2004 Silicon Graphics, Inc.  All rights reserved.
+ *
+ * This file should define an interface compatible with the IA-PC Multimedia
+ * Timers Draft Specification (rev. 0.97) from Intel.  Note that some
+ * hardware may not be able to safely export its registers to userspace,
+ * so the ioctl interface should support all necessary functionality.
+ *
+ * 11/01/01 - jbarnes - initial revision
+ * 9/10/04 - Christoph Lameter - remove interrupt support
+ * 9/17/04 - jbarnes - remove test program, move some #defines to the driver
+ */
+
+#ifndef _LINUX_MMTIMER_H
+#define _LINUX_MMTIMER_H
+
+/*
+ * Breakdown of the ioctl's available.  An 'optional' next to the command
+ * indicates that supporting this command is optional, while 'required'
+ * commands must be implemented if conformance is desired.
+ *
+ * MMTIMER_GETOFFSET - optional
+ *   Should return the offset (relative to the start of the page where the
+ *   registers are mapped) for the counter in question.
+ *
+ * MMTIMER_GETRES - required
+ *   The resolution of the clock in femto (10^-15) seconds
+ *
+ * MMTIMER_GETFREQ - required
+ *   Frequency of the clock in Hz
+ *
+ * MMTIMER_GETBITS - required
+ *   Number of bits in the clock's counter
+ *
+ * MMTIMER_MMAPAVAIL - required
+ *   Returns nonzero if the registers can be mmap'd into userspace, 0 otherwise
+ *
+ * MMTIMER_GETCOUNTER - required
+ *   Gets the current value in the counter
+ */
+#define MMTIMER_IOCTL_BASE 'm'
+
+#define MMTIMER_GETOFFSET _IO(MMTIMER_IOCTL_BASE, 0)
+#define MMTIMER_GETRES _IOR(MMTIMER_IOCTL_BASE, 1, unsigned long)
+#define MMTIMER_GETFREQ _IOR(MMTIMER_IOCTL_BASE, 2, unsigned long)
+#define MMTIMER_GETBITS _IO(MMTIMER_IOCTL_BASE, 4)
+#define MMTIMER_MMAPAVAIL _IO(MMTIMER_IOCTL_BASE, 6)
+#define MMTIMER_GETCOUNTER _IOR(MMTIMER_IOCTL_BASE, 9, unsigned long)
+
+#endif /* _LINUX_MMTIMER_H */
diff --git a/include/linux/mv643xx.h b/include/linux/mv643xx.h
new file mode 100644 (file)
index 0000000..a889dd9
--- /dev/null
@@ -0,0 +1,1039 @@
+/*
+ * mv64340.h - MV-64340 Internal registers definition file.
+ *
+ * Copyright 2002 Momentum Computer, Inc.
+ *     Author: Matthew Dharm <mdharm@momenco.com>
+ * Copyright 2002 GALILEO TECHNOLOGY, LTD. 
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __ASM_MV64340_H
+#define __ASM_MV64340_H
+
+#include <asm/addrspace.h>
+#include <asm/marvell.h>
+
+/****************************************/
+/* Processor Address Space              */
+/****************************************/
+
+/* DDR SDRAM BAR and size registers */
+
+#define MV64340_CS_0_BASE_ADDR                                      0x008
+#define MV64340_CS_0_SIZE                                           0x010
+#define MV64340_CS_1_BASE_ADDR                                      0x208
+#define MV64340_CS_1_SIZE                                           0x210
+#define MV64340_CS_2_BASE_ADDR                                      0x018
+#define MV64340_CS_2_SIZE                                           0x020
+#define MV64340_CS_3_BASE_ADDR                                      0x218
+#define MV64340_CS_3_SIZE                                           0x220
+
+/* Devices BAR and size registers */
+
+#define MV64340_DEV_CS0_BASE_ADDR                                   0x028
+#define MV64340_DEV_CS0_SIZE                                        0x030
+#define MV64340_DEV_CS1_BASE_ADDR                                   0x228
+#define MV64340_DEV_CS1_SIZE                                        0x230
+#define MV64340_DEV_CS2_BASE_ADDR                                   0x248
+#define MV64340_DEV_CS2_SIZE                                        0x250
+#define MV64340_DEV_CS3_BASE_ADDR                                   0x038
+#define MV64340_DEV_CS3_SIZE                                        0x040
+#define MV64340_BOOTCS_BASE_ADDR                                    0x238
+#define MV64340_BOOTCS_SIZE                                         0x240
+
+/* PCI 0 BAR and size registers */
+
+#define MV64340_PCI_0_IO_BASE_ADDR                                  0x048
+#define MV64340_PCI_0_IO_SIZE                                       0x050
+#define MV64340_PCI_0_MEMORY0_BASE_ADDR                             0x058
+#define MV64340_PCI_0_MEMORY0_SIZE                                  0x060
+#define MV64340_PCI_0_MEMORY1_BASE_ADDR                             0x080
+#define MV64340_PCI_0_MEMORY1_SIZE                                  0x088
+#define MV64340_PCI_0_MEMORY2_BASE_ADDR                             0x258
+#define MV64340_PCI_0_MEMORY2_SIZE                                  0x260
+#define MV64340_PCI_0_MEMORY3_BASE_ADDR                             0x280
+#define MV64340_PCI_0_MEMORY3_SIZE                                  0x288
+
+/* PCI 1 BAR and size registers */
+#define MV64340_PCI_1_IO_BASE_ADDR                                  0x090
+#define MV64340_PCI_1_IO_SIZE                                       0x098
+#define MV64340_PCI_1_MEMORY0_BASE_ADDR                             0x0a0
+#define MV64340_PCI_1_MEMORY0_SIZE                                  0x0a8
+#define MV64340_PCI_1_MEMORY1_BASE_ADDR                             0x0b0
+#define MV64340_PCI_1_MEMORY1_SIZE                                  0x0b8
+#define MV64340_PCI_1_MEMORY2_BASE_ADDR                             0x2a0
+#define MV64340_PCI_1_MEMORY2_SIZE                                  0x2a8
+#define MV64340_PCI_1_MEMORY3_BASE_ADDR                             0x2b0
+#define MV64340_PCI_1_MEMORY3_SIZE                                  0x2b8
+
+/* SRAM base address */
+#define MV64340_INTEGRATED_SRAM_BASE_ADDR                           0x268
+
+/* internal registers space base address */
+#define MV64340_INTERNAL_SPACE_BASE_ADDR                            0x068
+
+/* Enables the CS , DEV_CS , PCI 0 and PCI 1 
+   windows above */
+#define MV64340_BASE_ADDR_ENABLE                                    0x278
+
+/****************************************/
+/* PCI remap registers                  */
+/****************************************/
+      /* PCI 0 */
+#define MV64340_PCI_0_IO_ADDR_REMAP                                 0x0f0
+#define MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP                        0x0f8
+#define MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP                       0x320
+#define MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP                        0x100
+#define MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP                       0x328
+#define MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP                        0x2f8
+#define MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP                       0x330
+#define MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP                        0x300
+#define MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP                       0x338
+      /* PCI 1 */
+#define MV64340_PCI_1_IO_ADDR_REMAP                                 0x108
+#define MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP                        0x110
+#define MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP                       0x340
+#define MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP                        0x118
+#define MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP                       0x348
+#define MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP                        0x310
+#define MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP                       0x350
+#define MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP                        0x318
+#define MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP                       0x358
+#define MV64340_CPU_PCI_0_HEADERS_RETARGET_CONTROL                  0x3b0
+#define MV64340_CPU_PCI_0_HEADERS_RETARGET_BASE                     0x3b8
+#define MV64340_CPU_PCI_1_HEADERS_RETARGET_CONTROL                  0x3c0
+#define MV64340_CPU_PCI_1_HEADERS_RETARGET_BASE                     0x3c8
+#define MV64340_CPU_GE_HEADERS_RETARGET_CONTROL                     0x3d0
+#define MV64340_CPU_GE_HEADERS_RETARGET_BASE                        0x3d8
+#define MV64340_CPU_IDMA_HEADERS_RETARGET_CONTROL                   0x3e0
+#define MV64340_CPU_IDMA_HEADERS_RETARGET_BASE                      0x3e8
+
+/****************************************/
+/*         CPU Control Registers        */
+/****************************************/
+
+#define MV64340_CPU_CONFIG                                          0x000
+#define MV64340_CPU_MODE                                            0x120
+#define MV64340_CPU_MASTER_CONTROL                                  0x160
+#define MV64340_CPU_CROSS_BAR_CONTROL_LOW                           0x150
+#define MV64340_CPU_CROSS_BAR_CONTROL_HIGH                          0x158
+#define MV64340_CPU_CROSS_BAR_TIMEOUT                               0x168
+
+/****************************************/
+/* SMP RegisterS                        */
+/****************************************/
+
+#define MV64340_SMP_WHO_AM_I                                        0x200
+#define MV64340_SMP_CPU0_DOORBELL                                   0x214
+#define MV64340_SMP_CPU0_DOORBELL_CLEAR                             0x21C
+#define MV64340_SMP_CPU1_DOORBELL                                   0x224
+#define MV64340_SMP_CPU1_DOORBELL_CLEAR                             0x22C
+#define MV64340_SMP_CPU0_DOORBELL_MASK                              0x234
+#define MV64340_SMP_CPU1_DOORBELL_MASK                              0x23C
+#define MV64340_SMP_SEMAPHOR0                                       0x244
+#define MV64340_SMP_SEMAPHOR1                                       0x24c
+#define MV64340_SMP_SEMAPHOR2                                       0x254
+#define MV64340_SMP_SEMAPHOR3                                       0x25c
+#define MV64340_SMP_SEMAPHOR4                                       0x264
+#define MV64340_SMP_SEMAPHOR5                                       0x26c
+#define MV64340_SMP_SEMAPHOR6                                       0x274
+#define MV64340_SMP_SEMAPHOR7                                       0x27c
+
+/****************************************/
+/*  CPU Sync Barrier Register           */
+/****************************************/
+
+#define MV64340_CPU_0_SYNC_BARRIER_TRIGGER                          0x0c0
+#define MV64340_CPU_0_SYNC_BARRIER_VIRTUAL                          0x0c8
+#define MV64340_CPU_1_SYNC_BARRIER_TRIGGER                          0x0d0
+#define MV64340_CPU_1_SYNC_BARRIER_VIRTUAL                          0x0d8
+
+/****************************************/
+/* CPU Access Protect                   */
+/****************************************/
+
+#define MV64340_CPU_PROTECT_WINDOW_0_BASE_ADDR                      0x180
+#define MV64340_CPU_PROTECT_WINDOW_0_SIZE                           0x188
+#define MV64340_CPU_PROTECT_WINDOW_1_BASE_ADDR                      0x190
+#define MV64340_CPU_PROTECT_WINDOW_1_SIZE                           0x198
+#define MV64340_CPU_PROTECT_WINDOW_2_BASE_ADDR                      0x1a0
+#define MV64340_CPU_PROTECT_WINDOW_2_SIZE                           0x1a8
+#define MV64340_CPU_PROTECT_WINDOW_3_BASE_ADDR                      0x1b0
+#define MV64340_CPU_PROTECT_WINDOW_3_SIZE                           0x1b8
+
+
+/****************************************/
+/*          CPU Error Report            */
+/****************************************/
+
+#define MV64340_CPU_ERROR_ADDR_LOW                                  0x070
+#define MV64340_CPU_ERROR_ADDR_HIGH                                 0x078
+#define MV64340_CPU_ERROR_DATA_LOW                                  0x128
+#define MV64340_CPU_ERROR_DATA_HIGH                                 0x130
+#define MV64340_CPU_ERROR_PARITY                                    0x138
+#define MV64340_CPU_ERROR_CAUSE                                     0x140
+#define MV64340_CPU_ERROR_MASK                                      0x148
+
+/****************************************/
+/*      CPU Interface Debug Registers  */
+/****************************************/
+
+#define MV64340_PUNIT_SLAVE_DEBUG_LOW                               0x360
+#define MV64340_PUNIT_SLAVE_DEBUG_HIGH                              0x368
+#define MV64340_PUNIT_MASTER_DEBUG_LOW                              0x370
+#define MV64340_PUNIT_MASTER_DEBUG_HIGH                             0x378
+#define MV64340_PUNIT_MMASK                                         0x3e4
+
+/****************************************/
+/*  Integrated SRAM Registers           */
+/****************************************/
+
+#define MV64340_SRAM_CONFIG                                         0x380
+#define MV64340_SRAM_TEST_MODE                                      0X3F4
+#define MV64340_SRAM_ERROR_CAUSE                                    0x388
+#define MV64340_SRAM_ERROR_ADDR                                     0x390
+#define MV64340_SRAM_ERROR_ADDR_HIGH                                0X3F8
+#define MV64340_SRAM_ERROR_DATA_LOW                                 0x398
+#define MV64340_SRAM_ERROR_DATA_HIGH                                0x3a0
+#define MV64340_SRAM_ERROR_DATA_PARITY                              0x3a8
+
+/****************************************/
+/* SDRAM Configuration                  */
+/****************************************/
+
+#define MV64340_SDRAM_CONFIG                                        0x1400
+#define MV64340_D_UNIT_CONTROL_LOW                                  0x1404
+#define MV64340_D_UNIT_CONTROL_HIGH                                 0x1424
+#define MV64340_SDRAM_TIMING_CONTROL_LOW                            0x1408
+#define MV64340_SDRAM_TIMING_CONTROL_HIGH                           0x140c
+#define MV64340_SDRAM_ADDR_CONTROL                                  0x1410
+#define MV64340_SDRAM_OPEN_PAGES_CONTROL                            0x1414
+#define MV64340_SDRAM_OPERATION                                     0x1418
+#define MV64340_SDRAM_MODE                                          0x141c
+#define MV64340_EXTENDED_DRAM_MODE                                  0x1420
+#define MV64340_SDRAM_CROSS_BAR_CONTROL_LOW                         0x1430
+#define MV64340_SDRAM_CROSS_BAR_CONTROL_HIGH                        0x1434
+#define MV64340_SDRAM_CROSS_BAR_TIMEOUT                             0x1438
+#define MV64340_SDRAM_ADDR_CTRL_PADS_CALIBRATION                    0x14c0
+#define MV64340_SDRAM_DATA_PADS_CALIBRATION                         0x14c4
+
+/****************************************/
+/* SDRAM Error Report                   */
+/****************************************/
+
+#define MV64340_SDRAM_ERROR_DATA_LOW                                0x1444
+#define MV64340_SDRAM_ERROR_DATA_HIGH                               0x1440
+#define MV64340_SDRAM_ERROR_ADDR                                    0x1450
+#define MV64340_SDRAM_RECEIVED_ECC                                  0x1448
+#define MV64340_SDRAM_CALCULATED_ECC                                0x144c
+#define MV64340_SDRAM_ECC_CONTROL                                   0x1454
+#define MV64340_SDRAM_ECC_ERROR_COUNTER                             0x1458
+
+/******************************************/
+/*  Controlled Delay Line (CDL) Registers */
+/******************************************/
+
+#define MV64340_DFCDL_CONFIG0                                       0x1480
+#define MV64340_DFCDL_CONFIG1                                       0x1484
+#define MV64340_DLL_WRITE                                           0x1488
+#define MV64340_DLL_READ                                            0x148c
+#define MV64340_SRAM_ADDR                                           0x1490
+#define MV64340_SRAM_DATA0                                          0x1494
+#define MV64340_SRAM_DATA1                                          0x1498
+#define MV64340_SRAM_DATA2                                          0x149c
+#define MV64340_DFCL_PROBE                                          0x14a0
+
+/******************************************/
+/*   Debug Registers                      */
+/******************************************/
+
+#define MV64340_DUNIT_DEBUG_LOW                                     0x1460
+#define MV64340_DUNIT_DEBUG_HIGH                                    0x1464
+#define MV64340_DUNIT_MMASK                                         0X1b40
+
+/****************************************/
+/* Device Parameters                   */
+/****************************************/
+
+#define MV64340_DEVICE_BANK0_PARAMETERS                                    0x45c
+#define MV64340_DEVICE_BANK1_PARAMETERS                                    0x460
+#define MV64340_DEVICE_BANK2_PARAMETERS                                    0x464
+#define MV64340_DEVICE_BANK3_PARAMETERS                                    0x468
+#define MV64340_DEVICE_BOOT_BANK_PARAMETERS                        0x46c
+#define MV64340_DEVICE_INTERFACE_CONTROL                            0x4c0
+#define MV64340_DEVICE_INTERFACE_CROSS_BAR_CONTROL_LOW              0x4c8
+#define MV64340_DEVICE_INTERFACE_CROSS_BAR_CONTROL_HIGH             0x4cc
+#define MV64340_DEVICE_INTERFACE_CROSS_BAR_TIMEOUT                  0x4c4
+
+/****************************************/
+/* Device interrupt registers          */
+/****************************************/
+
+#define MV64340_DEVICE_INTERRUPT_CAUSE                             0x4d0
+#define MV64340_DEVICE_INTERRUPT_MASK                              0x4d4
+#define MV64340_DEVICE_ERROR_ADDR                                  0x4d8
+#define MV64340_DEVICE_ERROR_DATA                                  0x4dc
+#define MV64340_DEVICE_ERROR_PARITY                                0x4e0
+
+/****************************************/
+/* Device debug registers              */
+/****************************************/
+
+#define MV64340_DEVICE_DEBUG_LOW                                   0x4e4
+#define MV64340_DEVICE_DEBUG_HIGH                                  0x4e8
+#define MV64340_RUNIT_MMASK                                         0x4f0
+
+/****************************************/
+/* PCI Slave Address Decoding registers */
+/****************************************/
+
+#define MV64340_PCI_0_CS_0_BANK_SIZE                                0xc08
+#define MV64340_PCI_1_CS_0_BANK_SIZE                                0xc88
+#define MV64340_PCI_0_CS_1_BANK_SIZE                                0xd08
+#define MV64340_PCI_1_CS_1_BANK_SIZE                                0xd88
+#define MV64340_PCI_0_CS_2_BANK_SIZE                                0xc0c
+#define MV64340_PCI_1_CS_2_BANK_SIZE                                0xc8c
+#define MV64340_PCI_0_CS_3_BANK_SIZE                                0xd0c
+#define MV64340_PCI_1_CS_3_BANK_SIZE                                0xd8c
+#define MV64340_PCI_0_DEVCS_0_BANK_SIZE                             0xc10
+#define MV64340_PCI_1_DEVCS_0_BANK_SIZE                             0xc90
+#define MV64340_PCI_0_DEVCS_1_BANK_SIZE                             0xd10
+#define MV64340_PCI_1_DEVCS_1_BANK_SIZE                             0xd90
+#define MV64340_PCI_0_DEVCS_2_BANK_SIZE                             0xd18
+#define MV64340_PCI_1_DEVCS_2_BANK_SIZE                             0xd98
+#define MV64340_PCI_0_DEVCS_3_BANK_SIZE                             0xc14
+#define MV64340_PCI_1_DEVCS_3_BANK_SIZE                             0xc94
+#define MV64340_PCI_0_DEVCS_BOOT_BANK_SIZE                          0xd14
+#define MV64340_PCI_1_DEVCS_BOOT_BANK_SIZE                          0xd94
+#define MV64340_PCI_0_P2P_MEM0_BAR_SIZE                             0xd1c
+#define MV64340_PCI_1_P2P_MEM0_BAR_SIZE                             0xd9c
+#define MV64340_PCI_0_P2P_MEM1_BAR_SIZE                             0xd20
+#define MV64340_PCI_1_P2P_MEM1_BAR_SIZE                             0xda0
+#define MV64340_PCI_0_P2P_I_O_BAR_SIZE                              0xd24
+#define MV64340_PCI_1_P2P_I_O_BAR_SIZE                              0xda4
+#define MV64340_PCI_0_CPU_BAR_SIZE                                  0xd28
+#define MV64340_PCI_1_CPU_BAR_SIZE                                  0xda8
+#define MV64340_PCI_0_INTERNAL_SRAM_BAR_SIZE                        0xe00
+#define MV64340_PCI_1_INTERNAL_SRAM_BAR_SIZE                        0xe80
+#define MV64340_PCI_0_EXPANSION_ROM_BAR_SIZE                        0xd2c
+#define MV64340_PCI_1_EXPANSION_ROM_BAR_SIZE                        0xd9c
+#define MV64340_PCI_0_BASE_ADDR_REG_ENABLE                          0xc3c
+#define MV64340_PCI_1_BASE_ADDR_REG_ENABLE                          0xcbc
+#define MV64340_PCI_0_CS_0_BASE_ADDR_REMAP                         0xc48
+#define MV64340_PCI_1_CS_0_BASE_ADDR_REMAP                         0xcc8
+#define MV64340_PCI_0_CS_1_BASE_ADDR_REMAP                         0xd48
+#define MV64340_PCI_1_CS_1_BASE_ADDR_REMAP                         0xdc8
+#define MV64340_PCI_0_CS_2_BASE_ADDR_REMAP                         0xc4c
+#define MV64340_PCI_1_CS_2_BASE_ADDR_REMAP                         0xccc
+#define MV64340_PCI_0_CS_3_BASE_ADDR_REMAP                         0xd4c
+#define MV64340_PCI_1_CS_3_BASE_ADDR_REMAP                         0xdcc
+#define MV64340_PCI_0_CS_0_BASE_HIGH_ADDR_REMAP                            0xF04
+#define MV64340_PCI_1_CS_0_BASE_HIGH_ADDR_REMAP                            0xF84
+#define MV64340_PCI_0_CS_1_BASE_HIGH_ADDR_REMAP                            0xF08
+#define MV64340_PCI_1_CS_1_BASE_HIGH_ADDR_REMAP                            0xF88
+#define MV64340_PCI_0_CS_2_BASE_HIGH_ADDR_REMAP                            0xF0C
+#define MV64340_PCI_1_CS_2_BASE_HIGH_ADDR_REMAP                            0xF8C
+#define MV64340_PCI_0_CS_3_BASE_HIGH_ADDR_REMAP                            0xF10
+#define MV64340_PCI_1_CS_3_BASE_HIGH_ADDR_REMAP                            0xF90
+#define MV64340_PCI_0_DEVCS_0_BASE_ADDR_REMAP                      0xc50
+#define MV64340_PCI_1_DEVCS_0_BASE_ADDR_REMAP                      0xcd0
+#define MV64340_PCI_0_DEVCS_1_BASE_ADDR_REMAP                      0xd50
+#define MV64340_PCI_1_DEVCS_1_BASE_ADDR_REMAP                      0xdd0
+#define MV64340_PCI_0_DEVCS_2_BASE_ADDR_REMAP                      0xd58
+#define MV64340_PCI_1_DEVCS_2_BASE_ADDR_REMAP                      0xdd8
+#define MV64340_PCI_0_DEVCS_3_BASE_ADDR_REMAP                      0xc54
+#define MV64340_PCI_1_DEVCS_3_BASE_ADDR_REMAP                      0xcd4
+#define MV64340_PCI_0_DEVCS_BOOTCS_BASE_ADDR_REMAP                 0xd54
+#define MV64340_PCI_1_DEVCS_BOOTCS_BASE_ADDR_REMAP                 0xdd4
+#define MV64340_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_LOW                  0xd5c
+#define MV64340_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_LOW                  0xddc
+#define MV64340_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_HIGH                 0xd60
+#define MV64340_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_HIGH                 0xde0
+#define MV64340_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_LOW                  0xd64
+#define MV64340_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_LOW                  0xde4
+#define MV64340_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_HIGH                 0xd68
+#define MV64340_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_HIGH                 0xde8
+#define MV64340_PCI_0_P2P_I_O_BASE_ADDR_REMAP                       0xd6c
+#define MV64340_PCI_1_P2P_I_O_BASE_ADDR_REMAP                       0xdec 
+#define MV64340_PCI_0_CPU_BASE_ADDR_REMAP_LOW                       0xd70
+#define MV64340_PCI_1_CPU_BASE_ADDR_REMAP_LOW                       0xdf0
+#define MV64340_PCI_0_CPU_BASE_ADDR_REMAP_HIGH                      0xd74
+#define MV64340_PCI_1_CPU_BASE_ADDR_REMAP_HIGH                      0xdf4
+#define MV64340_PCI_0_INTEGRATED_SRAM_BASE_ADDR_REMAP               0xf00
+#define MV64340_PCI_1_INTEGRATED_SRAM_BASE_ADDR_REMAP               0xf80
+#define MV64340_PCI_0_EXPANSION_ROM_BASE_ADDR_REMAP                 0xf38
+#define MV64340_PCI_1_EXPANSION_ROM_BASE_ADDR_REMAP                 0xfb8
+#define MV64340_PCI_0_ADDR_DECODE_CONTROL                           0xd3c
+#define MV64340_PCI_1_ADDR_DECODE_CONTROL                           0xdbc
+#define MV64340_PCI_0_HEADERS_RETARGET_CONTROL                      0xF40
+#define MV64340_PCI_1_HEADERS_RETARGET_CONTROL                      0xFc0
+#define MV64340_PCI_0_HEADERS_RETARGET_BASE                         0xF44
+#define MV64340_PCI_1_HEADERS_RETARGET_BASE                         0xFc4
+#define MV64340_PCI_0_HEADERS_RETARGET_HIGH                         0xF48
+#define MV64340_PCI_1_HEADERS_RETARGET_HIGH                         0xFc8
+
+/***********************************/
+/*   PCI Control Register Map      */
+/***********************************/
+
+#define MV64340_PCI_0_DLL_STATUS_AND_COMMAND                        0x1d20
+#define MV64340_PCI_1_DLL_STATUS_AND_COMMAND                        0x1da0
+#define MV64340_PCI_0_MPP_PADS_DRIVE_CONTROL                        0x1d1C
+#define MV64340_PCI_1_MPP_PADS_DRIVE_CONTROL                        0x1d9C
+#define MV64340_PCI_0_COMMAND                                      0xc00
+#define MV64340_PCI_1_COMMAND                                      0xc80
+#define MV64340_PCI_0_MODE                                          0xd00
+#define MV64340_PCI_1_MODE                                          0xd80
+#define MV64340_PCI_0_RETRY                                        0xc04
+#define MV64340_PCI_1_RETRY                                        0xc84
+#define MV64340_PCI_0_READ_BUFFER_DISCARD_TIMER                     0xd04
+#define MV64340_PCI_1_READ_BUFFER_DISCARD_TIMER                     0xd84
+#define MV64340_PCI_0_MSI_TRIGGER_TIMER                             0xc38
+#define MV64340_PCI_1_MSI_TRIGGER_TIMER                             0xcb8
+#define MV64340_PCI_0_ARBITER_CONTROL                               0x1d00
+#define MV64340_PCI_1_ARBITER_CONTROL                               0x1d80
+#define MV64340_PCI_0_CROSS_BAR_CONTROL_LOW                         0x1d08
+#define MV64340_PCI_1_CROSS_BAR_CONTROL_LOW                         0x1d88
+#define MV64340_PCI_0_CROSS_BAR_CONTROL_HIGH                        0x1d0c
+#define MV64340_PCI_1_CROSS_BAR_CONTROL_HIGH                        0x1d8c
+#define MV64340_PCI_0_CROSS_BAR_TIMEOUT                             0x1d04
+#define MV64340_PCI_1_CROSS_BAR_TIMEOUT                             0x1d84
+#define MV64340_PCI_0_SYNC_BARRIER_TRIGGER_REG                      0x1D18
+#define MV64340_PCI_1_SYNC_BARRIER_TRIGGER_REG                      0x1D98
+#define MV64340_PCI_0_SYNC_BARRIER_VIRTUAL_REG                      0x1d10
+#define MV64340_PCI_1_SYNC_BARRIER_VIRTUAL_REG                      0x1d90
+#define MV64340_PCI_0_P2P_CONFIG                                    0x1d14
+#define MV64340_PCI_1_P2P_CONFIG                                    0x1d94
+
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_0_LOW                     0x1e00
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_0_HIGH                    0x1e04
+#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_0                         0x1e08
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_1_LOW                     0x1e10
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_1_HIGH                    0x1e14
+#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_1                         0x1e18
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_2_LOW                     0x1e20
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_2_HIGH                    0x1e24
+#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_2                         0x1e28
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_3_LOW                     0x1e30
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_3_HIGH                    0x1e34
+#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_3                         0x1e38
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_4_LOW                     0x1e40
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_4_HIGH                    0x1e44
+#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_4                         0x1e48
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_5_LOW                     0x1e50
+#define MV64340_PCI_0_ACCESS_CONTROL_BASE_5_HIGH                    0x1e54
+#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_5                         0x1e58
+
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_0_LOW                     0x1e80
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_0_HIGH                    0x1e84
+#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_0                         0x1e88
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_1_LOW                     0x1e90
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_1_HIGH                    0x1e94
+#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_1                         0x1e98
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_2_LOW                     0x1ea0
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_2_HIGH                    0x1ea4
+#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_2                         0x1ea8
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_3_LOW                     0x1eb0
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_3_HIGH                    0x1eb4
+#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_3                         0x1eb8
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_4_LOW                     0x1ec0
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_4_HIGH                    0x1ec4
+#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_4                         0x1ec8
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_5_LOW                     0x1ed0
+#define MV64340_PCI_1_ACCESS_CONTROL_BASE_5_HIGH                    0x1ed4
+#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_5                         0x1ed8
+
+/****************************************/
+/*   PCI Configuration Access Registers */
+/****************************************/
+
+#define MV64340_PCI_0_CONFIG_ADDR                                  0xcf8
+#define MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG                       0xcfc
+#define MV64340_PCI_1_CONFIG_ADDR                                  0xc78
+#define MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG                       0xc7c
+#define MV64340_PCI_0_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG                    0xc34
+#define MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG                    0xcb4
+
+/****************************************/
+/*   PCI Error Report Registers         */
+/****************************************/
+
+#define MV64340_PCI_0_SERR_MASK                                            0xc28
+#define MV64340_PCI_1_SERR_MASK                                            0xca8
+#define MV64340_PCI_0_ERROR_ADDR_LOW                                0x1d40
+#define MV64340_PCI_1_ERROR_ADDR_LOW                                0x1dc0
+#define MV64340_PCI_0_ERROR_ADDR_HIGH                               0x1d44
+#define MV64340_PCI_1_ERROR_ADDR_HIGH                               0x1dc4
+#define MV64340_PCI_0_ERROR_ATTRIBUTE                               0x1d48
+#define MV64340_PCI_1_ERROR_ATTRIBUTE                               0x1dc8
+#define MV64340_PCI_0_ERROR_COMMAND                                 0x1d50
+#define MV64340_PCI_1_ERROR_COMMAND                                 0x1dd0
+#define MV64340_PCI_0_ERROR_CAUSE                                   0x1d58
+#define MV64340_PCI_1_ERROR_CAUSE                                   0x1dd8
+#define MV64340_PCI_0_ERROR_MASK                                    0x1d5c
+#define MV64340_PCI_1_ERROR_MASK                                    0x1ddc
+
+/****************************************/
+/*   PCI Debug Registers                */
+/****************************************/
+
+#define MV64340_PCI_0_MMASK                                         0X1D24
+#define MV64340_PCI_1_MMASK                                         0X1DA4
+
+/*********************************************/
+/* PCI Configuration, Function 0, Registers  */
+/*********************************************/
+
+#define MV64340_PCI_DEVICE_AND_VENDOR_ID                           0x000
+#define MV64340_PCI_STATUS_AND_COMMAND                             0x004
+#define MV64340_PCI_CLASS_CODE_AND_REVISION_ID                     0x008
+#define MV64340_PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE      0x00C
+
+#define MV64340_PCI_SCS_0_BASE_ADDR_LOW                            0x010
+#define MV64340_PCI_SCS_0_BASE_ADDR_HIGH                           0x014
+#define MV64340_PCI_SCS_1_BASE_ADDR_LOW                            0x018
+#define MV64340_PCI_SCS_1_BASE_ADDR_HIGH                           0x01C
+#define MV64340_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_LOW                  0x020
+#define MV64340_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_HIGH                 0x024
+#define MV64340_PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID           0x02c
+#define MV64340_PCI_EXPANSION_ROM_BASE_ADDR_REG                            0x030
+#define MV64340_PCI_CAPABILTY_LIST_POINTER                          0x034
+#define MV64340_PCI_INTERRUPT_PIN_AND_LINE                         0x03C
+       /* capability list */
+#define MV64340_PCI_POWER_MANAGEMENT_CAPABILITY                     0x040
+#define MV64340_PCI_POWER_MANAGEMENT_STATUS_AND_CONTROL             0x044
+#define MV64340_PCI_VPD_ADDR                                        0x048
+#define MV64340_PCI_VPD_DATA                                        0x04c
+#define MV64340_PCI_MSI_MESSAGE_CONTROL                             0x050
+#define MV64340_PCI_MSI_MESSAGE_ADDR                                0x054
+#define MV64340_PCI_MSI_MESSAGE_UPPER_ADDR                          0x058
+#define MV64340_PCI_MSI_MESSAGE_DATA                                0x05c
+#define MV64340_PCI_X_COMMAND                                       0x060
+#define MV64340_PCI_X_STATUS                                        0x064
+#define MV64340_PCI_COMPACT_PCI_HOT_SWAP                            0x068
+
+/***********************************************/
+/*   PCI Configuration, Function 1, Registers  */
+/***********************************************/
+
+#define MV64340_PCI_SCS_2_BASE_ADDR_LOW                            0x110
+#define MV64340_PCI_SCS_2_BASE_ADDR_HIGH                           0x114
+#define MV64340_PCI_SCS_3_BASE_ADDR_LOW                            0x118
+#define MV64340_PCI_SCS_3_BASE_ADDR_HIGH                           0x11c
+#define MV64340_PCI_INTERNAL_SRAM_BASE_ADDR_LOW                    0x120
+#define MV64340_PCI_INTERNAL_SRAM_BASE_ADDR_HIGH                   0x124
+
+/***********************************************/
+/*  PCI Configuration, Function 2, Registers   */
+/***********************************************/
+
+#define MV64340_PCI_DEVCS_0_BASE_ADDR_LOW                          0x210
+#define MV64340_PCI_DEVCS_0_BASE_ADDR_HIGH                         0x214
+#define MV64340_PCI_DEVCS_1_BASE_ADDR_LOW                          0x218
+#define MV64340_PCI_DEVCS_1_BASE_ADDR_HIGH                         0x21c
+#define MV64340_PCI_DEVCS_2_BASE_ADDR_LOW                          0x220
+#define MV64340_PCI_DEVCS_2_BASE_ADDR_HIGH                         0x224
+
+/***********************************************/
+/*  PCI Configuration, Function 3, Registers   */
+/***********************************************/
+
+#define MV64340_PCI_DEVCS_3_BASE_ADDR_LOW                          0x310
+#define MV64340_PCI_DEVCS_3_BASE_ADDR_HIGH                         0x314
+#define MV64340_PCI_BOOT_CS_BASE_ADDR_LOW                          0x318
+#define MV64340_PCI_BOOT_CS_BASE_ADDR_HIGH                         0x31c
+#define MV64340_PCI_CPU_BASE_ADDR_LOW                              0x220
+#define MV64340_PCI_CPU_BASE_ADDR_HIGH                             0x224
+
+/***********************************************/
+/*  PCI Configuration, Function 4, Registers   */
+/***********************************************/
+
+#define MV64340_PCI_P2P_MEM0_BASE_ADDR_LOW                         0x410
+#define MV64340_PCI_P2P_MEM0_BASE_ADDR_HIGH                        0x414
+#define MV64340_PCI_P2P_MEM1_BASE_ADDR_LOW                         0x418
+#define MV64340_PCI_P2P_MEM1_BASE_ADDR_HIGH                        0x41c
+#define MV64340_PCI_P2P_I_O_BASE_ADDR                              0x420
+#define MV64340_PCI_INTERNAL_REGS_I_O_MAPPED_BASE_ADDR              0x424
+
+/****************************************/
+/* Messaging Unit Registers (I20)      */
+/****************************************/
+
+#define MV64340_I2O_INBOUND_MESSAGE_REG0_PCI_0_SIDE                0x010
+#define MV64340_I2O_INBOUND_MESSAGE_REG1_PCI_0_SIDE                0x014
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_PCI_0_SIDE               0x018
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_PCI_0_SIDE               0x01C
+#define MV64340_I2O_INBOUND_DOORBELL_REG_PCI_0_SIDE                0x020
+#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE          0x024
+#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE          0x028
+#define MV64340_I2O_OUTBOUND_DOORBELL_REG_PCI_0_SIDE               0x02C
+#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE         0x030
+#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE          0x034
+#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE       0x040
+#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE      0x044
+#define MV64340_I2O_QUEUE_CONTROL_REG_PCI_0_SIDE                   0x050
+#define MV64340_I2O_QUEUE_BASE_ADDR_REG_PCI_0_SIDE                 0x054
+#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE        0x060
+#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE        0x064
+#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE        0x068
+#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE        0x06C
+#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE       0x070
+#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE       0x074
+#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE       0x0F8
+#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE       0x0FC
+
+#define MV64340_I2O_INBOUND_MESSAGE_REG0_PCI_1_SIDE                0x090
+#define MV64340_I2O_INBOUND_MESSAGE_REG1_PCI_1_SIDE                0x094
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_PCI_1_SIDE               0x098
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_PCI_1_SIDE               0x09C
+#define MV64340_I2O_INBOUND_DOORBELL_REG_PCI_1_SIDE                0x0A0
+#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE          0x0A4
+#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE          0x0A8
+#define MV64340_I2O_OUTBOUND_DOORBELL_REG_PCI_1_SIDE               0x0AC
+#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE         0x0B0
+#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE          0x0B4
+#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE       0x0C0
+#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE      0x0C4
+#define MV64340_I2O_QUEUE_CONTROL_REG_PCI_1_SIDE                   0x0D0
+#define MV64340_I2O_QUEUE_BASE_ADDR_REG_PCI_1_SIDE                 0x0D4
+#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE        0x0E0
+#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE        0x0E4
+#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE        0x0E8
+#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE        0x0EC
+#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE       0x0F0
+#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE       0x0F4
+#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE       0x078
+#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE       0x07C
+
+#define MV64340_I2O_INBOUND_MESSAGE_REG0_CPU0_SIDE                 0x1C10
+#define MV64340_I2O_INBOUND_MESSAGE_REG1_CPU0_SIDE                 0x1C14
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_CPU0_SIDE                0x1C18
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_CPU0_SIDE                0x1C1C
+#define MV64340_I2O_INBOUND_DOORBELL_REG_CPU0_SIDE                 0x1C20
+#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE          0x1C24
+#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_CPU0_SIDE           0x1C28
+#define MV64340_I2O_OUTBOUND_DOORBELL_REG_CPU0_SIDE                0x1C2C
+#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE          0x1C30
+#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU0_SIDE           0x1C34
+#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE        0x1C40
+#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE       0x1C44
+#define MV64340_I2O_QUEUE_CONTROL_REG_CPU0_SIDE                    0x1C50
+#define MV64340_I2O_QUEUE_BASE_ADDR_REG_CPU0_SIDE                  0x1C54
+#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE         0x1C60
+#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE         0x1C64
+#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE         0x1C68
+#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE         0x1C6C
+#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE        0x1C70
+#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE        0x1C74
+#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE        0x1CF8
+#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE        0x1CFC
+#define MV64340_I2O_INBOUND_MESSAGE_REG0_CPU1_SIDE                 0x1C90
+#define MV64340_I2O_INBOUND_MESSAGE_REG1_CPU1_SIDE                 0x1C94
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_CPU1_SIDE                0x1C98
+#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_CPU1_SIDE                0x1C9C
+#define MV64340_I2O_INBOUND_DOORBELL_REG_CPU1_SIDE                 0x1CA0
+#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE          0x1CA4
+#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_CPU1_SIDE           0x1CA8
+#define MV64340_I2O_OUTBOUND_DOORBELL_REG_CPU1_SIDE                0x1CAC
+#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE          0x1CB0
+#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU1_SIDE           0x1CB4
+#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE        0x1CC0
+#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE       0x1CC4
+#define MV64340_I2O_QUEUE_CONTROL_REG_CPU1_SIDE                    0x1CD0
+#define MV64340_I2O_QUEUE_BASE_ADDR_REG_CPU1_SIDE                  0x1CD4
+#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE         0x1CE0
+#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE         0x1CE4
+#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE         0x1CE8
+#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE         0x1CEC
+#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE        0x1CF0
+#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE        0x1CF4
+#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE        0x1C78
+#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE        0x1C7C
+
+/****************************************/
+/*        Ethernet Unit Registers              */
+/****************************************/
+
+#define MV64340_ETH_PHY_ADDR_REG                                    0x2000
+#define MV64340_ETH_SMI_REG                                         0x2004
+#define MV64340_ETH_UNIT_DEFAULT_ADDR_REG                           0x2008
+#define MV64340_ETH_UNIT_DEFAULTID_REG                              0x200c
+#define MV64340_ETH_UNIT_INTERRUPT_CAUSE_REG                        0x2080
+#define MV64340_ETH_UNIT_INTERRUPT_MASK_REG                         0x2084
+#define MV64340_ETH_UNIT_INTERNAL_USE_REG                           0x24fc
+#define MV64340_ETH_UNIT_ERROR_ADDR_REG                             0x2094
+#define MV64340_ETH_BAR_0                                           0x2200
+#define MV64340_ETH_BAR_1                                           0x2208
+#define MV64340_ETH_BAR_2                                           0x2210
+#define MV64340_ETH_BAR_3                                           0x2218
+#define MV64340_ETH_BAR_4                                           0x2220
+#define MV64340_ETH_BAR_5                                           0x2228
+#define MV64340_ETH_SIZE_REG_0                                      0x2204
+#define MV64340_ETH_SIZE_REG_1                                      0x220c
+#define MV64340_ETH_SIZE_REG_2                                      0x2214
+#define MV64340_ETH_SIZE_REG_3                                      0x221c
+#define MV64340_ETH_SIZE_REG_4                                      0x2224
+#define MV64340_ETH_SIZE_REG_5                                      0x222c
+#define MV64340_ETH_HEADERS_RETARGET_BASE_REG                       0x2230
+#define MV64340_ETH_HEADERS_RETARGET_CONTROL_REG                    0x2234
+#define MV64340_ETH_HIGH_ADDR_REMAP_REG_0                           0x2280
+#define MV64340_ETH_HIGH_ADDR_REMAP_REG_1                           0x2284
+#define MV64340_ETH_HIGH_ADDR_REMAP_REG_2                           0x2288
+#define MV64340_ETH_HIGH_ADDR_REMAP_REG_3                           0x228c
+#define MV64340_ETH_BASE_ADDR_ENABLE_REG                            0x2290
+#define MV64340_ETH_ACCESS_PROTECTION_REG(port)                    (0x2294 + (port<<2))
+#define MV64340_ETH_MIB_COUNTERS_BASE(port)                        (0x3000 + (port<<7))
+#define MV64340_ETH_PORT_CONFIG_REG(port)                          (0x2400 + (port<<10))
+#define MV64340_ETH_PORT_CONFIG_EXTEND_REG(port)                   (0x2404 + (port<<10))
+#define MV64340_ETH_MII_SERIAL_PARAMETRS_REG(port)                 (0x2408 + (port<<10))
+#define MV64340_ETH_GMII_SERIAL_PARAMETRS_REG(port)                (0x240c + (port<<10))
+#define MV64340_ETH_VLAN_ETHERTYPE_REG(port)                       (0x2410 + (port<<10))
+#define MV64340_ETH_MAC_ADDR_LOW(port)                             (0x2414 + (port<<10))
+#define MV64340_ETH_MAC_ADDR_HIGH(port)                            (0x2418 + (port<<10))
+#define MV64340_ETH_SDMA_CONFIG_REG(port)                          (0x241c + (port<<10))
+#define MV64340_ETH_DSCP_0(port)                                   (0x2420 + (port<<10))
+#define MV64340_ETH_DSCP_1(port)                                   (0x2424 + (port<<10))
+#define MV64340_ETH_DSCP_2(port)                                   (0x2428 + (port<<10))
+#define MV64340_ETH_DSCP_3(port)                                   (0x242c + (port<<10))
+#define MV64340_ETH_DSCP_4(port)                                   (0x2430 + (port<<10))
+#define MV64340_ETH_DSCP_5(port)                                   (0x2434 + (port<<10))
+#define MV64340_ETH_DSCP_6(port)                                   (0x2438 + (port<<10))
+#define MV64340_ETH_PORT_SERIAL_CONTROL_REG(port)                  (0x243c + (port<<10))
+#define MV64340_ETH_VLAN_PRIORITY_TAG_TO_PRIORITY(port)            (0x2440 + (port<<10))
+#define MV64340_ETH_PORT_STATUS_REG(port)                          (0x2444 + (port<<10))
+#define MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port)               (0x2448 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_FIXED_PRIORITY(port)                  (0x244c + (port<<10))
+#define MV64340_ETH_PORT_TX_TOKEN_BUCKET_RATE_CONFIG(port)         (0x2450 + (port<<10))
+#define MV64340_ETH_MAXIMUM_TRANSMIT_UNIT(port)                    (0x2458 + (port<<10))
+#define MV64340_ETH_PORT_MAXIMUM_TOKEN_BUCKET_SIZE(port)           (0x245c + (port<<10))
+#define MV64340_ETH_INTERRUPT_CAUSE_REG(port)                      (0x2460 + (port<<10))
+#define MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port)               (0x2464 + (port<<10))
+#define MV64340_ETH_INTERRUPT_MASK_REG(port)                       (0x2468 + (port<<10))
+#define MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port)                (0x246c + (port<<10))
+#define MV64340_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port)             (0x2470 + (port<<10))
+#define MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port)             (0x2474 + (port<<10))
+#define MV64340_ETH_RX_MINIMAL_FRAME_SIZE_REG(port)                (0x247c + (port<<10))
+#define MV64340_ETH_RX_DISCARDED_FRAMES_COUNTER(port)              (0x2484 + (port<<10)
+#define MV64340_ETH_PORT_DEBUG_0_REG(port)                         (0x248c + (port<<10))
+#define MV64340_ETH_PORT_DEBUG_1_REG(port)                         (0x2490 + (port<<10))
+#define MV64340_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port)             (0x2494 + (port<<10))
+#define MV64340_ETH_INTERNAL_USE_REG(port)                         (0x24fc + (port<<10))
+#define MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port)                (0x2680 + (port<<10))
+#define MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(port)               (0x2684 + (port<<10))      
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port)              (0x260c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port)              (0x261c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port)              (0x262c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port)              (0x263c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port)              (0x264c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port)              (0x265c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port)              (0x266c + (port<<10))     
+#define MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port)              (0x267c + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port)              (0x26c0 + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_1(port)              (0x26c4 + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_2(port)              (0x26c8 + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_3(port)              (0x26cc + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_4(port)              (0x26d0 + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_5(port)              (0x26d4 + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_6(port)              (0x26d8 + (port<<10))     
+#define MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_7(port)              (0x26dc + (port<<10))     
+#define MV64340_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT(port)            (0x2700 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_1_TOKEN_BUCKET_COUNT(port)            (0x2710 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_2_TOKEN_BUCKET_COUNT(port)            (0x2720 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_3_TOKEN_BUCKET_COUNT(port)            (0x2730 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_4_TOKEN_BUCKET_COUNT(port)            (0x2740 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_5_TOKEN_BUCKET_COUNT(port)            (0x2750 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_6_TOKEN_BUCKET_COUNT(port)            (0x2760 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_7_TOKEN_BUCKET_COUNT(port)            (0x2770 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG(port)           (0x2704 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_1_TOKEN_BUCKET_CONFIG(port)           (0x2714 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_2_TOKEN_BUCKET_CONFIG(port)           (0x2724 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_3_TOKEN_BUCKET_CONFIG(port)           (0x2734 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_4_TOKEN_BUCKET_CONFIG(port)           (0x2744 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_5_TOKEN_BUCKET_CONFIG(port)           (0x2754 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_6_TOKEN_BUCKET_CONFIG(port)           (0x2764 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_7_TOKEN_BUCKET_CONFIG(port)           (0x2774 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_0_ARBITER_CONFIG(port)                (0x2708 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_1_ARBITER_CONFIG(port)                (0x2718 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_2_ARBITER_CONFIG(port)                (0x2728 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_3_ARBITER_CONFIG(port)                (0x2738 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_4_ARBITER_CONFIG(port)                (0x2748 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_5_ARBITER_CONFIG(port)                (0x2758 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_6_ARBITER_CONFIG(port)                (0x2768 + (port<<10))
+#define MV64340_ETH_TX_QUEUE_7_ARBITER_CONFIG(port)                (0x2778 + (port<<10))
+#define MV64340_ETH_PORT_TX_TOKEN_BUCKET_COUNT(port)               (0x2780 + (port<<10))
+#define MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port)   (0x3400 + (port<<10))
+#define MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port)     (0x3500 + (port<<10))
+#define MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE(port)             (0x3600 + (port<<10))
+
+/*******************************************/
+/*          CUNIT  Registers               */
+/*******************************************/
+
+         /* Address Decoding Register Map */
+           
+#define MV64340_CUNIT_BASE_ADDR_REG0                                0xf200
+#define MV64340_CUNIT_BASE_ADDR_REG1                                0xf208
+#define MV64340_CUNIT_BASE_ADDR_REG2                                0xf210
+#define MV64340_CUNIT_BASE_ADDR_REG3                                0xf218
+#define MV64340_CUNIT_SIZE0                                         0xf204
+#define MV64340_CUNIT_SIZE1                                         0xf20c
+#define MV64340_CUNIT_SIZE2                                         0xf214
+#define MV64340_CUNIT_SIZE3                                         0xf21c
+#define MV64340_CUNIT_HIGH_ADDR_REMAP_REG0                          0xf240
+#define MV64340_CUNIT_HIGH_ADDR_REMAP_REG1                          0xf244
+#define MV64340_CUNIT_BASE_ADDR_ENABLE_REG                          0xf250
+#define MV64340_MPSC0_ACCESS_PROTECTION_REG                         0xf254
+#define MV64340_MPSC1_ACCESS_PROTECTION_REG                         0xf258
+#define MV64340_CUNIT_INTERNAL_SPACE_BASE_ADDR_REG                  0xf25C
+
+        /*  Error Report Registers  */
+
+#define MV64340_CUNIT_INTERRUPT_CAUSE_REG                           0xf310
+#define MV64340_CUNIT_INTERRUPT_MASK_REG                            0xf314
+#define MV64340_CUNIT_ERROR_ADDR                                    0xf318
+
+        /*  Cunit Control Registers */
+
+#define MV64340_CUNIT_ARBITER_CONTROL_REG                           0xf300
+#define MV64340_CUNIT_CONFIG_REG                                    0xb40c
+#define MV64340_CUNIT_CRROSBAR_TIMEOUT_REG                          0xf304
+
+        /*  Cunit Debug Registers   */
+
+#define MV64340_CUNIT_DEBUG_LOW                                     0xf340
+#define MV64340_CUNIT_DEBUG_HIGH                                    0xf344
+#define MV64340_CUNIT_MMASK                                         0xf380
+
+        /*  MPSCs Clocks Routing Registers  */
+
+#define MV64340_MPSC_ROUTING_REG                                    0xb400
+#define MV64340_MPSC_RX_CLOCK_ROUTING_REG                           0xb404
+#define MV64340_MPSC_TX_CLOCK_ROUTING_REG                           0xb408
+
+        /*  MPSCs Interrupts Registers    */
+
+#define MV64340_MPSC_CAUSE_REG(port)                               (0xb804 + (port<<3))
+#define MV64340_MPSC_MASK_REG(port)                                (0xb884 + (port<<3))
+#define MV64340_MPSC_MAIN_CONFIG_LOW(port)                         (0x8000 + (port<<12))
+#define MV64340_MPSC_MAIN_CONFIG_HIGH(port)                        (0x8004 + (port<<12))    
+#define MV64340_MPSC_PROTOCOL_CONFIG(port)                         (0x8008 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG1(port)                            (0x800c + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG2(port)                            (0x8010 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG3(port)                            (0x8014 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG4(port)                            (0x8018 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG5(port)                            (0x801c + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG6(port)                            (0x8020 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG7(port)                            (0x8024 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG8(port)                            (0x8028 + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG9(port)                            (0x802c + (port<<12))    
+#define MV64340_MPSC_CHANNEL_REG10(port)                           (0x8030 + (port<<12))    
+        
+        /*  MPSC0 Registers      */
+
+
+/***************************************/
+/*          SDMA Registers             */
+/***************************************/
+
+#define MV64340_SDMA_CONFIG_REG(channel)                        (0x4000 + (channel<<13))        
+#define MV64340_SDMA_COMMAND_REG(channel)                       (0x4008 + (channel<<13))        
+#define MV64340_SDMA_CURRENT_RX_DESCRIPTOR_POINTER(channel)     (0x4810 + (channel<<13))        
+#define MV64340_SDMA_CURRENT_TX_DESCRIPTOR_POINTER(channel)     (0x4c10 + (channel<<13))        
+#define MV64340_SDMA_FIRST_TX_DESCRIPTOR_POINTER(channel)       (0x4c14 + (channel<<13)) 
+
+#define MV64340_SDMA_CAUSE_REG                                      0xb800
+#define MV64340_SDMA_MASK_REG                                       0xb880
+         
+/* BRG Interrupts */
+
+#define MV64340_BRG_CONFIG_REG(brg)                              (0xb200 + (brg<<3))
+#define MV64340_BRG_BAUDE_TUNING_REG(brg)                        (0xb208 + (brg<<3))
+#define MV64340_BRG_CAUSE_REG                                       0xb834
+#define MV64340_BRG_MASK_REG                                        0xb8b4
+
+/****************************************/
+/* DMA Channel Control                 */
+/****************************************/
+
+#define MV64340_DMA_CHANNEL0_CONTROL                               0x840
+#define MV64340_DMA_CHANNEL0_CONTROL_HIGH                          0x880
+#define MV64340_DMA_CHANNEL1_CONTROL                               0x844
+#define MV64340_DMA_CHANNEL1_CONTROL_HIGH                          0x884
+#define MV64340_DMA_CHANNEL2_CONTROL                               0x848
+#define MV64340_DMA_CHANNEL2_CONTROL_HIGH                          0x888
+#define MV64340_DMA_CHANNEL3_CONTROL                               0x84C
+#define MV64340_DMA_CHANNEL3_CONTROL_HIGH                          0x88C
+
+
+/****************************************/
+/*           IDMA Registers             */
+/****************************************/
+
+#define MV64340_DMA_CHANNEL0_BYTE_COUNT                             0x800
+#define MV64340_DMA_CHANNEL1_BYTE_COUNT                             0x804
+#define MV64340_DMA_CHANNEL2_BYTE_COUNT                             0x808
+#define MV64340_DMA_CHANNEL3_BYTE_COUNT                             0x80C
+#define MV64340_DMA_CHANNEL0_SOURCE_ADDR                            0x810
+#define MV64340_DMA_CHANNEL1_SOURCE_ADDR                            0x814
+#define MV64340_DMA_CHANNEL2_SOURCE_ADDR                            0x818
+#define MV64340_DMA_CHANNEL3_SOURCE_ADDR                            0x81c
+#define MV64340_DMA_CHANNEL0_DESTINATION_ADDR                       0x820
+#define MV64340_DMA_CHANNEL1_DESTINATION_ADDR                       0x824
+#define MV64340_DMA_CHANNEL2_DESTINATION_ADDR                       0x828
+#define MV64340_DMA_CHANNEL3_DESTINATION_ADDR                       0x82C
+#define MV64340_DMA_CHANNEL0_NEXT_DESCRIPTOR_POINTER                0x830
+#define MV64340_DMA_CHANNEL1_NEXT_DESCRIPTOR_POINTER                0x834
+#define MV64340_DMA_CHANNEL2_NEXT_DESCRIPTOR_POINTER                0x838
+#define MV64340_DMA_CHANNEL3_NEXT_DESCRIPTOR_POINTER                0x83C
+#define MV64340_DMA_CHANNEL0_CURRENT_DESCRIPTOR_POINTER             0x870
+#define MV64340_DMA_CHANNEL1_CURRENT_DESCRIPTOR_POINTER             0x874
+#define MV64340_DMA_CHANNEL2_CURRENT_DESCRIPTOR_POINTER             0x878
+#define MV64340_DMA_CHANNEL3_CURRENT_DESCRIPTOR_POINTER             0x87C
+
+ /*  IDMA Address Decoding Base Address Registers  */
+#define MV64340_DMA_BASE_ADDR_REG0                                  0xa00
+#define MV64340_DMA_BASE_ADDR_REG1                                  0xa08
+#define MV64340_DMA_BASE_ADDR_REG2                                  0xa10
+#define MV64340_DMA_BASE_ADDR_REG3                                  0xa18
+#define MV64340_DMA_BASE_ADDR_REG4                                  0xa20
+#define MV64340_DMA_BASE_ADDR_REG5                                  0xa28
+#define MV64340_DMA_BASE_ADDR_REG6                                  0xa30
+#define MV64340_DMA_BASE_ADDR_REG7                                  0xa38
+ /*  IDMA Address Decoding Size Address Register   */
+#define MV64340_DMA_SIZE_REG0                                       0xa04
+#define MV64340_DMA_SIZE_REG1                                       0xa0c
+#define MV64340_DMA_SIZE_REG2                                       0xa14
+#define MV64340_DMA_SIZE_REG3                                       0xa1c
+#define MV64340_DMA_SIZE_REG4                                       0xa24
+#define MV64340_DMA_SIZE_REG5                                       0xa2c
+#define MV64340_DMA_SIZE_REG6                                       0xa34
+#define MV64340_DMA_SIZE_REG7                                       0xa3C
+
+ /* IDMA Address Decoding High Address Remap and Access 
+                  Protection Registers                    */
+                  
+#define MV64340_DMA_HIGH_ADDR_REMAP_REG0                            0xa60
+#define MV64340_DMA_HIGH_ADDR_REMAP_REG1                            0xa64
+#define MV64340_DMA_HIGH_ADDR_REMAP_REG2                            0xa68
+#define MV64340_DMA_HIGH_ADDR_REMAP_REG3                            0xa6C
+#define MV64340_DMA_BASE_ADDR_ENABLE_REG                            0xa80
+#define MV64340_DMA_CHANNEL0_ACCESS_PROTECTION_REG                  0xa70
+#define MV64340_DMA_CHANNEL1_ACCESS_PROTECTION_REG                  0xa74
+#define MV64340_DMA_CHANNEL2_ACCESS_PROTECTION_REG                  0xa78
+#define MV64340_DMA_CHANNEL3_ACCESS_PROTECTION_REG                  0xa7c
+#define MV64340_DMA_ARBITER_CONTROL                                 0x860
+#define MV64340_DMA_CROSS_BAR_TIMEOUT                               0x8d0
+
+ /*  IDMA Headers Retarget Registers   */
+
+#define MV64340_DMA_HEADERS_RETARGET_CONTROL                        0xa84
+#define MV64340_DMA_HEADERS_RETARGET_BASE                           0xa88
+
+ /*  IDMA Interrupt Register  */
+
+#define MV64340_DMA_INTERRUPT_CAUSE_REG                             0x8c0
+#define MV64340_DMA_INTERRUPT_CAUSE_MASK                            0x8c4
+#define MV64340_DMA_ERROR_ADDR                                      0x8c8
+#define MV64340_DMA_ERROR_SELECT                                    0x8cc
+
+ /*  IDMA Debug Register ( for internal use )    */
+
+#define MV64340_DMA_DEBUG_LOW                                       0x8e0
+#define MV64340_DMA_DEBUG_HIGH                                      0x8e4
+#define MV64340_DMA_SPARE                                           0xA8C
+
+/****************************************/
+/* Timer_Counter                       */
+/****************************************/
+
+#define MV64340_TIMER_COUNTER0                                     0x850
+#define MV64340_TIMER_COUNTER1                                     0x854
+#define MV64340_TIMER_COUNTER2                                     0x858
+#define MV64340_TIMER_COUNTER3                                     0x85C
+#define MV64340_TIMER_COUNTER_0_3_CONTROL                          0x864
+#define MV64340_TIMER_COUNTER_0_3_INTERRUPT_CAUSE                  0x868
+#define MV64340_TIMER_COUNTER_0_3_INTERRUPT_MASK                   0x86c
+
+/****************************************/
+/*         Watchdog registers                  */
+/****************************************/
+
+#define MV64340_WATCHDOG_CONFIG_REG                                 0xb410
+#define MV64340_WATCHDOG_VALUE_REG                                  0xb414
+
+/****************************************/
+/* I2C Registers                        */
+/****************************************/
+
+#define MV64340_I2C_SLAVE_ADDR                                      0xc000
+#define MV64340_I2C_EXTENDED_SLAVE_ADDR                             0xc010
+#define MV64340_I2C_DATA                                            0xc004
+#define MV64340_I2C_CONTROL                                         0xc008
+#define MV64340_I2C_STATUS_BAUDE_RATE                               0xc00C
+#define MV64340_I2C_SOFT_RESET                                      0xc01c
+
+/****************************************/
+/* GPP Interface Registers              */
+/****************************************/
+
+#define MV64340_GPP_IO_CONTROL                                      0xf100
+#define MV64340_GPP_LEVEL_CONTROL                                   0xf110
+#define MV64340_GPP_VALUE                                           0xf104
+#define MV64340_GPP_INTERRUPT_CAUSE                                 0xf108
+#define MV64340_GPP_INTERRUPT_MASK0                                 0xf10c
+#define MV64340_GPP_INTERRUPT_MASK1                                 0xf114
+#define MV64340_GPP_VALUE_SET                                       0xf118
+#define MV64340_GPP_VALUE_CLEAR                                     0xf11c
+
+/****************************************/
+/* Interrupt Controller Registers       */
+/****************************************/
+
+/****************************************/
+/* Interrupts                          */
+/****************************************/
+
+#define MV64340_MAIN_INTERRUPT_CAUSE_LOW                            0x004
+#define MV64340_MAIN_INTERRUPT_CAUSE_HIGH                           0x00c
+#define MV64340_CPU_INTERRUPT0_MASK_LOW                             0x014
+#define MV64340_CPU_INTERRUPT0_MASK_HIGH                            0x01c
+#define MV64340_CPU_INTERRUPT0_SELECT_CAUSE                         0x024
+#define MV64340_CPU_INTERRUPT1_MASK_LOW                             0x034
+#define MV64340_CPU_INTERRUPT1_MASK_HIGH                            0x03c
+#define MV64340_CPU_INTERRUPT1_SELECT_CAUSE                         0x044
+#define MV64340_INTERRUPT0_MASK_0_LOW                               0x054
+#define MV64340_INTERRUPT0_MASK_0_HIGH                              0x05c
+#define MV64340_INTERRUPT0_SELECT_CAUSE                             0x064
+#define MV64340_INTERRUPT1_MASK_0_LOW                               0x074
+#define MV64340_INTERRUPT1_MASK_0_HIGH                              0x07c
+#define MV64340_INTERRUPT1_SELECT_CAUSE                             0x084
+
+/****************************************/
+/*      MPP Interface Registers         */
+/****************************************/
+
+#define MV64340_MPP_CONTROL0                                        0xf000
+#define MV64340_MPP_CONTROL1                                        0xf004
+#define MV64340_MPP_CONTROL2                                        0xf008
+#define MV64340_MPP_CONTROL3                                        0xf00c
+
+/****************************************/
+/*    Serial Initialization registers   */
+/****************************************/
+
+#define MV64340_SERIAL_INIT_LAST_DATA                               0xf324
+#define MV64340_SERIAL_INIT_CONTROL                                 0xf328
+#define MV64340_SERIAL_INIT_STATUS                                  0xf32c
+
+extern void mv64340_irq_init(unsigned int base);
+
+#endif /* __ASM_MV64340_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
new file mode 100644 (file)
index 0000000..7a8d869
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _IP_CONNTRACK_SCTP_H
+#define _IP_CONNTRACK_SCTP_H
+/* SCTP tracking. */
+
+enum sctp_conntrack {
+       SCTP_CONNTRACK_NONE,
+       SCTP_CONNTRACK_CLOSED,
+       SCTP_CONNTRACK_COOKIE_WAIT,
+       SCTP_CONNTRACK_COOKIE_ECHOED,
+       SCTP_CONNTRACK_ESTABLISHED,
+       SCTP_CONNTRACK_SHUTDOWN_SENT,
+       SCTP_CONNTRACK_SHUTDOWN_RECD,
+       SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
+       SCTP_CONNTRACK_MAX
+};
+
+struct ip_ct_sctp
+{
+       enum sctp_conntrack state;
+
+       u_int32_t vtag[IP_CT_DIR_MAX];
+       u_int32_t ttag[IP_CT_DIR_MAX];
+};
+
+#endif /* _IP_CONNTRACK_SCTP_H */
diff --git a/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h b/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h
new file mode 100644 (file)
index 0000000..baa83e7
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _IPT_CLUSTERIP_H_target
+#define _IPT_CLUSTERIP_H_target
+
+enum clusterip_hashmode {
+    CLUSTERIP_HASHMODE_SIP = 0,
+    CLUSTERIP_HASHMODE_SIP_SPT,
+    CLUSTERIP_HASHMODE_SIP_SPT_DPT,
+};
+
+#define CLUSTERIP_HASHMODE_MAX CLUSTERIP_HASHMODE_SIP_SPT_DPT
+
+#define CLUSTERIP_MAX_NODES 16
+
+#define CLUSTERIP_FLAG_NEW 0x00000001
+
+struct clusterip_config;
+
+struct ipt_clusterip_tgt_info {
+
+       u_int32_t flags;
+       struct clusterip_config *config;
+       
+       /* only relevant for new ones */
+       u_int8_t clustermac[6];
+       u_int16_t num_total_nodes;
+       u_int16_t num_local_nodes;
+       u_int16_t local_nodes[CLUSTERIP_MAX_NODES];
+       enum clusterip_hashmode hash_mode;
+       u_int32_t hash_initval;
+};
+
+#endif /*_IPT_CLUSTERIP_H_target*/
diff --git a/include/linux/netfilter_ipv4/ipt_CONNMARK.h b/include/linux/netfilter_ipv4/ipt_CONNMARK.h
new file mode 100644 (file)
index 0000000..d3c0253
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _IPT_CONNMARK_H_target
+#define _IPT_CONNMARK_H_target
+
+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.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.
+ */
+
+enum {
+       IPT_CONNMARK_SET = 0,
+       IPT_CONNMARK_SAVE,
+       IPT_CONNMARK_RESTORE
+};
+
+struct ipt_connmark_target_info {
+       unsigned long mark;
+       unsigned long mask;
+       u_int8_t mode;
+};
+
+#endif /*_IPT_CONNMARK_H_target*/
diff --git a/include/linux/netfilter_ipv4/ipt_comment.h b/include/linux/netfilter_ipv4/ipt_comment.h
new file mode 100644 (file)
index 0000000..85c1123
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _IPT_COMMENT_H
+#define _IPT_COMMENT_H
+
+#define IPT_MAX_COMMENT_LEN 256
+
+struct ipt_comment_info {
+       unsigned char comment[IPT_MAX_COMMENT_LEN];
+};
+
+#endif /* _IPT_COMMENT_H */
diff --git a/include/linux/netfilter_ipv4/ipt_connmark.h b/include/linux/netfilter_ipv4/ipt_connmark.h
new file mode 100644 (file)
index 0000000..4657327
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _IPT_CONNMARK_H
+#define _IPT_CONNMARK_H
+
+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.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.
+ */
+
+struct ipt_connmark_info {
+       unsigned long mark, mask;
+       u_int8_t invert;
+};
+
+#endif /*_IPT_CONNMARK_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_hashlimit.h b/include/linux/netfilter_ipv4/ipt_hashlimit.h
new file mode 100644 (file)
index 0000000..ac2cb64
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _IPT_HASHLIMIT_H
+#define _IPT_HASHLIMIT_H
+
+/* timings are in milliseconds. */
+#define IPT_HASHLIMIT_SCALE 10000
+/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
+   seconds, or one every 59 hours. */
+
+/* details of this structure hidden by the implementation */
+struct ipt_hashlimit_htable;
+
+#define IPT_HASHLIMIT_HASH_DIP 0x0001
+#define IPT_HASHLIMIT_HASH_DPT 0x0002
+#define IPT_HASHLIMIT_HASH_SIP 0x0004
+#define IPT_HASHLIMIT_HASH_SPT 0x0008
+
+struct hashlimit_cfg {
+       u_int32_t mode;   /* bitmask of IPT_HASHLIMIT_HASH_* */
+       u_int32_t avg;    /* Average secs between packets * scale */
+       u_int32_t burst;  /* Period multiplier for upper limit. */
+
+       /* user specified */
+       u_int32_t size;         /* how many buckets */
+       u_int32_t max;          /* max number of entries */
+       u_int32_t gc_interval;  /* gc interval */
+       u_int32_t expire;       /* when do entries expire? */
+};
+
+struct ipt_hashlimit_info {
+       char name [IFNAMSIZ];           /* name */
+       struct hashlimit_cfg cfg;
+       struct ipt_hashlimit_htable *hinfo;
+
+       /* Used internally by the kernel */
+       union {
+               void *ptr;
+               struct ipt_hashlimit_info *master;
+       } u;
+};
+#endif /*_IPT_HASHLIMIT_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_sctp.h b/include/linux/netfilter_ipv4/ipt_sctp.h
new file mode 100644 (file)
index 0000000..e93a9ec
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef _IPT_SCTP_H_
+#define _IPT_SCTP_H_
+
+#define IPT_SCTP_SRC_PORTS             0x01
+#define IPT_SCTP_DEST_PORTS            0x02
+#define IPT_SCTP_CHUNK_TYPES           0x04
+
+#define IPT_SCTP_VALID_FLAGS           0x07
+
+#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
+
+
+struct ipt_sctp_flag_info {
+       u_int8_t chunktype;
+       u_int8_t flag;
+       u_int8_t flag_mask;
+};
+
+#define IPT_NUM_SCTP_FLAGS     4
+
+struct ipt_sctp_info {
+       u_int16_t dpts[2];  /* Min, Max */
+       u_int16_t spts[2];  /* Min, Max */
+
+       u_int32_t chunkmap[256 / sizeof (u_int32_t)];  /* Bit mask of chunks to be matched according to RFC 2960 */
+
+#define SCTP_CHUNK_MATCH_ANY   0x01  /* Match if any of the chunk types are present */
+#define SCTP_CHUNK_MATCH_ALL   0x02  /* Match if all of the chunk types are present */
+#define SCTP_CHUNK_MATCH_ONLY  0x04  /* Match if these are the only chunk types present */
+
+       u_int32_t chunk_match_type;
+       struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
+       int flag_count;
+
+       u_int32_t flags;
+       u_int32_t invflags;
+};
+
+#define bytes(type) (sizeof(type) * 8)
+
+#define SCTP_CHUNKMAP_SET(chunkmap, type)              \
+       do {                                            \
+               chunkmap[type / bytes(u_int32_t)] |=    \
+                       1 << (type % bytes(u_int32_t)); \
+       } while (0)
+
+#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)                    \
+       do {                                                    \
+               chunkmap[type / bytes(u_int32_t)] &=            \
+                       ~(1 << (type % bytes(u_int32_t)));      \
+       } while (0)
+
+#define SCTP_CHUNKMAP_IS_SET(chunkmap, type)                   \
+({                                                             \
+       (chunkmap[type / bytes (u_int32_t)] &                   \
+               (1 << (type % bytes (u_int32_t)))) ? 1: 0;      \
+})
+
+#define SCTP_CHUNKMAP_RESET(chunkmap)                          \
+       do {                                                    \
+               int i;                                          \
+               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
+                       chunkmap[i] = 0;                        \
+       } while (0)
+
+#define SCTP_CHUNKMAP_SET_ALL(chunkmap)                        \
+       do {                                                    \
+               int i;                                          \
+               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
+                       chunkmap[i] = ~0;                       \
+       } while (0)
+
+#define SCTP_CHUNKMAP_COPY(destmap, srcmap)                    \
+       do {                                                    \
+               int i;                                          \
+               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
+                       destmap[i] = srcmap[i];                 \
+       } while (0)
+
+#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap)               \
+({                                                     \
+       int i;                                          \
+       int flag = 1;                                   \
+       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
+               if (chunkmap[i]) {                      \
+                       flag = 0;                       \
+                       break;                          \
+               }                                       \
+       }                                               \
+        flag;                                          \
+})
+
+#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)             \
+({                                                     \
+       int i;                                          \
+       int flag = 1;                                   \
+       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
+               if (chunkmap[i] != ~0) {                \
+                       flag = 0;                       \
+                               break;                  \
+               }                                       \
+       }                                               \
+        flag;                                          \
+})
+
+#endif /* _IPT_SCTP_H_ */
+
diff --git a/include/linux/netfilter_ipv6/ip6t_physdev.h b/include/linux/netfilter_ipv6/ip6t_physdev.h
new file mode 100644 (file)
index 0000000..c234731
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _IP6T_PHYSDEV_H
+#define _IP6T_PHYSDEV_H
+
+#ifdef __KERNEL__
+#include <linux/if.h>
+#endif
+
+#define IP6T_PHYSDEV_OP_IN             0x01
+#define IP6T_PHYSDEV_OP_OUT            0x02
+#define IP6T_PHYSDEV_OP_BRIDGED                0x04
+#define IP6T_PHYSDEV_OP_ISIN           0x08
+#define IP6T_PHYSDEV_OP_ISOUT          0x10
+#define IP6T_PHYSDEV_OP_MASK           (0x20 - 1)
+
+struct ip6t_physdev_info {
+       char physindev[IFNAMSIZ];
+       char in_mask[IFNAMSIZ];
+       char physoutdev[IFNAMSIZ];
+       char out_mask[IFNAMSIZ];
+       u_int8_t invert;
+       u_int8_t bitmask;
+};
+
+#endif /*_IP6T_PHYSDEV_H*/
diff --git a/include/linux/nfs4_acl.h b/include/linux/nfs4_acl.h
new file mode 100644 (file)
index 0000000..22aff4d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  include/linux/nfs4_acl.c
+ *
+ *  Common NFSv4 ACL handling definitions.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@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.
+ */
+
+#ifndef LINUX_NFS4_ACL_H
+#define LINUX_NFS4_ACL_H
+
+#include <linux/posix_acl.h>
+
+struct nfs4_acl *nfs4_acl_new(void);
+void nfs4_acl_free(struct nfs4_acl *);
+int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
+int nfs4_acl_get_whotype(char *, u32);
+int nfs4_acl_write_who(int who, char *p);
+int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
+                                       uid_t who, u32 mask);
+
+#define NFS4_ACL_TYPE_DEFAULT  0x01
+#define NFS4_ACL_DIR           0x02
+#define NFS4_ACL_OWNER         0x04
+
+struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *,
+                               struct posix_acl *, unsigned int flags);
+int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **,
+                               struct posix_acl **, unsigned int flags);
+
+#endif /* LINUX_NFS4_ACL_H */
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
new file mode 100644 (file)
index 0000000..4de843d
--- /dev/null
@@ -0,0 +1,326 @@
+#ifndef __LINUX_NODEMASK_H
+#define __LINUX_NODEMASK_H
+
+/*
+ * Nodemasks provide a bitmap suitable for representing the
+ * set of Node's in a system, one bit position per Node number.
+ *
+ * See detailed comments in the file linux/bitmap.h describing the
+ * data type on which these nodemasks are based.
+ *
+ * For details of nodemask_scnprintf() and nodemask_parse(),
+ * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ *
+ * The available nodemask operations are:
+ *
+ * void node_set(node, mask)           turn on bit 'node' in mask
+ * void node_clear(node, mask)         turn off bit 'node' in mask
+ * void nodes_setall(mask)             set all bits
+ * void nodes_clear(mask)              clear all bits
+ * int node_isset(node, mask)          true iff bit 'node' set in mask
+ * int node_test_and_set(node, mask)   test and set bit 'node' in mask
+ *
+ * void nodes_and(dst, src1, src2)     dst = src1 & src2  [intersection]
+ * void nodes_or(dst, src1, src2)      dst = src1 | src2  [union]
+ * void nodes_xor(dst, src1, src2)     dst = src1 ^ src2
+ * void nodes_andnot(dst, src1, src2)  dst = src1 & ~src2
+ * void nodes_complement(dst, src)     dst = ~src
+ *
+ * int nodes_equal(mask1, mask2)       Does mask1 == mask2?
+ * int nodes_intersects(mask1, mask2)  Do mask1 and mask2 intersect?
+ * int nodes_subset(mask1, mask2)      Is mask1 a subset of mask2?
+ * int nodes_empty(mask)               Is mask empty (no bits sets)?
+ * int nodes_full(mask)                        Is mask full (all bits sets)?
+ * int nodes_weight(mask)              Hamming weight - number of set bits
+ *
+ * void nodes_shift_right(dst, src, n) Shift right
+ * void nodes_shift_left(dst, src, n)  Shift left
+ *
+ * int first_node(mask)                        Number lowest set bit, or MAX_NUMNODES
+ * int next_node(node, mask)           Next node past 'node', or MAX_NUMNODES
+ *
+ * nodemask_t nodemask_of_node(node)   Return nodemask with bit 'node' set
+ * NODE_MASK_ALL                       Initializer - all bits set
+ * NODE_MASK_NONE                      Initializer - no bits set
+ * unsigned long *nodes_addr(mask)     Array of unsigned long's in mask
+ *
+ * int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
+ * int nodemask_parse(ubuf, ulen, mask)        Parse ascii string as nodemask
+ *
+ * for_each_node_mask(node, mask)      for-loop node over mask
+ *
+ * int num_online_nodes()              Number of online Nodes
+ * int num_possible_nodes()            Number of all possible Nodes
+ *
+ * int node_online(node)               Is some node online?
+ * int node_possible(node)             Is some node possible?
+ *
+ * int any_online_node(mask)           First online node in mask
+ *
+ * node_set_online(node)               set bit 'node' in node_online_map
+ * node_set_offline(node)              clear bit 'node' in node_online_map
+ *
+ * for_each_node(node)                 for-loop node over node_possible_map
+ * for_each_online_node(node)          for-loop node over node_online_map
+ *
+ * Subtlety:
+ * 1) The 'type-checked' form of node_isset() causes gcc (3.3.2, anyway)
+ *    to generate slightly worse code.  So use a simple one-line #define
+ *    for node_isset(), instead of wrapping an inline inside a macro, the
+ *    way we do the other calls.
+ */
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/bitmap.h>
+#include <linux/numa.h>
+#include <asm/bug.h>
+
+typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
+extern nodemask_t _unused_nodemask_arg_;
+
+#define node_set(node, dst) __node_set((node), &(dst))
+static inline void __node_set(int node, volatile nodemask_t *dstp)
+{
+       set_bit(node, dstp->bits);
+}
+
+#define node_clear(node, dst) __node_clear((node), &(dst))
+static inline void __node_clear(int node, volatile nodemask_t *dstp)
+{
+       clear_bit(node, dstp->bits);
+}
+
+#define nodes_setall(dst) __nodes_setall(&(dst), MAX_NUMNODES)
+static inline void __nodes_setall(nodemask_t *dstp, int nbits)
+{
+       bitmap_fill(dstp->bits, nbits);
+}
+
+#define nodes_clear(dst) __nodes_clear(&(dst), MAX_NUMNODES)
+static inline void __nodes_clear(nodemask_t *dstp, int nbits)
+{
+       bitmap_zero(dstp->bits, nbits);
+}
+
+/* No static inline type checking - see Subtlety (1) above. */
+#define node_isset(node, nodemask) test_bit((node), (nodemask).bits)
+
+#define node_test_and_set(node, nodemask) \
+                       __node_test_and_set((node), &(nodemask))
+static inline int __node_test_and_set(int node, nodemask_t *addr)
+{
+       return test_and_set_bit(node, addr->bits);
+}
+
+#define nodes_and(dst, src1, src2) \
+                       __nodes_and(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_and(nodemask_t *dstp, const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_or(dst, src1, src2) \
+                       __nodes_or(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_or(nodemask_t *dstp, const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_xor(dst, src1, src2) \
+                       __nodes_xor(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_xor(nodemask_t *dstp, const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_andnot(dst, src1, src2) \
+                       __nodes_andnot(&(dst), &(src1), &(src2), MAX_NUMNODES)
+static inline void __nodes_andnot(nodemask_t *dstp, const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_complement(dst, src) \
+                       __nodes_complement(&(dst), &(src), MAX_NUMNODES)
+static inline void __nodes_complement(nodemask_t *dstp,
+                                       const nodemask_t *srcp, int nbits)
+{
+       bitmap_complement(dstp->bits, srcp->bits, nbits);
+}
+
+#define nodes_equal(src1, src2) \
+                       __nodes_equal(&(src1), &(src2), MAX_NUMNODES)
+static inline int __nodes_equal(const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       return bitmap_equal(src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_intersects(src1, src2) \
+                       __nodes_intersects(&(src1), &(src2), MAX_NUMNODES)
+static inline int __nodes_intersects(const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       return bitmap_intersects(src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_subset(src1, src2) \
+                       __nodes_subset(&(src1), &(src2), MAX_NUMNODES)
+static inline int __nodes_subset(const nodemask_t *src1p,
+                                       const nodemask_t *src2p, int nbits)
+{
+       return bitmap_subset(src1p->bits, src2p->bits, nbits);
+}
+
+#define nodes_empty(src) __nodes_empty(&(src), MAX_NUMNODES)
+static inline int __nodes_empty(const nodemask_t *srcp, int nbits)
+{
+       return bitmap_empty(srcp->bits, nbits);
+}
+
+#define nodes_full(nodemask) __nodes_full(&(nodemask), MAX_NUMNODES)
+static inline int __nodes_full(const nodemask_t *srcp, int nbits)
+{
+       return bitmap_full(srcp->bits, nbits);
+}
+
+#define nodes_weight(nodemask) __nodes_weight(&(nodemask), MAX_NUMNODES)
+static inline int __nodes_weight(const nodemask_t *srcp, int nbits)
+{
+       return bitmap_weight(srcp->bits, nbits);
+}
+
+#define nodes_shift_right(dst, src, n) \
+                       __nodes_shift_right(&(dst), &(src), (n), MAX_NUMNODES)
+static inline void __nodes_shift_right(nodemask_t *dstp,
+                                       const nodemask_t *srcp, int n, int nbits)
+{
+       bitmap_shift_right(dstp->bits, srcp->bits, n, nbits);
+}
+
+#define nodes_shift_left(dst, src, n) \
+                       __nodes_shift_left(&(dst), &(src), (n), MAX_NUMNODES)
+static inline void __nodes_shift_left(nodemask_t *dstp,
+                                       const nodemask_t *srcp, int n, int nbits)
+{
+       bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
+}
+
+#define first_node(src) __first_node(&(src), MAX_NUMNODES)
+static inline int __first_node(const nodemask_t *srcp, int nbits)
+{
+       return min_t(int, nbits, find_first_bit(srcp->bits, nbits));
+}
+
+#define next_node(n, src) __next_node((n), &(src), MAX_NUMNODES)
+static inline int __next_node(int n, const nodemask_t *srcp, int nbits)
+{
+       return min_t(int, nbits, find_next_bit(srcp->bits, nbits, n+1));
+}
+
+#define nodemask_of_node(node)                                         \
+({                                                                     \
+       typeof(_unused_nodemask_arg_) m;                                \
+       if (sizeof(m) == sizeof(unsigned long)) {                       \
+               m.bits[0] = 1UL<<(node);                                \
+       } else {                                                        \
+               nodes_clear(m);                                         \
+               node_set((node), m);                                    \
+       }                                                               \
+       m;                                                              \
+})
+
+#define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES)
+
+#if MAX_NUMNODES <= BITS_PER_LONG
+
+#define NODE_MASK_ALL                                                  \
+((nodemask_t) { {                                                      \
+       [BITS_TO_LONGS(MAX_NUMNODES)-1] = NODE_MASK_LAST_WORD           \
+} })
+
+#else
+
+#define NODE_MASK_ALL                                                  \
+((nodemask_t) { {                                                      \
+       [0 ... BITS_TO_LONGS(MAX_NUMNODES)-2] = ~0UL,                   \
+       [BITS_TO_LONGS(MAX_NUMNODES)-1] = NODE_MASK_LAST_WORD           \
+} })
+
+#endif
+
+#define NODE_MASK_NONE                                                 \
+((nodemask_t) { {                                                      \
+       [0 ... BITS_TO_LONGS(MAX_NUMNODES)-1] =  0UL                    \
+} })
+
+#define nodes_addr(src) ((src).bits)
+
+#define nodemask_scnprintf(buf, len, src) \
+                       __nodemask_scnprintf((buf), (len), &(src), MAX_NUMNODES)
+static inline int __nodemask_scnprintf(char *buf, int len,
+                                       const nodemask_t *srcp, int nbits)
+{
+       return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+}
+
+#define nodemask_parse(ubuf, ulen, src) \
+                       __nodemask_parse((ubuf), (ulen), &(src), MAX_NUMNODES)
+static inline int __nodemask_parse(const char __user *buf, int len,
+                                       nodemask_t *dstp, int nbits)
+{
+       return bitmap_parse(buf, len, dstp->bits, nbits);
+}
+
+#if MAX_NUMNODES > 1
+#define for_each_node_mask(node, mask)                 \
+       for ((node) = first_node(mask);                 \
+               (node) < MAX_NUMNODES;                  \
+               (node) = next_node((node), (mask)))
+#else /* MAX_NUMNODES == 1 */
+#define for_each_node_mask(node, mask)                 \
+       if (!nodes_empty(mask))                         \
+               for ((node) = 0; (node) < 1; (node)++)
+#endif /* MAX_NUMNODES */
+
+/*
+ * The following particular system nodemasks and operations
+ * on them manage all possible and online nodes.
+ */
+
+extern nodemask_t node_online_map;
+extern nodemask_t node_possible_map;
+
+#if MAX_NUMNODES > 1
+#define num_online_nodes()     nodes_weight(node_online_map)
+#define num_possible_nodes()   nodes_weight(node_possible_map)
+#define node_online(node)      node_isset((node), node_online_map)
+#define node_possible(node)    node_isset((node), node_possible_map)
+#else
+#define num_online_nodes()     1
+#define num_possible_nodes()   1
+#define node_online(node)      ((node) == 0)
+#define node_possible(node)    ((node) == 0)
+#endif
+
+#define any_online_node(mask)                  \
+({                                             \
+       int node;                               \
+       for_each_node_mask(node, (mask))        \
+               if (node_online(node))          \
+                       break;                  \
+       node;                                   \
+})
+
+#define node_set_online(node)     set_bit((node), node_online_map.bits)
+#define node_set_offline(node)    clear_bit((node), node_online_map.bits)
+
+#define for_each_node(node)       for_each_node_mask((node), node_possible_map)
+#define for_each_online_node(node) for_each_node_mask((node), node_online_map)
+
+#endif /* __LINUX_NODEMASK_H */
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
new file mode 100644 (file)
index 0000000..857126a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * File                pci-acpi.h
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#ifndef _PCI_ACPI_H_
+#define _PCI_ACPI_H_
+
+#define OSC_QUERY_TYPE                 0
+#define OSC_SUPPORT_TYPE               1
+#define OSC_CONTROL_TYPE               2
+#define OSC_SUPPORT_MASKS              0x1f
+
+/*
+ * _OSC DW0 Definition 
+ */
+#define OSC_QUERY_ENABLE               1
+#define OSC_REQUEST_ERROR              2
+#define OSC_INVALID_UUID_ERROR         4
+#define OSC_INVALID_REVISION_ERROR     8
+#define OSC_CAPABILITIES_MASK_ERROR    16
+
+/*
+ * _OSC DW1 Definition (OS Support Fields)
+ */
+#define OSC_EXT_PCI_CONFIG_SUPPORT             1
+#define OSC_ACTIVE_STATE_PWR_SUPPORT           2
+#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT       4
+#define OSC_PCI_SEGMENT_GROUPS_SUPPORT         8
+#define OSC_MSI_SUPPORT                                16
+
+/*
+ * _OSC DW1 Definition (OS Control Fields)
+ */
+#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL      1
+#define OSC_SHPC_NATIVE_HP_CONTROL             2
+#define OSC_PCI_EXPRESS_PME_CONTROL            4
+#define OSC_PCI_EXPRESS_AER_CONTROL            8
+#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL  16
+
+#define OSC_CONTROL_MASKS      (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |    \
+                               OSC_SHPC_NATIVE_HP_CONTROL |            \
+                               OSC_PCI_EXPRESS_PME_CONTROL |           \
+                               OSC_PCI_EXPRESS_AER_CONTROL |           \
+                               OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+
+#ifdef CONFIG_ACPI
+extern acpi_status pci_osc_control_set(u32 flags);
+extern acpi_status pci_osc_support_set(u32 flags);
+#else
+#if !defined(acpi_status)
+typedef u32            acpi_status;
+#define AE_ERROR       (acpi_status) (0x0001)
+#endif    
+static inline acpi_status pci_osc_control_set(u32 flags) {return AE_ERROR;}
+static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} 
+#endif
+
+#endif /* _PCI_ACPI_H_ */
diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h
new file mode 100644 (file)
index 0000000..4e2d2a9
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2000 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
+ * DVD-RW devices.
+ *
+ */
+#ifndef __PKTCDVD_H
+#define __PKTCDVD_H
+
+#include <linux/types.h>
+
+/*
+ * 1 for normal debug messages, 2 is very verbose. 0 to turn it off.
+ */
+#define PACKET_DEBUG           1
+
+#define        MAX_WRITERS             8
+
+#define PKT_RB_POOL_SIZE       512
+
+/*
+ * How long we should hold a non-full packet before starting data gathering.
+ */
+#define PACKET_WAIT_TIME       (HZ * 5 / 1000)
+
+/*
+ * use drive write caching -- we need deferred error handling to be
+ * able to sucessfully recover with this option (drive will return good
+ * status as soon as the cdb is validated).
+ */
+#if defined(CONFIG_CDROM_PKTCDVD_WCACHE)
+#define USE_WCACHING           1
+#else
+#define USE_WCACHING           0
+#endif
+
+/*
+ * No user-servicable parts beyond this point ->
+ */
+
+/*
+ * device types
+ */
+#define PACKET_CDR             1
+#define        PACKET_CDRW             2
+#define PACKET_DVDR            3
+#define PACKET_DVDRW           4
+
+/*
+ * flags
+ */
+#define PACKET_WRITABLE                1       /* pd is writable */
+#define PACKET_NWA_VALID       2       /* next writable address valid */
+#define PACKET_LRA_VALID       3       /* last recorded address valid */
+#define PACKET_MERGE_SEGS      4       /* perform segment merging to keep */
+                                       /* underlying cdrom device happy */
+
+/*
+ * Disc status -- from READ_DISC_INFO
+ */
+#define PACKET_DISC_EMPTY      0
+#define PACKET_DISC_INCOMPLETE 1
+#define PACKET_DISC_COMPLETE   2
+#define PACKET_DISC_OTHER      3
+
+/*
+ * write type, and corresponding data block type
+ */
+#define PACKET_MODE1           1
+#define PACKET_MODE2           2
+#define PACKET_BLOCK_MODE1     8
+#define PACKET_BLOCK_MODE2     10
+
+/*
+ * Last session/border status
+ */
+#define PACKET_SESSION_EMPTY           0
+#define PACKET_SESSION_INCOMPLETE      1
+#define PACKET_SESSION_RESERVED                2
+#define PACKET_SESSION_COMPLETE                3
+
+#define PACKET_MCN                     "4a656e734178626f65323030300000"
+
+#undef PACKET_USE_LS
+
+#define PKT_CTRL_CMD_SETUP     0
+#define PKT_CTRL_CMD_TEARDOWN  1
+#define PKT_CTRL_CMD_STATUS    2
+
+struct pkt_ctrl_command {
+       __u32 command;                          /* in: Setup, teardown, status */
+       __u32 dev_index;                        /* in/out: Device index */
+       __u32 dev;                              /* in/out: Device nr for cdrw device */
+       __u32 pkt_dev;                          /* in/out: Device nr for packet device */
+       __u32 num_devices;                      /* out: Largest device index + 1 */
+       __u32 padding;                          /* Not used */
+};
+
+/*
+ * packet ioctls
+ */
+#define PACKET_IOCTL_MAGIC     ('X')
+#define PACKET_CTRL_CMD                _IOWR(PACKET_IOCTL_MAGIC, 1, struct pkt_ctrl_command)
+
+#ifdef __KERNEL__
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/cdrom.h>
+
+struct packet_settings
+{
+       __u8                    size;           /* packet size in (512 byte) sectors */
+       __u8                    fp;             /* fixed packets */
+       __u8                    link_loss;      /* the rest is specified
+                                                * as per Mt Fuji */
+       __u8                    write_type;
+       __u8                    track_mode;
+       __u8                    block_mode;
+};
+
+/*
+ * Very crude stats for now
+ */
+struct packet_stats
+{
+       unsigned long           pkt_started;
+       unsigned long           pkt_ended;
+       unsigned long           secs_w;
+       unsigned long           secs_rg;
+       unsigned long           secs_r;
+};
+
+struct packet_cdrw
+{
+       struct list_head        pkt_free_list;
+       struct list_head        pkt_active_list;
+       spinlock_t              active_list_lock; /* Serialize access to pkt_active_list */
+       struct task_struct      *thread;
+       atomic_t                pending_bios;
+};
+
+/*
+ * Switch to high speed reading after reading this many kilobytes
+ * with no interspersed writes.
+ */
+#define HI_SPEED_SWITCH 512
+
+struct packet_iosched
+{
+       atomic_t                attention;      /* Set to non-zero when queue processing is needed */
+       int                     writing;        /* Non-zero when writing, zero when reading */
+       spinlock_t              lock;           /* Protecting read/write queue manipulations */
+       struct bio              *read_queue;
+       struct bio              *read_queue_tail;
+       struct bio              *write_queue;
+       struct bio              *write_queue_tail;
+       int                     high_prio_read; /* An important read request has been queued */
+       int                     successive_reads;
+};
+
+/*
+ * 32 buffers of 2048 bytes
+ */
+#define PACKET_MAX_SIZE                32
+#define PAGES_PER_PACKET       (PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE)
+#define PACKET_MAX_SECTORS     (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9)
+
+enum packet_data_state {
+       PACKET_IDLE_STATE,                      /* Not used at the moment */
+       PACKET_WAITING_STATE,                   /* Waiting for more bios to arrive, so */
+                                               /* we don't have to do as much */
+                                               /* data gathering */
+       PACKET_READ_WAIT_STATE,                 /* Waiting for reads to fill in holes */
+       PACKET_WRITE_WAIT_STATE,                /* Waiting for the write to complete */
+       PACKET_RECOVERY_STATE,                  /* Recover after read/write errors */
+       PACKET_FINISHED_STATE,                  /* After write has finished */
+
+       PACKET_NUM_STATES                       /* Number of possible states */
+};
+
+/*
+ * Information needed for writing a single packet
+ */
+struct pktcdvd_device;
+
+struct packet_data
+{
+       struct list_head        list;
+
+       spinlock_t              lock;           /* Lock protecting state transitions and */
+                                               /* orig_bios list */
+
+       struct bio              *orig_bios;     /* Original bios passed to pkt_make_request */
+       struct bio              *orig_bios_tail;/* that will be handled by this packet */
+       int                     write_size;     /* Total size of all bios in the orig_bios */
+                                               /* list, measured in number of frames */
+
+       struct bio              *w_bio;         /* The bio we will send to the real CD */
+                                               /* device once we have all data for the */
+                                               /* packet we are going to write */
+       sector_t                sector;         /* First sector in this packet */
+       int                     frames;         /* Number of frames in this packet */
+
+       enum packet_data_state  state;          /* Current state */
+       atomic_t                run_sm;         /* Incremented whenever the state */
+                                               /* machine needs to be run */
+       long                    sleep_time;     /* Set this to non-zero to make the state */
+                                               /* machine run after this many jiffies. */
+
+       atomic_t                io_wait;        /* Number of pending IO operations */
+       atomic_t                io_errors;      /* Number of read/write errors during IO */
+
+       struct bio              *r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */
+       struct page             *pages[PAGES_PER_PACKET];
+
+       int                     cache_valid;    /* If non-zero, the data for the zone defined */
+                                               /* by the sector variable is completely cached */
+                                               /* in the pages[] vector. */
+
+       int                     id;             /* ID number for debugging */
+       struct pktcdvd_device   *pd;
+};
+
+struct pkt_rb_node {
+       struct rb_node          rb_node;
+       struct bio              *bio;
+};
+
+struct packet_stacked_data
+{
+       struct bio              *bio;           /* Original read request bio */
+       struct pktcdvd_device   *pd;
+};
+#define PSD_POOL_SIZE          64
+
+struct pktcdvd_device
+{
+       struct block_device     *bdev;          /* dev attached */
+       dev_t                   pkt_dev;        /* our dev */
+       char                    name[20];
+       struct packet_settings  settings;
+       struct packet_stats     stats;
+       int                     refcnt;         /* Open count */
+       int                     write_speed;    /* current write speed, kB/s */
+       int                     read_speed;     /* current read speed, kB/s */
+       unsigned long           offset;         /* start offset */
+       __u8                    mode_offset;    /* 0 / 8 */
+       __u8                    type;
+       unsigned long           flags;
+       __u16                   mmc3_profile;
+       __u32                   nwa;            /* next writable address */
+       __u32                   lra;            /* last recorded address */
+       struct packet_cdrw      cdrw;
+       wait_queue_head_t       wqueue;
+
+       spinlock_t              lock;           /* Serialize access to bio_queue */
+       struct rb_root          bio_queue;      /* Work queue of bios we need to handle */
+       int                     bio_queue_size; /* Number of nodes in bio_queue */
+       sector_t                current_sector; /* Keep track of where the elevator is */
+       atomic_t                scan_queue;     /* Set to non-zero when pkt_handle_queue */
+                                               /* needs to be run. */
+       mempool_t               *rb_pool;       /* mempool for pkt_rb_node allocations */
+
+       struct packet_iosched   iosched;
+       struct gendisk          *disk;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* __PKTCDVD_H */
diff --git a/include/linux/raid/raid10.h b/include/linux/raid/raid10.h
new file mode 100644 (file)
index 0000000..6070878
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _RAID10_H
+#define _RAID10_H
+
+#include <linux/raid/md.h>
+
+typedef struct mirror_info mirror_info_t;
+
+struct mirror_info {
+       mdk_rdev_t      *rdev;
+       sector_t        head_position;
+};
+
+typedef struct r10bio_s r10bio_t;
+
+struct r10_private_data_s {
+       mddev_t                 *mddev;
+       mirror_info_t           *mirrors;
+       int                     raid_disks;
+       int                     working_disks;
+       spinlock_t              device_lock;
+
+       /* geometry */
+       int                     near_copies;  /* number of copies layed out raid0 style */
+       int                     far_copies;   /* number of copies layed out
+                                              * at large strides across drives
+                                              */
+       int                     copies;       /* near_copies * far_copies.
+                                              * must be <= raid_disks
+                                              */
+       sector_t                stride;       /* distance between far copies.
+                                              * This is size / far_copies
+                                              */
+
+       int chunk_shift; /* shift from chunks to sectors */
+       sector_t chunk_mask;
+
+       struct list_head        retry_list;
+       /* for use when syncing mirrors: */
+
+       spinlock_t              resync_lock;
+       int nr_pending;
+       int barrier;
+       sector_t                next_resync;
+
+       wait_queue_head_t       wait_idle;
+       wait_queue_head_t       wait_resume;
+
+       mempool_t *r10bio_pool;
+       mempool_t *r10buf_pool;
+};
+
+typedef struct r10_private_data_s conf_t;
+
+/*
+ * this is the only point in the RAID code where we violate
+ * C type safety. mddev->private is an 'opaque' pointer.
+ */
+#define mddev_to_conf(mddev) ((conf_t *) mddev->private)
+
+/*
+ * this is our 'private' RAID10 bio.
+ *
+ * it contains information about what kind of IO operations were started
+ * for this RAID10 operation, and about their status:
+ */
+
+struct r10bio_s {
+       atomic_t                remaining; /* 'have we finished' count,
+                                           * used from IRQ handlers
+                                           */
+       sector_t                sector; /* virtual sector number */
+       int                     sectors;
+       unsigned long           state;
+       mddev_t                 *mddev;
+       /*
+        * original bio going to /dev/mdx
+        */
+       struct bio              *master_bio;
+       /*
+        * if the IO is in READ direction, then this is where we read
+        */
+       int                     read_slot;
+
+       struct list_head        retry_list;
+       /*
+        * if the IO is in WRITE direction, then multiple bios are used,
+        * one for each copy.
+        * When resyncing we also use one for each copy.
+        * When reconstructing, we use 2 bios, one for read, one for write.
+        * We choose the number when they are allocated.
+        */
+       struct {
+               struct bio              *bio;
+               sector_t addr;
+               int devnum;
+       } devs[0];
+};
+
+/* bits for r10bio.state */
+#define        R10BIO_Uptodate 0
+#define        R10BIO_IsSync   1
+#define        R10BIO_IsRecover 2
+#endif
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
new file mode 100644 (file)
index 0000000..e0a4faa
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _LINUX_RAMFS_H
+#define _LINUX_RAMFS_H
+
+struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev);
+struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
+        int flags, const char *dev_name, void *data);
+
+extern struct file_operations ramfs_file_operations;
+extern struct vm_operations_struct generic_file_vm_ops;
+
+#endif
diff --git a/include/linux/rslib.h b/include/linux/rslib.h
new file mode 100644 (file)
index 0000000..980c8f7
--- /dev/null
@@ -0,0 +1,105 @@
+/* 
+ * include/linux/rslib.h
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *   
+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * RS code lifted from reed solomon library written by Phil Karn
+ * Copyright 2002 Phil Karn, KA9Q
+ *
+ * $Id: rslib.h,v 1.3 2004/10/05 22:08:22 gleixner Exp $
+ *
+ * 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 _RSLIB_H_
+#define _RSLIB_H_
+
+#include <linux/list.h>
+
+/** 
+ * struct rs_control - rs control structure
+ * 
+ * @mm:                Bits per symbol
+ * @nn:                Symbols per block (= (1<<mm)-1)
+ * @alpha_to:  log lookup table
+ * @index_of:  Antilog lookup table
+ * @genpoly:   Generator polynomial 
+ * @nroots:    Number of generator roots = number of parity symbols
+ * @fcr:       First consecutive root, index form
+ * @prim:      Primitive element, index form 
+ * @iprim:     prim-th root of 1, index form 
+ * @gfpoly:    The primitive generator polynominal 
+ * @users:     Users of this structure 
+ * @list:      List entry for the rs control list
+*/
+struct rs_control {
+       int             mm;
+       int             nn;
+       uint16_t        *alpha_to;
+       uint16_t        *index_of;
+       uint16_t        *genpoly;
+       int             nroots;
+       int             fcr;
+       int             prim;
+       int             iprim;
+       int             gfpoly;
+       int             users;
+       struct list_head list;
+};
+
+/* General purpose RS codec, 8-bit data width, symbol width 1-15 bit  */
+#ifdef CONFIG_REED_SOLOMON_ENC8
+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
+              uint16_t invmsk);
+#endif
+#ifdef CONFIG_REED_SOLOMON_DEC8
+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, 
+               uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+              uint16_t *corr);
+#endif
+
+/* General purpose RS codec, 16-bit data width, symbol width 1-15 bit  */
+#ifdef CONFIG_REED_SOLOMON_ENC16
+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
+               uint16_t invmsk);
+#endif
+#ifdef CONFIG_REED_SOLOMON_DEC16
+int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
+               uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+               uint16_t *corr);
+#endif
+
+/* Create or get a matching rs control structure */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, 
+                          int nroots);
+
+/* Release a rs control structure */
+void free_rs(struct rs_control *rs);
+
+/** modulo replacement for galois field arithmetics
+ *
+ *  @rs:       the rs control structure
+ *  @x:                the value to reduce
+ *
+ *  where
+ *  rs->mm = number of bits per symbol 
+ *  rs->nn = (2^rs->mm) - 1
+ *  
+ *  Simple arithmetic modulo would return a wrong result for values
+ *  >= 3 * rs->nn
+*/
+static inline int rs_modnn(struct rs_control *rs, int x)
+{
+       while (x >= rs->nn) {
+               x -= rs->nn;
+               x = (x >> rs->mm) + (x & rs->nn);
+       }
+       return x;
+}
+
+#endif
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
new file mode 100644 (file)
index 0000000..7f717e9
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _LINUX_SCATTERLIST_H
+#define _LINUX_SCATTERLIST_H
+
+static inline void sg_init_one(struct scatterlist *sg,
+                              u8 *buf, unsigned int buflen)
+{
+       memset(sg, 0, sizeof(*sg));
+
+       sg->page = virt_to_page(buf);
+       sg->offset = offset_in_page(buf);
+       sg->length = buflen;
+}
+
+#endif /* _LINUX_SCATTERLIST_H */
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
new file mode 100644 (file)
index 0000000..823181a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/linux/serial_8250.h
+ *
+ *  Copyright (C) 2004 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _LINUX_SERIAL_8250_H
+#define _LINUX_SERIAL_8250_H
+
+#include <linux/serial_core.h>
+#include <linux/device.h>
+
+struct plat_serial8250_port {
+       unsigned long   iobase;         /* io base address */
+       void __iomem    *membase;       /* ioremap cookie or NULL */
+       unsigned long   mapbase;        /* resource base */
+       unsigned int    irq;            /* interrupt number */
+       unsigned int    uartclk;        /* UART clock rate */
+       unsigned char   regshift;       /* register shift */
+       unsigned char   iotype;         /* UPIO_* */
+       unsigned int    flags;          /* UPF_* flags */
+};
+
+#endif
diff --git a/include/linux/sunrpc/gss_spkm3.h b/include/linux/sunrpc/gss_spkm3.h
new file mode 100644 (file)
index 0000000..b5c9968
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  linux/include/linux/sunrpc/gss_spkm3.h
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+#include <linux/sunrpc/auth_gss.h>
+#include <linux/sunrpc/gss_err.h>
+#include <linux/sunrpc/gss_asn1.h>
+
+struct spkm3_ctx {
+       struct xdr_netobj       ctx_id; /* per message context id */
+       int                     qop;         /* negotiated qop */
+       struct xdr_netobj       mech_used;
+       unsigned int            ret_flags ;
+       unsigned int            req_flags ;
+       struct xdr_netobj       share_key;
+       int                     conf_alg;
+       struct crypto_tfm*      derived_conf_key;
+       int                     intg_alg;
+       struct crypto_tfm*      derived_integ_key;
+       int                     keyestb_alg;   /* alg used to get share_key */
+       int                     owf_alg;   /* one way function */
+};
+
+/* from openssl/objects.h */
+/* XXX need SEAL_ALG_NONE */
+#define NID_md5                4
+#define NID_dhKeyAgreement     28 
+#define NID_des_cbc            31 
+#define NID_sha1               64
+#define NID_cast5_cbc          108
+
+/* SPKM InnerContext Token types */
+
+#define SPKM_ERROR_TOK 3
+#define SPKM_MIC_TOK   4
+#define SPKM_WRAP_TOK  5
+#define SPKM_DEL_TOK   6
+
+u32 spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, struct xdr_buf * text, struct xdr_netobj * token, int toktype);
+
+u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int *qop_state, int toktype);
+
+#define CKSUMTYPE_RSA_MD5            0x0007
+
+s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
+                   struct xdr_netobj *cksum);
+void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
+int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, 
+                   int explen);
+void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, 
+                   unsigned char *ctxhdr, int elen, int zbit);
+void spkm3_make_mic_token(unsigned  char **tokp, int toklen, 
+                   struct xdr_netobj *mic_hdr,
+                   struct xdr_netobj *md5cksum, int md5elen, int md5zbit);
+u32 spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, 
+                   unsigned char **cksum);
diff --git a/include/linux/tc_act/tc_gact.h b/include/linux/tc_act/tc_gact.h
new file mode 100644 (file)
index 0000000..23a03eb
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __LINUX_TC_GACT_H
+#define __LINUX_TC_GACT_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_GACT 5
+struct tc_gact
+{
+       tc_gen;
+
+};
+
+struct tc_gact_p
+{
+#define PGACT_NONE              0
+#define PGACT_NETRAND           1
+#define PGACT_DETERM            2
+#define MAX_RAND                (PGACT_DETERM + 1 )
+       __u16                 ptype;
+       __u16                 pval;
+       int                   paction;
+};
+enum
+{
+       TCA_GACT_UNSPEC,
+       TCA_GACT_TM,
+       TCA_GACT_PARMS,
+       TCA_GACT_PROB,
+       __TCA_GACT_MAX
+};
+#define TCA_GACT_MAX (__TCA_GACT_MAX - 1)
+#endif
diff --git a/include/linux/tc_act/tc_ipt.h b/include/linux/tc_act/tc_ipt.h
new file mode 100644 (file)
index 0000000..4b6f7b6
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __LINUX_TC_IPT_H
+#define __LINUX_TC_IPT_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_IPT 6
+
+enum
+{
+       TCA_IPT_UNSPEC,
+       TCA_IPT_TABLE,
+       TCA_IPT_HOOK,
+       TCA_IPT_INDEX,
+       TCA_IPT_CNT,
+       TCA_IPT_TM,
+       TCA_IPT_TARG,
+       __TCA_IPT_MAX
+};
+#define TCA_IPT_MAX (__TCA_IPT_MAX - 1)
+                                                                                
+#endif
diff --git a/include/linux/tc_act/tc_mirred.h b/include/linux/tc_act/tc_mirred.h
new file mode 100644 (file)
index 0000000..71d6340
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __LINUX_TC_MIR_H
+#define __LINUX_TC_MIR_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_MIRRED 8
+#define TCA_EGRESS_REDIR 1  /* packet redirect to EGRESS*/
+#define TCA_EGRESS_MIRROR 2 /* mirror packet to EGRESS */
+#define TCA_INGRESS_REDIR 3  /* packet redirect to INGRESS*/
+#define TCA_INGRESS_MIRROR 4 /* mirror packet to INGRESS */
+                                                                                
+struct tc_mirred
+{
+       tc_gen;
+       int                     eaction;   /* one of IN/EGRESS_MIRROR/REDIR */
+       __u32                   ifindex;  /* ifindex of egress port */
+};
+                                                                                
+enum
+{
+       TCA_MIRRED_UNSPEC,
+       TCA_MIRRED_TM,
+       TCA_MIRRED_PARMS,
+       __TCA_MIRRED_MAX
+};
+#define TCA_MIRRED_MAX (__TCA_MIRRED_MAX - 1)
+                                                                                
+#endif
diff --git a/include/linux/tc_act/tc_pedit.h b/include/linux/tc_act/tc_pedit.h
new file mode 100644 (file)
index 0000000..83e56e3
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __LINUX_TC_PED_H
+#define __LINUX_TC_PED_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_PEDIT 7
+
+enum
+{
+       TCA_PEDIT_UNSPEC,
+       TCA_PEDIT_TM,
+       TCA_PEDIT_PARMS,
+       __TCA_PEDIT_MAX
+};
+#define TCA_PEDIT_MAX (__TCA_PEDIT_MAX - 1)
+                                                                                
+struct tc_pedit_key
+{
+       __u32           mask;  /* AND */
+       __u32           val;   /*XOR */
+       __u32           off;  /*offset */
+       __u32           at;
+       __u32           offmask;
+       __u32           shift;
+};
+                                                                                
+struct tc_pedit_sel
+{
+       tc_gen;
+       unsigned char           nkeys;
+       unsigned char           flags;
+       struct tc_pedit_key     keys[0];
+};
+#define tc_pedit tc_pedit_sel
+
+#endif
diff --git a/include/linux/usb_otg.h b/include/linux/usb_otg.h
new file mode 100644 (file)
index 0000000..c668314
--- /dev/null
@@ -0,0 +1,118 @@
+// include/linux/usb_otg.h 
+
+/*
+ * These APIs may be used between USB controllers.  USB device drivers
+ * (for either host or peripheral roles) don't use these calls; they
+ * continue to use just usb_device and usb_gadget.
+ */
+
+
+/* OTG defines lots of enumeration states before device reset */
+enum usb_otg_state {
+       OTG_STATE_UNDEFINED = 0,
+
+       /* single-role peripheral, and dual-role default-b */
+       OTG_STATE_B_IDLE,
+       OTG_STATE_B_SRP_INIT,
+       OTG_STATE_B_PERIPHERAL,
+
+       /* extra dual-role default-b states */
+       OTG_STATE_B_WAIT_ACON,
+       OTG_STATE_B_HOST,
+
+       /* dual-role default-a */
+       OTG_STATE_A_IDLE,
+       OTG_STATE_A_WAIT_VRISE,
+       OTG_STATE_A_WAIT_BCON,
+       OTG_STATE_A_HOST,
+       OTG_STATE_A_SUSPEND,
+       OTG_STATE_A_PERIPHERAL,
+       OTG_STATE_A_WAIT_VFALL,
+       OTG_STATE_A_VBUS_ERR,
+};
+
+/*
+ * the otg driver needs to interact with both device side and host side
+ * usb controllers.  it decides which controller is active at a given
+ * moment, using the transceiver, ID signal, HNP and sometimes static
+ * configuration information (including "board isn't wired for otg").
+ */
+struct otg_transceiver {
+       struct device           *dev;
+       const char              *label;
+
+       u8                      default_a;
+       enum usb_otg_state      state;
+
+       struct usb_bus          *host;
+       struct usb_gadget       *gadget;
+
+       /* to pass extra port status to the root hub */
+       u16                     port_status;
+       u16                     port_change;
+
+       /* bind/unbind the host controller */
+       int     (*set_host)(struct otg_transceiver *otg,
+                               struct usb_bus *host);
+
+       /* bind/unbind the peripheral controller */
+       int     (*set_peripheral)(struct otg_transceiver *otg,
+                               struct usb_gadget *gadget);
+
+       /* effective for B devices, ignored for A-peripheral */
+       int     (*set_power)(struct otg_transceiver *otg,
+                               unsigned mA);
+
+       /* for B devices only:  start session with A-Host */
+       int     (*start_srp)(struct otg_transceiver *otg);
+
+       /* start or continue HNP role switch */
+       int     (*start_hnp)(struct otg_transceiver *otg);
+
+};
+
+
+/* for board-specific init logic */
+extern int otg_set_transceiver(struct otg_transceiver *);
+
+
+/* for usb host and peripheral controller drivers */
+extern struct otg_transceiver *otg_get_transceiver(void);
+
+static inline int
+otg_start_hnp(struct otg_transceiver *otg)
+{
+       return otg->start_hnp(otg);
+}
+
+
+/* for HCDs */
+static inline int
+otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+{
+       return otg->set_host(otg, host);
+}
+
+
+/* for usb peripheral controller drivers */
+static inline int
+otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph)
+{
+       return otg->set_peripheral(otg, periph);
+}
+
+static inline int
+otg_set_power(struct otg_transceiver *otg, unsigned mA)
+{
+       return otg->set_power(otg, mA);
+}
+
+static inline int
+otg_start_srp(struct otg_transceiver *otg)
+{
+       return otg->start_srp(otg);
+}
+
+
+/* for OTG controller drivers (and maybe other stuff) */
+extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
new file mode 100644 (file)
index 0000000..4f2d012
--- /dev/null
@@ -0,0 +1,26 @@
+
+/*
+ * board initialization should put one of these into dev->platform_data
+ * and place the sl811hs onto platform_bus named "sl811-hcd".
+ */
+
+struct sl811_platform_data {
+       unsigned        can_wakeup:1;
+
+       /* given port_power, msec/2 after power on till power good */
+       u8              potpg;
+
+       /* mA/2 power supplied on this port (max = default = 250) */
+       u8              power;
+
+       /* sl811 relies on an external source of VBUS current */
+       void            (*port_power)(struct device *dev, int is_on);
+
+       /* pulse sl811 nRST (probably with a GPIO) */
+       void            (*reset)(struct device *dev);
+
+       // some boards need something like these:
+       // int          (*check_overcurrent)(struct device *dev);
+       // void         (*clock_enable)(struct device *dev, int is_on);
+};
+
diff --git a/include/linux/via.h b/include/linux/via.h
new file mode 100644 (file)
index 0000000..86ae3bc
--- /dev/null
@@ -0,0 +1,22 @@
+/* Miscellaneous definitions for VIA chipsets
+   Currently used only by drivers/parport/parport_pc.c */
+
+/* Values for SuperIO function select configuration register */
+#define VIA_FUNCTION_PARPORT_SPP     0x00
+#define VIA_FUNCTION_PARPORT_ECP     0x01
+#define VIA_FUNCTION_PARPORT_EPP     0x02
+#define VIA_FUNCTION_PARPORT_DISABLE 0x03
+#define VIA_FUNCTION_PROBE           0xFF /* Special magic value to be used in code, not to be written into chip */
+
+/* Bits for parallel port mode configuration register */
+#define VIA_PARPORT_ECPEPP 0X20
+#define VIA_PARPORT_BIDIR  0x80
+
+/* VIA configuration registers */
+#define VIA_CONFIG_INDEX 0x3F0
+#define VIA_CONFIG_DATA  0x3F1
+
+/* Mask for parallel port IRQ bits (in ISA PnP IRQ routing register 1) */
+#define VIA_IRQCONTROL_PARALLEL 0xF0
+/* Mask for parallel port DMA bits (in ISA PnP DMA routing register) */
+#define VIA_DMACONTROL_PARALLEL 0x0C
diff --git a/include/media/video-buf-dvb.h b/include/media/video-buf-dvb.h
new file mode 100644 (file)
index 0000000..53eac76
--- /dev/null
@@ -0,0 +1,34 @@
+#include <dvbdev.h>
+#include <dmxdev.h>
+#include <dvb_demux.h>
+#include <dvb_net.h>
+#include <dvb_frontend.h>
+
+struct videobuf_dvb {
+       /* filling that the job of the driver */
+       char                       *name;
+       struct dvb_frontend        *frontend;
+       struct videobuf_queue      dvbq;
+
+       /* video-buf-dvb state info */
+       struct semaphore           lock;
+       struct task_struct         *thread;
+       int                        nfeeds;
+
+       /* videobuf_dvb_(un)register manges this */
+       struct dvb_adapter         *adapter;
+       struct dvb_demux           demux;
+       struct dmxdev              dmxdev;
+       struct dmx_frontend        fe_hw;
+       struct dmx_frontend        fe_mem;
+       struct dvb_net             net;
+};
+
+int videobuf_dvb_register(struct videobuf_dvb *dvb);
+void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/include/net/act_api.h b/include/net/act_api.h
new file mode 100644 (file)
index 0000000..749637e
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef __NET_ACT_API_H
+#define __NET_ACT_API_H
+
+/*
+ * Public police action API for classifiers/qdiscs
+ */
+
+#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
+
+#define tca_gen(name) \
+struct tcf_##name *next; \
+       u32 index; \
+       int refcnt; \
+       int bindcnt; \
+       u32 capab; \
+       int action; \
+       struct tcf_t tm; \
+       struct gnet_stats_basic bstats; \
+       struct gnet_stats_queue qstats; \
+       struct gnet_stats_rate_est rate_est; \
+       spinlock_t *stats_lock; \
+       spinlock_t lock
+
+struct tcf_police
+{
+       tca_gen(police);
+       int             result;
+       u32             ewma_rate;
+       u32             burst;
+       u32             mtu;
+       u32             toks;
+       u32             ptoks;
+       psched_time_t   t_c;
+       struct qdisc_rate_table *R_tab;
+       struct qdisc_rate_table *P_tab;
+};
+
+#ifdef CONFIG_NET_CLS_ACT
+
+#define ACT_P_CREATED 1
+#define ACT_P_DELETED 1
+
+struct tcf_act_hdr
+{
+       tca_gen(act_hdr);
+};
+
+struct tc_action
+{
+       void *priv;
+       struct tc_action_ops *ops;
+       __u32   type;   /* for backward compat(TCA_OLD_COMPAT) */
+       __u32   order; 
+       struct tc_action *next;
+};
+
+#define TCA_CAP_NONE 0
+struct tc_action_ops
+{
+       struct tc_action_ops *next;
+       char    kind[IFNAMSIZ];
+       __u32   type; /* TBD to match kind */
+       __u32   capab;  /* capabilities includes 4 bit version */
+       struct module           *owner;
+       int     (*act)(struct sk_buff **, struct tc_action *);
+       int     (*get_stats)(struct sk_buff *, struct tc_action *);
+       int     (*dump)(struct sk_buff *, struct tc_action *,int , int);
+       int     (*cleanup)(struct tc_action *, int bind);
+       int     (*lookup)(struct tc_action *, u32 );
+       int     (*init)(struct rtattr *,struct rtattr *,struct tc_action *, int , int );
+       int     (*walk)(struct sk_buff *, struct netlink_callback *, int , struct tc_action *);
+};
+
+extern int tcf_register_action(struct tc_action_ops *a);
+extern int tcf_unregister_action(struct tc_action_ops *a);
+extern void tcf_action_destroy(struct tc_action *a, int bind);
+extern int tcf_action_exec(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res);
+extern int tcf_action_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,char *n, int ovr, int bind);
+extern int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action *a,char *n, int ovr, int bind);
+extern int tcf_action_dump(struct sk_buff *skb, struct tc_action *a, int, int);
+extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
+extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
+extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *);
+extern int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_action *,int , int );
+extern int tcf_act_police_dump(struct sk_buff *, struct tc_action *, int, int);
+extern int tcf_act_police(struct sk_buff **skb, struct tc_action *a);
+#endif /* CONFIG_NET_CLS_ACT */
+
+extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
+extern void tcf_police_destroy(struct tcf_police *p);
+extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
+extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
+extern int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p);
+
+static inline int
+tcf_police_release(struct tcf_police *p, int bind)
+{
+       int ret = 0;
+#ifdef CONFIG_NET_CLS_ACT
+       if (p) {
+               if (bind) {
+                        p->bindcnt--;
+               }
+               p->refcnt--;
+               if (p->refcnt <= 0 && !p->bindcnt) {
+                       tcf_police_destroy(p);
+                       ret = 1;
+               }
+       }
+#else
+       if (p && --p->refcnt == 0)
+               tcf_police_destroy(p);
+
+#endif /* CONFIG_NET_CLS_ACT */
+       return ret;
+}
+
+#endif
diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h
new file mode 100644 (file)
index 0000000..e3ec2eb
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __NET_GEN_STATS_H
+#define __NET_GEN_STATS_H
+
+#include <linux/gen_stats.h>
+#include <linux/socket.h>
+#include <linux/rtnetlink.h>
+#include <linux/pkt_sched.h>
+
+struct gnet_dump
+{
+       spinlock_t *      lock;
+       struct sk_buff *  skb;
+       struct rtattr *   tail;
+
+       /* Backward compatability */
+       int               compat_tc_stats;
+       int               compat_xstats;
+       struct rtattr *   xstats;
+       struct tc_stats   tc_stats;
+};
+
+extern int gnet_stats_start_copy(struct sk_buff *skb, int type,
+                                spinlock_t *lock, struct gnet_dump *d);
+
+extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type,
+                                       int tc_stats_type,int xstats_type,
+                                       spinlock_t *lock, struct gnet_dump *d);
+
+extern int gnet_stats_copy_basic(struct gnet_dump *d,
+                                struct gnet_stats_basic *b);
+extern int gnet_stats_copy_rate_est(struct gnet_dump *d,
+                                   struct gnet_stats_rate_est *r);
+extern int gnet_stats_copy_queue(struct gnet_dump *d,
+                                struct gnet_stats_queue *q);
+extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len);
+
+extern int gnet_stats_finish_copy(struct gnet_dump *d);
+
+extern int gen_new_estimator(struct gnet_stats_basic *bstats,
+                            struct gnet_stats_rate_est *rate_est,
+                            spinlock_t *stats_lock, struct rtattr *opt);
+extern void gen_kill_estimator(struct gnet_stats_basic *bstats,
+                              struct gnet_stats_rate_est *rate_est);
+
+#endif
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
new file mode 100644 (file)
index 0000000..c57504b
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef __NET_SCHED_GENERIC_H
+#define __NET_SCHED_GENERIC_H
+
+#include <linux/config.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
+#include <net/gen_stats.h>
+
+struct Qdisc_ops;
+struct qdisc_walker;
+struct tcf_walker;
+struct module;
+
+struct qdisc_rate_table
+{
+       struct tc_ratespec rate;
+       u32             data[256];
+       struct qdisc_rate_table *next;
+       int             refcnt;
+};
+
+struct Qdisc
+{
+       int                     (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
+       struct sk_buff *        (*dequeue)(struct Qdisc *dev);
+       unsigned                flags;
+#define TCQ_F_BUILTIN  1
+#define TCQ_F_THROTTLED        2
+#define TCQ_F_INGRESS  4
+       int                     padded;
+       struct Qdisc_ops        *ops;
+       u32                     handle;
+       u32                     parent;
+       atomic_t                refcnt;
+       struct sk_buff_head     q;
+       struct net_device       *dev;
+       struct list_head        list;
+
+       struct gnet_stats_basic bstats;
+       struct gnet_stats_queue qstats;
+       struct gnet_stats_rate_est      rate_est;
+       spinlock_t              *stats_lock;
+       struct rcu_head         q_rcu;
+       int                     (*reshape_fail)(struct sk_buff *skb,
+                                       struct Qdisc *q);
+
+       /* This field is deprecated, but it is still used by CBQ
+        * and it will live until better solution will be invented.
+        */
+       struct Qdisc            *__parent;
+};
+
+struct Qdisc_class_ops
+{
+       /* Child qdisc manipulation */
+       int                     (*graft)(struct Qdisc *, unsigned long cl,
+                                       struct Qdisc *, struct Qdisc **);
+       struct Qdisc *          (*leaf)(struct Qdisc *, unsigned long cl);
+
+       /* Class manipulation routines */
+       unsigned long           (*get)(struct Qdisc *, u32 classid);
+       void                    (*put)(struct Qdisc *, unsigned long);
+       int                     (*change)(struct Qdisc *, u32, u32,
+                                       struct rtattr **, unsigned long *);
+       int                     (*delete)(struct Qdisc *, unsigned long);
+       void                    (*walk)(struct Qdisc *, struct qdisc_walker * arg);
+
+       /* Filter manipulation */
+       struct tcf_proto **     (*tcf_chain)(struct Qdisc *, unsigned long);
+       unsigned long           (*bind_tcf)(struct Qdisc *, unsigned long,
+                                       u32 classid);
+       void                    (*unbind_tcf)(struct Qdisc *, unsigned long);
+
+       /* rtnetlink specific */
+       int                     (*dump)(struct Qdisc *, unsigned long,
+                                       struct sk_buff *skb, struct tcmsg*);
+       int                     (*dump_stats)(struct Qdisc *, unsigned long,
+                                       struct gnet_dump *);
+};
+
+struct Qdisc_ops
+{
+       struct Qdisc_ops        *next;
+       struct Qdisc_class_ops  *cl_ops;
+       char                    id[IFNAMSIZ];
+       int                     priv_size;
+
+       int                     (*enqueue)(struct sk_buff *, struct Qdisc *);
+       struct sk_buff *        (*dequeue)(struct Qdisc *);
+       int                     (*requeue)(struct sk_buff *, struct Qdisc *);
+       unsigned int            (*drop)(struct Qdisc *);
+
+       int                     (*init)(struct Qdisc *, struct rtattr *arg);
+       void                    (*reset)(struct Qdisc *);
+       void                    (*destroy)(struct Qdisc *);
+       int                     (*change)(struct Qdisc *, struct rtattr *arg);
+
+       int                     (*dump)(struct Qdisc *, struct sk_buff *);
+       int                     (*dump_stats)(struct Qdisc *, struct gnet_dump *);
+
+       struct module           *owner;
+};
+
+
+struct tcf_result
+{
+       unsigned long   class;
+       u32             classid;
+};
+
+struct tcf_proto_ops
+{
+       struct tcf_proto_ops    *next;
+       char                    kind[IFNAMSIZ];
+
+       int                     (*classify)(struct sk_buff*, struct tcf_proto*,
+                                       struct tcf_result *);
+       int                     (*init)(struct tcf_proto*);
+       void                    (*destroy)(struct tcf_proto*);
+
+       unsigned long           (*get)(struct tcf_proto*, u32 handle);
+       void                    (*put)(struct tcf_proto*, unsigned long);
+       int                     (*change)(struct tcf_proto*, unsigned long,
+                                       u32 handle, struct rtattr **,
+                                       unsigned long *);
+       int                     (*delete)(struct tcf_proto*, unsigned long);
+       void                    (*walk)(struct tcf_proto*, struct tcf_walker *arg);
+
+       /* rtnetlink specific */
+       int                     (*dump)(struct tcf_proto*, unsigned long,
+                                       struct sk_buff *skb, struct tcmsg*);
+
+       struct module           *owner;
+};
+
+struct tcf_proto
+{
+       /* Fast access part */
+       struct tcf_proto        *next;
+       void                    *root;
+       int                     (*classify)(struct sk_buff*, struct tcf_proto*,
+                                       struct tcf_result *);
+       u32                     protocol;
+
+       /* All the rest */
+       u32                     prio;
+       u32                     classid;
+       struct Qdisc            *q;
+       void                    *data;
+       struct tcf_proto_ops    *ops;
+};
+
+
+extern void qdisc_lock_tree(struct net_device *dev);
+extern void qdisc_unlock_tree(struct net_device *dev);
+
+#define sch_tree_lock(q)       qdisc_lock_tree((q)->dev)
+#define sch_tree_unlock(q)     qdisc_unlock_tree((q)->dev)
+#define tcf_tree_lock(tp)      qdisc_lock_tree((tp)->q->dev)
+#define tcf_tree_unlock(tp)    qdisc_unlock_tree((tp)->q->dev)
+
+static inline void
+tcf_destroy(struct tcf_proto *tp)
+{
+       tp->ops->destroy(tp);
+       module_put(tp->ops->owner);
+       kfree(tp);
+}
+
+#endif
diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h
new file mode 100644 (file)
index 0000000..8401ce1
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __NET_TC_GACT_H
+#define __NET_TC_GACT_H
+
+#include <net/pkt_sched.h>
+
+struct tcf_gact
+{
+        tca_gen(gact);
+#ifdef CONFIG_GACT_PROB
+        u16                 ptype;
+        u16                 pval;
+        int                 paction;
+#endif
+                                                                                
+};
+                                                                                
+#endif
diff --git a/include/net/tc_act/tc_ipt.h b/include/net/tc_act/tc_ipt.h
new file mode 100644 (file)
index 0000000..02ecceb
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef __NET_TC_IPT_H
+#define __NET_TC_IPT_H
+
+#include <net/act_api.h>
+
+struct ipt_entry_target;
+
+struct tcf_ipt
+{
+       tca_gen(ipt);
+       u32 hook;
+       char *tname;
+       struct ipt_entry_target *t;
+};
+
+#endif
diff --git a/include/net/tc_act/tc_mirred.h b/include/net/tc_act/tc_mirred.h
new file mode 100644 (file)
index 0000000..b5c32f6
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __NET_TC_MIR_H
+#define __NET_TC_MIR_H
+
+#include <net/act_api.h>
+
+struct tcf_mirred
+{
+       tca_gen(mirred);
+       int eaction;
+       int ifindex;
+       int ok_push;
+       struct net_device *dev;
+};
+
+#endif
diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h
new file mode 100644 (file)
index 0000000..29ddb66
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __NET_TC_PED_H
+#define __NET_TC_PED_H
+
+#include <net/act_api.h>
+
+struct tcf_pedit
+{
+       tca_gen(pedit);
+       unsigned char           nkeys;
+       unsigned char           flags;
+       struct tc_pedit_key     keys[0];
+};
+
+#endif
diff --git a/include/net/x25device.h b/include/net/x25device.h
new file mode 100644 (file)
index 0000000..cf36a20
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _X25DEVICE_H
+#define _X25DEVICE_H
+
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <linux/skbuff.h>
+
+static inline unsigned short x25_type_trans(struct sk_buff *skb,
+                                           struct net_device *dev)
+{
+       skb->mac.raw = skb->data;
+       skb->input_dev = skb->dev = dev;
+       skb->pkt_type = PACKET_HOST;
+       
+       return htons(ETH_P_X25);
+}
+#endif
diff --git a/include/sound/pcm-indirect.h b/include/sound/pcm-indirect.h
new file mode 100644 (file)
index 0000000..31fa7a5
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Helper functions for indirect PCM data transfer
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *                   Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SOUND_PCM_INDIRECT_H
+#define __SOUND_PCM_INDIRECT_H
+
+#include <sound/pcm.h>
+
+typedef struct sndrv_pcm_indirect {
+       unsigned int hw_buffer_size;    /* Byte size of hardware buffer */
+       unsigned int hw_queue_size;     /* Max queue size of hw buffer (0 = buffer size) */
+       unsigned int hw_data;   /* Offset to next dst (or src) in hw ring buffer */
+       unsigned int hw_io;     /* Ring buffer hw pointer */
+       int hw_ready;           /* Bytes ready for play (or captured) in hw ring buffer */
+       unsigned int sw_buffer_size;    /* Byte size of software buffer */
+       unsigned int sw_data;   /* Offset to next dst (or src) in sw ring buffer */
+       unsigned int sw_io;     /* Current software pointer in bytes */
+       int sw_ready;           /* Bytes ready to be transferred to/from hw */
+       snd_pcm_uframes_t appl_ptr;     /* Last seen appl_ptr */
+} snd_pcm_indirect_t;
+
+typedef void (*snd_pcm_indirect_copy_t)(snd_pcm_substream_t *substream,
+                                       snd_pcm_indirect_t *rec, size_t bytes);
+
+/*
+ * helper function for playback ack callback
+ */
+static inline void
+snd_pcm_indirect_playback_transfer(snd_pcm_substream_t *substream,
+                                  snd_pcm_indirect_t *rec,
+                                  snd_pcm_indirect_copy_t copy)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
+       snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
+       int qsize;
+
+       if (diff) {
+               if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
+                       diff += runtime->boundary;
+               rec->sw_ready += (int)frames_to_bytes(runtime, diff);
+               rec->appl_ptr = appl_ptr;
+       }
+       qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
+       while (rec->hw_ready < qsize && rec->sw_ready > 0) {
+               unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
+               unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
+               unsigned int bytes = qsize - rec->hw_ready;
+               if (rec->sw_ready < (int)bytes)
+                       bytes = rec->sw_ready;
+               if (hw_to_end < bytes)
+                       bytes = hw_to_end;
+               if (sw_to_end < bytes)
+                       bytes = sw_to_end;
+               if (! bytes)
+                       break;
+               copy(substream, rec, bytes);
+               rec->hw_data += bytes;
+               if (rec->hw_data == rec->hw_buffer_size)
+                       rec->hw_data = 0;
+               rec->sw_data += bytes;
+               if (rec->sw_data == rec->sw_buffer_size)
+                       rec->sw_data = 0;
+               rec->hw_ready += bytes;
+               rec->sw_ready -= bytes;
+       }
+}
+
+/*
+ * helper function for playback pointer callback
+ * ptr = current byte pointer
+ */
+static inline snd_pcm_uframes_t
+snd_pcm_indirect_playback_pointer(snd_pcm_substream_t *substream,
+                                 snd_pcm_indirect_t *rec, unsigned int ptr)
+{
+       int bytes = ptr - rec->hw_io;
+       if (bytes < 0)
+               bytes += rec->hw_buffer_size;
+       rec->hw_io = ptr;
+       rec->hw_ready -= bytes;
+       rec->sw_io += bytes;
+       if (rec->sw_io >= rec->sw_buffer_size)
+               rec->sw_io -= rec->sw_buffer_size;
+       if (substream->ops->ack)
+               substream->ops->ack(substream);
+       return bytes_to_frames(substream->runtime, rec->sw_io);
+}
+
+
+/*
+ * helper function for capture ack callback
+ */
+static inline void
+snd_pcm_indirect_capture_transfer(snd_pcm_substream_t *substream,
+                                 snd_pcm_indirect_t *rec,
+                                 snd_pcm_indirect_copy_t copy)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
+       snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
+
+       if (diff) {
+               if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
+                       diff += runtime->boundary;
+               rec->sw_ready -= frames_to_bytes(runtime, diff);
+               rec->appl_ptr = appl_ptr;
+       }
+       while (rec->hw_ready > 0 && 
+              rec->sw_ready < (int)rec->sw_buffer_size) {
+               size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
+               size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
+               size_t bytes = rec->sw_buffer_size - rec->sw_ready;
+               if (rec->hw_ready < (int)bytes)
+                       bytes = rec->hw_ready;
+               if (hw_to_end < bytes)
+                       bytes = hw_to_end;
+               if (sw_to_end < bytes)
+                       bytes = sw_to_end;
+               if (! bytes)
+                       break;
+               copy(substream, rec, bytes);
+               rec->hw_data += bytes;
+               if ((int)rec->hw_data == rec->hw_buffer_size)
+                       rec->hw_data = 0;
+               rec->sw_data += bytes;
+               if (rec->sw_data == rec->sw_buffer_size)
+                       rec->sw_data = 0;
+               rec->hw_ready -= bytes;
+               rec->sw_ready += bytes;
+       }
+}
+
+/*
+ * helper function for capture pointer callback,
+ * ptr = current byte pointer
+ */
+static inline snd_pcm_uframes_t
+snd_pcm_indirect_capture_pointer(snd_pcm_substream_t *substream,
+                                snd_pcm_indirect_t *rec, unsigned int ptr)
+{
+       int qsize;
+       int bytes = ptr - rec->hw_io;
+       if (bytes < 0)
+               bytes += rec->hw_buffer_size;
+       rec->hw_io = ptr;
+       rec->hw_ready += bytes;
+       qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
+       if (rec->hw_ready > qsize)
+               return SNDRV_PCM_POS_XRUN;
+       rec->sw_io += bytes;
+       if (rec->sw_io >= rec->sw_buffer_size)
+               rec->sw_io -= rec->sw_buffer_size;
+       if (substream->ops->ack)
+               substream->ops->ack(substream);
+       return bytes_to_frames(substream->runtime, rec->sw_io);
+}
+
+#endif /* __SOUND_PCM_INDIRECT_H */
diff --git a/include/video/epson1355.h b/include/video/epson1355.h
new file mode 100644 (file)
index 0000000..9759f29
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * include/video/epson13xx.h -- Epson 13xx frame buffer
+ *
+ * Copyright (C) Hewlett-Packard Company.  All rights reserved.
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ *
+ */
+
+#ifndef _EPSON13XX_H_
+#define _EPSON13XX_H_
+
+#define REG_REVISION_CODE              0x00
+#define REG_MEMORY_CONFIG              0x01
+#define REG_PANEL_TYPE                 0x02
+#define REG_MOD_RATE                   0x03
+#define REG_HORZ_DISP_WIDTH            0x04
+#define REG_HORZ_NONDISP_PERIOD        0x05
+#define REG_HRTC_START_POSITION        0x06
+#define REG_HRTC_PULSE_WIDTH           0x07
+#define REG_VERT_DISP_HEIGHT0          0x08
+#define REG_VERT_DISP_HEIGHT1          0x09
+#define REG_VERT_NONDISP_PERIOD        0x0A
+#define REG_VRTC_START_POSITION        0x0B
+#define REG_VRTC_PULSE_WIDTH           0x0C
+#define REG_DISPLAY_MODE               0x0D
+#define REG_SCRN1_LINE_COMPARE0        0x0E
+#define REG_SCRN1_LINE_COMPARE1        0x0F
+#define REG_SCRN1_DISP_START_ADDR0     0x10
+#define REG_SCRN1_DISP_START_ADDR1     0x11
+#define REG_SCRN1_DISP_START_ADDR2     0x12
+#define REG_SCRN2_DISP_START_ADDR0     0x13
+#define REG_SCRN2_DISP_START_ADDR1     0x14
+#define REG_SCRN2_DISP_START_ADDR2     0x15
+#define REG_MEM_ADDR_OFFSET0           0x16
+#define REG_MEM_ADDR_OFFSET1           0x17
+#define REG_PIXEL_PANNING              0x18
+#define REG_CLOCK_CONFIG               0x19
+#define REG_POWER_SAVE_CONFIG          0x1A
+#define REG_MISC                       0x1B
+#define REG_MD_CONFIG_READBACK0        0x1C
+#define REG_MD_CONFIG_READBACK1        0x1D
+#define REG_GPIO_CONFIG0               0x1E
+#define REG_GPIO_CONFIG1               0x1F
+#define REG_GPIO_CONTROL0              0x20
+#define REG_GPIO_CONTROL1              0x21
+#define REG_PERF_ENHANCEMENT0          0x22
+#define REG_PERF_ENHANCEMENT1          0x23
+#define REG_LUT_ADDR                   0x24
+#define REG_RESERVED_1                 0x25
+#define REG_LUT_DATA                   0x26
+#define REG_INK_CURSOR_CONTROL         0x27
+#define REG_CURSOR_X_POSITION0         0x28
+#define REG_CURSOR_X_POSITION1         0x29
+#define REG_CURSOR_Y_POSITION0         0x2A
+#define REG_CURSOR_Y_POSITION1         0x2B
+#define REG_INK_CURSOR_COLOR0_0        0x2C
+#define REG_INK_CURSOR_COLOR0_1        0x2D
+#define REG_INK_CURSOR_COLOR1_0        0x2E
+#define REG_INK_CURSOR_COLOR1_1        0x2F
+#define REG_INK_CURSOR_START_ADDR      0x30
+#define REG_ALTERNATE_FRM              0x31
+
+#endif
diff --git a/kernel/ckrm/ckrm_events.c b/kernel/ckrm/ckrm_events.c
new file mode 100644 (file)
index 0000000..aad5e25
--- /dev/null
@@ -0,0 +1,97 @@
+/* ckrm_events.c - Class-based Kernel Resource Management (CKRM)
+ *               - event handling routines
+ *
+ * Copyright (C) Hubertus Franke, IBM Corp. 2003, 2004
+ *           (C) Chandra Seetharaman,  IBM Corp. 2003
+ * 
+ * 
+ * Provides API for event registration and handling for different
+ * classtypes.
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/* Changes
+ *
+ * 29 Sep 2004
+ *        Separated from ckrm.c
+ *  
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/ckrm_events.h>
+
+/*******************************************************************
+ *   Event callback invocation
+ *******************************************************************/
+
+struct ckrm_hook_cb *ckrm_event_callbacks[CKRM_NONLATCHABLE_EVENTS];
+
+/* Registration / Deregistration / Invocation functions */
+
+int ckrm_register_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb)
+{
+       struct ckrm_hook_cb **cbptr;
+
+       if ((ev < CKRM_LATCHABLE_EVENTS) || (ev >= CKRM_NONLATCHABLE_EVENTS))
+               return 1;
+       cbptr = &ckrm_event_callbacks[ev];
+       while (*cbptr != NULL)
+               cbptr = &((*cbptr)->next);
+       *cbptr = cb;
+       return 0;
+}
+
+int ckrm_unregister_event_cb(enum ckrm_event ev, struct ckrm_hook_cb *cb)
+{
+       struct ckrm_hook_cb **cbptr;
+
+       if ((ev < CKRM_LATCHABLE_EVENTS) || (ev >= CKRM_NONLATCHABLE_EVENTS))
+               return -1;
+       cbptr = &ckrm_event_callbacks[ev];
+       while ((*cbptr != NULL) && (*cbptr != cb))
+               cbptr = &((*cbptr)->next);
+       if (*cbptr)
+               (*cbptr)->next = cb->next;
+       return (*cbptr == NULL);
+}
+
+int ckrm_register_event_set(struct ckrm_event_spec especs[])
+{
+       struct ckrm_event_spec *espec = especs;
+
+       for (espec = especs; espec->ev != -1; espec++)
+               ckrm_register_event_cb(espec->ev, &espec->cb);
+       return 0;
+}
+
+int ckrm_unregister_event_set(struct ckrm_event_spec especs[])
+{
+       struct ckrm_event_spec *espec = especs;
+
+       for (espec = especs; espec->ev != -1; espec++)
+               ckrm_unregister_event_cb(espec->ev, &espec->cb);
+       return 0;
+}
+
+#define ECC_PRINTK(fmt, args...) \
+// printk("%s: " fmt, __FUNCTION__ , ## args)
+
+void ckrm_invoke_event_cb_chain(enum ckrm_event ev, void *arg)
+{
+       struct ckrm_hook_cb *cb, *anchor;
+
+       ECC_PRINTK("%d %x\n", current, ev, arg);
+       if ((anchor = ckrm_event_callbacks[ev]) != NULL) {
+               for (cb = anchor; cb; cb = cb->next)
+                       (*cb->fct) (arg);
+       }
+}
+
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
new file mode 100644 (file)
index 0000000..4937873
--- /dev/null
@@ -0,0 +1,5 @@
+
+obj-y := handle.o manage.o spurious.o
+obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
+obj-$(CONFIG_PROC_FS) += proc.o
+
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
new file mode 100644 (file)
index 0000000..1681872
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * linux/kernel/irq/autoprobe.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the interrupt probing code and driver APIs.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+/*
+ * Autodetection depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck with
+ * "IRQ_WAITING" cleared and the interrupt disabled.
+ */
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *     probe_irq_on    - begin an interrupt autodetect
+ *
+ *     Commence probing for an interrupt. The interrupts are scanned
+ *     and a mask of potential interrupt lines is returned.
+ *
+ */
+unsigned long probe_irq_on(void)
+{
+       unsigned long val, delay;
+       irq_desc_t *desc;
+       unsigned int i;
+
+       down(&probe_sem);
+       /*
+        * something may have generated an irq long ago and we want to
+        * flush such a longstanding irq before considering it as spurious.
+        */
+       for (i = NR_IRQS-1; i > 0; i--) {
+               desc = irq_desc + i;
+
+               spin_lock_irq(&desc->lock);
+               if (!irq_desc[i].action)
+                       irq_desc[i].handler->startup(i);
+               spin_unlock_irq(&desc->lock);
+       }
+
+       /* Wait for longstanding interrupts to trigger. */
+       for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+               /* about 20ms delay */ barrier();
+
+       /*
+        * enable any unassigned irqs
+        * (we must startup again here because if a longstanding irq
+        * happened in the previous stage, it may have masked itself)
+        */
+       for (i = NR_IRQS-1; i > 0; i--) {
+               desc = irq_desc + i;
+
+               spin_lock_irq(&desc->lock);
+               if (!desc->action) {
+                       desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+                       if (desc->handler->startup(i))
+                               desc->status |= IRQ_PENDING;
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+
+       /*
+        * Wait for spurious interrupts to trigger
+        */
+       for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+               /* about 100ms delay */ barrier();
+
+       /*
+        * Now filter out any obviously spurious interrupts
+        */
+       val = 0;
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       /* It triggered already - consider it spurious. */
+                       if (!(status & IRQ_WAITING)) {
+                               desc->status = status & ~IRQ_AUTODETECT;
+                               desc->handler->shutdown(i);
+                       } else
+                               if (i < 32)
+                                       val |= 1 << i;
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+
+       return val;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+/**
+ *     probe_irq_mask - scan a bitmap of interrupt lines
+ *     @val:   mask of interrupts to consider
+ *
+ *     Scan the interrupt lines and return a bitmap of active
+ *     autodetect interrupts. The interrupt probe logic state
+ *     is then returned to its previous value.
+ *
+ *     Note: we need to scan all the irq's even though we will
+ *     only return autodetect irq numbers - just so that we reset
+ *     them all to a known state.
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+       unsigned int mask;
+       int i;
+
+       mask = 0;
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       if (i < 16 && !(status & IRQ_WAITING))
+                               mask |= 1 << i;
+
+                       desc->status = status & ~IRQ_AUTODETECT;
+                       desc->handler->shutdown(i);
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+       up(&probe_sem);
+
+       return mask & val;
+}
+
+/**
+ *     probe_irq_off   - end an interrupt autodetect
+ *     @val: mask of potential interrupts (unused)
+ *
+ *     Scans the unused interrupt lines and returns the line which
+ *     appears to have triggered the interrupt. If no interrupt was
+ *     found then zero is returned. If more than one interrupt is
+ *     found then minus the first candidate is returned to indicate
+ *     their is doubt.
+ *
+ *     The interrupt probe logic state is returned to its previous
+ *     value.
+ *
+ *     BUGS: When used in a module (which arguably shouldn't happen)
+ *     nothing prevents two IRQ probe callers from overlapping. The
+ *     results of this are non-optimal.
+ */
+int probe_irq_off(unsigned long val)
+{
+       int i, irq_found = 0, nr_irqs = 0;
+
+       for (i = 0; i < NR_IRQS; i++) {
+               irq_desc_t *desc = irq_desc + i;
+               unsigned int status;
+
+               spin_lock_irq(&desc->lock);
+               status = desc->status;
+
+               if (status & IRQ_AUTODETECT) {
+                       if (!(status & IRQ_WAITING)) {
+                               if (!nr_irqs)
+                                       irq_found = i;
+                               nr_irqs++;
+                       }
+                       desc->status = status & ~IRQ_AUTODETECT;
+                       desc->handler->shutdown(i);
+               }
+               spin_unlock_irq(&desc->lock);
+       }
+       up(&probe_sem);
+
+       if (nr_irqs > 1)
+               irq_found = -irq_found;
+       return irq_found;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
new file mode 100644 (file)
index 0000000..ebc2582
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * linux/kernel/irq/handle.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the core interrupt handling code.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include "internals.h"
+
+/*
+ * Linux has a controller-independent interrupt architecture.
+ * Every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * The code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic or
+ * having to touch the generic code.
+ *
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+       [0 ... NR_IRQS-1] = {
+               .handler = &no_irq_type,
+               .lock = SPIN_LOCK_UNLOCKED
+       }
+};
+
+/*
+ * Generic 'no controller' code
+ */
+static void end_none(unsigned int irq) { }
+static void enable_none(unsigned int irq) { }
+static void disable_none(unsigned int irq) { }
+static void shutdown_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+
+static void ack_none(unsigned int irq)
+{
+       /*
+        * 'what should we do if we get a hw irq event on an illegal vector'.
+        * each architecture has to answer this themself.
+        */
+       ack_bad_irq(irq);
+}
+
+struct hw_interrupt_type no_irq_type = {
+       .typename =     "none",
+       .startup =      startup_none,
+       .shutdown =     shutdown_none,
+       .enable =       enable_none,
+       .disable =      disable_none,
+       .ack =          ack_none,
+       .end =          end_none,
+       .set_affinity = NULL
+};
+
+/*
+ * Special, empty irq handler:
+ */
+irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+       return IRQ_NONE;
+}
+
+/*
+ * Exit an interrupt context. Process softirqs if needed and possible:
+ */
+void irq_exit(void)
+{
+       preempt_count() -= IRQ_EXIT_OFFSET;
+       if (!in_interrupt() && local_softirq_pending())
+               do_softirq();
+       preempt_enable_no_resched();
+}
+
+/*
+ * Have got an event to handle:
+ */
+fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+                               struct irqaction *action)
+{
+       int ret, retval = 0, status = 0;
+
+       if (!(action->flags & SA_INTERRUPT))
+               local_irq_enable();
+
+       do {
+               ret = action->handler(irq, action->dev_id, regs);
+               if (ret == IRQ_HANDLED)
+                       status |= action->flags;
+               retval |= ret;
+               action = action->next;
+       } while (action);
+
+       if (status & SA_SAMPLE_RANDOM)
+               add_interrupt_randomness(irq);
+       local_irq_disable();
+
+       return retval;
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       struct irqaction * action;
+       unsigned int status;
+
+       kstat_this_cpu.irqs[irq]++;
+       if (desc->status & IRQ_PER_CPU) {
+               irqreturn_t action_ret;
+
+               /*
+                * No locking required for CPU-local interrupts:
+                */
+               desc->handler->ack(irq);
+               action_ret = handle_IRQ_event(irq, regs, desc->action);
+               if (!noirqdebug)
+                       note_interrupt(irq, desc, action_ret);
+               desc->handler->end(irq);
+               return 1;
+       }
+
+       spin_lock(&desc->lock);
+       desc->handler->ack(irq);
+       /*
+        * REPLAY is when Linux resends an IRQ that was dropped earlier
+        * WAITING is used by probe to mark irqs that are being tested
+        */
+       status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+       status |= IRQ_PENDING; /* we _want_ to handle it */
+
+       /*
+        * If the IRQ is disabled for whatever reason, we cannot
+        * use the action we have.
+        */
+       action = NULL;
+       if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
+               action = desc->action;
+               status &= ~IRQ_PENDING; /* we commit to handling */
+               status |= IRQ_INPROGRESS; /* we are handling it */
+       }
+       desc->status = status;
+
+       /*
+        * If there is no IRQ handler or it was disabled, exit early.
+        * Since we set PENDING, if another processor is handling
+        * a different instance of this same irq, the other processor
+        * will take care of it.
+        */
+       if (unlikely(!action))
+               goto out;
+
+       /*
+        * Edge triggered interrupts need to remember
+        * pending events.
+        * This applies to any hw interrupts that allow a second
+        * instance of the same irq to arrive while we are in do_IRQ
+        * or in the handler. But the code here only handles the _second_
+        * instance of the irq, not the third or fourth. So it is mostly
+        * useful for irq hardware that does not mask cleanly in an
+        * SMP environment.
+        */
+       for (;;) {
+               irqreturn_t action_ret;
+
+               spin_unlock(&desc->lock);
+
+               action_ret = handle_IRQ_event(irq, regs, action);
+
+               spin_lock(&desc->lock);
+               if (!noirqdebug)
+                       note_interrupt(irq, desc, action_ret);
+               if (likely(!(desc->status & IRQ_PENDING)))
+                       break;
+               desc->status &= ~IRQ_PENDING;
+       }
+       desc->status &= ~IRQ_INPROGRESS;
+
+out:
+       /*
+        * The ->end() handler has to deal with interrupts which got
+        * disabled while the handler was running.
+        */
+       desc->handler->end(irq);
+       spin_unlock(&desc->lock);
+
+       return 1;
+}
+
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
new file mode 100644 (file)
index 0000000..46feba6
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * IRQ subsystem internal functions and variables:
+ */
+
+extern int noirqdebug;
+
+#ifdef CONFIG_PROC_FS
+extern void register_irq_proc(unsigned int irq);
+extern void register_handler_proc(unsigned int irq, struct irqaction *action);
+extern void unregister_handler_proc(unsigned int irq, struct irqaction *action);
+#else
+static inline void register_irq_proc(unsigned int irq) { }
+static inline void register_handler_proc(unsigned int irq,
+                                        struct irqaction *action) { }
+static inline void unregister_handler_proc(unsigned int irq,
+                                          struct irqaction *action) { }
+#endif
+
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
new file mode 100644 (file)
index 0000000..a164fe2
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * linux/kernel/irq/manage.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains driver APIs to the irq subsystem.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+
+#include "internals.h"
+
+#ifdef CONFIG_SMP
+
+/**
+ *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
+ *
+ *     This function waits for any pending IRQ handlers for this interrupt
+ *     to complete before returning. If you use this function while
+ *     holding a resource the IRQ handler may need you will deadlock.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+void synchronize_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_desc + irq;
+
+       while (desc->status & IRQ_INPROGRESS)
+               cpu_relax();
+}
+
+EXPORT_SYMBOL(synchronize_irq);
+
+#endif
+
+/**
+ *     disable_irq_nosync - disable an irq without waiting
+ *     @irq: Interrupt to disable
+ *
+ *     Disable the selected interrupt line.  Disables and Enables are
+ *     nested.
+ *     Unlike disable_irq(), this function does not ensure existing
+ *     instances of the IRQ handler have completed before returning.
+ *
+ *     This function may be called from IRQ context.
+ */
+void disable_irq_nosync(unsigned int irq)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       if (!desc->depth++) {
+               desc->status |= IRQ_DISABLED;
+               desc->handler->disable(irq);
+       }
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(disable_irq_nosync);
+
+/**
+ *     disable_irq - disable an irq and wait for completion
+ *     @irq: Interrupt to disable
+ *
+ *     Disable the selected interrupt line.  Enables and Disables are
+ *     nested.
+ *     This function waits for any pending IRQ handlers for this interrupt
+ *     to complete before returning. If you use this function while
+ *     holding a resource the IRQ handler may need you will deadlock.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+void disable_irq(unsigned int irq)
+{
+       irq_desc_t *desc = irq_desc + irq;
+
+       disable_irq_nosync(irq);
+       if (desc->action)
+               synchronize_irq(irq);
+}
+
+EXPORT_SYMBOL(disable_irq);
+
+/**
+ *     enable_irq - enable handling of an irq
+ *     @irq: Interrupt to enable
+ *
+ *     Undoes the effect of one call to disable_irq().  If this
+ *     matches the last disable, processing of interrupts on this
+ *     IRQ line is re-enabled.
+ *
+ *     This function may be called from IRQ context.
+ */
+void enable_irq(unsigned int irq)
+{
+       irq_desc_t *desc = irq_desc + irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       switch (desc->depth) {
+       case 0:
+               WARN_ON(1);
+               break;
+       case 1: {
+               unsigned int status = desc->status & ~IRQ_DISABLED;
+
+               desc->status = status;
+               if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+                       desc->status = status | IRQ_REPLAY;
+                       hw_resend_irq(desc->handler,irq);
+               }
+               desc->handler->enable(irq);
+               /* fall-through */
+       }
+       default:
+               desc->depth--;
+       }
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
+/*
+ * Internal function that tells the architecture code whether a
+ * particular irq has been exclusively allocated or is available
+ * for driver use.
+ */
+int can_request_irq(unsigned int irq, unsigned long irqflags)
+{
+       struct irqaction *action;
+
+       if (irq >= NR_IRQS)
+               return 0;
+
+       action = irq_desc[irq].action;
+       if (action)
+               if (irqflags & action->flags & SA_SHIRQ)
+                       action = NULL;
+
+       return !action;
+}
+
+/*
+ * Internal function to register an irqaction - typically used to
+ * allocate special interrupts that are part of the architecture.
+ */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       struct irqaction *old, **p;
+       unsigned long flags;
+       int shared = 0;
+
+       if (desc->handler == &no_irq_type)
+               return -ENOSYS;
+       /*
+        * Some drivers like serial.c use request_irq() heavily,
+        * so we have to be careful not to interfere with a
+        * running system.
+        */
+       if (new->flags & SA_SAMPLE_RANDOM) {
+               /*
+                * This function might sleep, we want to call it first,
+                * outside of the atomic block.
+                * Yes, this might clear the entropy pool if the wrong
+                * driver is attempted to be loaded, without actually
+                * installing a new handler, but is this really a problem,
+                * only the sysadmin is able to do this.
+                */
+               rand_initialize_irq(irq);
+       }
+
+       /*
+        * The following block of code has to be executed atomically
+        */
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
+       if ((old = *p) != NULL) {
+               /* Can't share interrupts unless both agree to */
+               if (!(old->flags & new->flags & SA_SHIRQ)) {
+                       spin_unlock_irqrestore(&desc->lock,flags);
+                       return -EBUSY;
+               }
+
+               /* add new interrupt at end of irq queue */
+               do {
+                       p = &old->next;
+                       old = *p;
+               } while (old);
+               shared = 1;
+       }
+
+       *p = new;
+
+       if (!shared) {
+               desc->depth = 0;
+               desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
+                                 IRQ_WAITING | IRQ_INPROGRESS);
+               if (desc->handler->startup)
+                       desc->handler->startup(irq);
+               else
+                       desc->handler->enable(irq);
+       }
+       spin_unlock_irqrestore(&desc->lock,flags);
+
+       new->irq = irq;
+       register_irq_proc(irq);
+       new->dir = NULL;
+       register_handler_proc(irq, new);
+
+       return 0;
+}
+
+/**
+ *     free_irq - free an interrupt
+ *     @irq: Interrupt line to free
+ *     @dev_id: Device identity to free
+ *
+ *     Remove an interrupt handler. The handler is removed and if the
+ *     interrupt line is no longer in use by any driver it is disabled.
+ *     On a shared IRQ the caller must ensure the interrupt is disabled
+ *     on the card it drives before calling this function. The function
+ *     does not return until any executing interrupts for this IRQ
+ *     have completed.
+ *
+ *     This function must not be called from interrupt context.
+ */
+void free_irq(unsigned int irq, void *dev_id)
+{
+       struct irq_desc *desc;
+       struct irqaction **p;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS)
+               return;
+
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
+       for (;;) {
+               struct irqaction * action = *p;
+
+               if (action) {
+                       struct irqaction **pp = p;
+
+                       p = &action->next;
+                       if (action->dev_id != dev_id)
+                               continue;
+
+                       /* Found it - now remove it from the list of entries */
+                       *pp = action->next;
+                       if (!desc->action) {
+                               desc->status |= IRQ_DISABLED;
+                               if (desc->handler->shutdown)
+                                       desc->handler->shutdown(irq);
+                               else
+                                       desc->handler->disable(irq);
+                       }
+                       spin_unlock_irqrestore(&desc->lock,flags);
+                       unregister_handler_proc(irq, action);
+
+                       /* Make sure it's not being used on another CPU */
+                       synchronize_irq(irq);
+                       kfree(action);
+                       return;
+               }
+               printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+               spin_unlock_irqrestore(&desc->lock,flags);
+               return;
+       }
+}
+
+EXPORT_SYMBOL(free_irq);
+
+/**
+ *     request_irq - allocate an interrupt line
+ *     @irq: Interrupt line to allocate
+ *     @handler: Function to be called when the IRQ occurs
+ *     @irqflags: Interrupt type flags
+ *     @devname: An ascii name for the claiming device
+ *     @dev_id: A cookie passed back to the handler function
+ *
+ *     This call allocates interrupt resources and enables the
+ *     interrupt line and IRQ handling. From the point this
+ *     call is made your handler function may be invoked. Since
+ *     your handler function must clear any interrupt the board
+ *     raises, you must take care both to initialise your hardware
+ *     and to set up the interrupt handler in the right order.
+ *
+ *     Dev_id must be globally unique. Normally the address of the
+ *     device data structure is used as the cookie. Since the handler
+ *     receives this value it makes sense to use it.
+ *
+ *     If your interrupt is shared you must pass a non NULL dev_id
+ *     as this is required when freeing the interrupt.
+ *
+ *     Flags:
+ *
+ *     SA_SHIRQ                Interrupt is shared
+ *     SA_INTERRUPT            Disable local interrupts while processing
+ *     SA_SAMPLE_RANDOM        The interrupt can be used for entropy
+ *
+ */
+int request_irq(unsigned int irq,
+               irqreturn_t (*handler)(int, void *, struct pt_regs *),
+               unsigned long irqflags, const char * devname, void *dev_id)
+{
+       struct irqaction * action;
+       int retval;
+
+       /*
+        * Sanity-check: shared interrupts must pass in a real dev-ID,
+        * otherwise we'll have trouble later trying to figure out
+        * which interrupt is which (messes up the interrupt freeing
+        * logic etc).
+        */
+       if ((irqflags & SA_SHIRQ) && !dev_id)
+               return -EINVAL;
+       if (irq >= NR_IRQS)
+               return -EINVAL;
+       if (!handler)
+               return -EINVAL;
+
+       action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
+       if (!action)
+               return -ENOMEM;
+
+       action->handler = handler;
+       action->flags = irqflags;
+       cpus_clear(action->mask);
+       action->name = devname;
+       action->next = NULL;
+       action->dev_id = dev_id;
+
+       retval = setup_irq(irq, action);
+       if (retval)
+               kfree(action);
+
+       return retval;
+}
+
+EXPORT_SYMBOL(request_irq);
+
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
new file mode 100644 (file)
index 0000000..f555f87
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * linux/kernel/irq/proc.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the /proc/irq/ handling code.
+ */
+
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+
+static struct proc_dir_entry *root_irq_dir, *irq_dir[NR_IRQS];
+
+#ifdef CONFIG_SMP
+
+/*
+ * The /proc/irq/<irq>/smp_affinity values:
+ */
+static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
+
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+static int irq_affinity_read_proc(char *page, char **start, off_t off,
+                                 int count, int *eof, void *data)
+{
+       int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
+
+       if (count - len < 2)
+               return -EINVAL;
+       len += sprintf(page + len, "\n");
+       return len;
+}
+
+int no_irq_affinity;
+static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
+                                  unsigned long count, void *data)
+{
+       unsigned int irq = (int)(long)data, full_count = count, err;
+       cpumask_t new_value, tmp;
+
+       if (!irq_desc[irq].handler->set_affinity || no_irq_affinity)
+               return -EIO;
+
+       err = cpumask_parse(buffer, count, new_value);
+       if (err)
+               return err;
+
+       /*
+        * Do not allow disabling IRQs completely - it's a too easy
+        * way to make the system unusable accidentally :-) At least
+        * one online CPU still has to be targeted.
+        */
+       cpus_and(tmp, new_value, cpu_online_map);
+       if (cpus_empty(tmp))
+               return -EINVAL;
+
+       irq_affinity[irq] = new_value;
+       irq_desc[irq].handler->set_affinity(irq, new_value);
+
+       return full_count;
+}
+
+#endif
+
+#define MAX_NAMELEN 128
+
+static int name_unique(unsigned int irq, struct irqaction *new_action)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       struct irqaction *action;
+
+       for (action = desc->action ; action; action = action->next)
+               if ((action != new_action) && action->name &&
+                               !strcmp(new_action->name, action->name))
+                       return 0;
+       return 1;
+}
+
+void register_handler_proc(unsigned int irq, struct irqaction *action)
+{
+       char name [MAX_NAMELEN];
+
+       if (!irq_dir[irq] || action->dir || !action->name ||
+                                       !name_unique(irq, action))
+               return;
+
+       memset(name, 0, MAX_NAMELEN);
+       snprintf(name, MAX_NAMELEN, "%s", action->name);
+
+       /* create /proc/irq/1234/handler/ */
+       action->dir = proc_mkdir(name, irq_dir[irq]);
+}
+
+#undef MAX_NAMELEN
+
+#define MAX_NAMELEN 10
+
+void register_irq_proc(unsigned int irq)
+{
+       char name [MAX_NAMELEN];
+
+       if (!root_irq_dir ||
+               (irq_desc[irq].handler == &no_irq_type) ||
+                       irq_dir[irq])
+               return;
+
+       memset(name, 0, MAX_NAMELEN);
+       sprintf(name, "%d", irq);
+
+       /* create /proc/irq/1234 */
+       irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+#ifdef CONFIG_SMP
+       {
+               struct proc_dir_entry *entry;
+
+               /* create /proc/irq/<irq>/smp_affinity */
+               entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+               if (entry) {
+                       entry->nlink = 1;
+                       entry->data = (void *)(long)irq;
+                       entry->read_proc = irq_affinity_read_proc;
+                       entry->write_proc = irq_affinity_write_proc;
+               }
+               smp_affinity_entry[irq] = entry;
+       }
+#endif
+}
+
+#undef MAX_NAMELEN
+
+void unregister_handler_proc(unsigned int irq, struct irqaction *action)
+{
+       if (action->dir)
+               remove_proc_entry(action->dir->name, irq_dir[irq]);
+}
+
+void init_irq_proc(void)
+{
+       int i;
+
+       /* create /proc/irq */
+       root_irq_dir = proc_mkdir("irq", NULL);
+       if (!root_irq_dir)
+               return;
+
+       /*
+        * Create entries for all existing IRQs.
+        */
+       for (i = 0; i < NR_IRQS; i++)
+               register_irq_proc(i);
+}
+
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
new file mode 100644 (file)
index 0000000..f6297c3
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * linux/kernel/irq/spurious.c
+ *
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains spurious interrupt handling.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+
+/*
+ * 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
+ * and try to turn the IRQ off.
+ *
+ * (The other 100-of-100,000 interrupts may have been a correctly
+ *  functioning device sharing an IRQ with the failing one)
+ *
+ * Called under desc->lock
+ */
+
+static void
+__report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+       struct irqaction *action;
+
+       if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
+               printk(KERN_ERR "irq event %d: bogus return value %x\n",
+                               irq, action_ret);
+       } else {
+               printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+       }
+       dump_stack();
+       printk(KERN_ERR "handlers:\n");
+       action = desc->action;
+       while (action) {
+               printk(KERN_ERR "[<%p>]", action->handler);
+               print_symbol(" (%s)",
+                       (unsigned long)action->handler);
+               printk("\n");
+               action = action->next;
+       }
+}
+
+void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+       static int count = 100;
+
+       if (count > 0) {
+               count--;
+               __report_bad_irq(irq, desc, action_ret);
+       }
+}
+
+void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+{
+       if (action_ret != IRQ_HANDLED) {
+               desc->irqs_unhandled++;
+               if (action_ret != IRQ_NONE)
+                       report_bad_irq(irq, desc, action_ret);
+       }
+
+       desc->irq_count++;
+       if (desc->irq_count < 100000)
+               return;
+
+       desc->irq_count = 0;
+       if (desc->irqs_unhandled > 99900) {
+               /*
+                * The interrupt is stuck
+                */
+               __report_bad_irq(irq, desc, action_ret);
+               /*
+                * Now kill the IRQ
+                */
+               printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
+               desc->status |= IRQ_DISABLED;
+               desc->handler->disable(irq);
+       }
+       desc->irqs_unhandled = 0;
+}
+
+int noirqdebug;
+
+int __init noirqdebug_setup(char *str)
+{
+       noirqdebug = 1;
+       printk(KERN_INFO "IRQ lockup detection disabled\n");
+       return 1;
+}
+
+__setup("noirqdebug", noirqdebug_setup);
+
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
new file mode 100644 (file)
index 0000000..2fbe06a
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * A simple kernel FIFO implementation.
+ *
+ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/kfifo.h>
+
+/*
+ * kfifo_init - allocates a new FIFO using a preallocated buffer
+ * @buffer: the preallocated buffer to be used.
+ * @size: the size of the internal buffer, this have to be a power of 2.
+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
+ * @lock: the lock to be used to protect the fifo buffer
+ *
+ * Do NOT pass the kfifo to kfifo_free() after use ! Simply free the
+ * struct kfifo with kfree().
+ */
+struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
+                        int gfp_mask, spinlock_t *lock)
+{
+       struct kfifo *fifo;
+
+       /* size must be a power of 2 */
+       BUG_ON(size & (size - 1));
+
+       fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
+       if (!fifo)
+               return ERR_PTR(-ENOMEM);
+
+       fifo->buffer = buffer;
+       fifo->size = size;
+       fifo->in = fifo->out = 0;
+       fifo->lock = lock;
+
+       return fifo;
+}
+EXPORT_SYMBOL(kfifo_init);
+
+/*
+ * kfifo_alloc - allocates a new FIFO and its internal buffer
+ * @size: the size of the internal buffer to be allocated.
+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
+ * @lock: the lock to be used to protect the fifo buffer
+ *
+ * The size will be rounded-up to a power of 2.
+ */
+struct kfifo *kfifo_alloc(unsigned int size, int gfp_mask, spinlock_t *lock)
+{
+       unsigned char *buffer;
+       struct kfifo *ret;
+
+       /*
+        * round up to the next power of 2, since our 'let the indices
+        * wrap' tachnique works only in this case.
+        */
+       if (size & (size - 1)) {
+               BUG_ON(size > 0x80000000);
+               size = roundup_pow_of_two(size);
+       }
+
+       buffer = kmalloc(size, gfp_mask);
+       if (!buffer)
+               return ERR_PTR(-ENOMEM);
+
+       ret = kfifo_init(buffer, size, gfp_mask, lock);
+
+       if (IS_ERR(ret))
+               kfree(buffer);
+
+       return ret;
+}
+EXPORT_SYMBOL(kfifo_alloc);
+
+/*
+ * kfifo_free - frees the FIFO
+ * @fifo: the fifo to be freed.
+ */
+void kfifo_free(struct kfifo *fifo)
+{
+       kfree(fifo->buffer);
+       kfree(fifo);
+}
+EXPORT_SYMBOL(kfifo_free);
+
+/*
+ * __kfifo_put - puts some data into the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ * @buffer: the data to be added.
+ * @len: the length of the data to be added.
+ *
+ * This function copies at most 'len' bytes from the 'buffer' into
+ * the FIFO depending on the free space, and returns the number of
+ * bytes copied.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int __kfifo_put(struct kfifo *fifo,
+                        unsigned char *buffer, unsigned int len)
+{
+       unsigned int l;
+
+       len = min(len, fifo->size - fifo->in + fifo->out);
+
+       /* first put the data starting from fifo->in to buffer end */
+       l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
+       memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
+
+       /* then put the rest (if any) at the beginning of the buffer */
+       memcpy(fifo->buffer, buffer + l, len - l);
+
+       fifo->in += len;
+
+       return len;
+}
+EXPORT_SYMBOL(__kfifo_put);
+
+/*
+ * __kfifo_get - gets some data from the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most 'len' bytes from the FIFO into the
+ * 'buffer' and returns the number of copied bytes.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int __kfifo_get(struct kfifo *fifo,
+                        unsigned char *buffer, unsigned int len)
+{
+       unsigned int l;
+
+       len = min(len, fifo->in - fifo->out);
+
+       /* first get the data from fifo->out until the end of the buffer */
+       l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
+       memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
+
+       /* then get the rest (if any) from the beginning of the buffer */
+       memcpy(buffer + l, fifo->buffer, len - l);
+
+       fifo->out += len;
+
+       return len;
+}
+EXPORT_SYMBOL(__kfifo_get);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
new file mode 100644 (file)
index 0000000..ca4e28b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  Kernel Probes (KProbes)
+ *  kernel/kprobes.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2004
+ *
+ * 2002-Oct    Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel
+ *             Probes initial implementation (includes suggestions from
+ *             Rusty Russell).
+ * 2004-Aug    Updated by Prasanna S Panchamukhi <prasanna@in.ibm.com> with
+ *             hlists and exceptions notifier as suggested by Andi Kleen.
+ * 2004-July   Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
+ *             interface to access function arguments.
+ * 2004-Sep    Prasanna S Panchamukhi <prasanna@in.ibm.com> Changed Kprobes
+ *             exceptions notifier to be first on the priority list.
+ */
+#include <linux/kprobes.h>
+#include <linux/spinlock.h>
+#include <linux/hash.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/cacheflush.h>
+#include <asm/errno.h>
+#include <asm/kdebug.h>
+
+#define KPROBE_HASH_BITS 6
+#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
+
+static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
+
+unsigned int kprobe_cpu = NR_CPUS;
+static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED;
+
+/* Locks kprobe: irqs must be disabled */
+void lock_kprobes(void)
+{
+       spin_lock(&kprobe_lock);
+       kprobe_cpu = smp_processor_id();
+}
+
+void unlock_kprobes(void)
+{
+       kprobe_cpu = NR_CPUS;
+       spin_unlock(&kprobe_lock);
+}
+
+/* You have to be holding the kprobe_lock */
+struct kprobe *get_kprobe(void *addr)
+{
+       struct hlist_head *head;
+       struct hlist_node *node;
+
+       head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
+       hlist_for_each(node, head) {
+               struct kprobe *p = hlist_entry(node, struct kprobe, hlist);
+               if (p->addr == addr)
+                       return p;
+       }
+       return NULL;
+}
+
+int register_kprobe(struct kprobe *p)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&kprobe_lock, flags);
+       INIT_HLIST_NODE(&p->hlist);
+       if (get_kprobe(p->addr)) {
+               ret = -EEXIST;
+               goto out;
+       }
+       hlist_add_head(&p->hlist,
+                      &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
+
+       arch_prepare_kprobe(p);
+       p->opcode = *p->addr;
+       *p->addr = BREAKPOINT_INSTRUCTION;
+       flush_icache_range((unsigned long) p->addr,
+                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+      out:
+       spin_unlock_irqrestore(&kprobe_lock, flags);
+       return ret;
+}
+
+void unregister_kprobe(struct kprobe *p)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&kprobe_lock, flags);
+       *p->addr = p->opcode;
+       hlist_del(&p->hlist);
+       flush_icache_range((unsigned long) p->addr,
+                          (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+       spin_unlock_irqrestore(&kprobe_lock, flags);
+}
+
+static struct notifier_block kprobe_exceptions_nb = {
+       .notifier_call = kprobe_exceptions_notify,
+       .priority = 0x7fffffff /* we need to notified first */
+};
+
+int register_jprobe(struct jprobe *jp)
+{
+       /* Todo: Verify probepoint is a function entry point */
+       jp->kp.pre_handler = setjmp_pre_handler;
+       jp->kp.break_handler = longjmp_break_handler;
+
+       return register_kprobe(&jp->kp);
+}
+
+void unregister_jprobe(struct jprobe *jp)
+{
+       unregister_kprobe(&jp->kp);
+}
+
+static int __init init_kprobes(void)
+{
+       int i, err = 0;
+
+       /* FIXME allocate the probe table, currently defined statically */
+       /* initialize all list heads */
+       for (i = 0; i < KPROBE_TABLE_SIZE; i++)
+               INIT_HLIST_HEAD(&kprobe_table[i]);
+
+       err = register_die_notifier(&kprobe_exceptions_nb);
+       return err;
+}
+
+__initcall(init_kprobes);
+
+EXPORT_SYMBOL_GPL(register_kprobe);
+EXPORT_SYMBOL_GPL(unregister_kprobe);
+EXPORT_SYMBOL_GPL(register_jprobe);
+EXPORT_SYMBOL_GPL(unregister_jprobe);
+EXPORT_SYMBOL_GPL(jprobe_return);
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
new file mode 100644 (file)
index 0000000..31f1a60
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * kernel/ksysfs.c - sysfs attributes in /sys/kernel, which
+ *                  are not related to any other subsystem
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * 
+ * This file is release under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#define KERNEL_ATTR_RO(_name) \
+static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
+
+#define KERNEL_ATTR_RW(_name) \
+static struct subsys_attribute _name##_attr = \
+       __ATTR(_name, 0644, _name##_show, _name##_store)
+
+#ifdef CONFIG_HOTPLUG
+static ssize_t hotplug_seqnum_show(struct subsystem *subsys, char *page)
+{
+       return sprintf(page, "%llu\n", (unsigned long long)hotplug_seqnum);
+}
+KERNEL_ATTR_RO(hotplug_seqnum);
+#endif
+
+static decl_subsys(kernel, NULL, NULL);
+
+static struct attribute * kernel_attrs[] = {
+#ifdef CONFIG_HOTPLUG
+       &hotplug_seqnum_attr.attr,
+#endif
+       NULL
+};
+
+static struct attribute_group kernel_attr_group = {
+       .attrs = kernel_attrs,
+};
+
+static int __init ksysfs_init(void)
+{
+       int error = subsystem_register(&kernel_subsys);
+       if (!error)
+               error = sysfs_create_group(&kernel_subsys.kset.kobj,
+                                          &kernel_attr_group);
+
+       return error;
+}
+
+core_initcall(ksysfs_init);
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
new file mode 100644 (file)
index 0000000..476da1f
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (2004) Linus Torvalds
+ *
+ * Author: Zwane Mwaikambo <zwane@fsmlabs.com>
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/preempt.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+int __lockfunc _spin_trylock(spinlock_t *lock)
+{
+       preempt_disable();
+       if (_raw_spin_trylock(lock))
+               return 1;
+       
+       preempt_enable();
+       return 0;
+}
+EXPORT_SYMBOL(_spin_trylock);
+
+int __lockfunc _write_trylock(rwlock_t *lock)
+{
+       preempt_disable();
+       if (_raw_write_trylock(lock))
+               return 1;
+
+       preempt_enable();
+       return 0;
+}
+EXPORT_SYMBOL(_write_trylock);
+
+#ifdef CONFIG_PREEMPT
+/*
+ * This could be a long-held lock.  If another CPU holds it for a long time,
+ * and that CPU is not asked to reschedule then *this* CPU will spin on the
+ * lock for a long time, even if *this* CPU is asked to reschedule.
+ *
+ * So what we do here, in the slow (contended) path is to spin on the lock by
+ * hand while permitting preemption.
+ *
+ * Called inside preempt_disable().
+ */
+static inline void __preempt_spin_lock(spinlock_t *lock)
+{
+       if (preempt_count() > 1) {
+               _raw_spin_lock(lock);
+               return;
+       }
+
+       do {
+               preempt_enable();
+               while (spin_is_locked(lock))
+                       cpu_relax();
+               preempt_disable();
+       } while (!_raw_spin_trylock(lock));
+}
+
+void __lockfunc _spin_lock(spinlock_t *lock)
+{
+       preempt_disable();
+       if (unlikely(!_raw_spin_trylock(lock)))
+               __preempt_spin_lock(lock);
+}
+
+static inline void __preempt_write_lock(rwlock_t *lock)
+{
+       if (preempt_count() > 1) {
+               _raw_write_lock(lock);
+               return;
+       }
+
+       do {
+               preempt_enable();
+               while (rwlock_is_locked(lock))
+                       cpu_relax();
+               preempt_disable();
+       } while (!_raw_write_trylock(lock));
+}
+
+void __lockfunc _write_lock(rwlock_t *lock)
+{
+       preempt_disable();
+       if (unlikely(!_raw_write_trylock(lock)))
+               __preempt_write_lock(lock);
+}
+#else
+void __lockfunc _spin_lock(spinlock_t *lock)
+{
+       preempt_disable();
+       _raw_spin_lock(lock);
+}
+
+void __lockfunc _write_lock(rwlock_t *lock)
+{
+       preempt_disable();
+       _raw_write_lock(lock);
+}
+#endif
+EXPORT_SYMBOL(_spin_lock);
+EXPORT_SYMBOL(_write_lock);
+
+void __lockfunc _read_lock(rwlock_t *lock)
+{
+       preempt_disable();
+       _raw_read_lock(lock);
+}
+EXPORT_SYMBOL(_read_lock);
+
+void __lockfunc _spin_unlock(spinlock_t *lock)
+{
+       _raw_spin_unlock(lock);
+       preempt_enable();
+}
+EXPORT_SYMBOL(_spin_unlock);
+
+void __lockfunc _write_unlock(rwlock_t *lock)
+{
+       _raw_write_unlock(lock);
+       preempt_enable();
+}
+EXPORT_SYMBOL(_write_unlock);
+
+void __lockfunc _read_unlock(rwlock_t *lock)
+{
+       _raw_read_unlock(lock);
+       preempt_enable();
+}
+EXPORT_SYMBOL(_read_unlock);
+
+unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       preempt_disable();
+       _raw_spin_lock_flags(lock, flags);
+       return flags;
+}
+EXPORT_SYMBOL(_spin_lock_irqsave);
+
+void __lockfunc _spin_lock_irq(spinlock_t *lock)
+{
+       local_irq_disable();
+       preempt_disable();
+       _raw_spin_lock(lock);
+}
+EXPORT_SYMBOL(_spin_lock_irq);
+
+void __lockfunc _spin_lock_bh(spinlock_t *lock)
+{
+       local_bh_disable();
+       preempt_disable();
+       _raw_spin_lock(lock);
+}
+EXPORT_SYMBOL(_spin_lock_bh);
+
+unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       preempt_disable();
+       _raw_read_lock(lock);
+       return flags;
+}
+EXPORT_SYMBOL(_read_lock_irqsave);
+
+void __lockfunc _read_lock_irq(rwlock_t *lock)
+{
+       local_irq_disable();
+       preempt_disable();
+       _raw_read_lock(lock);
+}
+EXPORT_SYMBOL(_read_lock_irq);
+
+void __lockfunc _read_lock_bh(rwlock_t *lock)
+{
+       local_bh_disable();
+       preempt_disable();
+       _raw_read_lock(lock);
+}
+EXPORT_SYMBOL(_read_lock_bh);
+
+unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       preempt_disable();
+       _raw_write_lock(lock);
+       return flags;
+}
+EXPORT_SYMBOL(_write_lock_irqsave);
+
+void __lockfunc _write_lock_irq(rwlock_t *lock)
+{
+       local_irq_disable();
+       preempt_disable();
+       _raw_write_lock(lock);
+}
+EXPORT_SYMBOL(_write_lock_irq);
+
+void __lockfunc _write_lock_bh(rwlock_t *lock)
+{
+       local_bh_disable();
+       preempt_disable();
+       _raw_write_lock(lock);
+}
+EXPORT_SYMBOL(_write_lock_bh);
+
+void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+{
+       _raw_spin_unlock(lock);
+       local_irq_restore(flags);
+       preempt_enable();
+}
+EXPORT_SYMBOL(_spin_unlock_irqrestore);
+
+void __lockfunc _spin_unlock_irq(spinlock_t *lock)
+{
+       _raw_spin_unlock(lock);
+       local_irq_enable();
+       preempt_enable();
+}
+EXPORT_SYMBOL(_spin_unlock_irq);
+
+void __lockfunc _spin_unlock_bh(spinlock_t *lock)
+{
+       _raw_spin_unlock(lock);
+       preempt_enable();
+       local_bh_enable();
+}
+EXPORT_SYMBOL(_spin_unlock_bh);
+
+void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+{
+       _raw_read_unlock(lock);
+       local_irq_restore(flags);
+       preempt_enable();
+}
+EXPORT_SYMBOL(_read_unlock_irqrestore);
+
+void __lockfunc _read_unlock_irq(rwlock_t *lock)
+{
+       _raw_read_unlock(lock);
+       local_irq_enable();
+       preempt_enable();
+}
+EXPORT_SYMBOL(_read_unlock_irq);
+
+void __lockfunc _read_unlock_bh(rwlock_t *lock)
+{
+       _raw_read_unlock(lock);
+       preempt_enable();
+       local_bh_enable();
+}
+EXPORT_SYMBOL(_read_unlock_bh);
+
+void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
+{
+       _raw_write_unlock(lock);
+       local_irq_restore(flags);
+       preempt_enable();
+}
+EXPORT_SYMBOL(_write_unlock_irqrestore);
+
+void __lockfunc _write_unlock_irq(rwlock_t *lock)
+{
+       _raw_write_unlock(lock);
+       local_irq_enable();
+       preempt_enable();
+}
+EXPORT_SYMBOL(_write_unlock_irq);
+
+void __lockfunc _write_unlock_bh(rwlock_t *lock)
+{
+       _raw_write_unlock(lock);
+       preempt_enable();
+       local_bh_enable();
+}
+EXPORT_SYMBOL(_write_unlock_bh);
+
+int __lockfunc _spin_trylock_bh(spinlock_t *lock)
+{
+       local_bh_disable();
+       preempt_disable();
+       if (_raw_spin_trylock(lock))
+               return 1;
+
+       preempt_enable();
+       local_bh_enable();
+       return 0;
+}
+EXPORT_SYMBOL(_spin_trylock_bh);
+
+int in_lock_functions(unsigned long addr)
+{
+       /* Linker adds these: start and end of __lockfunc functions */
+       extern char __lock_text_start[], __lock_text_end[];
+
+       return addr >= (unsigned long)__lock_text_start
+       && addr < (unsigned long)__lock_text_end;
+}
+EXPORT_SYMBOL(in_lock_functions);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
new file mode 100644 (file)
index 0000000..9f36b40
--- /dev/null
@@ -0,0 +1,84 @@
+
+#include <linux/linkage.h>
+#include <linux/errno.h>
+
+#include <asm/unistd.h>
+
+/*
+ * Non-implemented system calls get redirected here.
+ */
+asmlinkage long sys_ni_syscall(void)
+{
+       return -ENOSYS;
+}
+
+cond_syscall(sys_nfsservctl)
+cond_syscall(sys_quotactl)
+cond_syscall(sys_acct)
+cond_syscall(sys_lookup_dcookie)
+cond_syscall(sys_swapon)
+cond_syscall(sys_swapoff)
+cond_syscall(sys_init_module)
+cond_syscall(sys_delete_module)
+cond_syscall(sys_socketpair)
+cond_syscall(sys_bind)
+cond_syscall(sys_listen)
+cond_syscall(sys_accept)
+cond_syscall(sys_connect)
+cond_syscall(sys_getsockname)
+cond_syscall(sys_getpeername)
+cond_syscall(sys_sendto)
+cond_syscall(sys_send)
+cond_syscall(sys_recvfrom)
+cond_syscall(sys_recv)
+cond_syscall(sys_socket)
+cond_syscall(sys_setsockopt)
+cond_syscall(sys_getsockopt)
+cond_syscall(sys_shutdown)
+cond_syscall(sys_sendmsg)
+cond_syscall(sys_recvmsg)
+cond_syscall(sys_socketcall)
+cond_syscall(sys_futex)
+cond_syscall(compat_sys_futex)
+cond_syscall(sys_epoll_create)
+cond_syscall(sys_epoll_ctl)
+cond_syscall(sys_epoll_wait)
+cond_syscall(sys_semget)
+cond_syscall(sys_semop)
+cond_syscall(sys_semtimedop)
+cond_syscall(sys_semctl)
+cond_syscall(sys_msgget)
+cond_syscall(sys_msgsnd)
+cond_syscall(sys_msgrcv)
+cond_syscall(sys_msgctl)
+cond_syscall(sys_shmget)
+cond_syscall(sys_shmdt)
+cond_syscall(sys_shmctl)
+cond_syscall(sys_mq_open)
+cond_syscall(sys_mq_unlink)
+cond_syscall(sys_mq_timedsend)
+cond_syscall(sys_mq_timedreceive)
+cond_syscall(sys_mq_notify)
+cond_syscall(sys_mq_getsetattr)
+cond_syscall(compat_sys_mq_open)
+cond_syscall(compat_sys_mq_timedsend)
+cond_syscall(compat_sys_mq_timedreceive)
+cond_syscall(compat_sys_mq_notify)
+cond_syscall(compat_sys_mq_getsetattr)
+cond_syscall(sys_mbind)
+cond_syscall(sys_get_mempolicy)
+cond_syscall(sys_set_mempolicy)
+cond_syscall(compat_sys_mbind)
+cond_syscall(compat_sys_get_mempolicy)
+cond_syscall(compat_sys_set_mempolicy)
+cond_syscall(sys_add_key)
+cond_syscall(sys_request_key)
+cond_syscall(sys_keyctl)
+cond_syscall(compat_sys_keyctl)
+cond_syscall(compat_sys_socketcall)
+
+/* arch-specific weak syscall entries */
+cond_syscall(sys_pciconfig_read)
+cond_syscall(sys_pciconfig_write)
+cond_syscall(sys_pciconfig_iobase)
+
diff --git a/kernel/wait.c b/kernel/wait.c
new file mode 100644 (file)
index 0000000..791681c
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Generic waiting primitives.
+ *
+ * (C) 2004 William Irwin, Oracle
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <linux/hash.h>
+
+void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+       unsigned long flags;
+
+       wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+       spin_lock_irqsave(&q->lock, flags);
+       __add_wait_queue(q, wait);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(add_wait_queue);
+
+void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
+{
+       unsigned long flags;
+
+       wait->flags |= WQ_FLAG_EXCLUSIVE;
+       spin_lock_irqsave(&q->lock, flags);
+       __add_wait_queue_tail(q, wait);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(add_wait_queue_exclusive);
+
+void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->lock, flags);
+       __remove_wait_queue(q, wait);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(remove_wait_queue);
+
+
+/*
+ * Note: we use "set_current_state()" _after_ the wait-queue add,
+ * because we need a memory barrier there on SMP, so that any
+ * wake-function that tests for the wait-queue being active
+ * will be guaranteed to see waitqueue addition _or_ subsequent
+ * tests in this thread will see the wakeup having taken place.
+ *
+ * The spin_unlock() itself is semi-permeable and only protects
+ * one way (it only protects stuff inside the critical region and
+ * stops them from bleeding out - it would still allow subsequent
+ * loads to move into the the critical region).
+ */
+void fastcall
+prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+       unsigned long flags;
+
+       wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+       spin_lock_irqsave(&q->lock, flags);
+       if (list_empty(&wait->task_list))
+               __add_wait_queue(q, wait);
+       /*
+        * don't alter the task state if this is just going to
+        * queue an async wait queue callback
+        */
+       if (is_sync_wait(wait))
+               set_current_state(state);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(prepare_to_wait);
+
+void fastcall
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+       unsigned long flags;
+
+       wait->flags |= WQ_FLAG_EXCLUSIVE;
+       spin_lock_irqsave(&q->lock, flags);
+       if (list_empty(&wait->task_list))
+               __add_wait_queue_tail(q, wait);
+       /*
+        * don't alter the task state if this is just going to
+        * queue an async wait queue callback
+        */
+       if (is_sync_wait(wait))
+               set_current_state(state);
+       spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(prepare_to_wait_exclusive);
+
+void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+       unsigned long flags;
+
+       __set_current_state(TASK_RUNNING);
+       /*
+        * We can check for list emptiness outside the lock
+        * IFF:
+        *  - we use the "careful" check that verifies both
+        *    the next and prev pointers, so that there cannot
+        *    be any half-pending updates in progress on other
+        *    CPU's that we haven't seen yet (and that might
+        *    still change the stack area.
+        * and
+        *  - all other users take the lock (ie we can only
+        *    have _one_ other CPU that looks at or modifies
+        *    the list).
+        */
+       if (!list_empty_careful(&wait->task_list)) {
+               spin_lock_irqsave(&q->lock, flags);
+               list_del_init(&wait->task_list);
+               spin_unlock_irqrestore(&q->lock, flags);
+       }
+}
+EXPORT_SYMBOL(finish_wait);
+
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       int ret = default_wake_function(wait, mode, sync, key);
+
+       if (ret)
+               list_del_init(&wait->task_list);
+       return ret;
+}
+EXPORT_SYMBOL(autoremove_wake_function);
+
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
+{
+       struct wait_bit_key *key = arg;
+       struct wait_bit_queue *wait_bit
+               = container_of(wait, struct wait_bit_queue, wait);
+
+       if (wait_bit->key.flags != key->flags ||
+                       wait_bit->key.bit_nr != key->bit_nr ||
+                       test_bit(key->bit_nr, key->flags))
+               return 0;
+       else
+               return autoremove_wake_function(wait, mode, sync, key);
+}
+EXPORT_SYMBOL(wake_bit_function);
+
+/*
+ * To allow interruptible waiting and asynchronous (i.e. nonblocking)
+ * waiting, the actions of __wait_on_bit() and __wait_on_bit_lock() are
+ * permitted return codes. Nonzero return codes halt waiting and return.
+ */
+int __sched fastcall
+__wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q,
+                       int (*action)(void *), unsigned mode)
+{
+       int ret = 0;
+
+       do {
+               prepare_to_wait(wq, &q->wait, mode);
+               if (test_bit(q->key.bit_nr, q->key.flags))
+                       ret = (*action)(q->key.flags);
+       } while (test_bit(q->key.bit_nr, q->key.flags) && !ret);
+       finish_wait(wq, &q->wait);
+       return ret;
+}
+EXPORT_SYMBOL(__wait_on_bit);
+
+int __sched fastcall out_of_line_wait_on_bit(void *word, int bit,
+                                       int (*action)(void *), unsigned mode)
+{
+       wait_queue_head_t *wq = bit_waitqueue(word, bit);
+       DEFINE_WAIT_BIT(wait, word, bit);
+
+       return __wait_on_bit(wq, &wait, action, mode);
+}
+EXPORT_SYMBOL(out_of_line_wait_on_bit);
+
+int __sched fastcall
+__wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
+                       int (*action)(void *), unsigned mode)
+{
+       int ret = 0;
+
+       do {
+               prepare_to_wait_exclusive(wq, &q->wait, mode);
+               if (test_bit(q->key.bit_nr, q->key.flags)) {
+                       if ((ret = (*action)(q->key.flags)))
+                               break;
+               }
+       } while (test_and_set_bit(q->key.bit_nr, q->key.flags));
+       finish_wait(wq, &q->wait);
+       return ret;
+}
+EXPORT_SYMBOL(__wait_on_bit_lock);
+
+int __sched fastcall out_of_line_wait_on_bit_lock(void *word, int bit,
+                                       int (*action)(void *), unsigned mode)
+{
+       wait_queue_head_t *wq = bit_waitqueue(word, bit);
+       DEFINE_WAIT_BIT(wait, word, bit);
+
+       return __wait_on_bit_lock(wq, &wait, action, mode);
+}
+EXPORT_SYMBOL(out_of_line_wait_on_bit_lock);
+
+void fastcall __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
+{
+       struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
+       if (waitqueue_active(wq))
+               __wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, &key);
+}
+EXPORT_SYMBOL(__wake_up_bit);
+
+/**
+ * wake_up_bit - wake up a waiter on a bit
+ * @word: the word being waited on, a kernel virtual address
+ * @bit: the bit of the word being waited on
+ *
+ * There is a standard hashed waitqueue table for generic use. This
+ * is the part of the hashtable's accessor API that wakes up waiters
+ * on a bit. For instance, if one were to have waiters on a bitflag,
+ * one would call wake_up_bit() after clearing the bit.
+ *
+ * In order for this to function properly, as it uses waitqueue_active()
+ * internally, some kind of memory barrier must be done prior to calling
+ * this. Typically, this will be smp_mb__after_clear_bit(), but in some
+ * cases where bitflags are manipulated non-atomically under a lock, one
+ * may need to use a less regular barrier, such fs/inode.c's smp_mb(),
+ * because spin_unlock() does not guarantee a memory barrier.
+ */
+void fastcall wake_up_bit(void *word, int bit)
+{
+       __wake_up_bit(bit_waitqueue(word, bit), word, bit);
+}
+EXPORT_SYMBOL(wake_up_bit);
+
+fastcall wait_queue_head_t *bit_waitqueue(void *word, int bit)
+{
+       const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+       const struct zone *zone = page_zone(virt_to_page(word));
+       unsigned long val = (unsigned long)word << shift | bit;
+
+       return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
+}
+EXPORT_SYMBOL(bit_waitqueue);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
new file mode 100644 (file)
index 0000000..cd5d859
--- /dev/null
@@ -0,0 +1,100 @@
+
+config DEBUG_KERNEL
+       bool "Kernel debugging"
+       depends on (ALPHA || ARM || CRIS || H8300 || X86 || IA64 || M68K || M68KNOMMU || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SUPERH || SUPERH64 || SPARC32 || SPARC64 || USERMODE || V850 || X86_64)
+       help
+         Say Y here if you are developing drivers or trying to debug and
+         identify kernel problems.
+
+config MAGIC_SYSRQ
+       bool "Magic SysRq key"
+       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SUPERH || SUPERH64 || SPARC32 || SPARC64 || X86_64)
+       help
+         If you say Y here, you will have some control over the system even
+         if the system crashes for example during kernel debugging (e.g., you
+         will be able to flush the buffer cache to disk, reboot the system
+         immediately or dump some status information). This is accomplished
+         by pressing various keys while holding SysRq (Alt+PrintScreen). It
+         also works on a serial console (on PC hardware at least), if you
+         send a BREAK and then within 5 seconds a command keypress. The
+         keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+         unless you really know what this hack does.
+
+config MAGIC_SYSRQ
+       bool "Magic SysRq key"
+       depends on DEBUG_KERNEL && (H8300 || M68KNOMMU || V850)
+       depends (USERMODE && MCONSOLE)
+       help
+         Enables console device to interpret special characters as
+         commands to dump state information.
+
+config DEBUG_SLAB
+       bool "Debug memory allocations"
+       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || SPARC32 || SPARC64 || USERMODE || X86_64)
+       help
+         Say Y here to have the kernel do limited verification on memory
+         allocation as well as poisoning memory on free to catch use of freed
+         memory.
+
+config DEBUG_SPINLOCK
+       bool "Spinlock debugging"
+       depends on DEBUG_KERNEL && (ALPHA || ARM || X86 || IA64 || MIPS || PPC32 || (SUPERH && !SUPERH64) || SPARC32 || SPARC64 || USERMODE || X86_64)
+       help
+         Say Y here and build SMP to catch missing spinlock initialization
+         and certain other kinds of spinlock errors commonly made.  This is
+         best used in conjunction with the NMI watchdog so that spinlock
+         deadlocks are also debuggable.
+
+config DEBUG_SPINLOCK_SLEEP
+       bool "Sleep-inside-spinlock checking"
+       depends on DEBUG_KERNEL && (X86 || IA64 || MIPS || PPC32 || PPC64 || ARCH_S390 || SPARC32 || SPARC64)
+       help
+         If you say Y here, various routines which may sleep will become very
+         noisy if they are called with a spinlock held.
+
+config DEBUG_HIGHMEM
+       bool "Highmem debugging"
+       depends on DEBUG_KERNEL && HIGHMEM && (X86 || PPC32 || MIPS || SPARC32)
+       help
+         This options enables addition error checking for high memory systems.
+         Disable for production systems.
+
+config DEBUG_BUGVERBOSE
+       bool "Verbose BUG() reporting (adds 70K)"
+       depends on DEBUG_KERNEL && (ARM || ARM26 || M68K || SPARC32 || SPARC64)
+       help
+         Say Y here to make BUG() panics output the file name and line number
+         of the BUG call as well as the EIP and oops trace.  This aids
+         debugging but costs about 70-100K of memory.
+
+config DEBUG_INFO
+       bool "Compile the kernel with debug info"
+       depends on DEBUG_KERNEL && (ALPHA || CRIS || X86 || IA64 || M68K || MIPS || PARISC || PPC32 || PPC64 || ARCH_S390 || (SUPERH && !SUPERH64) || SPARC64 || V850 || X86_64)
+       help
+          If you say Y here the resulting kernel image will include
+         debugging info resulting in a larger kernel image.
+         Say Y here only if you plan to use gdb to debug the kernel.
+         If you don't debug the kernel, you can say N.
+
+config DEBUG_INFO
+       bool "Enable kernel debugging symbols"
+       depends on DEBUG_KERNEL && USERMODE
+       help
+        When this is enabled, the User-Mode Linux binary will include
+        debugging symbols.  This enlarges the binary by a few megabytes,
+        but aids in tracking down kernel problems in UML.  It is required
+        if you intend to do any kernel development.
+
+        If you're truly short on disk space or don't expect to report any
+        bugs back to the UML developers, say N, otherwise say Y.
+
+if !X86_64
+config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       depends on X86 || CRIS || M68KNOMMU || PARISC
+       help
+         If you say Y here the resulting kernel image will be slightly larger
+         and slower, but it will give very useful debugging information.
+         If you don't debug the kernel, you can say N, but we may not be able
+         to solve problems without frame pointers.
+endif
diff --git a/lib/iomap.c b/lib/iomap.c
new file mode 100644 (file)
index 0000000..d30ff1a
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Implement the default iomap interfaces
+ */
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+/*
+ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
+ * access or a MMIO access, these functions don't care. The info is
+ * encoded in the hardware mapping set up by the mapping functions
+ * (or the cookie itself, depending on implementation and hw).
+ *
+ * The generic routines don't assume any hardware mappings, and just
+ * encode the PIO/MMIO as part of the cookie. They coldly assume that
+ * the MMIO IO mappings are not in the low address range.
+ *
+ * Architectures for which this is not true can't use this generic
+ * implementation and should do their own copy.
+ *
+ * We encode the physical PIO addresses (0-0xffff) into the
+ * pointer by offsetting them with a constant (0x10000) and
+ * assuming that all the low addresses are always PIO. That means
+ * we can do some sanity checks on the low bits, and don't
+ * need to just take things for granted.
+ */
+#define PIO_OFFSET     0x10000UL
+#define PIO_MASK       0x0ffffUL
+#define PIO_RESERVED   0x40000UL
+
+/*
+ * Ugly macros are a way of life.
+ */
+#define VERIFY_PIO(port) BUG_ON((port & ~PIO_MASK) != PIO_OFFSET)
+
+#define IO_COND(addr, is_pio, is_mmio) do {                    \
+       unsigned long port = (unsigned long __force)addr;       \
+       if (port < PIO_RESERVED) {                              \
+               VERIFY_PIO(port);                               \
+               port &= PIO_MASK;                               \
+               is_pio;                                         \
+       } else {                                                \
+               is_mmio;                                        \
+       }                                                       \
+} while (0)
+
+unsigned int fastcall ioread8(void __iomem *addr)
+{
+       IO_COND(addr, return inb(port), return readb(addr));
+}
+unsigned int fastcall ioread16(void __iomem *addr)
+{
+       IO_COND(addr, return inw(port), return readw(addr));
+}
+unsigned int fastcall ioread32(void __iomem *addr)
+{
+       IO_COND(addr, return inl(port), return readl(addr));
+}
+EXPORT_SYMBOL(ioread8);
+EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread32);
+
+void fastcall iowrite8(u8 val, void __iomem *addr)
+{
+       IO_COND(addr, outb(val,port), writeb(val, addr));
+}
+void fastcall iowrite16(u16 val, void __iomem *addr)
+{
+       IO_COND(addr, outw(val,port), writew(val, addr));
+}
+void fastcall iowrite32(u32 val, void __iomem *addr)
+{
+       IO_COND(addr, outl(val,port), writel(val, addr));
+}
+EXPORT_SYMBOL(iowrite8);
+EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite32);
+
+/*
+ * These are the "repeat MMIO read/write" functions.
+ * Note the "__raw" accesses, since we don't want to
+ * convert to CPU byte order. We write in "IO byte
+ * order" (we also don't have IO barriers).
+ */
+static inline void mmio_insb(void __iomem *addr, u8 *dst, int count)
+{
+       while (--count >= 0) {
+               u8 data = __raw_readb(addr);
+               *dst = data;
+               dst++;
+       }
+}
+static inline void mmio_insw(void __iomem *addr, u16 *dst, int count)
+{
+       while (--count >= 0) {
+               u16 data = __raw_readw(addr);
+               *dst = data;
+               dst++;
+       }
+}
+static inline void mmio_insl(void __iomem *addr, u32 *dst, int count)
+{
+       while (--count >= 0) {
+               u32 data = __raw_readl(addr);
+               *dst = data;
+               dst++;
+       }
+}
+
+static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count)
+{
+       while (--count >= 0) {
+               __raw_writeb(*src, addr);
+               src++;
+       }
+}
+static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count)
+{
+       while (--count >= 0) {
+               __raw_writew(*src, addr);
+               src++;
+       }
+}
+static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count)
+{
+       while (--count >= 0) {
+               __raw_writel(*src, addr);
+               src++;
+       }
+}
+
+void fastcall ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       IO_COND(addr, insb(port,dst,count), mmio_insb(addr, dst, count));
+}
+void fastcall ioread16_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       IO_COND(addr, insw(port,dst,count), mmio_insw(addr, dst, count));
+}
+void fastcall ioread32_rep(void __iomem *addr, void *dst, unsigned long count)
+{
+       IO_COND(addr, insl(port,dst,count), mmio_insl(addr, dst, count));
+}
+EXPORT_SYMBOL(ioread8_rep);
+EXPORT_SYMBOL(ioread16_rep);
+EXPORT_SYMBOL(ioread32_rep);
+
+void fastcall iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       IO_COND(addr, outsb(port, src, count), mmio_outsb(addr, src, count));
+}
+void fastcall iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       IO_COND(addr, outsw(port, src, count), mmio_outsw(addr, src, count));
+}
+void fastcall iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+       IO_COND(addr, outsl(port, src,count), mmio_outsl(addr, src, count));
+}
+EXPORT_SYMBOL(iowrite8_rep);
+EXPORT_SYMBOL(iowrite16_rep);
+EXPORT_SYMBOL(iowrite32_rep);
+
+/* Create a virtual mapping cookie for an IO port range */
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+       if (port > PIO_MASK)
+               return NULL;
+       return (void __iomem *) (unsigned long) (port + PIO_OFFSET);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+       /* Nothing to do */
+}
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
+
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len || !start)
+               return NULL;
+       if (maxlen && len > maxlen)
+               len = maxlen;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+               return ioremap_nocache(start, len);
+       }
+       /* What? */
+       return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+{
+       IO_COND(addr, /* nothing */, iounmap(addr));
+}
+EXPORT_SYMBOL(pci_iomap);
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c
new file mode 100644 (file)
index 0000000..48dc05a
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * lib/kernel_lock.c
+ *
+ * This is the traditional BKL - big kernel lock. Largely
+ * relegated to obsolescense, but used by various less
+ * important (or lazy) subsystems.
+ */
+#include <linux/smp_lock.h>
+#include <linux/module.h>
+
+/*
+ * The 'big kernel lock'
+ *
+ * This spinlock is taken and released recursively by lock_kernel()
+ * and unlock_kernel().  It is transparently dropped and reaquired
+ * over schedule().  It is used to protect legacy code that hasn't
+ * been migrated to a proper locking design yet.
+ *
+ * Don't use in new code.
+ */
+static spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ * Acquire/release the underlying lock from the scheduler.
+ *
+ * This is called with preemption disabled, and should
+ * return an error value if it cannot get the lock and
+ * TIF_NEED_RESCHED gets set.
+ *
+ * If it successfully gets the lock, it should increment
+ * the preemption count like any spinlock does.
+ *
+ * (This works on UP too - _raw_spin_trylock will never
+ * return false in that case)
+ */
+int __lockfunc get_kernel_lock(void)
+{
+       while (!_raw_spin_trylock(&kernel_flag)) {
+               if (test_thread_flag(TIF_NEED_RESCHED))
+                       return -EAGAIN;
+               cpu_relax();
+       }
+       preempt_disable();
+       return 0;
+}
+
+void __lockfunc put_kernel_lock(void)
+{
+       _raw_spin_unlock(&kernel_flag);
+       preempt_enable_no_resched();
+}
+
+/*
+ * These are the BKL spinlocks - we try to be polite about preemption. 
+ * If SMP is not on (ie UP preemption), this all goes away because the
+ * _raw_spin_trylock() will always succeed.
+ */
+#ifdef CONFIG_PREEMPT
+static inline void __lock_kernel(void)
+{
+       preempt_disable();
+       if (unlikely(!_raw_spin_trylock(&kernel_flag))) {
+               /*
+                * If preemption was disabled even before this
+                * was called, there's nothing we can be polite
+                * about - just spin.
+                */
+               if (preempt_count() > 1) {
+                       _raw_spin_lock(&kernel_flag);
+                       return;
+               }
+
+               /*
+                * Otherwise, let's wait for the kernel lock
+                * with preemption enabled..
+                */
+               do {
+                       preempt_enable();
+                       while (spin_is_locked(&kernel_flag))
+                               cpu_relax();
+                       preempt_disable();
+               } while (!_raw_spin_trylock(&kernel_flag));
+       }
+}
+
+#else
+
+/*
+ * Non-preemption case - just get the spinlock
+ */
+static inline void __lock_kernel(void)
+{
+       _raw_spin_lock(&kernel_flag);
+}
+#endif
+
+static inline void __unlock_kernel(void)
+{
+       _raw_spin_unlock(&kernel_flag);
+       preempt_enable();
+}
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously, so we only need to
+ * worry about other CPU's.
+ */
+void __lockfunc lock_kernel(void)
+{
+       int depth = current->lock_depth+1;
+       if (likely(!depth))
+               __lock_kernel();
+       current->lock_depth = depth;
+}
+
+void __lockfunc unlock_kernel(void)
+{
+       BUG_ON(current->lock_depth < 0);
+       if (likely(--current->lock_depth < 0))
+               __unlock_kernel();
+}
+
+EXPORT_SYMBOL(lock_kernel);
+EXPORT_SYMBOL(unlock_kernel);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
new file mode 100644 (file)
index 0000000..5c78b21
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * kernel userspace event delivery
+ *
+ * Copyright (C) 2004 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004 Novell, Inc.  All rights reserved.
+ * Copyright (C) 2004 IBM, Inc. All rights reserved.
+ *
+ * Licensed under the GNU GPL v2.
+ *
+ * Authors:
+ *     Robert Love             <rml@novell.com>
+ *     Kay Sievers             <kay.sievers@vrfy.org>
+ *     Arjan van de Ven        <arjanv@redhat.com>
+ *     Greg Kroah-Hartman      <greg@kroah.com>
+ */
+
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/string.h>
+#include <linux/kobject_uevent.h>
+#include <linux/kobject.h>
+#include <net/sock.h>
+
+#define BUFFER_SIZE    1024    /* buffer for the hotplug env */
+#define NUM_ENVP       32      /* number of env pointers */
+
+#if defined(CONFIG_KOBJECT_UEVENT) || defined(CONFIG_HOTPLUG)
+static char *action_to_string(enum kobject_action action)
+{
+       switch (action) {
+       case KOBJ_ADD:
+               return "add";
+       case KOBJ_REMOVE:
+               return "remove";
+       case KOBJ_CHANGE:
+               return "change";
+       case KOBJ_MOUNT:
+               return "mount";
+       case KOBJ_UMOUNT:
+               return "umount";
+       case KOBJ_OFFLINE:
+               return "offline";
+       case KOBJ_ONLINE:
+               return "online";
+       default:
+               return NULL;
+       }
+}
+#endif
+
+#ifdef CONFIG_KOBJECT_UEVENT
+static struct sock *uevent_sock;
+
+/**
+ * send_uevent - notify userspace by sending event trough netlink socket
+ *
+ * @signal: signal name
+ * @obj: object path (kobject)
+ * @envp: possible hotplug environment to pass with the message
+ * @gfp_mask:
+ */
+static int send_uevent(const char *signal, const char *obj,
+                      char **envp, int gfp_mask)
+{
+       struct sk_buff *skb;
+       char *pos;
+       int len;
+
+       if (!uevent_sock)
+               return -EIO;
+
+       len = strlen(signal) + 1;
+       len += strlen(obj) + 1;
+
+       /* allocate buffer with the maximum possible message size */
+       skb = alloc_skb(len + BUFFER_SIZE, gfp_mask);
+       if (!skb)
+               return -ENOMEM;
+
+       pos = skb_put(skb, len);
+       sprintf(pos, "%s@%s", signal, obj);
+
+       /* copy the environment key by key to our continuous buffer */
+       if (envp) {
+               int i;
+
+               for (i = 2; envp[i]; i++) {
+                       len = strlen(envp[i]) + 1;
+                       pos = skb_put(skb, len);
+                       strcpy(pos, envp[i]);
+               }
+       }
+
+       return netlink_broadcast(uevent_sock, skb, 0, 1, gfp_mask);
+}
+
+static int do_kobject_uevent(struct kobject *kobj, enum kobject_action action, 
+                            struct attribute *attr, int gfp_mask)
+{
+       char *path;
+       char *attrpath;
+       char *signal;
+       int len;
+       int rc = -ENOMEM;
+
+       path = kobject_get_path(kobj, gfp_mask);
+       if (!path)
+               return -ENOMEM;
+
+       signal = action_to_string(action);
+       if (!signal)
+               return -EINVAL;
+
+       if (attr) {
+               len = strlen(path);
+               len += strlen(attr->name) + 2;
+               attrpath = kmalloc(len, gfp_mask);
+               if (!attrpath)
+                       goto exit;
+               sprintf(attrpath, "%s/%s", path, attr->name);
+               rc = send_uevent(signal, attrpath, NULL, gfp_mask);
+               kfree(attrpath);
+       } else
+               rc = send_uevent(signal, path, NULL, gfp_mask);
+
+exit:
+       kfree(path);
+       return rc;
+}
+
+/**
+ * kobject_uevent - notify userspace by sending event through netlink socket
+ * 
+ * @signal: signal name
+ * @kobj: struct kobject that the event is happening to
+ * @attr: optional struct attribute the event belongs to
+ */
+int kobject_uevent(struct kobject *kobj, enum kobject_action action,
+                  struct attribute *attr)
+{
+       return do_kobject_uevent(kobj, action, attr, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(kobject_uevent);
+
+int kobject_uevent_atomic(struct kobject *kobj, enum kobject_action action,
+                         struct attribute *attr)
+{
+       return do_kobject_uevent(kobj, action, attr, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
+
+static int __init kobject_uevent_init(void)
+{
+       uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL);
+
+       if (!uevent_sock) {
+               printk(KERN_ERR
+                      "kobject_uevent: unable to create netlink socket!\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+postcore_initcall(kobject_uevent_init);
+
+#else
+static inline int send_uevent(const char *signal, const char *obj,
+                             char **envp, int gfp_mask)
+{
+       return 0;
+}
+
+#endif /* CONFIG_KOBJECT_UEVENT */
+
+
+#ifdef CONFIG_HOTPLUG
+char hotplug_path[HOTPLUG_PATH_LEN] = "/sbin/hotplug";
+u64 hotplug_seqnum;
+static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * kobject_hotplug - notify userspace by executing /sbin/hotplug
+ *
+ * @action: action that is happening (usually "ADD" or "REMOVE")
+ * @kobj: struct kobject that the action is happening to
+ */
+void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
+{
+       char *argv [3];
+       char **envp = NULL;
+       char *buffer = NULL;
+       char *seq_buff;
+       char *scratch;
+       int i = 0;
+       int retval;
+       char *kobj_path = NULL;
+       char *name = NULL;
+       char *action_string;
+       u64 seq;
+       struct kobject *top_kobj = kobj;
+       struct kset *kset;
+       static struct kset_hotplug_ops null_hotplug_ops;
+       struct kset_hotplug_ops *hotplug_ops = &null_hotplug_ops;
+
+       /* If this kobj does not belong to a kset,
+          try to find a parent that does. */
+       if (!top_kobj->kset && top_kobj->parent) {
+               do {
+                       top_kobj = top_kobj->parent;
+               } while (!top_kobj->kset && top_kobj->parent);
+       }
+
+       if (top_kobj->kset)
+               kset = top_kobj->kset;
+       else
+               return;
+
+       if (kset->hotplug_ops)
+               hotplug_ops = kset->hotplug_ops;
+
+       /* If the kset has a filter operation, call it.
+          Skip the event, if the filter returns zero. */
+       if (hotplug_ops->filter) {
+               if (!hotplug_ops->filter(kset, kobj))
+                       return;
+       }
+
+       pr_debug ("%s\n", __FUNCTION__);
+
+       action_string = action_to_string(action);
+       if (!action_string)
+               return;
+
+       envp = kmalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
+       if (!envp)
+               return;
+       memset (envp, 0x00, NUM_ENVP * sizeof (char *));
+
+       buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
+       if (!buffer)
+               goto exit;
+
+       if (hotplug_ops->name)
+               name = hotplug_ops->name(kset, kobj);
+       if (name == NULL)
+               name = kset->kobj.name;
+
+       argv [0] = hotplug_path;
+       argv [1] = name;
+       argv [2] = NULL;
+
+       /* minimal command environment */
+       envp [i++] = "HOME=/";
+       envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+       scratch = buffer;
+
+       envp [i++] = scratch;
+       scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
+
+       kobj_path = kobject_get_path(kobj, GFP_KERNEL);
+       if (!kobj_path)
+               goto exit;
+
+       envp [i++] = scratch;
+       scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;
+
+       envp [i++] = scratch;
+       scratch += sprintf(scratch, "SUBSYSTEM=%s", name) + 1;
+
+       /* reserve space for the sequence,
+        * put the real one in after the hotplug call */
+       envp[i++] = seq_buff = scratch;
+       scratch += strlen("SEQNUM=18446744073709551616") + 1;
+
+       if (hotplug_ops->hotplug) {
+               /* have the kset specific function add its stuff */
+               retval = hotplug_ops->hotplug (kset, kobj,
+                                 &envp[i], NUM_ENVP - i, scratch,
+                                 BUFFER_SIZE - (scratch - buffer));
+               if (retval) {
+                       pr_debug ("%s - hotplug() returned %d\n",
+                                 __FUNCTION__, retval);
+                       goto exit;
+               }
+       }
+
+       spin_lock(&sequence_lock);
+       seq = ++hotplug_seqnum;
+       spin_unlock(&sequence_lock);
+       sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
+
+       pr_debug ("%s: %s %s seq=%llu %s %s %s %s %s\n",
+                 __FUNCTION__, argv[0], argv[1], (unsigned long long)seq,
+                 envp[0], envp[1], envp[2], envp[3], envp[4]);
+
+       send_uevent(action_string, kobj_path, envp, GFP_KERNEL);
+
+       if (!hotplug_path[0])
+               goto exit;
+
+       retval = call_usermodehelper (argv[0], argv, envp, 0);
+       if (retval)
+               pr_debug ("%s - call_usermodehelper returned %d\n",
+                         __FUNCTION__, retval);
+
+exit:
+       kfree(kobj_path);
+       kfree(buffer);
+       kfree(envp);
+       return;
+}
+EXPORT_SYMBOL(kobject_hotplug);
+
+/**
+ * add_hotplug_env_var - helper for creating hotplug environment variables
+ * @envp: Pointer to table of environment variables, as passed into
+ * hotplug() method.
+ * @num_envp: Number of environment variable slots available, as
+ * passed into hotplug() method.
+ * @cur_index: Pointer to current index into @envp.  It should be
+ * initialized to 0 before the first call to add_hotplug_env_var(),
+ * and will be incremented on success.
+ * @buffer: Pointer to buffer for environment variables, as passed
+ * into hotplug() method.
+ * @buffer_size: Length of @buffer, as passed into hotplug() method.
+ * @cur_len: Pointer to current length of space used in @buffer.
+ * Should be initialized to 0 before the first call to
+ * add_hotplug_env_var(), and will be incremented on success.
+ * @format: Format for creating environment variable (of the form
+ * "XXX=%x") for snprintf().
+ *
+ * Returns 0 if environment variable was added successfully or -ENOMEM
+ * if no space was available.
+ */
+int add_hotplug_env_var(char **envp, int num_envp, int *cur_index,
+                       char *buffer, int buffer_size, int *cur_len,
+                       const char *format, ...)
+{
+       va_list args;
+
+       /*
+        * We check against num_envp - 1 to make sure there is at
+        * least one slot left after we return, since the hotplug
+        * method needs to set the last slot to NULL.
+        */
+       if (*cur_index >= num_envp - 1)
+               return -ENOMEM;
+
+       envp[*cur_index] = buffer + *cur_len;
+
+       va_start(args, format);
+       *cur_len += vsnprintf(envp[*cur_index],
+                             max(buffer_size - *cur_len, 0),
+                             format, args) + 1;
+       va_end(args);
+
+       if (*cur_len > buffer_size)
+               return -ENOMEM;
+
+       (*cur_index)++;
+       return 0;
+}
+EXPORT_SYMBOL(add_hotplug_env_var);
+
+#endif /* CONFIG_HOTPLUG */
diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile
new file mode 100644 (file)
index 0000000..747a2de
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# This is a modified version of reed solomon lib, 
+#
+
+obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
+
diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c
new file mode 100644 (file)
index 0000000..d401dec
--- /dev/null
@@ -0,0 +1,272 @@
+/* 
+ * lib/reed_solomon/decode_rs.c
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *   
+ * Copyright 2002, Phil Karn, KA9Q
+ * May be used under the terms of the GNU General Public License (GPL)
+ *
+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
+ *
+ * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $
+ *
+ */
+
+/* Generic data width independent code which is included by the 
+ * wrappers.
+ */
+{ 
+       int deg_lambda, el, deg_omega;
+       int i, j, r, k, pad;
+       int nn = rs->nn;
+       int nroots = rs->nroots;
+       int fcr = rs->fcr;
+       int prim = rs->prim;
+       int iprim = rs->iprim;
+       uint16_t *alpha_to = rs->alpha_to;
+       uint16_t *index_of = rs->index_of;
+       uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
+       /* Err+Eras Locator poly and syndrome poly The maximum value
+        * of nroots is 8. So the necessary stack size will be about
+        * 220 bytes max.
+        */
+       uint16_t lambda[nroots + 1], syn[nroots];
+       uint16_t b[nroots + 1], t[nroots + 1], omega[nroots + 1];
+       uint16_t root[nroots], reg[nroots + 1], loc[nroots];
+       int count = 0;
+       uint16_t msk = (uint16_t) rs->nn;
+
+       /* Check length parameter for validity */
+       pad = nn - nroots - len;
+       if (pad < 0 || pad >= nn)
+               return -ERANGE;
+               
+       /* Does the caller provide the syndrome ? */
+       if (s != NULL) 
+               goto decode;
+
+       /* form the syndromes; i.e., evaluate data(x) at roots of
+        * g(x) */
+       for (i = 0; i < nroots; i++)
+               syn[i] = (((uint16_t) data[0]) ^ invmsk) & msk;
+
+       for (j = 1; j < len; j++) {
+               for (i = 0; i < nroots; i++) {
+                       if (syn[i] == 0) {
+                               syn[i] = (((uint16_t) data[j]) ^ 
+                                         invmsk) & msk;
+                       } else {
+                               syn[i] = ((((uint16_t) data[j]) ^
+                                          invmsk) & msk) ^ 
+                                       alpha_to[rs_modnn(rs, index_of[syn[i]] +
+                                                      (fcr + i) * prim)];
+                       }
+               }
+       }
+
+       for (j = 0; j < nroots; j++) {
+               for (i = 0; i < nroots; i++) {
+                       if (syn[i] == 0) {
+                               syn[i] = ((uint16_t) par[j]) & msk;
+                       } else {
+                               syn[i] = (((uint16_t) par[j]) & msk) ^ 
+                                       alpha_to[rs_modnn(rs, index_of[syn[i]] +
+                                                      (fcr+i)*prim)];
+                       }
+               }
+       }
+       s = syn;
+
+       /* Convert syndromes to index form, checking for nonzero condition */
+       syn_error = 0;
+       for (i = 0; i < nroots; i++) {
+               syn_error |= s[i];
+               s[i] = index_of[s[i]];
+       }
+
+       if (!syn_error) {
+               /* if syndrome is zero, data[] is a codeword and there are no
+                * errors to correct. So return data[] unmodified
+                */
+               count = 0;
+               goto finish;
+       }
+
+ decode:
+       memset(&lambda[1], 0, nroots * sizeof(lambda[0]));
+       lambda[0] = 1;
+
+       if (no_eras > 0) {
+               /* Init lambda to be the erasure locator polynomial */
+               lambda[1] = alpha_to[rs_modnn(rs, 
+                                             prim * (nn - 1 - eras_pos[0]))];
+               for (i = 1; i < no_eras; i++) {
+                       u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
+                       for (j = i + 1; j > 0; j--) {
+                               tmp = index_of[lambda[j - 1]];
+                               if (tmp != nn) {
+                                       lambda[j] ^= 
+                                               alpha_to[rs_modnn(rs, u + tmp)];
+                               }
+                       }
+               }
+       }
+
+       for (i = 0; i < nroots + 1; i++)
+               b[i] = index_of[lambda[i]];
+
+       /*
+        * Begin Berlekamp-Massey algorithm to determine error+erasure
+        * locator polynomial
+        */
+       r = no_eras;
+       el = no_eras;
+       while (++r <= nroots) { /* r is the step number */
+               /* Compute discrepancy at the r-th step in poly-form */
+               discr_r = 0;
+               for (i = 0; i < r; i++) {
+                       if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
+                               discr_r ^= 
+                                       alpha_to[rs_modnn(rs, 
+                                                         index_of[lambda[i]] +
+                                                         s[r - i - 1])];
+                       }
+               }
+               discr_r = index_of[discr_r];    /* Index form */
+               if (discr_r == nn) {
+                       /* 2 lines below: B(x) <-- x*B(x) */
+                       memmove (&b[1], b, nroots * sizeof (b[0]));
+                       b[0] = nn;
+               } else {
+                       /* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
+                       t[0] = lambda[0];
+                       for (i = 0; i < nroots; i++) {
+                               if (b[i] != nn) {
+                                       t[i + 1] = lambda[i + 1] ^ 
+                                               alpha_to[rs_modnn(rs, discr_r +
+                                                                 b[i])];
+                               } else
+                                       t[i + 1] = lambda[i + 1];
+                       }
+                       if (2 * el <= r + no_eras - 1) {
+                               el = r + no_eras - el;
+                               /*
+                                * 2 lines below: B(x) <-- inv(discr_r) *
+                                * lambda(x)
+                                */
+                               for (i = 0; i <= nroots; i++) {
+                                       b[i] = (lambda[i] == 0) ? nn :
+                                               rs_modnn(rs, index_of[lambda[i]]
+                                                        - discr_r + nn);
+                               }
+                       } else {
+                               /* 2 lines below: B(x) <-- x*B(x) */
+                               memmove(&b[1], b, nroots * sizeof(b[0]));
+                               b[0] = nn;
+                       }
+                       memcpy(lambda, t, (nroots + 1) * sizeof(t[0]));
+               }
+       }
+
+       /* Convert lambda to index form and compute deg(lambda(x)) */
+       deg_lambda = 0;
+       for (i = 0; i < nroots + 1; i++) {
+               lambda[i] = index_of[lambda[i]];
+               if (lambda[i] != nn)
+                       deg_lambda = i;
+       }
+       /* Find roots of error+erasure locator polynomial by Chien search */
+       memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0]));
+       count = 0;              /* Number of roots of lambda(x) */
+       for (i = 1, k = iprim - 1; i <= nn; i++, k = rs_modnn(rs, k + iprim)) {
+               q = 1;          /* lambda[0] is always 0 */
+               for (j = deg_lambda; j > 0; j--) {
+                       if (reg[j] != nn) {
+                               reg[j] = rs_modnn(rs, reg[j] + j);
+                               q ^= alpha_to[reg[j]];
+                       }
+               }
+               if (q != 0)
+                       continue;       /* Not a root */
+               /* store root (index-form) and error location number */
+               root[count] = i;
+               loc[count] = k;
+               /* If we've already found max possible roots,
+                * abort the search to save time
+                */
+               if (++count == deg_lambda)
+                       break;
+       }
+       if (deg_lambda != count) {
+               /*
+                * deg(lambda) unequal to number of roots => uncorrectable
+                * error detected
+                */
+               count = -1;
+               goto finish;
+       }
+       /*
+        * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
+        * x**nroots). in index form. Also find deg(omega).
+        */
+       deg_omega = deg_lambda - 1;
+       for (i = 0; i <= deg_omega; i++) {
+               tmp = 0;
+               for (j = i; j >= 0; j--) {
+                       if ((s[i - j] != nn) && (lambda[j] != nn))
+                               tmp ^=
+                                   alpha_to[rs_modnn(rs, s[i - j] + lambda[j])];
+               }
+               omega[i] = index_of[tmp];
+       }
+
+       /*
+        * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
+        * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
+        */
+       for (j = count - 1; j >= 0; j--) {
+               num1 = 0;
+               for (i = deg_omega; i >= 0; i--) {
+                       if (omega[i] != nn)
+                               num1 ^= alpha_to[rs_modnn(rs, omega[i] + 
+                                                       i * root[j])];
+               }
+               num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
+               den = 0;
+
+               /* lambda[i+1] for i even is the formal derivative
+                * lambda_pr of lambda[i] */
+               for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) {
+                       if (lambda[i + 1] != nn) {
+                               den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + 
+                                                      i * root[j])];
+                       }
+               }
+               /* Apply error to data */
+               if (num1 != 0 && loc[j] >= pad) {
+                       uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + 
+                                                      index_of[num2] +
+                                                      nn - index_of[den])];
+                       /* Store the error correction pattern, if a
+                        * correction buffer is available */
+                       if (corr) {
+                               corr[j] = cor;
+                       } else {
+                               /* If a data buffer is given and the
+                                * error is inside the message,
+                                * correct it */
+                               if (data && (loc[j] < (nn - nroots)))
+                                       data[loc[j] - pad] ^= cor;
+                       }
+               }
+       }
+
+finish:
+       if (eras_pos != NULL) {
+               for (i = 0; i < count; i++)
+                       eras_pos[i] = loc[i] - pad;
+       }
+       return count;
+
+}
diff --git a/lib/reed_solomon/encode_rs.c b/lib/reed_solomon/encode_rs.c
new file mode 100644 (file)
index 0000000..237bf65
--- /dev/null
@@ -0,0 +1,54 @@
+/* 
+ * lib/reed_solomon/encode_rs.c
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *   
+ * Copyright 2002, Phil Karn, KA9Q
+ * May be used under the terms of the GNU General Public License (GPL)
+ *
+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
+ *
+ * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $
+ *
+ */
+
+/* Generic data width independent code which is included by the 
+ * wrappers.
+ * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par)
+ */
+{
+       int i, j, pad;
+       int nn = rs->nn;
+       int nroots = rs->nroots;
+       uint16_t *alpha_to = rs->alpha_to;
+       uint16_t *index_of = rs->index_of;
+       uint16_t *genpoly = rs->genpoly;
+       uint16_t fb;
+       uint16_t msk = (uint16_t) rs->nn;
+
+       /* Check length parameter for validity */
+       pad = nn - nroots - len;
+       if (pad < 0 || pad >= nn)
+               return -ERANGE;
+
+       for (i = 0; i < len; i++) {
+               fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]];
+               /* feedback term is non-zero */
+               if (fb != nn) { 
+                       for (j = 1; j < nroots; j++) {
+                               par[j] ^= alpha_to[rs_modnn(rs, fb + 
+                                                        genpoly[nroots - j])];
+                       }
+               }
+               /* Shift */
+               memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1));
+               if (fb != nn) {
+                       par[nroots - 1] = alpha_to[rs_modnn(rs, 
+                                                           fb + genpoly[0])];
+               } else {
+                       par[nroots - 1] = 0;
+               }
+       }
+       return 0;
+}
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
new file mode 100644 (file)
index 0000000..87d4259
--- /dev/null
@@ -0,0 +1,335 @@
+/* 
+ * lib/reed_solomon/rslib.c
+ *
+ * Overview:
+ *   Generic Reed Solomon encoder / decoder library
+ *   
+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Reed Solomon code lifted from reed solomon library written by Phil Karn
+ * Copyright 2002 Phil Karn, KA9Q
+ *
+ * $Id: rslib.c,v 1.4 2004/10/05 22:07:53 gleixner Exp $
+ *
+ * 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.
+ *
+ * Description:
+ *     
+ * The generic Reed Solomon library provides runtime configurable
+ * encoding / decoding of RS codes.
+ * Each user must call init_rs to get a pointer to a rs_control
+ * structure for the given rs parameters. This structure is either
+ * generated or a already available matching control structure is used.
+ * If a structure is generated then the polynominal arrays for
+ * fast encoding / decoding are built. This can take some time so
+ * make sure not to call this function from a timecritical path.
+ * Usually a module / driver should initialize the neccecary 
+ * rs_control structure on module / driver init and release it
+ * on exit.
+ * The encoding puts the calculated syndrome into a given syndrom 
+ * buffer. 
+ * The decoding is a two step process. The first step calculates
+ * the syndrome over the received (data + syndrom) and calls the
+ * second stage, which does the decoding / error correction itself.
+ * Many hw encoders provide a syndrom calculation over the received
+ * data + syndrom and can call the second stage directly.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/rslib.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+
+/* This list holds all currently allocated rs control structures */
+static LIST_HEAD (rslist);
+/* Protection for the list */
+static DECLARE_MUTEX(rslistlock);
+
+/** 
+ * rs_init - Initialize a Reed-Solomon codec
+ *
+ * @symsize:   symbol size, bits (1-8)
+ * @gfpoly:    Field generator polynomial coefficients
+ * @fcr:       first root of RS code generator polynomial, index form
+ * @prim:      primitive element to generate polynomial roots
+ * @nroots:    RS code generator polynomial degree (number of roots)
+ *
+ * Allocate a control structure and the polynom arrays for faster
+ * en/decoding. Fill the arrays according to the given parameters
+ */
+static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, 
+                                  int prim, int nroots)
+{
+       struct rs_control *rs;
+       int i, j, sr, root, iprim;
+
+       /* Allocate the control structure */
+       rs = kmalloc(sizeof (struct rs_control), GFP_KERNEL);
+       if (rs == NULL)
+               return NULL;
+
+       INIT_LIST_HEAD(&rs->list);
+
+       rs->mm = symsize;
+       rs->nn = (1 << symsize) - 1;
+       rs->fcr = fcr;
+       rs->prim = prim;
+       rs->nroots = nroots;
+       rs->gfpoly = gfpoly;
+
+       /* Allocate the arrays */
+       rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
+       if (rs->alpha_to == NULL)
+               goto errrs;
+
+       rs->index_of = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
+       if (rs->index_of == NULL)
+               goto erralp;
+
+       rs->genpoly = kmalloc(sizeof(uint16_t) * (rs->nroots + 1), GFP_KERNEL);
+       if(rs->genpoly == NULL)
+               goto erridx;
+
+       /* Generate Galois field lookup tables */
+       rs->index_of[0] = rs->nn;       /* log(zero) = -inf */
+       rs->alpha_to[rs->nn] = 0;       /* alpha**-inf = 0 */
+       sr = 1;
+       for (i = 0; i < rs->nn; i++) {
+               rs->index_of[sr] = i;
+               rs->alpha_to[i] = sr;
+               sr <<= 1;
+               if (sr & (1 << symsize))
+                       sr ^= gfpoly;
+               sr &= rs->nn;
+       }
+       /* If it's not primitive, exit */
+       if(sr != 1)
+               goto errpol;
+
+       /* Find prim-th root of 1, used in decoding */
+       for(iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
+       /* prim-th root of 1, index form */
+       rs->iprim = iprim / prim;
+
+       /* Form RS code generator polynomial from its roots */
+       rs->genpoly[0] = 1;
+       for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
+               rs->genpoly[i + 1] = 1;
+               /* Multiply rs->genpoly[] by  @**(root + x) */
+               for (j = i; j > 0; j--) {
+                       if (rs->genpoly[j] != 0) {
+                               rs->genpoly[j] = rs->genpoly[j -1] ^ 
+                                       rs->alpha_to[rs_modnn(rs, 
+                                       rs->index_of[rs->genpoly[j]] + root)];
+                       } else
+                               rs->genpoly[j] = rs->genpoly[j - 1];
+               }
+               /* rs->genpoly[0] can never be zero */
+               rs->genpoly[0] = 
+                       rs->alpha_to[rs_modnn(rs, 
+                               rs->index_of[rs->genpoly[0]] + root)];
+       }
+       /* convert rs->genpoly[] to index form for quicker encoding */
+       for (i = 0; i <= nroots; i++)
+               rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
+       return rs;
+
+       /* Error exit */
+errpol:
+       kfree(rs->genpoly);
+erridx:
+       kfree(rs->index_of);
+erralp:
+       kfree(rs->alpha_to);
+errrs:
+       kfree(rs);
+       return NULL;
+}
+
+
+/** 
+ *  free_rs - Free the rs control structure, if its not longer used
+ *
+ *  @rs:       the control structure which is not longer used by the
+ *             caller
+ */
+void free_rs(struct rs_control *rs)
+{
+       down(&rslistlock);
+       rs->users--;
+       if(!rs->users) {
+               list_del(&rs->list);
+               kfree(rs->alpha_to);
+               kfree(rs->index_of);
+               kfree(rs->genpoly);
+               kfree(rs);
+       }
+       up(&rslistlock);
+}
+
+/** 
+ * init_rs - Find a matching or allocate a new rs control structure
+ *
+ *  @symsize:  the symbol size (number of bits)
+ *  @gfpoly:   the extended Galois field generator polynomial coefficients,
+ *             with the 0th coefficient in the low order bit. The polynomial
+ *             must be primitive;
+ *  @fcr:      the first consecutive root of the rs code generator polynomial 
+ *             in index form
+ *  @prim:     primitive element to generate polynomial roots
+ *  @nroots:   RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, 
+                          int nroots)
+{
+       struct list_head        *tmp;
+       struct rs_control       *rs;
+
+       /* Sanity checks */
+       if (symsize < 1)
+               return NULL;
+       if (fcr < 0 || fcr >= (1<<symsize))
+               return NULL;
+       if (prim <= 0 || prim >= (1<<symsize))
+               return NULL;
+       if (nroots < 0 || nroots >= (1<<symsize) || nroots > 8)
+               return NULL;
+       
+       down(&rslistlock);
+
+       /* Walk through the list and look for a matching entry */
+       list_for_each(tmp, &rslist) {
+               rs = list_entry(tmp, struct rs_control, list);
+               if (symsize != rs->mm)
+                       continue;
+               if (gfpoly != rs->gfpoly)
+                       continue;
+               if (fcr != rs->fcr)
+                       continue;       
+               if (prim != rs->prim)
+                       continue;       
+               if (nroots != rs->nroots)
+                       continue;
+               /* We have a matching one already */
+               rs->users++;
+               goto out;
+       }
+
+       /* Create a new one */
+       rs = rs_init(symsize, gfpoly, fcr, prim, nroots);
+       if (rs) {
+               rs->users = 1;
+               list_add(&rs->list, &rslist);
+       }
+out:   
+       up(&rslistlock);
+       return rs;
+}
+
+#ifdef CONFIG_REED_SOLOMON_ENC8
+/** 
+ *  encode_rs8 - Calculate the parity for data values (8bit data width)
+ *
+ *  @rs:       the rs control structure
+ *  @data:     data field of a given type
+ *  @len:      data length 
+ *  @par:      parity data, must be initialized by caller (usually all 0)
+ *  @invmsk:   invert data mask (will be xored on data)
+ *
+ *  The parity uses a uint16_t data type to enable
+ *  symbol size > 8. The calling code must take care of encoding of the
+ *  syndrome result for storage itself.
+ */
+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, 
+              uint16_t invmsk)
+{
+#include "encode_rs.c"
+}
+EXPORT_SYMBOL_GPL(encode_rs8);
+#endif
+
+#ifdef CONFIG_REED_SOLOMON_DEC8
+/** 
+ *  decode_rs8 - Decode codeword (8bit data width)
+ *
+ *  @rs:       the rs control structure
+ *  @data:     data field of a given type
+ *  @par:      received parity data field
+ *  @len:      data length
+ *  @s:                syndrome data field (if NULL, syndrome is calculated)
+ *  @no_eras:  number of erasures
+ *  @eras_pos: position of erasures, can be NULL
+ *  @invmsk:   invert data mask (will be xored on data, not on parity!)
+ *  @corr:     buffer to store correction bitmask on eras_pos
+ *
+ *  The syndrome and parity uses a uint16_t data type to enable
+ *  symbol size > 8. The calling code must take care of decoding of the
+ *  syndrome result and the received parity before calling this code.
+ */
+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
+              uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, 
+              uint16_t *corr)
+{
+#include "decode_rs.c"
+}
+EXPORT_SYMBOL_GPL(decode_rs8);
+#endif
+
+#ifdef CONFIG_REED_SOLOMON_ENC16
+/**
+ *  encode_rs16 - Calculate the parity for data values (16bit data width)
+ *
+ *  @rs:       the rs control structure
+ *  @data:     data field of a given type
+ *  @len:      data length 
+ *  @par:      parity data, must be initialized by caller (usually all 0)
+ *  @invmsk:   invert data mask (will be xored on data, not on parity!)
+ *
+ *  Each field in the data array contains up to symbol size bits of valid data.
+ */
+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, 
+       uint16_t invmsk)
+{
+#include "encode_rs.c"
+}
+EXPORT_SYMBOL_GPL(encode_rs16);
+#endif
+
+#ifdef CONFIG_REED_SOLOMON_DEC16
+/** 
+ *  decode_rs16 - Decode codeword (16bit data width)
+ *
+ *  @rs:       the rs control structure
+ *  @data:     data field of a given type
+ *  @par:      received parity data field
+ *  @len:      data length
+ *  @s:                syndrome data field (if NULL, syndrome is calculated)
+ *  @no_eras:  number of erasures
+ *  @eras_pos: position of erasures, can be NULL
+ *  @invmsk:   invert data mask (will be xored on data, not on parity!) 
+ *  @corr:     buffer to store correction bitmask on eras_pos
+ *
+ *  Each field in the data array contains up to symbol size bits of valid data.
+ */
+int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
+               uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, 
+               uint16_t *corr)
+{
+#include "decode_rs.c"
+}
+EXPORT_SYMBOL_GPL(decode_rs16);
+#endif
+
+EXPORT_SYMBOL_GPL(init_rs);
+EXPORT_SYMBOL_GPL(free_rs);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
+MODULE_AUTHOR("Phil Karn, Thomas Gleixner");
+
diff --git a/lib/zlib_inflate/inflate_sync.c b/lib/zlib_inflate/inflate_sync.c
new file mode 100644 (file)
index 0000000..e07bdb2
--- /dev/null
@@ -0,0 +1,148 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <linux/zutil.h>
+#include "infblock.h"
+#include "infutil.h"
+
+int zlib_inflateSync(
+       z_streamp z
+)
+{
+  uInt n;       /* number of bytes to look at */
+  Byte *p;      /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == NULL || z->state == NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != I_BAD)
+  {
+    z->state->mode = I_BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    static const Byte mark[4] = {0, 0, 0xff, 0xff};
+    if (*p == mark[m])
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  zlib_inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+ * but removes the length bytes of the resulting empty stored block. When
+ * decompressing, PPP checks that at the end of input packet, inflate is
+ * waiting for these length bytes.
+ */
+int zlib_inflateSyncPoint(
+       z_streamp z
+)
+{
+  if (z == NULL || z->state == NULL || z->state->blocks == NULL)
+    return Z_STREAM_ERROR;
+  return zlib_inflate_blocks_sync_point(z->state->blocks);
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+static int zlib_inflate_addhistory(inflate_blocks_statef *s,
+                                     z_stream              *z)
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Byte *p;              /* input data pointer */
+    uInt n;               /* bytes available there */
+    Byte *q;              /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+       return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+       return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+       t = n;  /* how many to do */
+       /* is there room until end of buffer? */
+       if (t > m) t = m;
+       /* update check information */
+       if (s->checkfn != NULL)
+           s->check = (*s->checkfn)(s->check, q, t);
+       memcpy(q, p, t);
+       q += t;
+       p += t;
+       n -= t;
+       z->total_out += t;
+       s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */      /* expand WWRAP macro by hand to handle s->read */
+       if (q == s->end) {
+           s->read = q = s->window;
+           m = WAVAIL;
+       }
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int zlib_inflateIncomp(
+       z_stream *z
+
+)
+{
+    if (z->state->mode != BLOCKS)
+       return Z_DATA_ERROR;
+    return zlib_inflate_addhistory(z->state->blocks, z);
+}
diff --git a/mm/thrash.c b/mm/thrash.c
new file mode 100644 (file)
index 0000000..7183937
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * mm/thrash.c
+ *
+ * Copyright (C) 2004, Red Hat, Inc.
+ * Copyright (C) 2004, Rik van Riel <riel@redhat.com>
+ * Released under the GPL, see the file COPYING for details.
+ *
+ * Simple token based thrashing protection, using the algorithm
+ * described in:  http://www.cs.wm.edu/~sjiang/token.pdf
+ */
+#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/swap.h>
+
+static spinlock_t swap_token_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long swap_token_timeout;
+unsigned long swap_token_check;
+struct mm_struct * swap_token_mm = &init_mm;
+
+#define SWAP_TOKEN_CHECK_INTERVAL (HZ * 2)
+#define SWAP_TOKEN_TIMEOUT (HZ * 300)
+
+/*
+ * Take the token away if the process had no page faults
+ * in the last interval, or if it has held the token for
+ * too long.
+ */
+#define SWAP_TOKEN_ENOUGH_RSS 1
+#define SWAP_TOKEN_TIMED_OUT 2
+static int should_release_swap_token(struct mm_struct *mm)
+{
+       int ret = 0;
+       if (!mm->recent_pagein)
+               ret = SWAP_TOKEN_ENOUGH_RSS;
+       else if (time_after(jiffies, swap_token_timeout))
+               ret = SWAP_TOKEN_TIMED_OUT;
+       mm->recent_pagein = 0;
+       return ret;
+}
+
+/*
+ * Try to grab the swapout protection token.  We only try to
+ * grab it once every TOKEN_CHECK_INTERVAL, both to prevent
+ * SMP lock contention and to check that the process that held
+ * the token before is no longer thrashing.
+ */
+void grab_swap_token(void)
+{
+       struct mm_struct *mm;
+       int reason;
+
+       /* We have the token. Let others know we still need it. */
+       if (has_swap_token(current->mm)) {
+               current->mm->recent_pagein = 1;
+               return;
+       }
+
+       if (time_after(jiffies, swap_token_check)) {
+
+               /* Can't get swapout protection if we exceed our RSS limit. */
+               // if (current->mm->rss > current->mm->rlimit_rss)
+               //      return;
+
+               /* ... or if we recently held the token. */
+               if (time_before(jiffies, current->mm->swap_token_time))
+                       return;
+
+               if (!spin_trylock(&swap_token_lock))
+                       return;
+
+               swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
+
+               mm = swap_token_mm;
+               if ((reason = should_release_swap_token(mm))) {
+                       unsigned long eligible = jiffies;
+                       if (reason == SWAP_TOKEN_TIMED_OUT) {
+                               eligible += SWAP_TOKEN_TIMEOUT;
+                       }
+                       mm->swap_token_time = eligible;
+                       swap_token_timeout = jiffies + SWAP_TOKEN_TIMEOUT;
+                       swap_token_mm = current->mm;
+               }
+               spin_unlock(&swap_token_lock);
+       }
+       return;
+}
+
+/* Called on process exit. */
+void __put_swap_token(struct mm_struct *mm)
+{
+       spin_lock(&swap_token_lock);
+       if (likely(mm == swap_token_mm)) {
+               swap_token_mm = &init_mm;
+               swap_token_check = jiffies;
+       }
+       spin_unlock(&swap_token_lock);
+}
diff --git a/mm/tiny-shmem.c b/mm/tiny-shmem.c
new file mode 100644 (file)
index 0000000..90abc63
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * tiny-shmem.c: simple shmemfs and tmpfs using ramfs code
+ *
+ * Matt Mackall <mpm@selenic.com> January, 2004
+ * derived from mm/shmem.c and fs/ramfs/inode.c
+ *
+ * This is intended for small system where the benefits of the full
+ * shmem code (swap-backed and resource-limited) are outweighed by
+ * their complexity. On systems without swap this code should be
+ * effectively equivalent, but much lighter weight.
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/vfs.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/swap.h>
+#include <linux/ramfs.h>
+
+static struct file_system_type tmpfs_fs_type = {
+       .name           = "tmpfs",
+       .get_sb         = ramfs_get_sb,
+       .kill_sb        = kill_litter_super,
+};
+
+static struct vfsmount *shm_mnt;
+
+static int __init init_tmpfs(void)
+{
+       register_filesystem(&tmpfs_fs_type);
+#ifdef CONFIG_TMPFS
+       devfs_mk_dir("shm");
+#endif
+       shm_mnt = kern_mount(&tmpfs_fs_type);
+       return 0;
+}
+module_init(init_tmpfs)
+
+/*
+ * shmem_file_setup - get an unlinked file living in tmpfs
+ *
+ * @name: name for dentry (to be seen in /proc/<pid>/maps
+ * @size: size to be set for the file
+ *
+ */
+struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
+{
+       int error;
+       struct file *file;
+       struct inode *inode;
+       struct dentry *dentry, *root;
+       struct qstr this;
+
+       if (IS_ERR(shm_mnt))
+               return (void *)shm_mnt;
+
+       error = -ENOMEM;
+       this.name = name;
+       this.len = strlen(name);
+       this.hash = 0; /* will go */
+       root = shm_mnt->mnt_root;
+       dentry = d_alloc(root, &this);
+       if (!dentry)
+               goto put_memory;
+
+       error = -ENFILE;
+       file = get_empty_filp();
+       if (!file)
+               goto put_dentry;
+
+       error = -ENOSPC;
+       inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);
+       if (!inode)
+               goto close_file;
+
+       d_instantiate(dentry, inode);
+       inode->i_size = size;
+       inode->i_nlink = 0;     /* It is unlinked */
+       file->f_vfsmnt = mntget(shm_mnt);
+       file->f_dentry = dentry;
+       file->f_mapping = inode->i_mapping;
+       file->f_op = &ramfs_file_operations;
+       file->f_mode = FMODE_WRITE | FMODE_READ;
+       return file;
+
+close_file:
+       put_filp(file);
+put_dentry:
+       dput(dentry);
+put_memory:
+       return ERR_PTR(error);
+}
+
+/*
+ * shmem_zero_setup - setup a shared anonymous mapping
+ *
+ * @vma: the vma to be mmapped is prepared by do_mmap_pgoff
+ */
+int shmem_zero_setup(struct vm_area_struct *vma)
+{
+       struct file *file;
+       loff_t size = vma->vm_end - vma->vm_start;
+
+       file = shmem_file_setup("dev/zero", size, vma->vm_flags);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       if (vma->vm_file)
+               fput(vma->vm_file);
+       vma->vm_file = file;
+       vma->vm_ops = &generic_file_vm_ops;
+       return 0;
+}
+
+int shmem_unuse(swp_entry_t entry, struct page *page)
+{
+       return 0;
+}
+
+EXPORT_SYMBOL(shmem_file_setup);
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c
new file mode 100644 (file)
index 0000000..7659844
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Moved here from drivers/net/net_init.c, which is:
+ *     Written 1993,1994,1995 by Donald Becker.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ltalk.h>
+
+static int ltalk_change_mtu(struct net_device *dev, int mtu)
+{
+       return -EINVAL;
+}
+
+static int ltalk_mac_addr(struct net_device *dev, void *addr)
+{      
+       return -EINVAL;
+}
+
+void ltalk_setup(struct net_device *dev)
+{
+       /* Fill in the fields of the device structure with localtalk-generic values. */
+       
+       dev->change_mtu         = ltalk_change_mtu;
+       dev->hard_header        = NULL;
+       dev->rebuild_header     = NULL;
+       dev->set_mac_address    = ltalk_mac_addr;
+       dev->hard_header_cache  = NULL;
+       dev->header_cache_update= NULL;
+
+       dev->type               = ARPHRD_LOCALTLK;
+       dev->hard_header_len    = LTALK_HLEN;
+       dev->mtu                = LTALK_MTU;
+       dev->addr_len           = LTALK_ALEN;
+       dev->tx_queue_len       = 10;   
+       
+       dev->broadcast[0]       = 0xFF;
+
+       dev->flags              = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP;
+}
+EXPORT_SYMBOL(ltalk_setup);
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
new file mode 100644 (file)
index 0000000..4d65f93
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * net/sched/gen_estimator.c   Simple rate estimator.
+ *
+ *             This 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:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes:
+ *              Jamal Hadi Salim - moved it to net/core and reshulfed
+ *              names to make it usable in general net subsystem.
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/init.h>
+#include <net/sock.h>
+#include <net/gen_stats.h>
+
+/*
+   This code is NOT intended to be used for statistics collection,
+   its purpose is to provide a base for statistical multiplexing
+   for controlled load service.
+   If you need only statistics, run a user level daemon which
+   periodically reads byte counters.
+
+   Unfortunately, rate estimation is not a very easy task.
+   F.e. I did not find a simple way to estimate the current peak rate
+   and even failed to formulate the problem 8)8)
+
+   So I preferred not to built an estimator into the scheduler,
+   but run this task separately.
+   Ideally, it should be kernel thread(s), but for now it runs
+   from timers, which puts apparent top bounds on the number of rated
+   flows, has minimal overhead on small, but is enough
+   to handle controlled load service, sets of aggregates.
+
+   We measure rate over A=(1<<interval) seconds and evaluate EWMA:
+
+   avrate = avrate*(1-W) + rate*W
+
+   where W is chosen as negative power of 2: W = 2^(-ewma_log)
+
+   The resulting time constant is:
+
+   T = A/(-ln(1-W))
+
+
+   NOTES.
+
+   * The stored value for avbps is scaled by 2^5, so that maximal
+     rate is ~1Gbit, avpps is scaled by 2^10.
+
+   * Minimal interval is HZ/4=250msec (it is the greatest common divisor
+     for HZ=100 and HZ=1024 8)), maximal interval
+     is (HZ*2^EST_MAX_INTERVAL)/4 = 8sec. Shorter intervals
+     are too expensive, longer ones can be implemented
+     at user level painlessly.
+ */
+
+#define EST_MAX_INTERVAL       5
+
+struct gen_estimator
+{
+       struct gen_estimator    *next;
+       struct gnet_stats_basic *bstats;
+       struct gnet_stats_rate_est      *rate_est;
+       spinlock_t              *stats_lock;
+       unsigned                interval;
+       int                     ewma_log;
+       u64                     last_bytes;
+       u32                     last_packets;
+       u32                     avpps;
+       u32                     avbps;
+};
+
+struct gen_estimator_head
+{
+       struct timer_list       timer;
+       struct gen_estimator    *list;
+};
+
+static struct gen_estimator_head elist[EST_MAX_INTERVAL+1];
+
+/* Estimator array lock */
+static rwlock_t est_lock = RW_LOCK_UNLOCKED;
+
+static void est_timer(unsigned long arg)
+{
+       int idx = (int)arg;
+       struct gen_estimator *e;
+
+       read_lock(&est_lock);
+       for (e = elist[idx].list; e; e = e->next) {
+               u64 nbytes;
+               u32 npackets;
+               u32 rate;
+
+               spin_lock(e->stats_lock);
+               nbytes = e->bstats->bytes;
+               npackets = e->bstats->packets;
+               rate = (nbytes - e->last_bytes)<<(7 - idx);
+               e->last_bytes = nbytes;
+               e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log;
+               e->rate_est->bps = (e->avbps+0xF)>>5;
+
+               rate = (npackets - e->last_packets)<<(12 - idx);
+               e->last_packets = npackets;
+               e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
+               e->rate_est->pps = (e->avpps+0x1FF)>>10;
+               spin_unlock(e->stats_lock);
+       }
+
+       mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+       read_unlock(&est_lock);
+}
+
+int gen_new_estimator(struct gnet_stats_basic *bstats,
+       struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
+{
+       struct gen_estimator *est;
+       struct gnet_estimator *parm = RTA_DATA(opt);
+
+       if (RTA_PAYLOAD(opt) < sizeof(*parm))
+               return -EINVAL;
+
+       if (parm->interval < -2 || parm->interval > 3)
+               return -EINVAL;
+
+       est = kmalloc(sizeof(*est), GFP_KERNEL);
+       if (est == NULL)
+               return -ENOBUFS;
+
+       memset(est, 0, sizeof(*est));
+       est->interval = parm->interval + 2;
+       est->bstats = bstats;
+       est->rate_est = rate_est;
+       est->stats_lock = stats_lock;
+       est->ewma_log = parm->ewma_log;
+       est->last_bytes = bstats->bytes;
+       est->avbps = rate_est->bps<<5;
+       est->last_packets = bstats->packets;
+       est->avpps = rate_est->pps<<10;
+
+       est->next = elist[est->interval].list;
+       if (est->next == NULL) {
+               init_timer(&elist[est->interval].timer);
+               elist[est->interval].timer.data = est->interval;
+               elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
+               elist[est->interval].timer.function = est_timer;
+               add_timer(&elist[est->interval].timer);
+       }
+       write_lock_bh(&est_lock);
+       elist[est->interval].list = est;
+       write_unlock_bh(&est_lock);
+       return 0;
+}
+
+void gen_kill_estimator(struct gnet_stats_basic *bstats,
+       struct gnet_stats_rate_est *rate_est)
+{
+       int idx;
+       struct gen_estimator *est, **pest;
+
+       for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
+               int killed = 0;
+               pest = &elist[idx].list;
+               while ((est=*pest) != NULL) {
+                       if (est->rate_est != rate_est || est->bstats != bstats) {
+                               pest = &est->next;
+                               continue;
+                       }
+
+                       write_lock_bh(&est_lock);
+                       *pest = est->next;
+                       write_unlock_bh(&est_lock);
+
+                       kfree(est);
+                       killed++;
+               }
+               if (killed && elist[idx].list == NULL)
+                       del_timer(&elist[idx].timer);
+       }
+}
+
+EXPORT_SYMBOL(gen_kill_estimator);
+EXPORT_SYMBOL(gen_new_estimator);
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
new file mode 100644 (file)
index 0000000..2b2ba65
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * net/core/gen_stats.c
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * Authors:  Thomas Graf <tgraf@suug.ch>
+ *           Jamal Hadi Salim
+ *           Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * See Documentation/networking/gen_stats.txt
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/rtnetlink.h>
+#include <linux/gen_stats.h>
+#include <net/gen_stats.h>
+
+
+static inline int
+gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size)
+{
+       RTA_PUT(d->skb, type, size, buf);
+       return 0;
+
+rtattr_failure:
+       spin_unlock_bh(d->lock);
+       return -1;
+}
+
+int
+gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type,
+       int xstats_type, spinlock_t *lock, struct gnet_dump *d)
+{
+       spin_lock_bh(lock);
+       d->lock = lock;
+       d->tail = (struct rtattr *) skb->tail;
+       d->skb = skb;
+       d->compat_tc_stats = tc_stats_type;
+       d->compat_xstats = xstats_type;
+       d->xstats = NULL;
+
+       if (d->compat_tc_stats)
+               memset(&d->tc_stats, 0, sizeof(d->tc_stats));
+
+       return gnet_stats_copy(d, type, NULL, 0);
+}
+
+int
+gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
+       struct gnet_dump *d)
+{
+       return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d);
+}
+
+
+int
+gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic *b)
+{
+       if (d->compat_tc_stats) {
+               d->tc_stats.bytes = b->bytes;
+               d->tc_stats.packets = b->packets;
+       }
+       
+       return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b));
+}
+
+int
+gnet_stats_copy_rate_est(struct gnet_dump *d, struct gnet_stats_rate_est *r)
+{
+       if (d->compat_tc_stats) {
+               d->tc_stats.bps = r->bps;
+               d->tc_stats.pps = r->pps;
+       }
+
+       return gnet_stats_copy(d, TCA_STATS_RATE_EST, r, sizeof(*r));
+}
+
+int
+gnet_stats_copy_queue(struct gnet_dump *d, struct gnet_stats_queue *q)
+{
+       if (d->compat_tc_stats) {
+               d->tc_stats.drops = q->drops;
+               d->tc_stats.qlen = q->qlen;
+               d->tc_stats.backlog = q->backlog;
+               d->tc_stats.overlimits = q->overlimits;
+       }
+               
+       return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));
+}
+
+int
+gnet_stats_copy_app(struct gnet_dump *d, void *st, int len)
+{
+       if (d->compat_xstats)
+               d->xstats = (struct rtattr *) d->skb->tail;
+       return gnet_stats_copy(d, TCA_STATS_APP, st, len);
+}
+
+int
+gnet_stats_finish_copy(struct gnet_dump *d)
+{
+       d->tail->rta_len = d->skb->tail - (u8 *) d->tail;
+
+       if (d->compat_tc_stats)
+               if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
+                       sizeof(d->tc_stats)) < 0)
+                       return -1;
+
+       if (d->compat_xstats && d->xstats) {
+               if (gnet_stats_copy(d, d->compat_xstats, RTA_DATA(d->xstats),
+                       RTA_PAYLOAD(d->xstats)) < 0)
+                       return -1;
+       }
+
+       spin_unlock_bh(d->lock);
+       return 0;
+}
+
+
+EXPORT_SYMBOL(gnet_stats_start_copy);
+EXPORT_SYMBOL(gnet_stats_copy_basic);
+EXPORT_SYMBOL(gnet_stats_copy_rate_est);
+EXPORT_SYMBOL(gnet_stats_copy_queue);
+EXPORT_SYMBOL(gnet_stats_copy_app);
+EXPORT_SYMBOL(gnet_stats_finish_copy);
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
new file mode 100644 (file)
index 0000000..d504a28
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _FIB_LOOKUP_H
+#define _FIB_LOOKUP_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <net/ip_fib.h>
+
+struct fib_alias {
+       struct list_head        fa_list;
+       struct fib_info         *fa_info;
+       u8                      fa_tos;
+       u8                      fa_type;
+       u8                      fa_scope;
+       u8                      fa_state;
+};
+
+#define FA_S_ACCESSED  0x01
+
+/* Exported by fib_semantics.c */
+extern int fib_semantic_match(struct list_head *head,
+                             const struct flowi *flp,
+                             struct fib_result *res, int prefixlen);
+extern void fib_release_info(struct fib_info *);
+extern struct fib_info *fib_create_info(const struct rtmsg *r,
+                                       struct kern_rta *rta,
+                                       const struct nlmsghdr *,
+                                       int *err);
+extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *,
+                       struct kern_rta *rta, struct fib_info *fi);
+extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+                        u8 tb_id, u8 type, u8 scope, void *dst,
+                        int dst_len, u8 tos, struct fib_info *fi);
+
+#endif /* _FIB_LOOKUP_H */
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
new file mode 100644 (file)
index 0000000..0cefc6f
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Connection tracking protocol helper module for SCTP.
+ * 
+ * SCTP is defined in RFC 2960. References to various sections in this code 
+ * are to this RFC.
+ * 
+ * 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.
+ */
+
+/*
+ * Added support for proc manipulation of timeouts.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/sctp.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+#if 0
+#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Protects conntrack->proto.sctp */
+static DECLARE_RWLOCK(sctp_lock);
+
+/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+   closely.  They're more complex. --RR 
+
+   And so for me for SCTP :D -Kiran */
+
+static const char *sctp_conntrack_names[] = {
+       "NONE",
+       "CLOSED",
+       "COOKIE_WAIT",
+       "COOKIE_ECHOED",
+       "ESTABLISHED",
+       "SHUTDOWN_SENT",
+       "SHUTDOWN_RECD",
+       "SHUTDOWN_ACK_SENT",
+};
+
+#define SECS  * HZ
+#define MINS  * 60 SECS
+#define HOURS * 60 MINS
+#define DAYS  * 24 HOURS
+
+unsigned long ip_ct_sctp_timeout_closed            =  10 SECS;
+unsigned long ip_ct_sctp_timeout_cookie_wait       =   3 SECS;
+unsigned long ip_ct_sctp_timeout_cookie_echoed     =   3 SECS;
+unsigned long ip_ct_sctp_timeout_established       =   5 DAYS;
+unsigned long ip_ct_sctp_timeout_shutdown_sent     = 300 SECS / 1000;
+unsigned long ip_ct_sctp_timeout_shutdown_recd     = 300 SECS / 1000;
+unsigned long ip_ct_sctp_timeout_shutdown_ack_sent =   3 SECS;
+
+static unsigned long * sctp_timeouts[]
+= { NULL,                                  /* SCTP_CONNTRACK_NONE  */
+    &ip_ct_sctp_timeout_closed,                   /* SCTP_CONNTRACK_CLOSED */
+    &ip_ct_sctp_timeout_cookie_wait,       /* SCTP_CONNTRACK_COOKIE_WAIT */
+    &ip_ct_sctp_timeout_cookie_echoed,     /* SCTP_CONNTRACK_COOKIE_ECHOED */
+    &ip_ct_sctp_timeout_established,       /* SCTP_CONNTRACK_ESTABLISHED */
+    &ip_ct_sctp_timeout_shutdown_sent,     /* SCTP_CONNTRACK_SHUTDOWN_SENT */
+    &ip_ct_sctp_timeout_shutdown_recd,     /* SCTP_CONNTRACK_SHUTDOWN_RECD */
+    &ip_ct_sctp_timeout_shutdown_ack_sent  /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */
+ };
+
+#define sNO SCTP_CONNTRACK_NONE
+#define        sCL SCTP_CONNTRACK_CLOSED
+#define        sCW SCTP_CONNTRACK_COOKIE_WAIT
+#define        sCE SCTP_CONNTRACK_COOKIE_ECHOED
+#define        sES SCTP_CONNTRACK_ESTABLISHED
+#define        sSS SCTP_CONNTRACK_SHUTDOWN_SENT
+#define        sSR SCTP_CONNTRACK_SHUTDOWN_RECD
+#define        sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
+#define        sIV SCTP_CONNTRACK_MAX
+
+/* 
+       These are the descriptions of the states:
+
+NOTE: These state names are tantalizingly similar to the states of an 
+SCTP endpoint. But the interpretation of the states is a little different,
+considering that these are the states of the connection and not of an end 
+point. Please note the subtleties. -Kiran
+
+NONE              - Nothing so far.
+COOKIE WAIT       - We have seen an INIT chunk in the original direction, or also 
+                    an INIT_ACK chunk in the reply direction.
+COOKIE ECHOED     - We have seen a COOKIE_ECHO chunk in the original direction.
+ESTABLISHED       - We have seen a COOKIE_ACK in the reply direction.
+SHUTDOWN_SENT     - We have seen a SHUTDOWN chunk in the original direction.
+SHUTDOWN_RECD     - We have seen a SHUTDOWN chunk in the reply directoin.
+SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite
+                    to that of the SHUTDOWN chunk.
+CLOSED            - We have seen a SHUTDOWN_COMPLETE chunk in the direction of 
+                    the SHUTDOWN chunk. Connection is closed.
+*/
+
+/* TODO
+ - I have assumed that the first INIT is in the original direction. 
+ This messes things when an INIT comes in the reply direction in CLOSED
+ state.
+ - Check the error type in the reply dir before transitioning from 
+cookie echoed to closed.
+ - Sec 5.2.4 of RFC 2960
+ - Multi Homing support.
+*/
+
+/* SCTP conntrack state transitions */
+static enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
+       {
+/*     ORIGINAL        */
+/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
+/* init         */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA},
+/* init_ack     */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},
+/* abort        */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
+/* shutdown     */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},
+/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},
+/* error        */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/
+/* cookie_echo  */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */
+/* cookie_ack   */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */
+/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL}
+       },
+       {
+/*     REPLY   */
+/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
+/* init         */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */
+/* init_ack     */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},
+/* abort        */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
+/* shutdown     */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},
+/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},
+/* error        */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},
+/* cookie_echo  */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */
+/* cookie_ack   */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},
+/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL}
+       }
+};
+
+static int sctp_pkt_to_tuple(const struct sk_buff *skb,
+                            unsigned int dataoff,
+                            struct ip_conntrack_tuple *tuple)
+{
+       sctp_sctphdr_t _hdr, *hp;
+
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       /* Actually only need first 8 bytes. */
+       hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
+       if (hp == NULL)
+               return 0;
+
+       tuple->src.u.sctp.port = hp->source;
+       tuple->dst.u.sctp.port = hp->dest;
+       return 1;
+}
+
+static int sctp_invert_tuple(struct ip_conntrack_tuple *tuple,
+                            const struct ip_conntrack_tuple *orig)
+{
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       tuple->src.u.sctp.port = orig->dst.u.sctp.port;
+       tuple->dst.u.sctp.port = orig->src.u.sctp.port;
+       return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int sctp_print_tuple(struct seq_file *s,
+                           const struct ip_conntrack_tuple *tuple)
+{
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       return seq_printf(s, "sport=%hu dport=%hu ",
+                         ntohs(tuple->src.u.sctp.port),
+                         ntohs(tuple->dst.u.sctp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static int sctp_print_conntrack(struct seq_file *s,
+                               const struct ip_conntrack *conntrack)
+{
+       enum sctp_conntrack state;
+
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       READ_LOCK(&sctp_lock);
+       state = conntrack->proto.sctp.state;
+       READ_UNLOCK(&sctp_lock);
+
+       return seq_printf(s, "%s ", sctp_conntrack_names[state]);
+}
+
+#define for_each_sctp_chunk(skb, sch, _sch, offset, count)             \
+for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0;        \
+       offset < skb->len &&                                            \
+       (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch));   \
+       offset += (htons(sch->length) + 3) & ~3, count++)
+
+/* Some validity checks to make sure the chunks are fine */
+static int do_basic_checks(struct ip_conntrack *conntrack,
+                          const struct sk_buff *skb,
+                          char *map)
+{
+       u_int32_t offset, count;
+       sctp_chunkhdr_t _sch, *sch;
+       int flag;
+
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       flag = 0;
+
+       for_each_sctp_chunk (skb, sch, _sch, offset, count) {
+               DEBUGP("Chunk Num: %d  Type: %d\n", count, sch->type);
+
+               if (sch->type == SCTP_CID_INIT 
+                       || sch->type == SCTP_CID_INIT_ACK
+                       || sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
+                       flag = 1;
+               }
+
+               /* Cookie Ack/Echo chunks not the first OR 
+                  Init / Init Ack / Shutdown compl chunks not the only chunks */
+               if ((sch->type == SCTP_CID_COOKIE_ACK 
+                       || sch->type == SCTP_CID_COOKIE_ECHO
+                       || flag)
+                    && count !=0 ) {
+                       DEBUGP("Basic checks failed\n");
+                       return 1;
+               }
+
+               if (map) {
+                       set_bit(sch->type, (void *)map);
+               }
+       }
+
+       DEBUGP("Basic checks passed\n");
+       return 0;
+}
+
+static int new_state(enum ip_conntrack_dir dir,
+                    enum sctp_conntrack cur_state,
+                    int chunk_type)
+{
+       int i;
+
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       DEBUGP("Chunk type: %d\n", chunk_type);
+
+       switch (chunk_type) {
+               case SCTP_CID_INIT: 
+                       DEBUGP("SCTP_CID_INIT\n");
+                       i = 0; break;
+               case SCTP_CID_INIT_ACK: 
+                       DEBUGP("SCTP_CID_INIT_ACK\n");
+                       i = 1; break;
+               case SCTP_CID_ABORT: 
+                       DEBUGP("SCTP_CID_ABORT\n");
+                       i = 2; break;
+               case SCTP_CID_SHUTDOWN: 
+                       DEBUGP("SCTP_CID_SHUTDOWN\n");
+                       i = 3; break;
+               case SCTP_CID_SHUTDOWN_ACK: 
+                       DEBUGP("SCTP_CID_SHUTDOWN_ACK\n");
+                       i = 4; break;
+               case SCTP_CID_ERROR: 
+                       DEBUGP("SCTP_CID_ERROR\n");
+                       i = 5; break;
+               case SCTP_CID_COOKIE_ECHO: 
+                       DEBUGP("SCTP_CID_COOKIE_ECHO\n");
+                       i = 6; break;
+               case SCTP_CID_COOKIE_ACK: 
+                       DEBUGP("SCTP_CID_COOKIE_ACK\n");
+                       i = 7; break;
+               case SCTP_CID_SHUTDOWN_COMPLETE: 
+                       DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n");
+                       i = 8; break;
+               default:
+                       /* Other chunks like DATA, SACK, HEARTBEAT and
+                       its ACK do not cause a change in state */
+                       DEBUGP("Unknown chunk type, Will stay in %s\n", 
+                                               sctp_conntrack_names[cur_state]);
+                       return cur_state;
+       }
+
+       DEBUGP("dir: %d   cur_state: %s  chunk_type: %d  new_state: %s\n", 
+                       dir, sctp_conntrack_names[cur_state], chunk_type,
+                       sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
+
+       return sctp_conntracks[dir][i][cur_state];
+}
+
+/* Returns verdict for packet, or -1 for invalid. */
+static int sctp_packet(struct ip_conntrack *conntrack,
+                      const struct sk_buff *skb,
+                      enum ip_conntrack_info ctinfo)
+{
+       enum sctp_conntrack newconntrack, oldsctpstate;
+       struct iphdr *iph = skb->nh.iph;
+       sctp_sctphdr_t _sctph, *sh;
+       sctp_chunkhdr_t _sch, *sch;
+       u_int32_t offset, count;
+       char map[256 / sizeof (char)] = {0};
+
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
+       if (sh == NULL)
+               return -1;
+
+       if (do_basic_checks(conntrack, skb, map) != 0)
+               return -1;
+
+       /* Check the verification tag (Sec 8.5) */
+       if (!test_bit(SCTP_CID_INIT, (void *)map)
+               && !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)
+               && !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map)
+               && !test_bit(SCTP_CID_ABORT, (void *)map)
+               && !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
+               && (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
+               DEBUGP("Verification tag check failed\n");
+               return -1;
+       }
+
+       oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
+       for_each_sctp_chunk (skb, sch, _sch, offset, count) {
+               WRITE_LOCK(&sctp_lock);
+
+               /* Special cases of Verification tag check (Sec 8.5.1) */
+               if (sch->type == SCTP_CID_INIT) {
+                       /* Sec 8.5.1 (A) */
+                       if (sh->vtag != 0) {
+                               WRITE_UNLOCK(&sctp_lock);
+                               return -1;
+                       }
+               } else if (sch->type == SCTP_CID_ABORT) {
+                       /* Sec 8.5.1 (B) */
+                       if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
+                               && !(sh->vtag == conntrack->proto.sctp.vtag
+                                                       [1 - CTINFO2DIR(ctinfo)])) {
+                               WRITE_UNLOCK(&sctp_lock);
+                               return -1;
+                       }
+               } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
+                       /* Sec 8.5.1 (C) */
+                       if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
+                               && !(sh->vtag == conntrack->proto.sctp.vtag
+                                                       [1 - CTINFO2DIR(ctinfo)] 
+                                       && (sch->flags & 1))) {
+                               WRITE_UNLOCK(&sctp_lock);
+                               return -1;
+                       }
+               } else if (sch->type == SCTP_CID_COOKIE_ECHO) {
+                       /* Sec 8.5.1 (D) */
+                       if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
+                               WRITE_UNLOCK(&sctp_lock);
+                               return -1;
+                       }
+               }
+
+               oldsctpstate = conntrack->proto.sctp.state;
+               newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type);
+
+               /* Invalid */
+               if (newconntrack == SCTP_CONNTRACK_MAX) {
+                       DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
+                              CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
+                       WRITE_UNLOCK(&sctp_lock);
+                       return -1;
+               }
+
+               /* If it is an INIT or an INIT ACK note down the vtag */
+               if (sch->type == SCTP_CID_INIT 
+                       || sch->type == SCTP_CID_INIT_ACK) {
+                       sctp_inithdr_t _inithdr, *ih;
+
+                       ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
+                                               sizeof(_inithdr), &_inithdr);
+                       if (ih == NULL) {
+                                       WRITE_UNLOCK(&sctp_lock);
+                                       return -1;
+                       }
+                       DEBUGP("Setting vtag %x for dir %d\n", 
+                                       ih->init_tag, CTINFO2DIR(ctinfo));
+                       conntrack->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = ih->init_tag;
+               }
+
+               conntrack->proto.sctp.state = newconntrack;
+               WRITE_UNLOCK(&sctp_lock);
+       }
+
+       ip_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]);
+
+       if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
+               && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
+               && newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
+               DEBUGP("Setting assured bit\n");
+               set_bit(IPS_ASSURED_BIT, &conntrack->status);
+       }
+
+       return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int sctp_new(struct ip_conntrack *conntrack, 
+                   const struct sk_buff *skb)
+{
+       enum sctp_conntrack newconntrack;
+       struct iphdr *iph = skb->nh.iph;
+       sctp_sctphdr_t _sctph, *sh;
+       sctp_chunkhdr_t _sch, *sch;
+       u_int32_t offset, count;
+       char map[256 / sizeof (char)] = {0};
+
+       DEBUGP(__FUNCTION__);
+       DEBUGP("\n");
+
+       sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
+       if (sh == NULL)
+               return 0;
+
+       if (do_basic_checks(conntrack, skb, map) != 0)
+               return 0;
+
+       /* If an OOTB packet has any of these chunks discard (Sec 8.4) */
+       if ((test_bit (SCTP_CID_ABORT, (void *)map))
+               || (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map))
+               || (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) {
+               return 0;
+       }
+
+       newconntrack = SCTP_CONNTRACK_MAX;
+       for_each_sctp_chunk (skb, sch, _sch, offset, count) {
+               /* Don't need lock here: this conntrack not in circulation yet */
+               newconntrack = new_state (IP_CT_DIR_ORIGINAL, 
+                                               SCTP_CONNTRACK_NONE, sch->type);
+
+               /* Invalid: delete conntrack */
+               if (newconntrack == SCTP_CONNTRACK_MAX) {
+                       DEBUGP("ip_conntrack_sctp: invalid new deleting.\n");
+                       return 0;
+               }
+
+               /* Copy the vtag into the state info */
+               if (sch->type == SCTP_CID_INIT) {
+                       if (sh->vtag == 0) {
+                               sctp_inithdr_t _inithdr, *ih;
+
+                               ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
+                                                       sizeof(_inithdr), &_inithdr);
+                               if (ih == NULL)
+                                       return 0;
+
+                               DEBUGP("Setting vtag %x for new conn\n", 
+                                       ih->init_tag);
+
+                               conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = 
+                                                               ih->init_tag;
+                       } else {
+                               /* Sec 8.5.1 (A) */
+                               return 0;
+                       }
+               }
+               /* If it is a shutdown ack OOTB packet, we expect a return
+                  shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
+               else {
+                       DEBUGP("Setting vtag %x for new conn OOTB\n", 
+                               sh->vtag);
+                       conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
+               }
+
+               conntrack->proto.sctp.state = newconntrack;
+       }
+
+       return 1;
+}
+
+static int sctp_exp_matches_pkt(struct ip_conntrack_expect *exp,
+                               const struct sk_buff *skb)
+{
+       /* To be implemented */
+       return 0;
+}
+
+struct ip_conntrack_protocol ip_conntrack_protocol_sctp = { 
+       .proto           = IPPROTO_SCTP, 
+       .name            = "sctp",
+       .pkt_to_tuple    = sctp_pkt_to_tuple, 
+       .invert_tuple    = sctp_invert_tuple, 
+       .print_tuple     = sctp_print_tuple, 
+       .print_conntrack = sctp_print_conntrack,
+       .packet          = sctp_packet, 
+       .new             = sctp_new, 
+       .destroy         = NULL, 
+       .exp_matches_pkt = sctp_exp_matches_pkt, 
+       .me              = THIS_MODULE 
+};
+
+#ifdef CONFIG_SYSCTL
+static ctl_table ip_ct_sysctl_table[] = {
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,
+               .procname       = "ip_conntrack_sctp_timeout_closed",
+               .data           = &ip_ct_sctp_timeout_closed,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,
+               .procname       = "ip_conntrack_sctp_timeout_cookie_wait",
+               .data           = &ip_ct_sctp_timeout_cookie_wait,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,
+               .procname       = "ip_conntrack_sctp_timeout_cookie_echoed",
+               .data           = &ip_ct_sctp_timeout_cookie_echoed,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,
+               .procname       = "ip_conntrack_sctp_timeout_established",
+               .data           = &ip_ct_sctp_timeout_established,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,
+               .procname       = "ip_conntrack_sctp_timeout_shutdown_sent",
+               .data           = &ip_ct_sctp_timeout_shutdown_sent,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,
+               .procname       = "ip_conntrack_sctp_timeout_shutdown_recd",
+               .data           = &ip_ct_sctp_timeout_shutdown_recd,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       {
+               .ctl_name       = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT,
+               .procname       = "ip_conntrack_sctp_timeout_shutdown_ack_sent",
+               .data           = &ip_ct_sctp_timeout_shutdown_ack_sent,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
+       { .ctl_name = 0 }
+};
+
+static ctl_table ip_ct_netfilter_table[] = {
+       {
+               .ctl_name       = NET_IPV4_NETFILTER,
+               .procname       = "netfilter",
+               .mode           = 0555,
+               .child          = ip_ct_sysctl_table,
+       },
+       { .ctl_name = 0 }
+};
+
+static ctl_table ip_ct_ipv4_table[] = {
+       {
+               .ctl_name       = NET_IPV4,
+               .procname       = "ipv4",
+               .mode           = 0555,
+               .child          = ip_ct_netfilter_table,
+       },
+       { .ctl_name = 0 }
+};
+
+static ctl_table ip_ct_net_table[] = {
+       {
+               .ctl_name       = CTL_NET,
+               .procname       = "net",
+               .mode           = 0555, 
+               .child          = ip_ct_ipv4_table,
+       },
+       { .ctl_name = 0 }
+};
+
+static struct ctl_table_header *ip_ct_sysctl_header;
+#endif
+
+int __init init(void)
+{
+       int ret;
+
+       ret = ip_conntrack_protocol_register(&ip_conntrack_protocol_sctp);
+       if (ret) {
+               printk("ip_conntrack_proto_sctp: protocol register failed\n");
+               goto out;
+       }
+
+#ifdef CONFIG_SYSCTL
+       ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
+       if (ip_ct_sysctl_header == NULL) {
+               printk("ip_conntrack_proto_sctp: can't register to sysctl.\n");
+               goto cleanup;
+       }
+#endif
+
+       return ret;
+
+#ifdef CONFIG_SYSCTL
+ cleanup:
+       ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
+#endif
+ out:
+       DEBUGP("SCTP conntrack module loading %s\n", 
+                                       ret ? "failed": "succeeded");
+       return ret;
+}
+
+void __exit fini(void)
+{
+       ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
+#ifdef CONFIG_SYSCTL
+       unregister_sysctl_table(ip_ct_sysctl_header);
+#endif
+       DEBUGP("SCTP conntrack module unloaded\n");
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kiran Kumar Immidi");
+MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP");
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
new file mode 100644 (file)
index 0000000..68002ff
--- /dev/null
@@ -0,0 +1,760 @@
+/* Cluster IP hashmark target 
+ * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
+ * based on ideas of Fabio Olive Leite <olive@unixforge.org>
+ *
+ * Development of this code funded by SuSE Linux AG, http://www.suse.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/jhash.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
+#include <linux/if_arp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <net/checksum.h>
+
+#include <linux/netfilter_arp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+#define CLUSTERIP_VERSION "0.6"
+
+#define DEBUG_CLUSTERIP
+
+#ifdef DEBUG_CLUSTERIP
+#define DEBUGP printk
+#else
+#define DEBUGP
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("iptables target for CLUSTERIP");
+
+struct clusterip_config {
+       struct list_head list;                  /* list of all configs */
+       atomic_t refcount;                      /* reference count */
+
+       u_int32_t clusterip;                    /* the IP address */
+       u_int8_t clustermac[ETH_ALEN];          /* the MAC address */
+       struct net_device *dev;                 /* device */
+       u_int16_t num_total_nodes;              /* total number of nodes */
+       u_int16_t num_local_nodes;              /* number of local nodes */
+       u_int16_t local_nodes[CLUSTERIP_MAX_NODES];     /* node number array */
+
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *pde;             /* proc dir entry */
+#endif
+       enum clusterip_hashmode hash_mode;      /* which hashing mode */
+       u_int32_t hash_initval;                 /* hash initialization */
+};
+
+static LIST_HEAD(clusterip_configs);
+
+/* clusterip_lock protects the clusterip_configs list _AND_ the configurable
+ * data within all structurses (num_local_nodes, local_nodes[]) */
+DECLARE_RWLOCK(clusterip_lock);
+
+#ifdef CONFIG_PROC_FS
+static struct file_operations clusterip_proc_fops;
+static struct proc_dir_entry *clusterip_procdir;
+#endif
+
+static inline void
+clusterip_config_get(struct clusterip_config *c) {
+       atomic_inc(&c->refcount);
+}
+
+static inline void
+clusterip_config_put(struct clusterip_config *c) {
+       if (atomic_dec_and_test(&c->refcount)) {
+               WRITE_LOCK(&clusterip_lock);
+               list_del(&c->list);
+               WRITE_UNLOCK(&clusterip_lock);
+               dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0);
+               dev_put(c->dev);
+               kfree(c);
+       }
+}
+
+
+static struct clusterip_config *
+__clusterip_config_find(u_int32_t clusterip)
+{
+       struct list_head *pos;
+
+       MUST_BE_READ_LOCKED(&clusterip_lock);
+       list_for_each(pos, &clusterip_configs) {
+               struct clusterip_config *c = list_entry(pos, 
+                                       struct clusterip_config, list);
+               if (c->clusterip == clusterip) {
+                       return c;
+               }
+       }
+
+       return NULL;
+}
+
+static inline struct clusterip_config *
+clusterip_config_find_get(u_int32_t clusterip)
+{
+       struct clusterip_config *c;
+
+       READ_LOCK(&clusterip_lock);
+       c = __clusterip_config_find(clusterip);
+       if (!c) {
+               READ_UNLOCK(&clusterip_lock);
+               return NULL;
+       }
+       atomic_inc(&c->refcount);
+       READ_UNLOCK(&clusterip_lock);
+
+       return c;
+}
+
+static struct clusterip_config *
+clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip,
+                       struct net_device *dev)
+{
+       struct clusterip_config *c;
+       char buffer[16];
+
+       c = kmalloc(sizeof(*c), GFP_ATOMIC);
+       if (!c)
+               return NULL;
+
+       memset(c, 0, sizeof(*c));
+       c->dev = dev;
+       c->clusterip = ip;
+       memcpy(&c->clustermac, &i->clustermac, ETH_ALEN);
+       c->num_total_nodes = i->num_total_nodes;
+       c->num_local_nodes = i->num_local_nodes;
+       memcpy(&c->local_nodes, &i->local_nodes, sizeof(&c->local_nodes));
+       c->hash_mode = i->hash_mode;
+       c->hash_initval = i->hash_initval;
+       atomic_set(&c->refcount, 1);
+
+#ifdef CONFIG_PROC_FS
+       /* create proc dir entry */
+       sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+       c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, clusterip_procdir);
+       if (!c->pde) {
+               kfree(c);
+               return NULL;
+       }
+       c->pde->proc_fops = &clusterip_proc_fops;
+       c->pde->data = c;
+#endif
+
+       WRITE_LOCK(&clusterip_lock);
+       list_add(&c->list, &clusterip_configs);
+       WRITE_UNLOCK(&clusterip_lock);
+
+       return c;
+}
+
+static int
+clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
+{
+       int i;
+
+       WRITE_LOCK(&clusterip_lock);
+
+       if (c->num_local_nodes >= CLUSTERIP_MAX_NODES
+           || nodenum > CLUSTERIP_MAX_NODES) {
+               WRITE_UNLOCK(&clusterip_lock);
+               return 1;
+       }
+
+       /* check if we alrady have this number in our array */
+       for (i = 0; i < c->num_local_nodes; i++) {
+               if (c->local_nodes[i] == nodenum) {
+                       WRITE_UNLOCK(&clusterip_lock);
+                       return 1;
+               }
+       }
+
+       c->local_nodes[c->num_local_nodes++] = nodenum;
+
+       WRITE_UNLOCK(&clusterip_lock);
+       return 0;
+}
+
+static int
+clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum)
+{
+       int i;
+
+       WRITE_LOCK(&clusterip_lock);
+
+       if (c->num_local_nodes <= 1 || nodenum > CLUSTERIP_MAX_NODES) {
+               WRITE_UNLOCK(&clusterip_lock);
+               return 1;
+       }
+               
+       for (i = 0; i < c->num_local_nodes; i++) {
+               if (c->local_nodes[i] == nodenum) {
+                       int size = sizeof(u_int16_t)*(c->num_local_nodes-(i+1));
+                       memmove(&c->local_nodes[i], &c->local_nodes[i+1], size);
+                       c->num_local_nodes--;
+                       WRITE_UNLOCK(&clusterip_lock);
+                       return 0;
+               }
+       }
+
+       WRITE_UNLOCK(&clusterip_lock);
+       return 1;
+}
+
+static inline u_int32_t
+clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
+{
+       struct iphdr *iph = skb->nh.iph;
+       unsigned long hashval;
+       u_int16_t sport, dport;
+       struct tcphdr *th;
+       struct udphdr *uh;
+       struct icmphdr *ih;
+
+       switch (iph->protocol) {
+       case IPPROTO_TCP:
+               th = (void *)iph+iph->ihl*4;
+               sport = ntohs(th->source);
+               dport = ntohs(th->dest);
+               break;
+       case IPPROTO_UDP:
+               uh = (void *)iph+iph->ihl*4;
+               sport = ntohs(uh->source);
+               dport = ntohs(uh->dest);
+               break;
+       case IPPROTO_ICMP:
+               ih = (void *)iph+iph->ihl*4;
+               sport = ntohs(ih->un.echo.id);
+               dport = (ih->type<<8)|ih->code;
+               break;
+       default:
+               if (net_ratelimit()) {
+                       printk(KERN_NOTICE "CLUSTERIP: unknown protocol `%u'\n",
+                               iph->protocol);
+               }
+               sport = dport = 0;
+       }
+
+       switch (config->hash_mode) {
+       case CLUSTERIP_HASHMODE_SIP:
+               hashval = jhash_1word(ntohl(iph->saddr),
+                                     config->hash_initval);
+               break;
+       case CLUSTERIP_HASHMODE_SIP_SPT:
+               hashval = jhash_2words(ntohl(iph->saddr), sport, 
+                                      config->hash_initval);
+               break;
+       case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
+               hashval = jhash_3words(ntohl(iph->saddr), sport, dport,
+                                      config->hash_initval);
+               break;
+       default:
+               /* to make gcc happy */
+               hashval = 0;
+               /* This cannot happen, unless the check function wasn't called
+                * at rule load time */
+               printk("CLUSTERIP: unknown mode `%u'\n", config->hash_mode);
+               BUG();
+               break;
+       }
+
+       /* node numbers are 1..n, not 0..n */
+       return ((hashval % config->num_total_nodes)+1);
+}
+
+static inline int
+clusterip_responsible(struct clusterip_config *config, u_int32_t hash)
+{
+       int i;
+
+       READ_LOCK(&clusterip_lock);
+
+       if (config->num_local_nodes == 0) {
+               READ_UNLOCK(&clusterip_lock);
+               return 0;
+       }
+
+       for (i = 0; i < config->num_local_nodes; i++) {
+               if (config->local_nodes[i] == hash) {
+                       READ_UNLOCK(&clusterip_lock);
+                       return 1;
+               }
+       }
+
+       READ_UNLOCK(&clusterip_lock);
+
+       return 0;
+}
+
+/*********************************************************************** 
+ * IPTABLES TARGET 
+ ***********************************************************************/
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+       enum ip_conntrack_info ctinfo;
+       struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
+       u_int32_t hash;
+
+       /* don't need to clusterip_config_get() here, since refcount
+        * is only decremented by destroy() - and ip_tables guarantees
+        * that the ->target() function isn't called after ->destroy() */
+
+       if (!ct) {
+               printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
+                       /* FIXME: need to drop invalid ones, since replies
+                        * to outgoing connections of other nodes will be 
+                        * marked as INVALID */
+               return NF_DROP;
+       }
+
+       /* special case: ICMP error handling. conntrack distinguishes between
+        * error messages (RELATED) and information requests (see below) */
+       if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
+           && (ctinfo == IP_CT_RELATED 
+               || ctinfo == IP_CT_IS_REPLY+IP_CT_IS_REPLY))
+               return IPT_CONTINUE;
+
+       /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO, 
+        * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
+        * on, which all have an ID field [relevant for hashing]. */
+
+       hash = clusterip_hashfn(*pskb, cipinfo->config);
+
+       switch (ctinfo) {
+               case IP_CT_NEW:
+                       ct->mark = hash;
+                       break;
+               case IP_CT_RELATED:
+               case IP_CT_RELATED+IP_CT_IS_REPLY:
+                       /* FIXME: we don't handle expectations at the
+                        * moment.  they can arrive on a different node than
+                        * the master connection (e.g. FTP passive mode) */
+               case IP_CT_ESTABLISHED:
+               case IP_CT_ESTABLISHED+IP_CT_IS_REPLY:
+                       break;
+               default:
+                       break;
+       }
+
+#ifdef DEBUG_CLUSTERP
+       DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+#endif
+       DEBUGP("hash=%u ct_hash=%lu ", hash, ct->mark);
+       if (!clusterip_responsible(cipinfo->config, hash)) {
+               DEBUGP("not responsible\n");
+               return NF_DROP;
+       }
+       DEBUGP("responsible\n");
+
+       /* despite being received via linklayer multicast, this is
+        * actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
+       (*pskb)->pkt_type = PACKET_HOST;
+
+       return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ipt_entry *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+       struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+
+       struct clusterip_config *config;
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info))) {
+               printk(KERN_WARNING "CLUSTERIP: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)));
+               return 0;
+       }
+
+       if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
+           cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
+           cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
+               printk(KERN_WARNING "CLUSTERIP: unknown mode `%u'\n",
+                       cipinfo->hash_mode);
+               return 0;
+
+       }
+       if (e->ip.dmsk.s_addr != 0xffffffff
+           || e->ip.dst.s_addr == 0) {
+               printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
+               return 0;
+       }
+
+       /* FIXME: further sanity checks */
+
+       config = clusterip_config_find_get(e->ip.dst.s_addr);
+       if (!config) {
+               if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
+                       printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr));
+                       return 0;
+               } else {
+                       struct net_device *dev;
+
+                       if (e->ip.iniface[0] == '\0') {
+                               printk(KERN_WARNING "CLUSTERIP: Please specify an interface name\n");
+                               return 0;
+                       }
+
+                       dev = dev_get_by_name(e->ip.iniface);
+                       if (!dev) {
+                               printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface);
+                               return 0;
+                       }
+
+                       config = clusterip_config_init(cipinfo, 
+                                                       e->ip.dst.s_addr, dev);
+                       if (!config) {
+                               printk(KERN_WARNING "CLUSTERIP: cannot allocate config\n");
+                               dev_put(dev);
+                               return 0;
+                       }
+                       dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0);
+               }
+       }
+
+       cipinfo->config = config;
+
+       return 1;
+}
+
+/* drop reference count of cluster config when rule is deleted */
+static void destroy(void *matchinfo, unsigned int matchinfosize)
+{
+       struct ipt_clusterip_tgt_info *cipinfo = matchinfo;
+
+       /* we first remove the proc entry and then drop the reference
+        * count.  In case anyone still accesses the file, the open/close
+        * functions are also incrementing the refcount on their own */
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry(cipinfo->config->pde->name,
+                         cipinfo->config->pde->parent);
+#endif
+       clusterip_config_put(cipinfo->config);
+}
+
+static struct ipt_target clusterip_tgt = { 
+       .name = "CLUSTERIP",
+       .target = &target, 
+       .checkentry = &checkentry, 
+       .destroy = &destroy,
+       .me = THIS_MODULE
+};
+
+
+/*********************************************************************** 
+ * ARP MANGLING CODE 
+ ***********************************************************************/
+
+/* hardcoded for 48bit ethernet and 32bit ipv4 addresses */
+struct arp_payload {
+       u_int8_t src_hw[ETH_ALEN];
+       u_int32_t src_ip;
+       u_int8_t dst_hw[ETH_ALEN];
+       u_int32_t dst_ip;
+} __attribute__ ((packed));
+
+#ifdef CLUSTERIP_DEBUG
+static void arp_print(struct arp_payload *payload) 
+{
+#define HBUFFERLEN 30
+       char hbuffer[HBUFFERLEN];
+       int j,k;
+       const char hexbuf[]= "0123456789abcdef";
+
+       for (k=0, j=0; k < HBUFFERLEN-3 && j < ETH_ALEN; j++) {
+               hbuffer[k++]=hexbuf[(payload->src_hw[j]>>4)&15];
+               hbuffer[k++]=hexbuf[payload->src_hw[j]&15];
+               hbuffer[k++]=':';
+       }
+       hbuffer[--k]='\0';
+
+       printk("src %u.%u.%u.%u@%s, dst %u.%u.%u.%u\n", 
+               NIPQUAD(payload->src_ip), hbuffer,
+               NIPQUAD(payload->dst_ip));
+}
+#endif
+
+static unsigned int
+arp_mangle(unsigned int hook,
+          struct sk_buff **pskb,
+          const struct net_device *in,
+          const struct net_device *out,
+          int (*okfn)(struct sk_buff *))
+{
+       struct arphdr *arp = (*pskb)->nh.arph;
+       struct arp_payload *payload;
+       struct clusterip_config *c;
+
+       /* we don't care about non-ethernet and non-ipv4 ARP */
+       if (arp->ar_hrd != htons(ARPHRD_ETHER)
+           || arp->ar_pro != htons(ETH_P_IP)
+           || 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))
+               return NF_ACCEPT;
+
+       payload = (void *)(arp+1);
+
+       /* if there is no clusterip configuration for the arp reply's 
+        * source ip, we don't want to mangle it */
+       c = clusterip_config_find_get(payload->src_ip);
+       if (!c)
+               return NF_ACCEPT;
+
+       /* normally the linux kernel always replies to arp queries of 
+        * addresses on different interfacs.  However, in the CLUSTERIP case
+        * this wouldn't work, since we didn't subscribe the mcast group on
+        * other interfaces */
+       if (c->dev != out) {
+               DEBUGP("CLUSTERIP: not mangling arp reply on different "
+                      "interface: cip'%s'-skb'%s'\n", c->dev->name, out->name);
+               clusterip_config_put(c);
+               return NF_ACCEPT;
+       }
+
+       /* mangle reply hardware address */
+       memcpy(payload->src_hw, c->clustermac, arp->ar_hln);
+
+#ifdef CLUSTERIP_DEBUG
+       DEBUGP(KERN_DEBUG "CLUSTERIP mangled arp reply: ");
+       arp_print(payload);
+#endif
+
+       clusterip_config_put(c);
+
+       return NF_ACCEPT;
+}
+
+static struct nf_hook_ops cip_arp_ops = {
+       .hook = arp_mangle,
+       .pf = NF_ARP,
+       .hooknum = NF_ARP_OUT,
+       .priority = -1
+};
+
+/*********************************************************************** 
+ * PROC DIR HANDLING 
+ ***********************************************************************/
+
+#ifdef CONFIG_PROC_FS
+
+static void *clusterip_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct clusterip_config *c = pde->data;
+       unsigned int *nodeidx;
+
+       READ_LOCK(&clusterip_lock);
+       if (*pos >= c->num_local_nodes)
+               return NULL;
+
+       nodeidx = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+       if (!nodeidx)
+               return ERR_PTR(-ENOMEM);
+
+       *nodeidx = *pos;
+       return nodeidx;
+}
+
+static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct clusterip_config *c = pde->data;
+       unsigned int *nodeidx = (unsigned int *)v;
+
+       *pos = ++(*nodeidx);
+       if (*pos >= c->num_local_nodes) {
+               kfree(v);
+               return NULL;
+       }
+       return nodeidx;
+}
+
+static void clusterip_seq_stop(struct seq_file *s, void *v)
+{
+       kfree(v);
+
+       READ_UNLOCK(&clusterip_lock);
+}
+
+static int clusterip_seq_show(struct seq_file *s, void *v)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct clusterip_config *c = pde->data;
+       unsigned int *nodeidx = (unsigned int *)v;
+
+       if (*nodeidx != 0) 
+               seq_putc(s, ',');
+       seq_printf(s, "%u", c->local_nodes[*nodeidx]);
+
+       if (*nodeidx == c->num_local_nodes-1)
+               seq_putc(s, '\n');
+
+       return 0;
+}
+
+static struct seq_operations clusterip_seq_ops = {
+       .start  = clusterip_seq_start,
+       .next   = clusterip_seq_next,
+       .stop   = clusterip_seq_stop,
+       .show   = clusterip_seq_show,
+};
+
+static int clusterip_proc_open(struct inode *inode, struct file *file)
+{
+       int ret = seq_open(file, &clusterip_seq_ops);
+
+       if (!ret) {
+               struct seq_file *sf = file->private_data;
+               struct proc_dir_entry *pde = PDE(inode);
+               struct clusterip_config *c = pde->data;
+
+               sf->private = pde;
+
+               clusterip_config_get(c);
+       }
+
+       return ret;
+}
+
+static int clusterip_proc_release(struct inode *inode, struct file *file)
+{
+       struct proc_dir_entry *pde = PDE(inode);
+       struct clusterip_config *c = pde->data;
+       int ret;
+
+       ret = seq_release(inode, file);
+
+       if (!ret)
+               clusterip_config_put(c);
+
+       return ret;
+}
+
+static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
+                               size_t size, loff_t *ofs)
+{
+#define PROC_WRITELEN  10
+       char buffer[PROC_WRITELEN+1];
+       struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+       struct clusterip_config *c = pde->data;
+       unsigned long nodenum;
+
+       if (copy_from_user(buffer, input, PROC_WRITELEN))
+               return -EFAULT;
+
+       if (*buffer == '+') {
+               nodenum = simple_strtoul(buffer+1, NULL, 10);
+               if (clusterip_add_node(c, nodenum))
+                       return -ENOMEM;
+       } else if (*buffer == '-') {
+               nodenum = simple_strtoul(buffer+1, NULL,10);
+               if (clusterip_del_node(c, nodenum))
+                       return -ENOENT;
+       } else
+               return -EIO;
+
+       return size;
+}
+
+static struct file_operations clusterip_proc_fops = {
+       .owner   = THIS_MODULE,
+       .open    = clusterip_proc_open,
+       .read    = seq_read,
+       .write   = clusterip_proc_write,
+       .llseek  = seq_lseek,
+       .release = clusterip_proc_release,
+};
+
+#endif /* CONFIG_PROC_FS */
+
+static int init_or_cleanup(int fini)
+{
+       int ret;
+
+       if (fini)
+               goto cleanup;
+
+       if (ipt_register_target(&clusterip_tgt)) {
+               ret = -EINVAL;
+               goto cleanup_none;
+       }
+
+       if (nf_register_hook(&cip_arp_ops) < 0) {
+               ret = -EINVAL;
+               goto cleanup_target;
+       }
+
+#ifdef CONFIG_PROC_FS
+       clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net);
+       if (!clusterip_procdir) {
+               printk(KERN_ERR "CLUSTERIP: Unable to proc dir entry\n");
+               ret = -ENOMEM;
+               goto cleanup_hook;
+       }
+#endif /* CONFIG_PROC_FS */
+
+       printk(KERN_NOTICE "ClusterIP Version %s loaded successfully\n",
+               CLUSTERIP_VERSION);
+
+       return 0;
+
+cleanup:
+       printk(KERN_NOTICE "ClusterIP Version %s unloading\n",
+               CLUSTERIP_VERSION);
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
+#endif
+cleanup_hook:
+       nf_unregister_hook(&cip_arp_ops);
+cleanup_target:
+       ipt_unregister_target(&clusterip_tgt);
+cleanup_none:
+       return -EINVAL;
+}
+
+static int __init init(void)
+{
+       return init_or_cleanup(0);
+}
+
+static void __exit fini(void)
+{
+       init_or_cleanup(1);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c
new file mode 100644 (file)
index 0000000..30ddd3e
--- /dev/null
@@ -0,0 +1,118 @@
+/* This kernel module is used to modify the connection mark values, or
+ * to optionally restore the skb nfmark from the connection mark
+ *
+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
+MODULE_DESCRIPTION("IP tables CONNMARK matching module");
+MODULE_LICENSE("GPL");
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct ipt_connmark_target_info *markinfo = targinfo;
+       unsigned long diff;
+       unsigned long nfmark;
+       unsigned long newmark;
+
+       enum ip_conntrack_info ctinfo;
+       struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
+       if (ct) {
+           switch(markinfo->mode) {
+           case IPT_CONNMARK_SET:
+               newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
+               if (newmark != ct->mark)
+                   ct->mark = newmark;
+               break;
+           case IPT_CONNMARK_SAVE:
+               newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
+               if (ct->mark != newmark)
+                   ct->mark = newmark;
+               break;
+           case IPT_CONNMARK_RESTORE:
+               nfmark = (*pskb)->nfmark;
+               diff = (ct->mark ^ nfmark) & markinfo->mask;
+               if (diff != 0) {
+                   (*pskb)->nfmark = nfmark ^ diff;
+                   (*pskb)->nfcache |= NFC_ALTERED;
+               }
+               break;
+           }
+       }
+
+       return IPT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ipt_entry *e,
+          void *targinfo,
+          unsigned int targinfosize,
+          unsigned int hook_mask)
+{
+       struct ipt_connmark_target_info *matchinfo = targinfo;
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
+               printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
+               return 0;
+       }
+
+       if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
+           if (strcmp(tablename, "mangle") != 0) {
+                   printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+                   return 0;
+           }
+       }
+
+       return 1;
+}
+
+static struct ipt_target ipt_connmark_reg = {
+       .name = "CONNMARK",
+       .target = &target,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ipt_register_target(&ipt_connmark_reg);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_connmark_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_comment.c b/net/ipv4/netfilter/ipt_comment.c
new file mode 100644 (file)
index 0000000..6b76a1e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Implements a dummy match to allow attaching comments to rules
+ *
+ * 2003-05-13 Brad Fisher (brad@info-link.net)
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_comment.h>
+
+MODULE_AUTHOR("Brad Fisher <brad@info-link.net>");
+MODULE_DESCRIPTION("iptables comment match module");
+MODULE_LICENSE("GPL");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+       /* We always match */
+       return 1;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ipt_ip *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       /* Check the size */
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_comment_info)))
+               return 0;
+       return 1;
+}
+
+static struct ipt_match comment_match = {
+       .name           = "comment",
+       .match          = match,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ipt_register_match(&comment_match);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&comment_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_connmark.c b/net/ipv4/netfilter/ipt_connmark.c
new file mode 100644 (file)
index 0000000..2706f96
--- /dev/null
@@ -0,0 +1,81 @@
+/* This kernel module matches connection mark values set by the
+ * CONNMARK target
+ *
+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
+MODULE_DESCRIPTION("IP tables connmark match module");
+MODULE_LICENSE("GPL");
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_connmark.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+       const struct ipt_connmark_info *info = matchinfo;
+       enum ip_conntrack_info ctinfo;
+       struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+       if (!ct)
+               return 0;
+
+       return ((ct->mark & info->mask) == info->mark) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ipt_ip *ip,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct ipt_match connmark_match = {
+       .name = "connmark",
+       .match = &match,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ipt_register_match(&connmark_match);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&connmark_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
new file mode 100644 (file)
index 0000000..04c95d8
--- /dev/null
@@ -0,0 +1,713 @@
+/* iptables match extension to limit the number of packets per second
+ * seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
+ *
+ * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
+ *
+ * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $
+ *
+ * Development of this code was funded by Astaro AG, http://www.astaro.com/
+ *
+ * based on ipt_limit.c by:
+ * Jérôme de Vivie     <devivie@info.enserb.u-bordeaux.fr>
+ * Hervé Eychenne      <eychenne@info.enserb.u-bordeaux.fr>
+ * Rusty Russell       <rusty@rustcorp.com.au>
+ *
+ * The general idea is to create a hash table for every dstip and have a
+ * seperate limit counter per tuple.  This way you can do something like 'limit
+ * the number of syn packets for each of my internal addresses.
+ *
+ * Ideally this would just be implemented as a general 'hash' match, which would
+ * allow us to attach any iptables target to it's hash buckets.  But this is
+ * not possible in the current iptables architecture.  As always, pkttables for
+ * 2.7.x will help ;)
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/sctp.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#define ASSERT_READ_LOCK(x) 
+#define ASSERT_WRITE_LOCK(x) 
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_hashlimit.h>
+
+/* FIXME: this is just for IP_NF_ASSERRT */
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+#define MS2JIFFIES(x) ((x*HZ)/1000)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("iptables match for limiting per hash-bucket");
+
+/* need to declare this at the top */
+static struct proc_dir_entry *hashlimit_procdir;
+static struct file_operations dl_file_ops;
+
+/* hash table crap */
+
+struct dsthash_dst {
+       u_int32_t src_ip;
+       u_int32_t dst_ip;
+       /* ports have to be consecutive !!! */
+       u_int16_t src_port;
+       u_int16_t dst_port;
+};
+
+struct dsthash_ent {
+       /* static / read-only parts in the beginning */
+       struct list_head list;
+       struct dsthash_dst dst;
+
+       /* modified structure members in the end */
+       unsigned long expires;          /* precalculated expiry time */
+       struct {
+               unsigned long prev;     /* last modification */
+               u_int32_t credit;
+               u_int32_t credit_cap, cost;
+       } rateinfo;
+};
+
+struct ipt_hashlimit_htable {
+       struct list_head list;          /* global list of all htables */
+       atomic_t use;
+
+       struct hashlimit_cfg cfg;       /* config */
+
+       /* used internally */
+       spinlock_t lock;                /* lock for list_head */
+       u_int32_t rnd;                  /* random seed for hash */
+       struct timer_list timer;        /* timer for gc */
+       atomic_t count;                 /* number entries in table */
+
+       /* seq_file stuff */
+       struct proc_dir_entry *pde;
+
+       struct list_head hash[0];       /* hashtable itself */
+};
+
+DECLARE_RWLOCK(hashlimit_lock);                /* protects htables list */
+static LIST_HEAD(hashlimit_htables);
+static kmem_cache_t *hashlimit_cachep;
+
+static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
+{
+       return (ent->dst.dst_ip == b->dst_ip 
+               && ent->dst.dst_port == b->dst_port
+               && ent->dst.src_port == b->src_port
+               && ent->dst.src_ip == b->src_ip);
+}
+
+static inline u_int32_t
+hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
+{
+       return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 & dst->src_port), 
+                            dst->src_ip, ht->rnd) % ht->cfg.size);
+}
+
+static inline struct dsthash_ent *
+__dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst)
+{
+       struct dsthash_ent *ent;
+       u_int32_t hash = hash_dst(ht, dst);
+       ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
+       return ent;
+}
+
+/* allocate dsthash_ent, initialize dst, put in htable and lock it */
+static struct dsthash_ent *
+__dsthash_alloc_init(struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst)
+{
+       struct dsthash_ent *ent;
+
+       /* initialize hash with random val at the time we allocate
+        * the first hashtable entry */
+       if (!ht->rnd)
+               get_random_bytes(&ht->rnd, 4);
+
+       if (ht->cfg.max &&
+           atomic_read(&ht->count) >= ht->cfg.max) {
+               /* FIXME: do something. question is what.. */
+               if (net_ratelimit())
+                       printk(KERN_WARNING 
+                               "ipt_hashlimit: max count of %u reached\n", 
+                               ht->cfg.max);
+               return NULL;
+       }
+
+       ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC);
+       if (!ent) {
+               if (net_ratelimit())
+                       printk(KERN_ERR 
+                               "ipt_hashlimit: can't allocate dsthash_ent\n");
+               return NULL;
+       }
+
+       atomic_inc(&ht->count);
+
+       ent->dst.dst_ip = dst->dst_ip;
+       ent->dst.dst_port = dst->dst_port;
+       ent->dst.src_ip = dst->src_ip;
+       ent->dst.src_port = dst->src_port;
+
+       list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
+
+       return ent;
+}
+
+static inline void 
+__dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent)
+{
+       list_del(&ent->list);
+       kmem_cache_free(hashlimit_cachep, ent);
+       atomic_dec(&ht->count);
+}
+static void htable_gc(unsigned long htlong);
+
+static int htable_create(struct ipt_hashlimit_info *minfo)
+{
+       int i;
+       unsigned int size;
+       struct ipt_hashlimit_htable *hinfo;
+
+       if (minfo->cfg.size)
+               size = minfo->cfg.size;
+       else {
+               size = (((num_physpages << PAGE_SHIFT) / 16384)
+                        / sizeof(struct list_head));
+               if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
+                       size = 8192;
+               if (size < 16)
+                       size = 16;
+       }
+       /* FIXME: don't use vmalloc() here or anywhere else -HW */
+       hinfo = vmalloc(sizeof(struct ipt_hashlimit_htable)
+                       + (sizeof(struct list_head) * size));
+       if (!hinfo) {
+               printk(KERN_ERR "ipt_hashlimit: Unable to create hashtable\n");
+               return -1;
+       }
+       minfo->hinfo = hinfo;
+
+       /* copy match config into hashtable config */
+       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
+       hinfo->cfg.size = size;
+       if (!hinfo->cfg.max)
+               hinfo->cfg.max = 8 * hinfo->cfg.size;
+       else if (hinfo->cfg.max < hinfo->cfg.size)
+               hinfo->cfg.max = hinfo->cfg.size;
+
+       for (i = 0; i < hinfo->cfg.size; i++)
+               INIT_LIST_HEAD(&hinfo->hash[i]);
+
+       atomic_set(&hinfo->count, 0);
+       atomic_set(&hinfo->use, 1);
+       hinfo->rnd = 0;
+       spin_lock_init(&hinfo->lock);
+       hinfo->pde = create_proc_entry(minfo->name, 0, hashlimit_procdir);
+       if (!hinfo->pde) {
+               vfree(hinfo);
+               return -1;
+       }
+       hinfo->pde->proc_fops = &dl_file_ops;
+       hinfo->pde->data = hinfo;
+
+       init_timer(&hinfo->timer);
+       hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
+       hinfo->timer.data = (unsigned long )hinfo;
+       hinfo->timer.function = htable_gc;
+       add_timer(&hinfo->timer);
+
+       WRITE_LOCK(&hashlimit_lock);
+       list_add(&hinfo->list, &hashlimit_htables);
+       WRITE_UNLOCK(&hashlimit_lock);
+
+       return 0;
+}
+
+static int select_all(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he)
+{
+       return 1;
+}
+
+static int select_gc(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he)
+{
+       return (jiffies >= he->expires);
+}
+
+static void htable_selective_cleanup(struct ipt_hashlimit_htable *ht,
+                               int (*select)(struct ipt_hashlimit_htable *ht, 
+                                             struct dsthash_ent *he))
+{
+       int i;
+
+       IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
+
+       /* lock hash table and iterate over it */
+       spin_lock_bh(&ht->lock);
+       for (i = 0; i < ht->cfg.size; i++) {
+               struct dsthash_ent *dh, *n;
+               list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
+                       if ((*select)(ht, dh))
+                               __dsthash_free(ht, dh);
+               }
+       }
+       spin_unlock_bh(&ht->lock);
+}
+
+/* hash table garbage collector, run by timer */
+static void htable_gc(unsigned long htlong)
+{
+       struct ipt_hashlimit_htable *ht = (struct ipt_hashlimit_htable *)htlong;
+
+       htable_selective_cleanup(ht, select_gc);
+
+       /* re-add the timer accordingly */
+       ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
+       add_timer(&ht->timer);
+}
+
+static void htable_destroy(struct ipt_hashlimit_htable *hinfo)
+{
+       /* remove timer, if it is pending */
+       if (timer_pending(&hinfo->timer))
+               del_timer(&hinfo->timer);
+
+       /* remove proc entry */
+       remove_proc_entry(hinfo->pde->name, hashlimit_procdir);
+
+       htable_selective_cleanup(hinfo, select_all);
+       vfree(hinfo);
+}
+
+static struct ipt_hashlimit_htable *htable_find_get(char *name)
+{
+       struct ipt_hashlimit_htable *hinfo;
+
+       READ_LOCK(&hashlimit_lock);
+       list_for_each_entry(hinfo, &hashlimit_htables, list) {
+               if (!strcmp(name, hinfo->pde->name)) {
+                       atomic_inc(&hinfo->use);
+                       READ_UNLOCK(&hashlimit_lock);
+                       return hinfo;
+               }
+       }
+       READ_UNLOCK(&hashlimit_lock);
+
+       return NULL;
+}
+
+static void htable_put(struct ipt_hashlimit_htable *hinfo)
+{
+       if (atomic_dec_and_test(&hinfo->use)) {
+               WRITE_LOCK(&hashlimit_lock);
+               list_del(&hinfo->list);
+               WRITE_UNLOCK(&hashlimit_lock);
+               htable_destroy(hinfo);
+       }
+}
+
+
+/* The algorithm used is the Simple Token Bucket Filter (TBF)
+ * see net/sched/sch_tbf.c in the linux source tree
+ */
+
+/* Rusty: This is my (non-mathematically-inclined) understanding of
+   this algorithm.  The `average rate' in jiffies becomes your initial
+   amount of credit `credit' and the most credit you can ever have
+   `credit_cap'.  The `peak rate' becomes the cost of passing the
+   test, `cost'.
+
+   `prev' tracks the last packet hit: you gain one credit per jiffy.
+   If you get credit balance more than this, the extra credit is
+   discarded.  Every time the match passes, you lose `cost' credits;
+   if you don't have that many, the test fails.
+
+   See Alexey's formal explanation in net/sched/sch_tbf.c.
+
+   To get the maximum range, we multiply by this factor (ie. you get N
+   credits per jiffy).  We want to allow a rate as low as 1 per day
+   (slowest userspace tool allows), which means
+   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
+*/
+#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
+
+/* Repeated shift and or gives us all 1s, final shift and add 1 gives
+ * us the power of 2 below the theoretical max, so GCC simply does a
+ * shift. */
+#define _POW2_BELOW2(x) ((x)|((x)>>1))
+#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
+#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
+#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
+#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
+#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
+
+#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
+
+/* Precision saver. */
+static inline u_int32_t
+user2credits(u_int32_t user)
+{
+       /* If multiplying would overflow... */
+       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
+               /* Divide first. */
+               return (user / IPT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
+
+       return (user * HZ * CREDITS_PER_JIFFY) / IPT_HASHLIMIT_SCALE;
+}
+
+static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
+{
+       dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) 
+                                       * CREDITS_PER_JIFFY;
+       if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
+               dh->rateinfo.credit = dh->rateinfo.credit_cap;
+}
+
+static inline int get_ports(const struct sk_buff *skb, int offset, 
+                           u16 ports[2])
+{
+       union {
+               struct tcphdr th;
+               struct udphdr uh;
+               sctp_sctphdr_t sctph;
+       } hdr_u, *ptr_u;
+
+       /* Must not be a fragment. */
+       if (offset)
+               return 1;
+
+       /* Must be big enough to read ports (both UDP and TCP have
+          them at the start). */
+       ptr_u = skb_header_pointer(skb, skb->nh.iph->ihl*4, 8, &hdr_u); 
+       if (!ptr_u)
+               return 1;
+
+       switch (skb->nh.iph->protocol) {
+               case IPPROTO_TCP:
+                       ports[0] = ptr_u->th.source;
+                       ports[1] = ptr_u->th.dest;
+                       break;
+               case IPPROTO_UDP:
+                       ports[0] = ptr_u->uh.source;
+                       ports[1] = ptr_u->uh.dest;
+                       break;
+               case IPPROTO_SCTP:
+                       ports[0] = ptr_u->sctph.source;
+                       ports[1] = ptr_u->sctph.dest;
+                       break;
+               default:
+                       /* all other protocols don't supprot per-port hash
+                        * buckets */
+                       ports[0] = ports[1] = 0;
+                       break;
+       }
+
+       return 0;
+}
+
+
+static int
+hashlimit_match(const struct sk_buff *skb,
+               const struct net_device *in,
+               const struct net_device *out,
+               const void *matchinfo,
+               int offset,
+               int *hotdrop)
+{
+       struct ipt_hashlimit_info *r = 
+               ((struct ipt_hashlimit_info *)matchinfo)->u.master;
+       struct ipt_hashlimit_htable *hinfo = r->hinfo;
+       unsigned long now = jiffies;
+       struct dsthash_ent *dh;
+       struct dsthash_dst dst;
+
+       /* build 'dst' according to hinfo->cfg and current packet */
+       memset(&dst, 0, sizeof(dst));
+       if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DIP)
+               dst.dst_ip = skb->nh.iph->daddr;
+       if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SIP)
+               dst.src_ip = skb->nh.iph->saddr;
+       if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT
+           ||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) {
+               u_int16_t ports[2];
+               if (get_ports(skb, offset, ports)) {
+                       /* We've been asked to examine this packet, and we
+                         can't.  Hence, no choice but to drop. */
+                       *hotdrop = 1;
+                       return 0;
+               }
+               if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT)
+                       dst.src_port = ports[0];
+               if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT)
+                       dst.dst_port = ports[1];
+       } 
+
+       spin_lock_bh(&hinfo->lock);
+       dh = __dsthash_find(hinfo, &dst);
+       if (!dh) {
+               dh = __dsthash_alloc_init(hinfo, &dst);
+
+               if (!dh) {
+                       /* enomem... don't match == DROP */
+                       if (net_ratelimit())
+                               printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
+                       spin_unlock_bh(&hinfo->lock);
+                       return 0;
+               }
+
+               dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
+
+               dh->rateinfo.prev = jiffies;
+               dh->rateinfo.credit = user2credits(hinfo->cfg.avg * 
+                                                       hinfo->cfg.burst);
+               dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * 
+                                                       hinfo->cfg.burst);
+               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
+
+               spin_unlock_bh(&hinfo->lock);
+               return 1;
+       }
+
+       /* update expiration timeout */
+       dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
+
+       rateinfo_recalc(dh, now);
+       if (dh->rateinfo.credit >= dh->rateinfo.cost) {
+               /* We're underlimit. */
+               dh->rateinfo.credit -= dh->rateinfo.cost;
+               spin_unlock_bh(&hinfo->lock);
+               return 1;
+       }
+
+               spin_unlock_bh(&hinfo->lock);
+
+       /* default case: we're overlimit, thus don't match */
+       return 0;
+}
+
+static int
+hashlimit_checkentry(const char *tablename,
+                    const struct ipt_ip *ip,
+                    void *matchinfo,
+                    unsigned int matchsize,
+                    unsigned int hook_mask)
+{
+       struct ipt_hashlimit_info *r = matchinfo;
+
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_hashlimit_info)))
+               return 0;
+
+       /* Check for overflow. */
+       if (r->cfg.burst == 0
+           || user2credits(r->cfg.avg * r->cfg.burst) < 
+                                       user2credits(r->cfg.avg)) {
+               printk(KERN_ERR "ipt_hashlimit: Overflow, try lower: %u/%u\n",
+                      r->cfg.avg, r->cfg.burst);
+               return 0;
+       }
+
+       if (r->cfg.mode == 0 
+           || r->cfg.mode > (IPT_HASHLIMIT_HASH_DPT
+                         |IPT_HASHLIMIT_HASH_DIP
+                         |IPT_HASHLIMIT_HASH_SIP
+                         |IPT_HASHLIMIT_HASH_SPT))
+               return 0;
+
+       if (!r->cfg.gc_interval)
+               return 0;
+       
+       if (!r->cfg.expire)
+               return 0;
+
+       r->hinfo = htable_find_get(r->name);
+       if (!r->hinfo && (htable_create(r) != 0)) {
+               return 0;
+       }
+
+       /* Ugly hack: For SMP, we only want to use one set */
+       r->u.master = r;
+
+       return 1;
+}
+
+static void
+hashlimit_destroy(void *matchinfo, unsigned int matchsize)
+{
+       struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo;
+
+       htable_put(r->hinfo);
+}
+
+static struct ipt_match ipt_hashlimit = { 
+       .name = "hashlimit", 
+       .match = hashlimit_match, 
+       .checkentry = hashlimit_checkentry, 
+       .destroy = hashlimit_destroy,
+       .me = THIS_MODULE 
+};
+
+/* PROC stuff */
+
+static void *dl_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct ipt_hashlimit_htable *htable = pde->data;
+       unsigned int *bucket;
+
+       spin_lock_bh(&htable->lock);
+       if (*pos >= htable->cfg.size)
+               return NULL;
+
+       bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+       if (!bucket)
+               return ERR_PTR(-ENOMEM);
+
+       *bucket = *pos;
+       return bucket;
+}
+
+static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct ipt_hashlimit_htable *htable = pde->data;
+       unsigned int *bucket = (unsigned int *)v;
+
+       *pos = ++(*bucket);
+       if (*pos >= htable->cfg.size) {
+               kfree(v);
+               return NULL;
+       }
+       return bucket;
+}
+
+static void dl_seq_stop(struct seq_file *s, void *v)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct ipt_hashlimit_htable *htable = pde->data;
+       unsigned int *bucket = (unsigned int *)v;
+
+       kfree(bucket);
+
+       spin_unlock_bh(&htable->lock);
+}
+
+static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
+{
+       /* recalculate to show accurate numbers */
+       rateinfo_recalc(ent, jiffies);
+
+       return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n",
+                       (ent->expires - jiffies)/HZ,
+                       NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port),
+                       NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port),
+                       ent->rateinfo.credit, ent->rateinfo.credit_cap,
+                       ent->rateinfo.cost);
+}
+
+static int dl_seq_show(struct seq_file *s, void *v)
+{
+       struct proc_dir_entry *pde = s->private;
+       struct ipt_hashlimit_htable *htable = pde->data;
+       unsigned int *bucket = (unsigned int *)v;
+
+       if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
+                     struct dsthash_ent *, s)) {
+               /* buffer was filled and unable to print that tuple */
+               return 1;
+       }
+       return 0;
+}
+
+static struct seq_operations dl_seq_ops = {
+       .start = dl_seq_start,
+       .next  = dl_seq_next,
+       .stop  = dl_seq_stop,
+       .show  = dl_seq_show
+};
+
+static int dl_proc_open(struct inode *inode, struct file *file)
+{
+       int ret = seq_open(file, &dl_seq_ops);
+
+       if (!ret) {
+               struct seq_file *sf = file->private_data;
+               sf->private = PDE(inode);
+       }
+       return ret;
+}
+
+static struct file_operations dl_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = dl_proc_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release
+};
+
+static int init_or_fini(int fini)
+{
+       int ret = 0;
+
+       if (fini)
+               goto cleanup;
+
+       if (ipt_register_match(&ipt_hashlimit)) {
+               ret = -EINVAL;
+               goto cleanup_nothing;
+       }
+
+       /* FIXME: do we really want HWCACHE_ALIGN since our objects are
+        * quite small ? */
+       hashlimit_cachep = kmem_cache_create("ipt_hashlimit",
+                                           sizeof(struct dsthash_ent), 0,
+                                           SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (!hashlimit_cachep) {
+               printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n");
+               ret = -ENOMEM;
+               goto cleanup_unreg_match;
+       }
+
+       hashlimit_procdir = proc_mkdir("ipt_hashlimit", proc_net);
+       if (!hashlimit_procdir) {
+               printk(KERN_ERR "Unable to create proc dir entry\n");
+               ret = -ENOMEM;
+               goto cleanup_free_slab;
+       }
+
+       return ret;
+
+cleanup:
+       remove_proc_entry("ipt_hashlimit", proc_net);
+cleanup_free_slab:
+       kmem_cache_destroy(hashlimit_cachep);
+cleanup_unreg_match:
+       ipt_unregister_match(&ipt_hashlimit);
+cleanup_nothing:
+       return ret;
+       
+}
+
+static int __init init(void)
+{
+       return init_or_fini(0);
+}
+
+static void __exit fini(void)
+{
+       init_or_fini(1);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_sctp.c b/net/ipv4/netfilter/ipt_sctp.c
new file mode 100644 (file)
index 0000000..fe2b327
--- /dev/null
@@ -0,0 +1,203 @@
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/ip.h>
+#include <linux/sctp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_sctp.h>
+
+#ifdef DEBUG_SCTP
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
+                                             || (!!((invflag) & (option)) ^ (cond)))
+
+static int
+match_flags(const struct ipt_sctp_flag_info *flag_info,
+           const int flag_count,
+           u_int8_t chunktype,
+           u_int8_t chunkflags)
+{
+       int i;
+
+       for (i = 0; i < flag_count; i++) {
+               if (flag_info[i].chunktype == chunktype) {
+                       return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
+               }
+       }
+
+       return 1;
+}
+
+static int
+match_packet(const struct sk_buff *skb,
+            const u_int32_t *chunkmap,
+            int chunk_match_type,
+            const struct ipt_sctp_flag_info *flag_info,
+            const int flag_count,
+            int *hotdrop)
+{
+       int offset;
+       u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
+       sctp_chunkhdr_t _sch, *sch;
+
+#ifdef DEBUG_SCTP
+       int i = 0;
+#endif
+
+       if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
+               SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
+       }
+
+       offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
+       do {
+               sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
+               if (sch == NULL) {
+                       duprintf("Dropping invalid SCTP packet.\n");
+                       *hotdrop = 1;
+                       return 0;
+               }
+
+               duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
+                               ++i, offset, sch->type, htons(sch->length), sch->flags);
+
+               offset += (htons(sch->length) + 3) & ~3;
+
+               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
+
+               if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) {
+                       switch (chunk_match_type) {
+                       case SCTP_CHUNK_MATCH_ANY:
+                               if (match_flags(flag_info, flag_count, 
+                                       sch->type, sch->flags)) {
+                                       return 1;
+                               }
+                               break;
+
+                       case SCTP_CHUNK_MATCH_ALL:
+                               if (match_flags(flag_info, flag_count, 
+                                       sch->type, sch->flags)) {
+                                       SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
+                               }
+                               break;
+
+                       case SCTP_CHUNK_MATCH_ONLY:
+                               if (!match_flags(flag_info, flag_count, 
+                                       sch->type, sch->flags)) {
+                                       return 0;
+                               }
+                               break;
+                       }
+               } else {
+                       switch (chunk_match_type) {
+                       case SCTP_CHUNK_MATCH_ONLY:
+                               return 0;
+                       }
+               }
+       } while (offset < skb->len);
+
+       switch (chunk_match_type) {
+       case SCTP_CHUNK_MATCH_ALL:
+               return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
+       case SCTP_CHUNK_MATCH_ANY:
+               return 0;
+       case SCTP_CHUNK_MATCH_ONLY:
+               return 1;
+       }
+
+       /* This will never be reached, but required to stop compiler whine */
+       return 0;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      int *hotdrop)
+{
+       const struct ipt_sctp_info *info;
+       sctp_sctphdr_t _sh, *sh;
+
+       info = (const struct ipt_sctp_info *)matchinfo;
+
+       if (offset) {
+               duprintf("Dropping non-first fragment.. FIXME\n");
+               return 0;
+       }
+       
+       sh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_sh), &_sh);
+       if (sh == NULL) {
+               duprintf("Dropping evil TCP offset=0 tinygram.\n");
+               *hotdrop = 1;
+               return 0;
+               }
+       duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
+
+       return  SCCHECK(((ntohs(sh->source) >= info->spts[0]) 
+                       && (ntohs(sh->source) <= info->spts[1])), 
+                       IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
+               && SCCHECK(((ntohs(sh->dest) >= info->dpts[0]) 
+                       && (ntohs(sh->dest) <= info->dpts[1])), 
+                       IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
+               && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
+                                       info->flag_info, info->flag_count, 
+                                       hotdrop),
+                          IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
+}
+
+static int
+checkentry(const char *tablename,
+          const struct ipt_ip *ip,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       const struct ipt_sctp_info *info;
+
+       info = (const struct ipt_sctp_info *)matchinfo;
+
+       return ip->proto == IPPROTO_SCTP
+               && !(ip->invflags & IPT_INV_PROTO)
+               && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
+               && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
+               && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
+               && !(info->invflags & ~info->flags)
+               && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
+                       (info->chunk_match_type &
+                               (SCTP_CHUNK_MATCH_ALL 
+                               | SCTP_CHUNK_MATCH_ANY
+                               | SCTP_CHUNK_MATCH_ONLY)));
+}
+
+static struct ipt_match sctp_match = 
+{ 
+       .list = { NULL, NULL},
+       .name = "sctp",
+       .match = &match,
+       .checkentry = &checkentry,
+       .destroy = NULL,
+       .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return ipt_register_match(&sctp_match);
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_match(&sctp_match);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kiran Kumar Immidi");
+MODULE_DESCRIPTION("Match for SCTP protocol packets");
+
diff --git a/net/ipv6/netfilter/ip6t_physdev.c b/net/ipv6/netfilter/ip6t_physdev.c
new file mode 100644 (file)
index 0000000..f4eebb4
--- /dev/null
@@ -0,0 +1,136 @@
+/* Kernel module to match the bridge port in and
+ * out device for IP packets coming into contact with a bridge. */
+
+/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * 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/skbuff.h>
+#include <linux/netfilter_ipv6/ip6t_physdev.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_bridge.h>
+#define MATCH   1
+#define NOMATCH 0
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
+MODULE_DESCRIPTION("iptables bridge physical device match module");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       int i;
+       static const char nulldevname[IFNAMSIZ];
+       const struct ip6t_physdev_info *info = matchinfo;
+       unsigned int ret;
+       const char *indev, *outdev;
+       struct nf_bridge_info *nf_bridge;
+
+       /* Not a bridged IP packet or no info available yet:
+        * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
+        * the destination device will be a bridge. */
+       if (!(nf_bridge = skb->nf_bridge)) {
+               /* Return MATCH if the invert flags of the used options are on */
+               if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) &&
+                   !(info->invert & IP6T_PHYSDEV_OP_BRIDGED))
+                       return NOMATCH;
+               if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN) &&
+                   !(info->invert & IP6T_PHYSDEV_OP_ISIN))
+                       return NOMATCH;
+               if ((info->bitmask & IP6T_PHYSDEV_OP_ISOUT) &&
+                   !(info->invert & IP6T_PHYSDEV_OP_ISOUT))
+                       return NOMATCH;
+               if ((info->bitmask & IP6T_PHYSDEV_OP_IN) &&
+                   !(info->invert & IP6T_PHYSDEV_OP_IN))
+                       return NOMATCH;
+               if ((info->bitmask & IP6T_PHYSDEV_OP_OUT) &&
+                   !(info->invert & IP6T_PHYSDEV_OP_OUT))
+                       return NOMATCH;
+               return MATCH;
+       }
+
+       /* This only makes sense in the FORWARD and POSTROUTING chains */
+       if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) &&
+           (!!(nf_bridge->mask & BRNF_BRIDGED) ^
+           !(info->invert & IP6T_PHYSDEV_OP_BRIDGED)))
+               return NOMATCH;
+
+       if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN &&
+           (!nf_bridge->physindev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISIN))) ||
+           (info->bitmask & IP6T_PHYSDEV_OP_ISOUT &&
+           (!nf_bridge->physoutdev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISOUT))))
+               return NOMATCH;
+
+       if (!(info->bitmask & IP6T_PHYSDEV_OP_IN))
+               goto match_outdev;
+       indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
+       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+               ret |= (((const unsigned int *)indev)[i]
+                       ^ ((const unsigned int *)info->physindev)[i])
+                       & ((const unsigned int *)info->in_mask)[i];
+       }
+
+       if ((ret == 0) ^ !(info->invert & IP6T_PHYSDEV_OP_IN))
+               return NOMATCH;
+
+match_outdev:
+       if (!(info->bitmask & IP6T_PHYSDEV_OP_OUT))
+               return MATCH;
+       outdev = nf_bridge->physoutdev ?
+                nf_bridge->physoutdev->name : nulldevname;
+       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+               ret |= (((const unsigned int *)outdev)[i]
+                       ^ ((const unsigned int *)info->physoutdev)[i])
+                       & ((const unsigned int *)info->out_mask)[i];
+       }
+
+       return (ret != 0) ^ !(info->invert & IP6T_PHYSDEV_OP_OUT);
+}
+
+static int
+checkentry(const char *tablename,
+                      const struct ip6t_ip6 *ip,
+                      void *matchinfo,
+                      unsigned int matchsize,
+                      unsigned int hook_mask)
+{
+       const struct ip6t_physdev_info *info = matchinfo;
+
+       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_physdev_info)))
+               return 0;
+       if (!(info->bitmask & IP6T_PHYSDEV_OP_MASK) ||
+           info->bitmask & ~IP6T_PHYSDEV_OP_MASK)
+               return 0;
+       return 1;
+}
+
+static struct ip6t_match physdev_match = {
+       .name           = "physdev",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ip6t_register_match(&physdev_match);
+}
+
+static void __exit fini(void)
+{
+       ip6t_unregister_match(&physdev_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/sched/gact.c b/net/sched/gact.c
new file mode 100644 (file)
index 0000000..5607f5e
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * net/sched/gact.c    Generic actions
+ *
+ *             This 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   Jamal Hadi Salim (2002-4)
+ *
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/tc_act/tc_gact.h>
+#include <net/tc_act/tc_gact.h>
+
+/* use generic hash table */
+#define MY_TAB_SIZE    16
+#define MY_TAB_MASK    15
+static u32 idx_gen;
+static struct tcf_gact *tcf_gact_ht[MY_TAB_SIZE];
+static rwlock_t gact_lock = RW_LOCK_UNLOCKED;
+
+/* ovewrride the defaults */
+#define tcf_st  tcf_gact
+#define tc_st  tc_gact
+#define tcf_t_lock   gact_lock
+#define tcf_ht tcf_gact_ht
+
+#define CONFIG_NET_ACT_INIT 1
+#include <net/pkt_act.h>
+
+#ifdef CONFIG_GACT_PROB
+typedef int (*g_rand)(struct tcf_gact *p);
+int
+gact_net_rand(struct tcf_gact *p) {
+       if (net_random()%p->pval)
+               return p->action;
+       return p->paction;
+}
+
+int
+gact_determ(struct tcf_gact *p) {
+       if (p->stats.packets%p->pval)
+               return p->action;
+       return p->paction;
+}
+
+
+g_rand gact_rand[MAX_RAND]= { NULL,gact_net_rand, gact_determ};
+
+#endif
+int
+tcf_gact_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,int ovr,int bind)
+{
+       struct rtattr *tb[TCA_GACT_MAX];
+       struct tc_gact *parm = NULL;
+#ifdef CONFIG_GACT_PROB
+       struct tc_gact_p *p_parm = NULL;
+#endif
+       struct tcf_gact *p = NULL;
+       int ret = 0;
+       int size = sizeof (*p);
+
+       if (rtattr_parse(tb, TCA_GACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0)
+               return -1;
+
+       if (NULL == a || NULL == tb[TCA_GACT_PARMS - 1]) {
+               printk("BUG: tcf_gact_init called with NULL params\n");
+               return -1;
+       }
+
+       parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]);
+#ifdef CONFIG_GACT_PROB
+       if (NULL != tb[TCA_GACT_PROB - 1]) {
+               p_parm = RTA_DATA(tb[TCA_GACT_PROB - 1]);
+       }
+#endif
+
+       p = tcf_hash_check(parm, a, ovr, bind);
+
+       if (NULL == p) {
+               p = tcf_hash_create(parm,est,a,size,ovr, bind);
+
+               if (NULL == p) {
+                       return -1;
+               } else {
+                       p->refcnt = 1;
+                       ret = 1;
+                       goto override;
+               }
+       }
+
+       if (ovr) {
+override:
+               p->action = parm->action;
+#ifdef CONFIG_GACT_PROB
+               if (NULL != p_parm) {
+                       p->paction = p_parm->paction;
+                       p->pval = p_parm->pval;
+                       p->ptype = p_parm->ptype;
+               } else {
+                       p->paction = p->pval = p->ptype = 0;
+               }
+#endif
+       }
+
+       return ret;
+}
+
+int
+tcf_gact_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_gact *p;
+       p = PRIV(a,gact);
+       if (NULL != p)
+               return tcf_hash_release(p, bind);
+       return 0;
+}
+
+int
+tcf_gact(struct sk_buff **pskb, struct tc_action *a)
+{
+       struct tcf_gact *p;
+       struct sk_buff *skb = *pskb;
+       int action = TC_ACT_SHOT;
+
+       p = PRIV(a,gact);
+
+       if (NULL == p) {
+               if (net_ratelimit())
+                       printk("BUG: tcf_gact called with NULL params\n");
+               return -1;
+       }
+
+       spin_lock(&p->lock);
+#ifdef CONFIG_GACT_PROB
+       if (p->ptype && NULL != gact_rand[p->ptype])
+               action = gact_rand[p->ptype](p);
+       else
+               action = p->action;
+#else
+       action = p->action;
+#endif
+       p->stats.bytes += skb->len;
+       p->stats.packets++;
+       if (TC_ACT_SHOT == action)
+               p->stats.drops++;
+       p->tm.lastuse = jiffies;
+       spin_unlock(&p->lock);
+
+       return action;
+}
+
+int
+tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+{
+       unsigned char *b = skb->tail;
+       struct tc_gact opt;
+#ifdef CONFIG_GACT_PROB
+       struct tc_gact_p p_opt;
+#endif
+       struct tcf_gact *p;
+       struct tcf_t t;
+
+       p = PRIV(a,gact);
+       if (NULL == p) {
+               printk("BUG: tcf_gact_dump called with NULL params\n");
+               goto rtattr_failure;
+       }
+
+       opt.index = p->index;
+       opt.refcnt = p->refcnt - ref;
+       opt.bindcnt = p->bindcnt - bind;
+       opt.action = p->action;
+       RTA_PUT(skb, TCA_GACT_PARMS, sizeof (opt), &opt);
+#ifdef CONFIG_GACT_PROB
+       if (p->ptype) {
+               p_opt.paction = p->paction;
+               p_opt.pval = p->pval;
+               p_opt.ptype = p->ptype;
+               RTA_PUT(skb, TCA_GACT_PROB, sizeof (p_opt), &p_opt);
+       } 
+#endif
+       t.install = jiffies - p->tm.install;
+       t.lastuse = jiffies - p->tm.lastuse;
+       t.expires = p->tm.expires;
+       RTA_PUT(skb, TCA_GACT_TM, sizeof (t), &t);
+       return skb->len;
+
+      rtattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+int
+tcf_gact_stats(struct sk_buff *skb, struct tc_action *a)
+{
+       struct tcf_gact *p;
+       p = PRIV(a,gact);
+       if (NULL != p)
+               return qdisc_copy_stats(skb, &p->stats,p->stats_lock);
+
+       return 1;
+}
+
+struct tc_action_ops act_gact_ops = {
+       .next           =       NULL,
+       .kind           =       "gact",
+       .type           =       TCA_ACT_GACT,
+       .capab          =       TCA_CAP_NONE,
+       .owner          =       THIS_MODULE,
+       .act            =       tcf_gact,
+       .get_stats      =       tcf_gact_stats,
+       .dump           =       tcf_gact_dump,
+       .cleanup        =       tcf_gact_cleanup,
+       .lookup         =       tcf_hash_search,
+       .init           =       tcf_gact_init,
+       .walk           =       tcf_generic_walker
+};
+
+MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
+MODULE_DESCRIPTION("Generic Classifier actions");
+MODULE_LICENSE("GPL");
+
+static int __init
+gact_init_module(void)
+{
+#ifdef CONFIG_GACT_PROB
+       printk("GACT probability on\n");
+#else
+       printk("GACT probability NOT on\n");
+#endif
+       return tcf_register_action(&act_gact_ops);
+}
+
+static void __exit
+gact_cleanup_module(void)
+{
+       tcf_unregister_action(&act_gact_ops);
+}
+
+module_init(gact_init_module);
+module_exit(gact_cleanup_module);
diff --git a/net/sched/ipt.c b/net/sched/ipt.c
new file mode 100644 (file)
index 0000000..386d948
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * net/sched/ipt.c     iptables target interface
+ *
+ *TODO: Add other tables. For now we only support the ipv4 table targets
+ *
+ *             This 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:  Jamal Hadi Salim (2002-4)
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/tc_act/tc_ipt.h>
+#include <net/tc_act/tc_ipt.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+/* use generic hash table */
+#define MY_TAB_SIZE     16
+#define MY_TAB_MASK     15
+
+static u32 idx_gen;
+static struct tcf_ipt *tcf_ipt_ht[MY_TAB_SIZE];
+/* ipt hash table lock */
+static rwlock_t ipt_lock = RW_LOCK_UNLOCKED;
+
+/* ovewrride the defaults */
+#define tcf_st  tcf_ipt
+#define tcf_t_lock   ipt_lock
+#define tcf_ht tcf_ipt_ht
+
+#include <net/pkt_act.h>
+
+static inline int
+init_targ(struct tcf_ipt *p)
+{
+       struct ipt_target *target;
+       int ret = 0;
+       struct ipt_entry_target *t = p->t;
+       target = __ipt_find_target_lock(t->u.user.name, &ret);
+
+       if (!target) {
+               printk("init_targ: Failed to find %s\n", t->u.user.name);
+               return -1;
+       }
+
+       DPRINTK("init_targ: found %s\n", target->name);
+       /* we really need proper ref counting
+        seems to be only needed for modules?? Talk to laforge */
+/*      if (target->me)
+              __MOD_INC_USE_COUNT(target->me);
+*/
+       t->u.kernel.target = target;
+
+       __ipt_mutex_up();
+
+       if (t->u.kernel.target->checkentry
+           && !t->u.kernel.target->checkentry(p->tname, NULL, t->data,
+                                              t->u.target_size
+                                              - sizeof (*t), p->hook)) {
+/*              if (t->u.kernel.target->me)
+             __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
+*/
+               DPRINTK("ip_tables: check failed for `%s'.\n",
+                       t->u.kernel.target->name);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int
+tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind)
+{
+       struct ipt_entry_target *t;
+       unsigned h;
+       struct rtattr *tb[TCA_IPT_MAX];
+       struct tcf_ipt *p;
+       int ret = 0;
+       u32 index = 0;
+       u32 hook = 0;
+
+       if (NULL == a || NULL == rta ||
+           (rtattr_parse(tb, TCA_IPT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) <
+            0)) {
+               return -1;
+       }
+
+
+       if (tb[TCA_IPT_INDEX - 1]) {
+               index = *(u32 *) RTA_DATA(tb[TCA_IPT_INDEX - 1]);
+               DPRINTK("ipt index %d\n", index);
+       }
+
+       if (index && (p = tcf_hash_lookup(index)) != NULL) {
+               a->priv = (void *) p;
+               spin_lock(&p->lock);
+               if (bind) {
+                       p->bindcnt += 1;
+                       p->refcnt += 1;
+               }
+               if (ovr) {
+                       goto override;
+               }
+               spin_unlock(&p->lock);
+               return ret;
+       }
+
+       if (NULL == tb[TCA_IPT_TARG - 1] || NULL == tb[TCA_IPT_HOOK - 1]) {
+               return -1;
+       }
+
+       p = kmalloc(sizeof (*p), GFP_KERNEL);
+       if (p == NULL)
+               return -1;
+
+       memset(p, 0, sizeof (*p));
+       p->refcnt = 1;
+       ret = 1;
+       spin_lock_init(&p->lock);
+       p->stats_lock = &p->lock;
+       if (bind)
+               p->bindcnt = 1;
+
+override:
+       hook = *(u32 *) RTA_DATA(tb[TCA_IPT_HOOK - 1]);
+
+       t = (struct ipt_entry_target *) RTA_DATA(tb[TCA_IPT_TARG - 1]);
+
+       p->t = kmalloc(t->u.target_size, GFP_KERNEL);
+       if (p->t == NULL) {
+               if (ovr) {
+                       printk("ipt policy messed up \n");
+                       spin_unlock(&p->lock);
+                       return -1;
+               }
+               kfree(p);
+               return -1;
+       }
+
+       memcpy(p->t, RTA_DATA(tb[TCA_IPT_TARG - 1]), t->u.target_size);
+       DPRINTK(" target NAME %s size %d data[0] %x data[1] %x\n",
+               t->u.user.name, t->u.target_size, t->data[0], t->data[1]);
+
+       p->tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
+
+       if (p->tname == NULL) {
+               if (ovr) {
+                       printk("ipt policy messed up 2 \n");
+                       spin_unlock(&p->lock);
+                       return -1;
+               }
+               kfree(p->t);
+               kfree(p);
+               return -1;
+       } else {
+               int csize = IFNAMSIZ - 1;
+
+               memset(p->tname, 0, IFNAMSIZ);
+               if (tb[TCA_IPT_TABLE - 1]) {
+                       if (strlen((char *) RTA_DATA(tb[TCA_IPT_TABLE - 1])) <
+                           csize)
+                               csize = strlen(RTA_DATA(tb[TCA_IPT_TABLE - 1]));
+                       strncpy(p->tname, RTA_DATA(tb[TCA_IPT_TABLE - 1]),
+                               csize);
+                       DPRINTK("table name %s\n", p->tname);
+               } else {
+                       strncpy(p->tname, "mangle", 1 + strlen("mangle"));
+               }
+       }
+
+       if (0 > init_targ(p)) {
+               if (ovr) {
+                       printk("ipt policy messed up 2 \n");
+                       spin_unlock(&p->lock);
+                       return -1;
+               }
+               kfree(p->tname);
+               kfree(p->t);
+               kfree(p);
+               return -1;
+       }
+
+       if (ovr) {
+               spin_unlock(&p->lock);
+               return -1;
+       }
+
+       p->index = index ? : tcf_hash_new_index();
+
+       p->tm.lastuse = jiffies;
+       /*
+       p->tm.expires = jiffies;
+       */
+       p->tm.install = jiffies;
+#ifdef CONFIG_NET_ESTIMATOR
+       if (est)
+               gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
+#endif
+       h = tcf_hash(p->index);
+       write_lock_bh(&ipt_lock);
+       p->next = tcf_ipt_ht[h];
+       tcf_ipt_ht[h] = p;
+       write_unlock_bh(&ipt_lock);
+       a->priv = (void *) p;
+       return ret;
+
+}
+
+static int
+tcf_ipt_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_ipt *p;
+       p = PRIV(a,ipt);
+       if (NULL != p)
+               return tcf_hash_release(p, bind);
+       return 0;
+}
+
+static int
+tcf_ipt(struct sk_buff **pskb, struct tc_action *a)
+{
+       int ret = 0, result = 0;
+       struct tcf_ipt *p;
+       struct sk_buff *skb = *pskb;
+
+       p = PRIV(a,ipt);
+
+       if (NULL == p || NULL == skb) {
+               return -1;
+       }
+
+       spin_lock(&p->lock);
+
+       p->tm.lastuse = jiffies;
+       p->bstats.bytes += skb->len;
+       p->bstats.packets++;
+
+       if (skb_cloned(skb) ) {
+               if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+                       return -1;
+               }
+       }
+       /* yes, we have to worry about both in and out dev
+        worry later - danger - this API seems to have changed
+        from earlier kernels */
+
+       ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL,
+                                           p->hook, p->t->data, (void *)NULL);
+       switch (ret) {
+       case NF_ACCEPT:
+               result = TC_ACT_OK;
+               break;
+       case NF_DROP:
+               result = TC_ACT_SHOT;
+               p->qstats.drops++;
+               break;
+       case IPT_CONTINUE:
+               result = TC_ACT_PIPE;
+               break;
+       default:
+               if (net_ratelimit())
+                       printk("Bogus netfilter code %d assume ACCEPT\n", ret);
+               result = TC_POLICE_OK;
+               break;
+       }
+       spin_unlock(&p->lock);
+       return result;
+
+}
+
+static int
+tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+{
+       struct ipt_entry_target *t;
+       struct tcf_t tm;
+       struct tc_cnt c;
+       unsigned char *b = skb->tail;
+
+       struct tcf_ipt *p;
+
+       p = PRIV(a,ipt);
+       if (NULL == p) {
+               printk("BUG: tcf_ipt_dump called with NULL params\n");
+               goto rtattr_failure;
+       }
+       /* for simple targets kernel size == user size
+       ** user name = target name
+       ** for foolproof you need to not assume this
+       */
+
+       t = kmalloc(p->t->u.user.target_size, GFP_ATOMIC);
+
+       if (NULL == t)
+               goto rtattr_failure;
+
+       c.bindcnt = p->bindcnt - bind;
+       c.refcnt = p->refcnt - ref;
+       memcpy(t, p->t, p->t->u.user.target_size);
+       strcpy(t->u.user.name, p->t->u.kernel.target->name);
+
+       DPRINTK("\ttcf_ipt_dump tablename %s length %d\n", p->tname,
+               strlen(p->tname));
+       DPRINTK
+           ("\tdump target name %s size %d size user %d data[0] %x data[1] %x\n",
+            p->t->u.kernel.target->name, p->t->u.target_size, p->t->u.user.target_size,
+            p->t->data[0], p->t->data[1]);
+       RTA_PUT(skb, TCA_IPT_TARG, p->t->u.user.target_size, t);
+       RTA_PUT(skb, TCA_IPT_INDEX, 4, &p->index);
+       RTA_PUT(skb, TCA_IPT_HOOK, 4, &p->hook);
+       RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c);
+       RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, p->tname);
+       tm.install = jiffies_to_clock_t(jiffies - p->tm.install);
+       tm.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+       tm.expires = jiffies_to_clock_t(p->tm.expires);
+       RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
+       return skb->len;
+
+      rtattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static struct tc_action_ops act_ipt_ops = {
+       .next           =       NULL,
+       .kind           =       "ipt",
+       .type           =       TCA_ACT_IPT,
+       .capab          =       TCA_CAP_NONE,
+       .owner          =       THIS_MODULE,
+       .act            =       tcf_ipt,
+       .dump           =       tcf_ipt_dump,
+       .cleanup        =       tcf_ipt_cleanup,
+       .lookup         =       tcf_hash_search,
+       .init           =       tcf_ipt_init,
+       .walk           =       tcf_generic_walker
+};
+
+MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
+MODULE_DESCRIPTION("Iptables target actions");
+MODULE_LICENSE("GPL");
+
+static int __init
+ipt_init_module(void)
+{
+       return tcf_register_action(&act_ipt_ops);
+}
+
+static void __exit
+ipt_cleanup_module(void)
+{
+       tcf_unregister_action(&act_ipt_ops);
+}
+
+module_init(ipt_init_module);
+module_exit(ipt_cleanup_module);
diff --git a/net/sched/mirred.c b/net/sched/mirred.c
new file mode 100644 (file)
index 0000000..07e3ba1
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * net/sched/mirred.c  packet mirroring and redirect actions
+ *
+ *             This 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:    Jamal Hadi Salim (2002-4)
+ *
+ * TODO: Add ingress support (and socket redirect support)
+ *
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/tc_act/tc_mirred.h>
+#include <net/tc_act/tc_mirred.h>
+
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+
+/* use generic hash table */
+#define MY_TAB_SIZE     8
+#define MY_TAB_MASK     (MY_TAB_SIZE - 1)
+static u32 idx_gen;
+static struct tcf_mirred *tcf_mirred_ht[MY_TAB_SIZE];
+static rwlock_t mirred_lock = RW_LOCK_UNLOCKED;
+
+/* ovewrride the defaults */
+#define tcf_st  tcf_mirred
+#define tc_st  tc_mirred
+#define tcf_t_lock   mirred_lock
+#define tcf_ht tcf_mirred_ht
+
+#define CONFIG_NET_ACT_INIT 1
+#include <net/pkt_act.h>
+
+static inline int
+tcf_mirred_release(struct tcf_mirred *p, int bind)
+{
+       if (p) {
+               if (bind) {
+                       p->bindcnt--;
+               }
+
+               p->refcnt--;
+               if(!p->bindcnt && p->refcnt <= 0) {
+                       dev_put(p->dev);
+                       tcf_hash_destroy(p);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int
+tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,int ovr, int bind)
+{
+       struct rtattr *tb[TCA_MIRRED_MAX];
+       struct tc_mirred *parm;
+       struct tcf_mirred *p;
+       struct net_device *dev = NULL;
+       int size = sizeof (*p), new = 0;
+
+
+       if (rtattr_parse(tb, TCA_MIRRED_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) {
+               DPRINTK("tcf_mirred_init BUG in user space couldnt parse properly\n");
+               return -1;
+       }
+
+       if (NULL == a || NULL == tb[TCA_MIRRED_PARMS - 1]) {
+               DPRINTK("BUG: tcf_mirred_init called with NULL params\n");
+               return -1;
+       }
+
+       parm = RTA_DATA(tb[TCA_MIRRED_PARMS - 1]);
+
+       p = tcf_hash_check(parm, a, ovr, bind);
+       if (NULL == p) { /* new */
+               p = tcf_hash_create(parm,est,a,size,ovr,bind);
+               new = 1;
+               if (NULL == p)
+                       return -1;
+       }
+
+       if (parm->ifindex) {
+               dev = dev_get_by_index(parm->ifindex);
+               if (NULL == dev) {
+                       printk("BUG: tcf_mirred_init called with bad device\n");
+                       return -1;
+               }
+               switch (dev->type) {
+                       case ARPHRD_TUNNEL:
+                       case ARPHRD_TUNNEL6:
+                       case ARPHRD_SIT:
+                       case ARPHRD_IPGRE:
+                       case ARPHRD_VOID:
+                       case ARPHRD_NONE:
+                               p->ok_push = 0;
+                               break;
+                       default:
+                               p->ok_push = 1;
+                               break;
+               }
+       } else {
+               if (new) {
+                       kfree(p);
+                       return -1;
+               }       
+       }
+
+       if (new || ovr) {
+               spin_lock(&p->lock);
+               p->action = parm->action;
+               p->eaction = parm->eaction;
+               if (parm->ifindex) {
+                       p->ifindex = parm->ifindex;
+                       if (ovr)
+                               dev_put(p->dev);
+                       p->dev = dev;
+               }
+               spin_unlock(&p->lock);
+       }
+
+
+       DPRINTK(" tcf_mirred_init index %d action %d eaction %d device %s ifndex %d\n",parm->index,parm->action,parm->eaction,dev->name,parm->ifindex);
+       return new;
+
+}
+
+static int
+tcf_mirred_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_mirred *p;
+       p = PRIV(a,mirred);
+       if (NULL != p)
+               return tcf_mirred_release(p, bind);
+       return 0;
+}
+
+static int
+tcf_mirred(struct sk_buff **pskb, struct tc_action *a)
+{
+       struct tcf_mirred *p;
+       struct net_device *dev;
+       struct sk_buff *skb2 = NULL;
+       struct sk_buff *skb = *pskb;
+       __u32 at = G_TC_AT(skb->tc_verd);
+
+       if (NULL == a) {
+               if (net_ratelimit())
+                       printk("BUG: tcf_mirred called with NULL action!\n");
+               return -1;
+       }
+
+       p = PRIV(a,mirred);
+
+       if (NULL == p) {
+               if (net_ratelimit())
+                       printk("BUG: tcf_mirred called with NULL params\n");
+               return -1;
+       }
+
+       spin_lock(&p->lock);
+
+               dev = p->dev;
+       p->tm.lastuse = jiffies;
+
+       if (NULL == dev || !(dev->flags&IFF_UP) ) {
+               if (net_ratelimit())
+                       printk("mirred to Houston: device %s is gone!\n",
+                                       dev?dev->name:"");
+bad_mirred:
+               if (NULL != skb2)
+                       kfree_skb(skb2);
+               p->qstats.overlimits++;
+               p->bstats.bytes += skb->len;
+               p->bstats.packets++;
+               spin_unlock(&p->lock);
+               /* should we be asking for packet to be dropped?
+                * may make sense for redirect case only 
+               */
+               return TC_ACT_SHOT;
+       } 
+
+       skb2 = skb_clone(skb, GFP_ATOMIC);
+       if (skb2 == NULL) {
+               goto bad_mirred;
+       }
+       if (TCA_EGRESS_MIRROR != p->eaction &&
+               TCA_EGRESS_REDIR != p->eaction) {
+               if (net_ratelimit())
+                       printk("tcf_mirred unknown action %d\n",p->eaction);
+               goto bad_mirred;
+       }
+
+       p->bstats.bytes += skb2->len;
+       p->bstats.packets++;
+       if ( !(at & AT_EGRESS)) {
+               if (p->ok_push) {
+                       skb_push(skb2, skb2->dev->hard_header_len);
+               }
+       }
+
+       /* mirror is always swallowed */
+       if (TCA_EGRESS_MIRROR != p->eaction)
+               skb2->tc_verd = SET_TC_FROM(skb2->tc_verd,at);
+
+       skb2->dev = dev;
+       skb2->input_dev = skb->dev;
+       dev_queue_xmit(skb2);
+       spin_unlock(&p->lock);
+       return p->action;
+}
+
+static int
+tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref)
+{
+       unsigned char *b = skb->tail;
+       struct tc_mirred opt;
+       struct tcf_mirred *p;
+       struct tcf_t t;
+
+       p = PRIV(a,mirred);
+       if (NULL == p) {
+               printk("BUG: tcf_mirred_dump called with NULL params\n");
+               goto rtattr_failure;
+       }
+
+       opt.index = p->index;
+       opt.action = p->action;
+       opt.refcnt = p->refcnt - ref;
+       opt.bindcnt = p->bindcnt - bind;
+       opt.eaction = p->eaction;
+       opt.ifindex = p->ifindex;
+       DPRINTK(" tcf_mirred_dump index %d action %d eaction %d ifndex %d\n",p->index,p->action,p->eaction,p->ifindex);
+       RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof (opt), &opt);
+       t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+       t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+       t.expires = jiffies_to_clock_t(p->tm.expires);
+       RTA_PUT(skb, TCA_MIRRED_TM, sizeof (t), &t);
+       return skb->len;
+
+      rtattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static struct tc_action_ops act_mirred_ops = {
+       .next           =       NULL,
+       .kind           =       "mirred",
+       .type           =       TCA_ACT_MIRRED,
+       .capab          =       TCA_CAP_NONE,
+       .owner          =       THIS_MODULE,
+       .act            =       tcf_mirred,
+       .dump           =       tcf_mirred_dump,
+       .cleanup        =       tcf_mirred_cleanup,
+       .lookup         =       tcf_hash_search,
+       .init           =       tcf_mirred_init,
+       .walk           =       tcf_generic_walker
+};
+
+MODULE_AUTHOR("Jamal Hadi Salim(2002)");
+MODULE_DESCRIPTION("Device Mirror/redirect actions");
+MODULE_LICENSE("GPL");
+
+
+static int __init
+mirred_init_module(void)
+{
+       printk("Mirror/redirect action on\n");
+       return tcf_register_action(&act_mirred_ops);
+}
+
+static void __exit
+mirred_cleanup_module(void)
+{
+       tcf_unregister_action(&act_mirred_ops);
+}
+
+module_init(mirred_init_module);
+module_exit(mirred_cleanup_module);
+
diff --git a/net/sched/pedit.c b/net/sched/pedit.c
new file mode 100644 (file)
index 0000000..23debf3
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * net/sched/pedit.c   Generic packet editor
+ *
+ *             This 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:    Jamal Hadi Salim (2002-4)
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/tc_act/tc_pedit.h>
+#include <net/tc_act/tc_pedit.h>
+
+
+#define PEDIT_DEB 1
+
+/* use generic hash table */
+#define MY_TAB_SIZE     16
+#define MY_TAB_MASK     15
+static u32 idx_gen;
+static struct tcf_pedit *tcf_pedit_ht[MY_TAB_SIZE];
+static rwlock_t pedit_lock = RW_LOCK_UNLOCKED;
+
+#define tcf_st  tcf_pedit
+#define tc_st  tc_pedit
+#define tcf_t_lock   pedit_lock
+#define tcf_ht tcf_pedit_ht
+
+#define CONFIG_NET_ACT_INIT 1
+#include <net/pkt_act.h>
+
+
+static int
+tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,int ovr, int bind)
+{
+       struct rtattr *tb[TCA_PEDIT_MAX];
+       struct tc_pedit *parm;
+       int size = 0;
+       int ret = 0;
+       struct tcf_pedit *p = NULL;
+
+       if (rtattr_parse(tb, TCA_PEDIT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0)
+               return -1;
+
+       if (NULL == a || NULL == tb[TCA_PEDIT_PARMS - 1]) {
+               printk("BUG: tcf_pedit_init called with NULL params\n");
+               return -1;
+       }
+
+       parm = RTA_DATA(tb[TCA_PEDIT_PARMS - 1]);
+
+       p = tcf_hash_check(parm, a, ovr, bind);
+
+       if (NULL == p) { /* new */
+
+               if (!parm->nkeys)
+                       return -1;
+
+               size = sizeof (*p)+ (parm->nkeys*sizeof(struct tc_pedit_key));
+
+               p = tcf_hash_create(parm,est,a,size,ovr,bind);
+
+               if (NULL == p)
+                       return -1;
+               ret = 1;
+               goto override;
+       } 
+
+       if (ovr) {
+override:
+               p->flags = parm->flags;
+               p->nkeys = parm->nkeys;
+               p->action = parm->action;
+               memcpy(p->keys,parm->keys,parm->nkeys*(sizeof(struct tc_pedit_key)));
+       }
+
+       return ret;
+}
+
+static int
+tcf_pedit_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_pedit *p;
+       p = PRIV(a,pedit);
+       if (NULL != p)
+               return  tcf_hash_release(p, bind);
+       return 0;
+}
+
+/*
+**
+*/
+static int
+tcf_pedit(struct sk_buff **pskb, struct tc_action *a)
+{
+       struct tcf_pedit *p;
+       struct sk_buff *skb = *pskb;
+       int i, munged = 0;
+       u8 *pptr;
+
+       p = PRIV(a,pedit);
+
+       if (NULL == p) {
+               printk("BUG: tcf_pedit called with NULL params\n");
+               return -1; /* change to something symbolic */
+       }
+
+       if (!(skb->tc_verd & TC_OK2MUNGE)) {
+               /* should we set skb->cloned? */
+               if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+                       return p->action;
+               }
+       }
+
+       pptr = skb->nh.raw;
+
+       spin_lock(&p->lock);
+
+       p->tm.lastuse = jiffies;
+
+       if (0 < p->nkeys) {
+               struct tc_pedit_key *tkey = p->keys;
+
+               for (i = p->nkeys; i > 0; i--, tkey++) {
+                       u32 *ptr ;
+
+                       int offset = tkey->off;
+                       if (tkey->offmask) {
+                               if (skb->len > tkey->at) {
+                                        char *j = pptr+tkey->at;
+                                        offset +=((*j&tkey->offmask)>>tkey->shift);
+                               } else {
+                                       goto bad;
+                               }
+                       }
+
+                       if (offset % 4) {
+                               printk("offset must be on 32 bit boundaries\n");
+                               goto bad;
+                       }
+
+                       if (skb->len < 0 || (offset > 0 && offset > skb->len)) {
+                               printk("offset %d cant exceed pkt length %d\n",
+                                               offset, skb->len);
+                               goto bad;
+                       }
+
+
+                       ptr = (u32 *)(pptr+offset);
+                       /* just do it, baby */
+                       *ptr = ((*ptr & tkey->mask) ^ tkey->val);
+                       munged++;
+               }
+               
+               if (munged)
+                       skb->tc_verd = SET_TC_MUNGED(skb->tc_verd);
+               goto done;
+       } else {
+               printk("pedit BUG: index %d\n",p->index);
+       }
+
+bad:
+       p->qstats.overlimits++;
+done:
+       p->bstats.bytes += skb->len;
+       p->bstats.packets++;
+       spin_unlock(&p->lock);
+       return p->action;
+}
+
+static int
+tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref)
+{
+       unsigned char *b = skb->tail;
+       struct tc_pedit *opt;
+       struct tcf_pedit *p;
+       struct tcf_t t;
+       int s; 
+               
+
+       p = PRIV(a,pedit);
+
+       if (NULL == p) {
+               printk("BUG: tcf_pedit_dump called with NULL params\n");
+               goto rtattr_failure;
+       }
+
+       s = sizeof (*opt)+(p->nkeys*sizeof(struct tc_pedit_key));
+
+       /* netlink spinlocks held above us - must use ATOMIC
+        * */
+       opt = kmalloc(s, GFP_ATOMIC);
+       if (opt == NULL)
+               return -ENOBUFS;
+
+       memset(opt, 0, s);
+
+       memcpy(opt->keys,p->keys,p->nkeys*(sizeof(struct tc_pedit_key)));
+       opt->index = p->index;
+       opt->nkeys = p->nkeys;
+       opt->flags = p->flags;
+       opt->action = p->action;
+       opt->refcnt = p->refcnt - ref;
+       opt->bindcnt = p->bindcnt - bind;
+
+
+#ifdef PEDIT_DEB
+       {                
+               /* Debug - get rid of later */
+               int i;
+               struct tc_pedit_key *key = opt->keys;
+
+               for (i=0; i<opt->nkeys; i++, key++) {
+                       printk( "\n key #%d",i);
+                       printk( "  at %d: val %08x mask %08x",
+                       (unsigned int)key->off,
+                       (unsigned int)key->val,
+                       (unsigned int)key->mask);
+                                                                                               }
+                                                                                       }
+#endif
+
+       RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt);
+       t.install = jiffies_to_clock_t(jiffies - p->tm.install);
+       t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
+       t.expires = jiffies_to_clock_t(p->tm.expires);
+       RTA_PUT(skb, TCA_PEDIT_TM, sizeof (t), &t);
+       return skb->len;
+
+rtattr_failure:
+       skb_trim(skb, b - skb->data);
+       return -1;
+}
+
+static
+struct tc_action_ops act_pedit_ops = {
+       .kind           =       "pedit",
+       .type           =       TCA_ACT_PEDIT,
+       .capab          =       TCA_CAP_NONE,
+       .owner          =       THIS_MODULE,
+       .act            =       tcf_pedit,
+       .dump           =       tcf_pedit_dump,
+       .cleanup        =       tcf_pedit_cleanup,
+       .lookup         =       tcf_hash_search,
+       .init           =       tcf_pedit_init,
+       .walk           =       tcf_generic_walker
+};
+
+MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
+MODULE_DESCRIPTION("Generic Packet Editor actions");
+MODULE_LICENSE("GPL");
+
+static int __init
+pedit_init_module(void)
+{
+       return tcf_register_action(&act_pedit_ops);
+}
+
+static void __exit
+pedit_cleanup_module(void)
+{
+       tcf_unregister_action(&act_pedit_ops);
+}
+
+module_init(pedit_init_module);
+module_exit(pedit_cleanup_module);
+
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
new file mode 100644 (file)
index 0000000..2887de1
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ *  linux/net/sunrpc/gss_spkm3_mech.c
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@umich.edu>
+ *  J. Bruce Fields <bfields@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/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/in.h>
+#include <linux/sunrpc/svcauth_gss.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY       RPCDBG_AUTH
+#endif
+
+struct xdr_netobj gss_mech_spkm3_oid =
+   {7, "\053\006\001\005\005\001\003"};
+
+static inline int
+get_bytes(char **ptr, const char *end, void *res, int len)
+{
+       char *p, *q;
+       p = *ptr;
+       q = p + len;
+       if (q > end || q < p)
+               return -1;
+       memcpy(res, p, len);
+       *ptr = q;
+       return 0;
+}
+
+static inline int
+get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
+{
+       char *p, *q;
+       p = *ptr;
+       if (get_bytes(&p, end, &res->len, sizeof(res->len)))
+               return -1;
+       q = p + res->len;
+       if(res->len == 0)
+               goto out_nocopy;
+       if (q > end || q < p)
+               return -1;
+       if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
+               return -1;
+       memcpy(res->data, p, res->len);
+out_nocopy:
+       *ptr = q;
+       return 0;
+}
+
+static inline int
+get_key(char **p, char *end, struct crypto_tfm **res, int *resalg)
+{
+       struct xdr_netobj       key = {
+               .len = 0,
+               .data = NULL,
+       };
+       int                     alg_mode,setkey = 0;
+       char                    *alg_name;
+
+       if (get_bytes(p, end, resalg, sizeof(int)))
+               goto out_err;
+       if ((get_netobj(p, end, &key)))
+               goto out_err;
+
+       switch (*resalg) {
+               case NID_des_cbc:
+                       alg_name = "des";
+                       alg_mode = CRYPTO_TFM_MODE_CBC;
+                       setkey = 1;
+                       break;
+               case NID_md5:
+                       if (key.len == 0) {
+                               dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
+                       }
+                       alg_name = "md5";
+                       alg_mode = 0;
+                       setkey = 0;
+                       break;
+               case NID_cast5_cbc:
+                       dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n");
+                       goto out_err;
+                       break;
+               default:
+                       dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
+                       goto out_err_free_key;
+       }
+       if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
+               goto out_err_free_key;
+       if (setkey) {
+               if (crypto_cipher_setkey(*res, key.data, key.len))
+                       goto out_err_free_tfm;
+       }
+
+       if(key.len > 0)
+               kfree(key.data);
+       return 0;
+
+out_err_free_tfm:
+       crypto_free_tfm(*res);
+out_err_free_key:
+       if(key.len > 0)
+               kfree(key.data);
+out_err:
+       return -1;
+}
+
+static u32
+gss_import_sec_context_spkm3(struct xdr_netobj *inbuf,
+                               struct gss_ctx *ctx_id)
+{
+       char    *p = inbuf->data;
+       char    *end = inbuf->data + inbuf->len;
+       struct  spkm3_ctx *ctx;
+
+       if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
+               goto out_err;
+       memset(ctx, 0, sizeof(*ctx));
+
+       if (get_netobj(&p, end, &ctx->ctx_id))
+               goto out_err_free_ctx;
+
+       if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop)))
+               goto out_err_free_ctx_id;
+
+       if (get_netobj(&p, end, &ctx->mech_used))
+               goto out_err_free_mech;
+
+       if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)))
+               goto out_err_free_mech;
+
+       if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags)))
+               goto out_err_free_mech;
+
+       if (get_netobj(&p, end, &ctx->share_key))
+               goto out_err_free_s_key;
+
+       if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) {
+               dprintk("RPC: SPKM3 confidentiality key will be NULL\n");
+       }
+
+       if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) {
+               dprintk("RPC: SPKM3 integrity key will be NULL\n");
+       }
+
+       if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
+               goto out_err_free_s_key;
+
+       if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
+               goto out_err_free_s_key;
+
+       if (p != end)
+               goto out_err_free_s_key;
+
+       ctx_id->internal_ctx_id = ctx;
+
+       dprintk("Succesfully imported new spkm context.\n");
+       return 0;
+
+out_err_free_s_key:
+       kfree(ctx->share_key.data);
+out_err_free_mech:
+       kfree(ctx->mech_used.data);
+out_err_free_ctx_id:
+       kfree(ctx->ctx_id.data);
+out_err_free_ctx:
+       kfree(ctx);
+out_err:
+       return GSS_S_FAILURE;
+}
+
+void
+gss_delete_sec_context_spkm3(void *internal_ctx) {
+       struct spkm3_ctx *sctx = internal_ctx;
+
+       if(sctx->derived_integ_key)
+               crypto_free_tfm(sctx->derived_integ_key);
+       if(sctx->derived_conf_key)
+               crypto_free_tfm(sctx->derived_conf_key);
+       if(sctx->share_key.data)
+               kfree(sctx->share_key.data);
+       if(sctx->mech_used.data)
+               kfree(sctx->mech_used.data);
+       kfree(sctx);
+}
+
+u32
+gss_verify_mic_spkm3(struct gss_ctx            *ctx,
+                       struct xdr_buf          *signbuf,
+                       struct xdr_netobj       *checksum,
+                       u32             *qstate) {
+       u32 maj_stat = 0;
+       int qop_state = 0;
+       struct spkm3_ctx *sctx = ctx->internal_ctx_id;
+
+       dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n");
+       maj_stat = spkm3_read_token(sctx, checksum, signbuf, &qop_state,
+                                  SPKM_MIC_TOK);
+
+       if (!maj_stat && qop_state)
+           *qstate = qop_state;
+
+       dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
+       return maj_stat;
+}
+
+u32
+gss_get_mic_spkm3(struct gss_ctx       *ctx,
+                    u32                qop,
+                    struct xdr_buf     *message_buffer,
+                    struct xdr_netobj  *message_token) {
+       u32 err = 0;
+       struct spkm3_ctx *sctx = ctx->internal_ctx_id;
+
+       dprintk("RPC: gss_get_mic_spkm3\n");
+
+       err = spkm3_make_token(sctx, qop, message_buffer,
+                             message_token, SPKM_MIC_TOK);
+       return err;
+}
+
+static struct gss_api_ops gss_spkm3_ops = {
+       .gss_import_sec_context = gss_import_sec_context_spkm3,
+       .gss_get_mic            = gss_get_mic_spkm3,
+       .gss_verify_mic         = gss_verify_mic_spkm3,
+       .gss_delete_sec_context = gss_delete_sec_context_spkm3,
+};
+
+static struct pf_desc gss_spkm3_pfs[] = {
+       {RPC_AUTH_GSS_SPKM, 0, RPC_GSS_SVC_NONE, "spkm3"},
+       {RPC_AUTH_GSS_SPKMI, 0, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
+};
+
+static struct gss_api_mech gss_spkm3_mech = {
+       .gm_name        = "spkm3",
+       .gm_owner       = THIS_MODULE,
+       .gm_ops         = &gss_spkm3_ops,
+       .gm_pf_num      = ARRAY_SIZE(gss_spkm3_pfs),
+       .gm_pfs         = gss_spkm3_pfs,
+};
+
+static int __init init_spkm3_module(void)
+{
+       int status;
+
+       status = gss_mech_register(&gss_spkm3_mech);
+       if (status)
+               printk("Failed to register spkm3 gss mechanism!\n");
+       return 0;
+}
+
+static void __exit cleanup_spkm3_module(void)
+{
+       gss_mech_unregister(&gss_spkm3_mech);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_spkm3_module);
+module_exit(cleanup_spkm3_module);
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
new file mode 100644 (file)
index 0000000..2533986
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *  linux/net/sunrpc/gss_spkm3_seal.c
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@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/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+/*
+ * spkm3_make_token()
+ *
+ * Only SPKM_MIC_TOK with md5 intg-alg is supported
+ */
+
+u32
+spkm3_make_token(struct spkm3_ctx *ctx, int qop_req,
+                  struct xdr_buf * text, struct xdr_netobj * token,
+                  int toktype)
+{
+       s32                     checksum_type;
+       char                    tokhdrbuf[25];
+       struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
+       struct xdr_netobj       mic_hdr = {.len = 0, .data = tokhdrbuf};
+       int                     tmsglen, tokenlen = 0;
+       unsigned char           *ptr;
+       s32                     now;
+       int                     ctxelen = 0, ctxzbit = 0;
+       int                     md5elen = 0, md5zbit = 0;
+
+       dprintk("RPC: spkm3_make_token\n");
+
+       now = jiffies;
+       if (qop_req != 0)
+               goto out_err;
+
+       if (ctx->ctx_id.len != 16) {
+               dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
+                       ctx->ctx_id.len);
+               goto out_err;
+       }
+               
+       switch (ctx->intg_alg) {
+               case NID_md5:
+                       checksum_type = CKSUMTYPE_RSA_MD5;
+                       break;
+               default:
+                       dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not"
+                               " supported\n", ctx->intg_alg);
+                       goto out_err;
+       }
+       /* XXX since we don't support WRAP, perhaps we don't care... */
+       if (ctx->conf_alg != NID_cast5_cbc) {
+               dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n",
+                       ctx->conf_alg);
+               goto out_err;
+       }
+
+       if (toktype == SPKM_MIC_TOK) {
+               tmsglen = 0;
+               /* Calculate checksum over the mic-header */
+               asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
+               spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
+                                        ctxelen, ctxzbit);
+
+               if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len, 
+                                            text, &md5cksum))
+                       goto out_err;
+
+               asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
+               tokenlen = 10 + ctxelen + 1 + 2 + md5elen + 1;
+
+               /* Create token header using generic routines */
+               token->len = g_token_size(&ctx->mech_used, tokenlen + tmsglen);
+
+               ptr = token->data;
+               g_make_token_header(&ctx->mech_used, tokenlen + tmsglen, &ptr);
+
+               spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
+       } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
+               dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n");
+               goto out_err;
+       }
+       kfree(md5cksum.data);
+
+       /* XXX need to implement sequence numbers, and ctx->expired */
+
+       return  GSS_S_COMPLETE;
+out_err:
+       if (md5cksum.data) 
+               kfree(md5cksum.data);
+       token->data = NULL;
+       token->len = 0;
+       return GSS_S_FAILURE;
+}
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
new file mode 100644 (file)
index 0000000..46c08a0
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ *  linux/net/sunrpc/gss_spkm3_token.c
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@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/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+/*
+ * asn1_bitstring_len()
+ *
+ * calculate the asn1 bitstring length of the xdr_netobject
+ */
+void
+asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
+{
+       int i, zbit = 0,elen = in->len;
+       char *ptr;
+
+       ptr = &in->data[in->len -1];
+
+       /* count trailing 0's */
+       for(i = in->len; i > 0; i--) {
+               if (*ptr == 0) { 
+                       ptr--;
+                       elen--;
+               } else
+                       break;
+       }
+
+       /* count number of 0 bits in final octet */
+       ptr = &in->data[elen - 1];
+       for(i = 0; i < 8; i++) {
+               short mask = 0x01;
+
+               if (!((mask << i) & *ptr))
+                       zbit++;
+               else
+                       break;
+       }
+       *enclen = elen;
+       *zerobits = zbit;
+}
+
+/*
+ * decode_asn1_bitstring()
+ * 
+ * decode a bitstring into a buffer of the expected length.
+ * enclen = bit string length
+ * explen = expected length (define in rfc)
+ */
+int
+decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
+{
+       if (!(out->data = kmalloc(explen,GFP_KERNEL)))
+               return 0;
+       out->len = explen;
+       memset(out->data, 0, explen);
+       memcpy(out->data, in, enclen);
+       return 1;
+}
+
+/* 
+ * SPKMInnerContextToken choice SPKM_MIC asn1 token layout
+ * 
+ * contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
+ *
+ * tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
+ *
+ * pos  value
+ * ----------
+ * [0] a4  SPKM-MIC tag
+ * [1] ??  innertoken length  (max 44) 
+ * 
+ * 
+ * tok_hdr piece of checksum data starts here 
+ *
+ * the maximum mic-header len = 9 + 17 = 26 
+ *     mic-header
+ *     ----------
+ * [2] 30      SEQUENCE tag  
+ * [3] ??      mic-header length: (max 23) = TokenID + ContextID 
+ *
+ *             TokenID  - all fields constant and can be hardcoded
+ *             -------
+ * [4]   02    Type 2
+ * [5]   02    Length 2 
+ * [6][7] 01 01        TokenID (SPKM_MIC_TOK)
+ *
+ *             ContextID  - encoded length not constant, calculated
+ *             ---------
+ * [8] 03      Type 3
+ * [9] ??      encoded length
+ * [10]        ??      ctxzbit
+ * [11]                contextid
+ *
+ * mic_header piece of checksum data ends here. 
+ *
+ *     int-cksum - encoded length not constant, calculated
+ *     ---------
+ * [??]        03      Type 3
+ * [??]        ??      encoded length 
+ * [??]        ??      md5zbit         
+ * [??]                int-cksum (NID_md5 = 16)
+ *
+ * maximum SPKM-MIC innercontext token length = 
+ *      10 + encoded contextid_size(17 max) + 2 + encoded  
+ *       cksum_size (17 maxfor NID_md5) = 46
+ */
+
+/*
+ * spkm3_mic_header()
+ *
+ * Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
+ * elen: 16 byte context id asn1 bitstring encoded length
+ */
+void
+spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
+{
+       char *hptr = *hdrbuf;
+       char *top = *hdrbuf;
+
+       *(u8 *)hptr++ = 0x30;
+       *(u8 *)hptr++ = elen + 7;  /* on the wire header length */
+
+       /* tokenid */
+       *(u8 *)hptr++ = 0x02;
+       *(u8 *)hptr++ = 0x02;
+       *(u8 *)hptr++ = 0x01;
+       *(u8 *)hptr++ = 0x01;
+
+       /* coniextid */
+       *(u8 *)hptr++ = 0x03;
+       *(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
+       *(u8 *)hptr++ = zbit;
+       memcpy(hptr, ctxdata, elen);
+       hptr += elen;
+       *hdrlen = hptr - top; 
+}
+               
+/* 
+ * spkm3_mic_innercontext_token()
+ *
+ * *tokp points to the beginning of the SPKM_MIC token  described 
+ * in rfc 2025, section 3.2.1: 
+ *
+ */
+void
+spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
+{
+       unsigned char *ict = *tokp;
+
+       *(u8 *)ict++ = 0xa4;
+       *(u8 *)ict++ = toklen - 2; 
+       memcpy(ict, mic_hdr->data, mic_hdr->len);
+       ict += mic_hdr->len;
+
+       *(u8 *)ict++ = 0x03;
+       *(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
+       *(u8 *)ict++ = md5zbit;
+       memcpy(ict, md5cksum->data, md5elen);
+}
+
+u32
+spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
+{
+       struct xdr_netobj       spkm3_ctx_id = {.len =0, .data = NULL};
+       unsigned char           *ptr = *tokp;
+       int                     ctxelen;
+       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
+
+       /* spkm3 innercontext token preamble */
+       if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
+               dprintk("RPC: BAD SPKM ictoken preamble\n"); 
+               goto out;
+       }
+
+       *mic_hdrlen = ptr[3];
+
+       /* token type */
+       if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
+               dprintk("RPC: BAD asn1 SPKM3 token type\n");
+               goto out;
+       }
+
+       /* only support SPKM_MIC_TOK */
+       if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
+               dprintk("RPC: ERROR unsupported SPKM3 token \n");
+               goto out;
+       }
+
+       /* contextid */
+       if (ptr[8] != 0x03) {
+               dprintk("RPC: BAD SPKM3 asn1 context-id type\n");
+               goto out;
+       }
+
+       ctxelen = ptr[9];
+       if (ctxelen > 17) {  /* length includes asn1 zbit octet */
+               dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen);
+               goto out;
+       }
+
+       /* ignore ptr[10] */
+
+       if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
+               goto out;
+
+       /*
+       * in the current implementation: the optional int-alg is not present 
+       * so the default int-alg (md5) is used the optional snd-seq field is 
+       * also not present 
+       */
+
+       if (*mic_hdrlen != 6 + ctxelen) {
+               dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq\n", *mic_hdrlen);
+               goto out;
+       }
+       /* checksum */
+        *cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
+
+       ret = GSS_S_COMPLETE;
+out:
+       if (spkm3_ctx_id.data)
+               kfree(spkm3_ctx_id.data);
+       return ret;
+}
+
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
new file mode 100644 (file)
index 0000000..65ce81b
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *  linux/net/sunrpc/gss_spkm3_unseal.c
+ *
+ *  Copyright (c) 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@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/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/sunrpc/gss_spkm3.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+/*
+ * spkm3_read_token()
+ * 
+ * only SPKM_MIC_TOK with md5 intg-alg is supported
+ */
+u32
+spkm3_read_token(struct spkm3_ctx *ctx,
+               struct xdr_netobj *read_token,    /* checksum */
+               struct xdr_buf *message_buffer, /* signbuf */
+               int *qop_state, int toktype)
+{
+       s32                     code;
+       struct xdr_netobj       wire_cksum = {.len =0, .data = NULL};
+       struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
+       unsigned char           *ptr = (unsigned char *)read_token->data;
+       unsigned char           *cksum;
+       int                     bodysize, md5elen;
+       int                     mic_hdrlen;
+       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
+
+       dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len);
+
+       if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
+                                       &bodysize, &ptr, read_token->len))
+               goto out;
+
+       /* decode the token */
+
+       if (toktype == SPKM_MIC_TOK) {
+
+               if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) 
+                       goto out;
+
+               if (*cksum++ != 0x03) {
+                       dprintk("RPC: spkm3_read_token BAD checksum type\n");
+                       goto out;
+               }
+               md5elen = *cksum++; 
+               cksum++;        /* move past the zbit */
+       
+               if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
+                       goto out;
+
+               /* HARD CODED FOR MD5 */
+
+               /* compute the checksum of the message.
+               *  ptr + 2 = start of header piece of checksum
+               *  mic_hdrlen + 2 = length of header piece of checksum
+               */
+               ret = GSS_S_DEFECTIVE_TOKEN;
+               code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2, 
+                                       mic_hdrlen + 2, 
+                                       message_buffer, &md5cksum);
+
+               if (code)
+                       goto out;
+
+               dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n", 
+                       wire_cksum.len);
+               dprintk("          md5cksum.data\n");
+               print_hexl((u32 *) md5cksum.data, 16, 0);
+               dprintk("          cksum.data:\n");
+               print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0);
+
+               ret = GSS_S_BAD_SIG;
+               code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
+               if (code)
+                       goto out;
+
+       } else { 
+               dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype);
+               goto out;
+       }
+
+       /* XXX: need to add expiration and sequencing */
+       ret = GSS_S_COMPLETE;
+out:
+       if (md5cksum.data) 
+               kfree(md5cksum.data);
+       if (wire_cksum.data) 
+               kfree(wire_cksum.data);
+       return ret;
+}
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
new file mode 100644 (file)
index 0000000..2821a2b
--- /dev/null
@@ -0,0 +1,155 @@
+# ==========================================================================
+# Building binaries on the host system
+# Binaries are used during the compilation of the kernel, for example
+# to preprocess a data file.
+#
+# Both C and C++ is supported, but preferred language is C for such utilities.
+#
+# Samle syntax (see Documentation/kbuild/makefile.txt for reference)
+# hostprogs-y := bin2hex
+# Will compile bin2hex.c and create an executable named bin2hex
+#
+# hostprogs-y    := lxdialog
+# lxdialog-objs := checklist.o lxdialog.o
+# Will compile lxdialog.c and checklist.c, and then link the executable
+# lxdialog, based on checklist.o and lxdialog.o
+#
+# hostprogs-y      := qconf
+# qconf-cxxobjs   := qconf.o
+# qconf-objs      := menu.o
+# Will compile qconf as a C++ program, and menu as a C program.
+# They are linked as C++ code to the executable qconf
+
+# hostprogs-y := conf
+# conf-objs  := conf.o libkconfig.so
+# libkconfig-objs := expr.o type.o
+# Will create a shared library named libkconfig.so that consist of
+# expr.o and type.o (they are both compiled as C code and the object file
+# are made as position independent code).
+# conf.c is compiled as a c program, and conf.o is linked together with
+# libkconfig.so as the executable conf.
+# Note: Shared libraries consisting of C++ files are not supported
+
+__hostprogs := $(sort $(hostprogs-y)$(hostprogs-m))
+
+# hostprogs-y := tools/build may have been specified. Retreive directory
+obj-dirs += $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
+obj-dirs := $(strip $(sort $(filter-out ./,$(obj-dirs))))
+
+
+# C code
+# Executables compiled from a single .c file
+host-csingle   := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
+
+# C executables linked based on several .o files
+host-cmulti    := $(foreach m,$(__hostprogs),\
+                  $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
+
+# Object (.o) files compiled from .c files
+host-cobjs     := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
+
+# C++ code
+# C++ executables compiled from at least on .cc file
+# and zero or more .c files
+host-cxxmulti  := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
+
+# C++ Object (.o) files compiled from .cc files
+host-cxxobjs   := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
+
+# Shared libaries (only .c supported)
+# Shared libraries (.so) - all .so files referenced in "xxx-objs"
+host-cshlib    := $(sort $(filter %.so, $(host-cobjs)))
+# Remove .so files from "xxx-objs"
+host-cobjs     := $(filter-out %.so,$(host-cobjs))
+
+#Object (.o) files used by the shared libaries
+host-cshobjs   := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+
+__hostprogs     := $(addprefix $(obj)/,$(__hostprogs))
+host-csingle   := $(addprefix $(obj)/,$(host-csingle))
+host-cmulti    := $(addprefix $(obj)/,$(host-cmulti))
+host-cobjs     := $(addprefix $(obj)/,$(host-cobjs))
+host-cxxmulti  := $(addprefix $(obj)/,$(host-cxxmulti))
+host-cxxobjs   := $(addprefix $(obj)/,$(host-cxxobjs))
+host-cshlib    := $(addprefix $(obj)/,$(host-cshlib))
+host-cshobjs   := $(addprefix $(obj)/,$(host-cshobjs))
+obj-dirs        := $(addprefix $(obj)/,$(obj-dirs))
+
+#####
+# Handle options to gcc. Support building with separate output directory
+
+_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   $(HOSTCFLAGS_$(*F).o)
+_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) $(HOSTCXXFLAGS_$(*F).o)
+
+ifeq ($(KBUILD_SRC),)
+__hostc_flags  = $(_hostc_flags)
+__hostcxx_flags        = $(_hostcxx_flags)
+else
+__hostc_flags  = -I$(obj) $(call flags,_hostc_flags)
+__hostcxx_flags        = -I$(obj) $(call flags,_hostcxx_flags)
+endif
+
+hostc_flags    = -Wp,-MD,$(depfile) $(__hostc_flags)
+hostcxx_flags  = -Wp,-MD,$(depfile) $(__hostcxx_flags)
+
+#####
+# Compile programs on the host
+
+# Create executable from a single .c file
+# host-csingle -> Executable
+quiet_cmd_host-csingle         = HOSTCC  $@
+      cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(HOST_LOADLIBES) -o $@ $<
+$(host-csingle): %: %.c FORCE
+       $(call if_changed_dep,host-csingle)
+
+# Link an executable based on list of .o files, all plain c
+# host-cmulti -> executable
+quiet_cmd_host-cmulti  = HOSTLD  $@
+      cmd_host-cmulti  = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
+                         $(addprefix $(obj)/,$($(@F)-objs)) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cmulti)
+
+# Create .o file from a single .c file
+# host-cobjs -> .o
+quiet_cmd_host-cobjs   = HOSTCC  $@
+      cmd_host-cobjs   = $(HOSTCC) $(hostc_flags) -c -o $@ $<
+$(host-cobjs): %.o: %.c FORCE
+       $(call if_changed_dep,host-cobjs)
+
+# Link an executable based on list of .o files, a mixture of .c and .cc
+# host-cxxmulti -> executable
+quiet_cmd_host-cxxmulti        = HOSTLD  $@
+      cmd_host-cxxmulti        = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
+                         $(foreach o,objs cxxobjs,\
+                         $(addprefix $(obj)/,$($(@F)-$(o)))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cxxmulti): %: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cxxmulti)
+
+# Create .o file from a single .cc (C++) file
+quiet_cmd_host-cxxobjs = HOSTCXX $@
+      cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
+$(host-cxxobjs): %.o: %.cc FORCE
+       $(call if_changed_dep,host-cxxobjs)
+
+# Compile .c file, create position independent .o file
+# host-cshobjs -> .o
+quiet_cmd_host-cshobjs = HOSTCC  -fPIC $@
+      cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
+$(host-cshobjs): %.o: %.c FORCE
+       $(call if_changed_dep,host-cshobjs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cshlib)
+quiet_cmd_host-cshlib  = HOSTLLD -shared $@
+      cmd_host-cshlib  = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
+                         $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cshlib): %: $(host-cshobjs) FORCE
+       $(call if_changed,host-cshlib)
+
+targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) 
+
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
new file mode 100644 (file)
index 0000000..2a697c3
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/bash
+# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
+# Released under the terms of the GNU GPL
+#
+# Generate a newline separated list of entries from the file/directory pointed
+# out by the environment variable: CONFIG_INITRAMFS_SOURCE
+#
+# If CONFIG_INITRAMFS_SOURCE is non-existing then generate a small dummy file.
+#
+# The output is suitable for gen_init_cpio as found in usr/Makefile.
+#
+# TODO:  Add support for symlinks, sockets and pipes when gen_init_cpio
+#        supports them.
+
+simple_initramfs() {
+       cat <<-EOF
+               # This is a very simple initramfs
+
+               dir /dev 0755 0 0
+               nod /dev/console 0600 0 0 c 5 1
+               dir /root 0700 0 0
+       EOF
+}
+
+filetype() {
+       local argv1="$1"
+
+       if [ -f "${argv1}" ]; then
+               echo "file"
+       elif [ -d "${argv1}" ]; then
+               echo "dir"
+       elif [ -b "${argv1}" -o -c "${argv1}" ]; then
+               echo "nod"
+       else
+               echo "invalid"
+       fi
+       return 0
+}
+
+print_mtime() {
+       local argv1="$1"
+       local my_mtime="0"
+
+       if [ -e "${argv1}" ]; then
+               my_mtime=$(find "${argv1}" -printf "%T@\n" | sort -r | head -n 1)
+       fi
+       
+       echo "# Last modified: ${my_mtime}"
+       echo
+}
+
+parse() {
+       local location="$1"
+       local name="${location/${srcdir}//}"
+       local mode="$2"
+       local uid="$3"
+       local gid="$4"
+       local ftype=$(filetype "${location}")
+       local str="${mode} ${uid} ${gid}"
+
+       [ "${ftype}" == "invalid" ] && return 0
+       [ "${location}" == "${srcdir}" ] && return 0
+
+       case "${ftype}" in
+               "file")
+                       str="${ftype} ${name} ${location} ${str}"
+                       ;;
+               "nod")
+                       local dev_type=
+                       local maj=$(LC_ALL=C ls -l "${location}" | \
+                                       gawk '{sub(/,/, "", $5); print $5}')
+                       local min=$(LC_ALL=C ls -l "${location}" | \
+                                       gawk '{print $6}')
+
+                       if [ -b "${location}" ]; then
+                               dev_type="b"
+                       else
+                               dev_type="c"
+                       fi
+                       str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}"
+                       ;;
+               *)
+                       str="${ftype} ${name} ${str}"
+                       ;;
+       esac
+
+       echo "${str}"
+
+       return 0
+}
+
+if [ -z "$1" ]; then
+       simple_initramfs
+elif [ -f "$1" ]; then
+       print_mtime "$1"
+       cat "$1"
+elif [ -d "$1" ]; then
+       srcdir=$(echo "$1" | sed -e 's://*:/:g')
+       dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null)
+
+       # If $dirlist is only one line, then the directory is empty
+       if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+               print_mtime "$1"
+               
+               echo "${dirlist}" | \
+               while read x; do
+                       parse ${x}
+               done
+       else
+               # Failsafe in case directory is empty
+               simple_initramfs
+       fi
+else
+       echo "  $0: Cannot open '$1' (CONFIG_INITRAMFS_SOURCE)" >&2
+       exit 1
+fi
+
+exit 0
diff --git a/scripts/mksysmap b/scripts/mksysmap
new file mode 100644 (file)
index 0000000..2904d3b
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh -x
+# Based on the vmlinux file create the System.map file
+# System.map is used by module-init tools and some debugging
+# tools to retreive the actual addresses of symbols in the kernel.
+#
+# Usage
+# mksysmap vmlinux System.map
+
+
+#####
+# Generate System.map (actual filename passed as second argument)
+
+# $NM produces the following output:
+# f0081e80 T alloc_vfsmnt
+
+#   The second row specify the type of the symbol:
+#   A = Absolute
+#   B = Uninitialised data (.bss)
+#   C = Comon symbol
+#   D = Initialised data
+#   G = Initialised data for small objects
+#   I = Indirect reference to another symbol
+#   N = Debugging symbol
+#   R = Read only
+#   S = Uninitialised data for small objects
+#   T = Text code symbol
+#   U = Undefined symbol
+#   V = Weak symbol
+#   W = Weak symbol
+#   Corresponding small letters are local symbols
+
+# For System.map filter away:
+#   a - local absolute symbols
+#   U - undefined global symbols
+#   w - local weak symbols
+
+# readprofile starts reading symbols when _stext is found, and
+# continue until it finds a symbol which is not either of 'T', 't',
+# 'W' or 'w'. __crc_ are 'A' and placed in the middle
+# so we just ignore them to let readprofile continue to work.
+# (At least sparc64 has __crc_ in the middle).
+
+$NM -n $1 | grep -v '\( [aUw] \)\|\(__crc_\)' > $2
+
diff --git a/scripts/namespace.pl b/scripts/namespace.pl
new file mode 100644 (file)
index 0000000..399c831
--- /dev/null
@@ -0,0 +1,449 @@
+#!/usr/bin/perl -w
+#
+#      namespace.pl.  Mon Aug 30 2004
+#
+#      Perform a name space analysis on the linux kernel.
+#
+#      Copyright Keith Owens <kaos@ocs.com.au>.  GPL.
+#
+#      Invoke by changing directory to the top of the kernel object
+#      tree then namespace.pl, no parameters.
+#
+#      Tuned for 2.1.x kernels with the new module handling, it will
+#      work with 2.0 kernels as well.
+#
+#      Last change 2.6.9-rc1, adding support for separate source and object
+#      trees.
+#
+#      The source must be compiled/assembled first, the object files
+#      are the primary input to this script.  Incomplete or missing
+#      objects will result in a flawed analysis.  Compile both vmlinux
+#      and modules.
+#
+#      Even with complete objects, treat the result of the analysis
+#      with caution.  Some external references are only used by
+#      certain architectures, others with certain combinations of
+#      configuration parameters.  Ideally the source should include
+#      something like
+#
+#      #ifndef CONFIG_...
+#      static
+#      #endif
+#      symbol_definition;
+#
+#      so the symbols are defined as static unless a particular
+#      CONFIG_... requires it to be external.
+#
+#      A symbol that is suffixed with '(export only)' has these properties
+#
+#      * It is global.
+#      * It is marked EXPORT_SYMBOL or EXPORT_SYMBOL_GPL, either in the same
+#        source file or a different source file.
+#      * Given the current .config, nothing uses the symbol.
+#
+#      The symbol is a candidate for conversion to static, plus removal of the
+#      export.  But be careful that a different .config might use the symbol.
+#
+#
+#      Name space analysis and cleanup is an iterative process.  You cannot
+#      expect to find all the problems in a single pass.
+#
+#      * Identify possibly unnecessary global declarations, verify that they
+#        really are unnecessary and change them to static.
+#      * Compile and fix up gcc warnings about static, removing dead symbols
+#        as necessary.
+#      * make clean and rebuild with different configs (especially
+#        CONFIG_MODULES=n) to see which symbols are being defined when the
+#        config does not require them.  These symbols bloat the kernel object
+#        for no good reason, which is frustrating for embedded systems.
+#      * Wrap config sensitive symbols in #ifdef CONFIG_foo, as long as the
+#        code does not get too ugly.
+#      * Repeat the name space analysis until you can live with with the
+#        result.
+#
+
+require 5;     # at least perl 5
+use strict;
+use File::Find;
+
+my $nm = "/usr/bin/nm -p";
+my $objdump = "/usr/bin/objdump -s -j .comment";
+my $srctree = "";
+my $objtree = "";
+$srctree = "$ENV{'srctree'}/" if (exists($ENV{'srctree'}));
+$objtree = "$ENV{'objtree'}/" if (exists($ENV{'objtree'}));
+
+if ($#ARGV != -1) {
+       print STDERR "usage: $0 takes no parameters\n";
+       die("giving up\n");
+}
+
+my %nmdata = ();       # nm data for each object
+my %def = ();          # all definitions for each name
+my %ksymtab = ();      # names that appear in __ksymtab_
+my %ref = ();          # $ref{$name} exists if there is a true external reference to $name
+my %export = ();       # $export{$name} exists if there is an EXPORT_... of $name
+
+&find(\&linux_objects, '.');   # find the objects and do_nm on them
+&list_multiply_defined();
+&resolve_external_references();
+&list_extra_externals();
+
+exit(0);
+
+sub linux_objects
+{
+       # Select objects, ignoring objects which are only created by
+       # merging other objects.  Also ignore all of modules, scripts
+       # and compressed.  Most conglomerate objects are handled by do_nm,
+       # this list only contains the special cases.  These include objects
+       # that are linked from just one other object and objects for which
+       # there is really no permanent source file.
+       my $basename = $_;
+       $_ = $File::Find::name;
+       s:^\./::;
+       if (/.*\.o$/ &&
+               ! (
+               m:/built-in.o$:
+               || m:arch/i386/kernel/vsyscall-syms.o$:
+               || m:arch/ia64/ia32/ia32.o$:
+               || m:arch/ia64/kernel/gate-syms.o$:
+               || m:arch/ia64/lib/__divdi3.o$:
+               || m:arch/ia64/lib/__divsi3.o$:
+               || m:arch/ia64/lib/__moddi3.o$:
+               || m:arch/ia64/lib/__modsi3.o$:
+               || m:arch/ia64/lib/__udivdi3.o$:
+               || m:arch/ia64/lib/__udivsi3.o$:
+               || m:arch/ia64/lib/__umoddi3.o$:
+               || m:arch/ia64/lib/__umodsi3.o$:
+               || m:arch/ia64/scripts/check_gas_for_hint.o$:
+               || m:arch/ia64/sn/kernel/xp.o$:
+               || m:boot/bbootsect.o$:
+               || m:boot/bsetup.o$:
+               || m:/bootsect.o$:
+               || m:/boot/setup.o$:
+               || m:/compressed/:
+               || m:drivers/cdrom/driver.o$:
+               || m:drivers/char/drm/tdfx_drv.o$:
+               || m:drivers/ide/ide-detect.o$:
+               || m:drivers/ide/pci/idedriver-pci.o$:
+               || m:drivers/media/media.o$:
+               || m:drivers/scsi/sd_mod.o$:
+               || m:drivers/video/video.o$:
+               || m:fs/devpts/devpts.o$:
+               || m:fs/exportfs/exportfs.o$:
+               || m:fs/hugetlbfs/hugetlbfs.o$:
+               || m:fs/msdos/msdos.o$:
+               || m:fs/nls/nls.o$:
+               || m:fs/ramfs/ramfs.o$:
+               || m:fs/romfs/romfs.o$:
+               || m:fs/vfat/vfat.o$:
+               || m:init/mounts.o$:
+               || m:^modules/:
+               || m:net/netlink/netlink.o$:
+               || m:net/sched/sched.o$:
+               || m:/piggy.o$:
+               || m:^scripts/:
+               || m:sound/.*/snd-:
+               || m:^.*/\.tmp_:
+               || m:^\.tmp_:
+               || m:/vmlinux-obj.o$:
+               )
+       ) {
+               do_nm($basename, $_);
+       }
+       $_ = $basename;         # File::Find expects $_ untouched (undocumented)
+}
+
+sub do_nm
+{
+       my ($basename, $fullname) = @_;
+       my ($source, $type, $name);
+       if (! -e $basename) {
+               printf STDERR "$basename does not exist\n";
+               return;
+       }
+       if ($fullname !~ /\.o$/) {
+               printf STDERR "$fullname is not an object file\n";
+               return;
+       }
+       ($source = $fullname) =~ s/\.o$//;
+       if (-e "$objtree$source.c" || -e "$objtree$source.S") {
+               $source = "$objtree$source";
+       } else {
+               $source = "$srctree$source";
+       }
+       if (! -e "$source.c" && ! -e "$source.S") {
+               # No obvious source, exclude the object if it is conglomerate
+               if (! open(OBJDUMPDATA, "$objdump $basename|")) {
+                       printf STDERR "$objdump $fullname failed $!\n";
+                       return;
+               }
+               my $comment;
+               while (<OBJDUMPDATA>) {
+                       chomp();
+                       if (/^In archive/) {
+                               # Archives are always conglomerate
+                               $comment = "GCC:GCC:";
+                               last;
+                       }
+                       next if (! /^[ 0-9a-f]{5,} /);
+                       $comment .= substr($_, 43);
+               }
+               close(OBJDUMPDATA);
+               if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
+                       printf STDERR "No source file found for $fullname\n";
+               }
+               return;
+       }
+       if (! open(NMDATA, "$nm $basename|")) {
+               printf STDERR "$nm $fullname failed $!\n";
+               return;
+       }
+       my @nmdata;
+       while (<NMDATA>) {
+               chop;
+               ($type, $name) = (split(/ +/, $_, 3))[1..2];
+               # Expected types
+               # A absolute symbol
+               # B weak external reference to data that has been resolved
+               # C global variable, uninitialised
+               # D global variable, initialised
+               # G global variable, initialised, small data section
+               # R global array, initialised
+               # S global variable, uninitialised, small bss
+               # T global label/procedure
+               # U external reference
+               # W weak external reference to text that has been resolved
+               # a assembler equate
+               # b static variable, uninitialised
+               # d static variable, initialised
+               # g static variable, initialised, small data section
+               # r static array, initialised
+               # s static variable, uninitialised, small bss
+               # t static label/procedures
+               # w weak external reference to text that has not been resolved
+               # ? undefined type, used a lot by modules
+               if ($type !~ /^[ABCDGRSTUWabdgrstw?]$/) {
+                       printf STDERR "nm output for $fullname contains unknown type '$_'\n";
+               }
+               elsif ($name =~ /\./) {
+                       # name with '.' is local static
+               }
+               else {
+                       $type = 'R' if ($type eq '?');  # binutils replaced ? with R at one point
+                       # binutils keeps changing the type for exported symbols, force it to R
+                       $type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
+                       $name =~ s/_R[a-f0-9]{8}$//;    # module versions adds this
+                       if ($type =~ /[ABCDGRSTW]/ &&
+                               $name ne 'init_module' &&
+                               $name ne 'cleanup_module' &&
+                               $name ne 'Using_Versions' &&
+                               $name !~ /^Version_[0-9]+$/ &&
+                               $name !~ /^__parm_/ &&
+                               $name !~ /^__kstrtab/ &&
+                               $name !~ /^__ksymtab/ &&
+                               $name !~ /^__kcrctab_/ &&
+                               $name !~ /^__exitcall_/ &&
+                               $name !~ /^__initcall_/ &&
+                               $name !~ /^__kdb_initcall_/ &&
+                               $name !~ /^__kdb_exitcall_/ &&
+                               $name !~ /^__module_/ &&
+                               $name !~ /^__mod_/ &&
+                               $name !~ /^__crc_/ &&
+                               $name ne '__this_module' &&
+                               $name ne 'kernel_version') {
+                               if (!exists($def{$name})) {
+                                       $def{$name} = [];
+                               }
+                               push(@{$def{$name}}, $fullname);
+                       }
+                       push(@nmdata, "$type $name");
+                       if ($name =~ /^__ksymtab_/) {
+                               $name = substr($name, 10);
+                               if (!exists($ksymtab{$name})) {
+                                       $ksymtab{$name} = [];
+                               }
+                               push(@{$ksymtab{$name}}, $fullname);
+                       }
+               }
+       }
+       close(NMDATA);
+       if ($#nmdata < 0) {
+               if (
+                       $fullname ne "lib/brlock.o"
+                       && $fullname ne "lib/dec_and_lock.o"
+                       && $fullname ne "fs/xfs/xfs_macros.o"
+                       && $fullname ne "drivers/ide/ide-probe-mini.o"
+                       && $fullname ne "usr/initramfs_data.o"
+                       && $fullname ne "drivers/acpi/executer/exdump.o"
+                       && $fullname ne "drivers/acpi/resources/rsdump.o"
+                       && $fullname ne "drivers/acpi/namespace/nsdumpdv.o"
+                       && $fullname ne "drivers/acpi/namespace/nsdump.o"
+                       && $fullname ne "arch/ia64/sn/kernel/sn2/io.o"
+                       && $fullname ne "arch/ia64/kernel/gate-data.o"
+                       && $fullname ne "drivers/ieee1394/oui.o"
+                       && $fullname ne "security/capability.o"
+                       && $fullname ne "sound/core/wrappers.o"
+                       && $fullname ne "fs/ntfs/sysctl.o"
+                       && $fullname ne "fs/jfs/jfs_debug.o"
+               ) {
+                       printf "No nm data for $fullname\n";
+               }
+               return;
+       }
+       $nmdata{$fullname} = \@nmdata;
+}
+
+sub drop_def
+{
+       my ($object, $name) = @_;
+       my $nmdata = $nmdata{$object};
+       my ($i, $j);
+       for ($i = 0; $i <= $#{$nmdata}; ++$i) {
+               if ($name eq (split(' ', $nmdata->[$i], 2))[1]) {
+                       splice(@{$nmdata{$object}}, $i, 1);
+                       my $def = $def{$name};
+                       for ($j = 0; $j < $#{$def{$name}}; ++$j) {
+                               if ($def{$name}[$j] eq $object) {
+                                       splice(@{$def{$name}}, $j, 1);
+                               }
+                       }
+                       last;
+               }
+       }
+}
+
+sub list_multiply_defined
+{
+       my ($name, $module);
+       foreach $name (keys(%def)) {
+               if ($#{$def{$name}} > 0) {
+                       # Special case for cond_syscall
+                       if ($#{$def{$name}} == 1 && $name =~ /^sys_/ &&
+                           ($def{$name}[0] eq "kernel/sys.o" ||
+                            $def{$name}[1] eq "kernel/sys.o")) {
+                               &drop_def("kernel/sys.o", $name);
+                               next;
+                       }
+                       # Special case for i386 entry code
+                       if ($#{$def{$name}} == 1 && $name =~ /^__kernel_/ &&
+                           $def{$name}[0] eq "arch/i386/kernel/vsyscall-int80.o" &&
+                           $def{$name}[1] eq "arch/i386/kernel/vsyscall-sysenter.o") {
+                               &drop_def("arch/i386/kernel/vsyscall-sysenter.o", $name);
+                               next;
+                       }
+                       printf "$name is multiply defined in :-\n";
+                       foreach $module (@{$def{$name}}) {
+                               printf "\t$module\n";
+                       }
+               }
+       }
+}
+
+sub resolve_external_references
+{
+       my ($object, $type, $name, $i, $j, $kstrtab, $ksymtab, $export);
+       printf "\n";
+       foreach $object (keys(%nmdata)) {
+               my $nmdata = $nmdata{$object};
+               for ($i = 0; $i <= $#{$nmdata}; ++$i) {
+                       ($type, $name) = split(' ', $nmdata->[$i], 2);
+                       if ($type eq "U" || $type eq "w") {
+                               if (exists($def{$name}) || exists($ksymtab{$name})) {
+                                       # add the owning object to the nmdata
+                                       $nmdata->[$i] = "$type $name $object";
+                                       # only count as a reference if it is not EXPORT_...
+                                       $kstrtab = "R __kstrtab_$name";
+                                       $ksymtab = "R __ksymtab_$name";
+                                       $export = 0;
+                                       for ($j = 0; $j <= $#{$nmdata}; ++$j) {
+                                               if ($nmdata->[$j] eq $kstrtab ||
+                                                   $nmdata->[$j] eq $ksymtab) {
+                                                       $export = 1;
+                                                       last;
+                                               }
+                                       }
+                                       if ($export) {
+                                               $export{$name} = "";
+                                       }
+                                       else {
+                                               $ref{$name} = ""
+                                       }
+                               }
+                               elsif (    $name ne "mod_use_count_"
+                                       && $name ne "__initramfs_end"
+                                       && $name ne "__initramfs_start"
+                                       && $name ne "_einittext"
+                                       && $name ne "_sinittext"
+                                       && $name ne "kallsyms_names"
+                                       && $name ne "kallsyms_num_syms"
+                                       && $name ne "kallsyms_addresses"
+                                       && $name ne "__this_module"
+                                       && $name ne "_etext"
+                                       && $name ne "_edata"
+                                       && $name ne "_end"
+                                       && $name ne "__bss_start"
+                                       && $name ne "_text"
+                                       && $name ne "_stext"
+                                       && $name ne "__gp"
+                                       && $name ne "ia64_unw_start"
+                                       && $name ne "ia64_unw_end"
+                                       && $name ne "__init_begin"
+                                       && $name ne "__init_end"
+                                       && $name ne "__bss_stop"
+                                       && $name ne "__nosave_begin"
+                                       && $name ne "__nosave_end"
+                                       && $name ne "pg0"
+                                       && $name ne "__module_text_address"
+                                       && $name !~ /^__sched_text_/
+                                       && $name !~ /^__start_/
+                                       && $name !~ /^__end_/
+                                       && $name !~ /^__stop_/
+                                       && $name !~ /^__scheduling_functions_.*_here/
+                                       && $name !~ /^__.*initcall_/
+                                       && $name !~ /^__.*per_cpu_start/
+                                       && $name !~ /^__.*per_cpu_end/
+                                       && $name !~ /^__alt_instructions/
+                                       && $name !~ /^__setup_/
+                               ) {
+                                       printf "Cannot resolve ";
+                                       printf "weak " if ($type eq "w");
+                                       printf "reference to $name from $object\n";
+                               }
+                       }
+               }
+       }
+}
+
+sub list_extra_externals
+{
+       my %noref = ();
+       my ($name, @module, $module, $export);
+       foreach $name (keys(%def)) {
+               if (! exists($ref{$name})) {
+                       @module = @{$def{$name}};
+                       foreach $module (@module) {
+                               if (! exists($noref{$module})) {
+                                       $noref{$module} = [];
+                               }
+                               push(@{$noref{$module}}, $name);
+                       }
+               }
+       }
+       if (%noref) {
+               printf "\nExternally defined symbols with no external references\n";
+               foreach $module (sort(keys(%noref))) {
+                       printf "  $module\n";
+                       foreach (sort(@{$noref{$module}})) {
+                               if (exists($export{$_})) {
+                                       $export = " (export only)";
+                               }
+                               else {
+                                       $export = "";
+                               }
+                               printf "    $_$export\n";
+                       }
+               }
+       }
+}
diff --git a/security/keys/Makefile b/security/keys/Makefile
new file mode 100644 (file)
index 0000000..ddb495d
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for key management
+#
+
+obj-y := \
+       key.o \
+       keyring.o \
+       keyctl.o \
+       process_keys.o \
+       user_defined.o \
+       request_key.o
+
+obj-$(CONFIG_KEYS_COMPAT) += compat.o
+obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
new file mode 100644 (file)
index 0000000..17c038c
--- /dev/null
@@ -0,0 +1,78 @@
+/* compat.c: 32-bit compatibility syscall for 64-bit systems
+ *
+ * Copyright (C) 2004 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/sched.h>
+#include <linux/syscalls.h>
+#include <linux/keyctl.h>
+#include <linux/compat.h>
+#include "internal.h"
+
+/*****************************************************************************/
+/*
+ * the key control system call, 32-bit compatibility version for 64-bit archs
+ * - this should only be called if the 64-bit arch uses weird pointers in
+ *   32-bit mode or doesn't guarantee that the top 32-bits of the argument
+ *   registers on taking a 32-bit syscall are zero
+ * - if you can, you should call sys_keyctl directly
+ */
+asmlinkage long compat_sys_keyctl(u32 option,
+                             u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+{
+       switch (option) {
+       case KEYCTL_GET_KEYRING_ID:
+               return keyctl_get_keyring_ID(arg2, arg3);
+
+       case KEYCTL_JOIN_SESSION_KEYRING:
+               return keyctl_join_session_keyring(compat_ptr(arg3));
+
+       case KEYCTL_UPDATE:
+               return keyctl_update_key(arg2, compat_ptr(arg3), arg4);
+
+       case KEYCTL_REVOKE:
+               return keyctl_revoke_key(arg2);
+
+       case KEYCTL_DESCRIBE:
+               return keyctl_describe_key(arg2, compat_ptr(arg3), arg4);
+
+       case KEYCTL_CLEAR:
+               return keyctl_keyring_clear(arg2);
+
+       case KEYCTL_LINK:
+               return keyctl_keyring_link(arg2, arg3);
+
+       case KEYCTL_UNLINK:
+               return keyctl_keyring_unlink(arg2, arg3);
+
+       case KEYCTL_SEARCH:
+               return keyctl_keyring_search(arg2, compat_ptr(arg3),
+                                            compat_ptr(arg4), arg5);
+
+       case KEYCTL_READ:
+               return keyctl_read_key(arg2, compat_ptr(arg3), arg4);
+
+       case KEYCTL_CHOWN:
+               return keyctl_chown_key(arg2, arg3, arg4);
+
+       case KEYCTL_SETPERM:
+               return keyctl_setperm_key(arg2, arg3);
+
+       case KEYCTL_INSTANTIATE:
+               return keyctl_instantiate_key(arg2, compat_ptr(arg3), arg4,
+                                             arg5);
+
+       case KEYCTL_NEGATE:
+               return keyctl_negate_key(arg2, arg3, arg4);
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+} /* end compat_sys_keyctl() */
diff --git a/security/keys/internal.h b/security/keys/internal.h
new file mode 100644 (file)
index 0000000..67b2b93
--- /dev/null
@@ -0,0 +1,123 @@
+/* internal.h: authentication token and access key management internal defs
+ *
+ * Copyright (C) 2003 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.
+ */
+
+#ifndef _INTERNAL_H
+#define _INTERNAL_H
+
+#include <linux/key.h>
+#include <linux/key-ui.h>
+
+extern struct key_type key_type_dead;
+extern struct key_type key_type_user;
+
+/*****************************************************************************/
+/*
+ * keep track of keys for a user
+ * - this needs to be separate to user_struct to avoid a refcount-loop
+ *   (user_struct pins some keyrings which pin this struct)
+ * - this also keeps track of keys under request from userspace for this UID
+ */
+struct key_user {
+       struct rb_node          node;
+       struct list_head        consq;          /* construction queue */
+       spinlock_t              lock;
+       atomic_t                usage;          /* for accessing qnkeys & qnbytes */
+       atomic_t                nkeys;          /* number of keys */
+       atomic_t                nikeys;         /* number of instantiated keys */
+       uid_t                   uid;
+       int                     qnkeys;         /* number of keys allocated to this user */
+       int                     qnbytes;        /* number of bytes allocated to this user */
+};
+
+#define KEYQUOTA_MAX_KEYS      100
+#define KEYQUOTA_MAX_BYTES     10000
+#define KEYQUOTA_LINK_BYTES    4               /* a link in a keyring is worth 4 bytes */
+
+extern struct rb_root  key_user_tree;
+extern spinlock_t      key_user_lock;
+extern struct key_user root_key_user;
+
+extern struct key_user *key_user_lookup(uid_t uid);
+extern void key_user_put(struct key_user *user);
+
+
+
+extern struct rb_root key_serial_tree;
+extern spinlock_t key_serial_lock;
+extern struct semaphore key_alloc_sem;
+extern struct rw_semaphore key_construction_sem;
+extern wait_queue_head_t request_key_conswq;
+
+
+extern void keyring_publish_name(struct key *keyring);
+
+extern int __key_link(struct key *keyring, struct key *key);
+
+extern struct key *__keyring_search_one(struct key *keyring,
+                                       const struct key_type *type,
+                                       const char *description,
+                                       key_perm_t perm);
+
+typedef int (*key_match_func_t)(const struct key *, const void *);
+
+extern struct key *keyring_search_aux(struct key *keyring,
+                                     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 *find_keyring_by_name(const char *name, key_serial_t bound);
+
+extern int install_thread_keyring(struct task_struct *tsk);
+
+/*
+ * keyctl functions
+ */
+extern long keyctl_get_keyring_ID(key_serial_t, int);
+extern long keyctl_join_session_keyring(const char __user *);
+extern long keyctl_update_key(key_serial_t, const void __user *, size_t);
+extern long keyctl_revoke_key(key_serial_t);
+extern long keyctl_keyring_clear(key_serial_t);
+extern long keyctl_keyring_link(key_serial_t, key_serial_t);
+extern long keyctl_keyring_unlink(key_serial_t, key_serial_t);
+extern long keyctl_describe_key(key_serial_t, char __user *, size_t);
+extern long keyctl_keyring_search(key_serial_t, const char __user *,
+                                 const char __user *, key_serial_t);
+extern long keyctl_read_key(key_serial_t, char __user *, size_t);
+extern long keyctl_chown_key(key_serial_t, uid_t, gid_t);
+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);
+
+
+/*
+ * debugging key validation
+ */
+#ifdef KEY_DEBUGGING
+extern void __key_check(const struct key *);
+
+static inline void key_check(const struct key *key)
+{
+       if (key && (IS_ERR(key) || key->magic != KEY_DEBUG_MAGIC))
+               __key_check(key);
+}
+
+#else
+
+#define key_check(key) do {} while(0)
+
+#endif
+
+#endif /* _INTERNAL_H */
diff --git a/security/keys/key.c b/security/keys/key.c
new file mode 100644 (file)
index 0000000..df264ad
--- /dev/null
@@ -0,0 +1,1039 @@
+/* key.c: basic authentication token and access key management
+ *
+ * Copyright (C) 2004 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/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include "internal.h"
+
+static kmem_cache_t    *key_jar;
+static key_serial_t    key_serial_next = 3;
+struct rb_root         key_serial_tree; /* tree of keys indexed by serial */
+spinlock_t             key_serial_lock = SPIN_LOCK_UNLOCKED;
+
+struct rb_root key_user_tree; /* tree of quota records indexed by UID */
+spinlock_t     key_user_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(key_types_list);
+static DECLARE_RWSEM(key_types_sem);
+
+static void key_cleanup(void *data);
+static DECLARE_WORK(key_cleanup_task, key_cleanup, NULL);
+
+/* we serialise key instantiation and link */
+DECLARE_RWSEM(key_construction_sem);
+
+/* any key who's type gets unegistered will be re-typed to this */
+struct key_type key_type_dead = {
+       .name           = "dead",
+};
+
+#ifdef KEY_DEBUGGING
+void __key_check(const struct key *key)
+{
+       printk("__key_check: key %p {%08x} should be {%08x}\n",
+              key, key->magic, KEY_DEBUG_MAGIC);
+       BUG();
+}
+#endif
+
+/*****************************************************************************/
+/*
+ * get the key quota record for a user, allocating a new record if one doesn't
+ * already exist
+ */
+struct key_user *key_user_lookup(uid_t uid)
+{
+       struct key_user *candidate = NULL, *user;
+       struct rb_node *parent = NULL;
+       struct rb_node **p = &key_user_tree.rb_node;
+
+ try_again:
+       spin_lock(&key_user_lock);
+
+       /* search the tree for a user record with a matching UID */
+       while (*p) {
+               parent = *p;
+               user = rb_entry(parent, struct key_user, node);
+
+               if (uid < user->uid)
+                       p = &(*p)->rb_left;
+               else if (uid > user->uid)
+                       p = &(*p)->rb_right;
+               else
+                       goto found;
+       }
+
+       /* if we get here, we failed to find a match in the tree */
+       if (!candidate) {
+               /* allocate a candidate user record if we don't already have
+                * one */
+               spin_unlock(&key_user_lock);
+
+               user = NULL;
+               candidate = kmalloc(sizeof(struct key_user), GFP_KERNEL);
+               if (unlikely(!candidate))
+                       goto out;
+
+               /* the allocation may have scheduled, so we need to repeat the
+                * search lest someone else added the record whilst we were
+                * asleep */
+               goto try_again;
+       }
+
+       /* if we get here, then the user record still hadn't appeared on the
+        * second pass - so we use the candidate record */
+       atomic_set(&candidate->usage, 1);
+       atomic_set(&candidate->nkeys, 0);
+       atomic_set(&candidate->nikeys, 0);
+       candidate->uid = uid;
+       candidate->qnkeys = 0;
+       candidate->qnbytes = 0;
+       spin_lock_init(&candidate->lock);
+       INIT_LIST_HEAD(&candidate->consq);
+
+       rb_link_node(&candidate->node, parent, p);
+       rb_insert_color(&candidate->node, &key_user_tree);
+       spin_unlock(&key_user_lock);
+       user = candidate;
+       goto out;
+
+       /* okay - we found a user record for this UID */
+ found:
+       atomic_inc(&user->usage);
+       spin_unlock(&key_user_lock);
+       if (candidate)
+               kfree(candidate);
+ out:
+       return user;
+
+} /* end key_user_lookup() */
+
+/*****************************************************************************/
+/*
+ * dispose of a user structure
+ */
+void key_user_put(struct key_user *user)
+{
+       if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
+               rb_erase(&user->node, &key_user_tree);
+               spin_unlock(&key_user_lock);
+
+               kfree(user);
+       }
+
+} /* end key_user_put() */
+
+/*****************************************************************************/
+/*
+ * insert a key with a fixed serial number
+ */
+static void __init __key_insert_serial(struct key *key)
+{
+       struct rb_node *parent, **p;
+       struct key *xkey;
+
+       parent = NULL;
+       p = &key_serial_tree.rb_node;
+
+       while (*p) {
+               parent = *p;
+               xkey = rb_entry(parent, struct key, serial_node);
+
+               if (key->serial < xkey->serial)
+                       p = &(*p)->rb_left;
+               else if (key->serial > xkey->serial)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       /* we've found a suitable hole - arrange for this key to occupy it */
+       rb_link_node(&key->serial_node, parent, p);
+       rb_insert_color(&key->serial_node, &key_serial_tree);
+
+} /* end __key_insert_serial() */
+
+/*****************************************************************************/
+/*
+ * assign a key the next unique serial number
+ * - we work through all the serial numbers between 2 and 2^31-1 in turn and
+ *   then wrap
+ */
+static inline void key_alloc_serial(struct key *key)
+{
+       struct rb_node *parent, **p;
+       struct key *xkey;
+
+       spin_lock(&key_serial_lock);
+
+       /* propose a likely serial number and look for a hole for it in the
+        * serial number tree */
+       key->serial = key_serial_next;
+       if (key->serial < 3)
+               key->serial = 3;
+       key_serial_next = key->serial + 1;
+
+       parent = NULL;
+       p = &key_serial_tree.rb_node;
+
+       while (*p) {
+               parent = *p;
+               xkey = rb_entry(parent, struct key, serial_node);
+
+               if (key->serial < xkey->serial)
+                       p = &(*p)->rb_left;
+               else if (key->serial > xkey->serial)
+                       p = &(*p)->rb_right;
+               else
+                       goto serial_exists;
+       }
+       goto insert_here;
+
+       /* we found a key with the proposed serial number - walk the tree from
+        * that point looking for the next unused serial number */
+ serial_exists:
+       for (;;) {
+               key->serial = key_serial_next;
+               if (key->serial < 2)
+                       key->serial = 2;
+               key_serial_next = key->serial + 1;
+
+               if (!parent->rb_parent)
+                       p = &key_serial_tree.rb_node;
+               else if (parent->rb_parent->rb_left == parent)
+                       p = &parent->rb_parent->rb_left;
+               else
+                       p = &parent->rb_parent->rb_right;
+
+               parent = rb_next(parent);
+               if (!parent)
+                       break;
+
+               xkey = rb_entry(parent, struct key, serial_node);
+               if (key->serial < xkey->serial)
+                       goto insert_here;
+       }
+
+       /* we've found a suitable hole - arrange for this key to occupy it */
+ insert_here:
+       rb_link_node(&key->serial_node, parent, p);
+       rb_insert_color(&key->serial_node, &key_serial_tree);
+
+       spin_unlock(&key_serial_lock);
+
+} /* end key_alloc_serial() */
+
+/*****************************************************************************/
+/*
+ * allocate a key of the specified type
+ * - update the user's quota to reflect the existence of the key
+ * - called from a key-type operation with key_types_sem read-locked by either
+ *   key_create_or_update() or by key_duplicate(); this prevents unregistration
+ *   of the key type
+ * - upon return the key is as yet uninstantiated; the caller needs to either
+ *   instantiate the key or discard it before returning
+ */
+struct key *key_alloc(struct key_type *type, const char *desc,
+                     uid_t uid, gid_t gid, key_perm_t perm,
+                     int not_in_quota)
+{
+       struct key_user *user = NULL;
+       struct key *key;
+       size_t desclen, quotalen;
+
+       key = ERR_PTR(-EINVAL);
+       if (!desc || !*desc)
+               goto error;
+
+       desclen = strlen(desc) + 1;
+       quotalen = desclen + type->def_datalen;
+
+       /* get hold of the key tracking for this user */
+       user = key_user_lookup(uid);
+       if (!user)
+               goto no_memory_1;
+
+       /* check that the user's quota permits allocation of another key and
+        * its description */
+       if (!not_in_quota) {
+               spin_lock(&user->lock);
+               if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS &&
+                   user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
+                   )
+                       goto no_quota;
+
+               user->qnkeys++;
+               user->qnbytes += quotalen;
+               spin_unlock(&user->lock);
+       }
+
+       /* allocate and initialise the key and its description */
+       key = kmem_cache_alloc(key_jar, SLAB_KERNEL);
+       if (!key)
+               goto no_memory_2;
+
+       if (desc) {
+               key->description = kmalloc(desclen, GFP_KERNEL);
+               if (!key->description)
+                       goto no_memory_3;
+
+               memcpy(key->description, desc, desclen);
+       }
+
+       atomic_set(&key->usage, 1);
+       rwlock_init(&key->lock);
+       init_rwsem(&key->sem);
+       key->type = type;
+       key->user = user;
+       key->quotalen = quotalen;
+       key->datalen = type->def_datalen;
+       key->uid = uid;
+       key->gid = gid;
+       key->perm = perm;
+       key->flags = 0;
+       key->expiry = 0;
+       key->payload.data = NULL;
+
+       if (!not_in_quota)
+               key->flags |= KEY_FLAG_IN_QUOTA;
+
+       memset(&key->type_data, 0, sizeof(key->type_data));
+
+#ifdef KEY_DEBUGGING
+       key->magic = KEY_DEBUG_MAGIC;
+#endif
+
+       /* publish the key by giving it a serial number */
+       atomic_inc(&user->nkeys);
+       key_alloc_serial(key);
+
+ error:
+       return key;
+
+ no_memory_3:
+       kmem_cache_free(key_jar, key);
+ no_memory_2:
+       if (!not_in_quota) {
+               spin_lock(&user->lock);
+               user->qnkeys--;
+               user->qnbytes -= quotalen;
+               spin_unlock(&user->lock);
+       }
+       key_user_put(user);
+ no_memory_1:
+       key = ERR_PTR(-ENOMEM);
+       goto error;
+
+ no_quota:
+       spin_unlock(&user->lock);
+       key_user_put(user);
+       key = ERR_PTR(-EDQUOT);
+       goto error;
+
+} /* end key_alloc() */
+
+EXPORT_SYMBOL(key_alloc);
+
+/*****************************************************************************/
+/*
+ * reserve an amount of quota for the key's payload
+ */
+int key_payload_reserve(struct key *key, size_t datalen)
+{
+       int delta = (int) datalen - key->datalen;
+       int ret = 0;
+
+       key_check(key);
+
+       /* contemplate the quota adjustment */
+       if (delta != 0 && key->flags & KEY_FLAG_IN_QUOTA) {
+               spin_lock(&key->user->lock);
+
+               if (delta > 0 &&
+                   key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES
+                   ) {
+                       ret = -EDQUOT;
+               }
+               else {
+                       key->user->qnbytes += delta;
+                       key->quotalen += delta;
+               }
+               spin_unlock(&key->user->lock);
+       }
+
+       /* change the recorded data length if that didn't generate an error */
+       if (ret == 0)
+               key->datalen = datalen;
+
+       return ret;
+
+} /* end key_payload_reserve() */
+
+EXPORT_SYMBOL(key_payload_reserve);
+
+/*****************************************************************************/
+/*
+ * instantiate a key and link it into the target keyring atomically
+ * - called with the target keyring's semaphore writelocked
+ */
+static int __key_instantiate_and_link(struct key *key,
+                                     const void *data,
+                                     size_t datalen,
+                                     struct key *keyring)
+{
+       int ret, awaken;
+
+       key_check(key);
+       key_check(keyring);
+
+       awaken = 0;
+       ret = -EBUSY;
+
+       down_write(&key_construction_sem);
+
+       /* can't instantiate twice */
+       if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
+               /* 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;
+
+                       if (key->flags & KEY_FLAG_USER_CONSTRUCT) {
+                               key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
+                               awaken = 1;
+                       }
+
+                       write_unlock(&key->lock);
+
+                       /* and link it into the destination keyring */
+                       if (keyring)
+                               ret = __key_link(keyring, key);
+               }
+       }
+
+       up_write(&key_construction_sem);
+
+       /* wake up anyone waiting for a key to be constructed */
+       if (awaken)
+               wake_up_all(&request_key_conswq);
+
+       return ret;
+
+} /* end __key_instantiate_and_link() */
+
+/*****************************************************************************/
+/*
+ * instantiate a key and link it into the target keyring atomically
+ */
+int key_instantiate_and_link(struct key *key,
+                            const void *data,
+                            size_t datalen,
+                            struct key *keyring)
+{
+       int ret;
+
+       if (keyring)
+               down_write(&keyring->sem);
+
+       ret = __key_instantiate_and_link(key, data, datalen, keyring);
+
+       if (keyring)
+               up_write(&keyring->sem);
+
+       return ret;
+} /* end key_instantiate_and_link() */
+
+EXPORT_SYMBOL(key_instantiate_and_link);
+
+/*****************************************************************************/
+/*
+ * negatively instantiate a key and link it into the target keyring atomically
+ */
+int key_negate_and_link(struct key *key,
+                       unsigned timeout,
+                       struct key *keyring)
+{
+       struct timespec now;
+       int ret, awaken;
+
+       key_check(key);
+       key_check(keyring);
+
+       awaken = 0;
+       ret = -EBUSY;
+
+       if (keyring)
+               down_write(&keyring->sem);
+
+       down_write(&key_construction_sem);
+
+       /* can't instantiate twice */
+       if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
+               /* mark the key as being negatively instantiated */
+               write_lock(&key->lock);
+
+               atomic_inc(&key->user->nikeys);
+               key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
+               now = current_kernel_time();
+               key->expiry = now.tv_sec + timeout;
+
+               if (key->flags & KEY_FLAG_USER_CONSTRUCT) {
+                       key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
+                       awaken = 1;
+               }
+
+               write_unlock(&key->lock);
+               ret = 0;
+
+               /* and link it into the destination keyring */
+               if (keyring)
+                       ret = __key_link(keyring, key);
+       }
+
+       up_write(&key_construction_sem);
+
+       if (keyring)
+               up_write(&keyring->sem);
+
+       /* wake up anyone waiting for a key to be constructed */
+       if (awaken)
+               wake_up_all(&request_key_conswq);
+
+       return ret;
+
+} /* end key_negate_and_link() */
+
+EXPORT_SYMBOL(key_negate_and_link);
+
+/*****************************************************************************/
+/*
+ * do cleaning up in process context so that we don't have to disable
+ * interrupts all over the place
+ */
+static void key_cleanup(void *data)
+{
+       struct rb_node *_n;
+       struct key *key;
+
+ go_again:
+       /* look for a dead key in the tree */
+       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 (atomic_read(&key->usage) == 0)
+                       goto found_dead_key;
+       }
+
+       spin_unlock(&key_serial_lock);
+       return;
+
+ found_dead_key:
+       /* we found a dead key - once we've removed it from the tree, we can
+        * drop the lock */
+       rb_erase(&key->serial_node, &key_serial_tree);
+       spin_unlock(&key_serial_lock);
+
+       /* deal with the user's key tracking and quota */
+       if (key->flags & KEY_FLAG_IN_QUOTA) {
+               spin_lock(&key->user->lock);
+               key->user->qnkeys--;
+               key->user->qnbytes -= key->quotalen;
+               spin_unlock(&key->user->lock);
+       }
+
+       atomic_dec(&key->user->nkeys);
+       if (key->flags & KEY_FLAG_INSTANTIATED)
+               atomic_dec(&key->user->nikeys);
+
+       key_user_put(key->user);
+
+       /* now throw away the key memory */
+       if (key->type->destroy)
+               key->type->destroy(key);
+
+       kfree(key->description);
+
+#ifdef KEY_DEBUGGING
+       key->magic = KEY_DEBUG_MAGIC_X;
+#endif
+       kmem_cache_free(key_jar, key);
+
+       /* there may, of course, be more than one key to destroy */
+       goto go_again;
+
+} /* end key_cleanup() */
+
+/*****************************************************************************/
+/*
+ * dispose of a reference to a key
+ * - when all the references are gone, we schedule the cleanup task to come and
+ *   pull it out of the tree in definite process context
+ */
+void key_put(struct key *key)
+{
+       if (key) {
+               key_check(key);
+
+               if (atomic_dec_and_test(&key->usage))
+                       schedule_work(&key_cleanup_task);
+       }
+
+} /* end key_put() */
+
+EXPORT_SYMBOL(key_put);
+
+/*****************************************************************************/
+/*
+ * find a key by its serial number
+ */
+struct key *key_lookup(key_serial_t id)
+{
+       struct rb_node *n;
+       struct key *key;
+
+       spin_lock(&key_serial_lock);
+
+       /* search the tree for the specified key */
+       n = key_serial_tree.rb_node;
+       while (n) {
+               key = rb_entry(n, struct key, serial_node);
+
+               if (id < key->serial)
+                       n = n->rb_left;
+               else if (id > key->serial)
+                       n = n->rb_right;
+               else
+                       goto found;
+       }
+
+ not_found:
+       key = ERR_PTR(-ENOKEY);
+       goto error;
+
+ found:
+       /* pretent doesn't exist if it's dead */
+       if (atomic_read(&key->usage) == 0 ||
+           (key->flags & KEY_FLAG_DEAD) ||
+           key->type == &key_type_dead)
+               goto not_found;
+
+       /* this races with key_put(), but that doesn't matter since key_put()
+        * doesn't actually change the key
+        */
+       atomic_inc(&key->usage);
+
+ error:
+       spin_unlock(&key_serial_lock);
+       return key;
+
+} /* end key_lookup() */
+
+/*****************************************************************************/
+/*
+ * find and lock the specified key type against removal
+ * - we return with the sem readlocked
+ */
+struct key_type *key_type_lookup(const char *type)
+{
+       struct key_type *ktype;
+
+       down_read(&key_types_sem);
+
+       /* look up the key type to see if it's one of the registered kernel
+        * types */
+       list_for_each_entry(ktype, &key_types_list, link) {
+               if (strcmp(ktype->name, type) == 0)
+                       goto found_kernel_type;
+       }
+
+       up_read(&key_types_sem);
+       ktype = ERR_PTR(-ENOKEY);
+
+ found_kernel_type:
+       return ktype;
+
+} /* end key_type_lookup() */
+
+/*****************************************************************************/
+/*
+ * unlock a key type
+ */
+void key_type_put(struct key_type *ktype)
+{
+       up_read(&key_types_sem);
+
+} /* end key_type_put() */
+
+/*****************************************************************************/
+/*
+ * attempt to update an existing key
+ * - the key has an incremented refcount
+ * - we need to put the key if we get an error
+ */
+static inline struct key *__key_update(struct key *key, const void *payload,
+                                      size_t plen)
+{
+       int ret;
+
+       /* need write permission on the key to update it */
+       ret = -EACCES;
+       if (!key_permission(key, KEY_WRITE))
+               goto error;
+
+       ret = -EEXIST;
+       if (!key->type->update)
+               goto error;
+
+       down_write(&key->sem);
+
+       ret = key->type->update(key, payload, plen);
+
+       if (ret == 0) {
+               /* updating a negative key instantiates it */
+               write_lock(&key->lock);
+               key->flags &= ~KEY_FLAG_NEGATIVE;
+               write_unlock(&key->lock);
+       }
+
+       up_write(&key->sem);
+
+       if (ret < 0)
+               goto error;
+ out:
+       return key;
+
+ error:
+       key_put(key);
+       key = ERR_PTR(ret);
+       goto out;
+
+} /* end __key_update() */
+
+/*****************************************************************************/
+/*
+ * search the specified keyring for a key of the same description; if one is
+ * found, update it, otherwise add a new one
+ */
+struct key *key_create_or_update(struct key *keyring,
+                                const char *type,
+                                const char *description,
+                                const void *payload,
+                                size_t plen,
+                                int not_in_quota)
+{
+       struct key_type *ktype;
+       struct key *key = NULL;
+       key_perm_t perm;
+       int ret;
+
+       key_check(keyring);
+
+       /* look up the key type to see if it's one of the registered kernel
+        * types */
+       ktype = key_type_lookup(type);
+       if (IS_ERR(ktype)) {
+               key = ERR_PTR(-ENODEV);
+               goto error;
+       }
+
+       ret = -EINVAL;
+       if (!ktype->match || !ktype->instantiate)
+               goto error_2;
+
+       /* search for an existing key of the same type and description in the
+        * destination keyring
+        */
+       down_write(&keyring->sem);
+
+       key = __keyring_search_one(keyring, ktype, description, 0);
+       if (!IS_ERR(key))
+               goto found_matching_key;
+
+       /* if we're going to allocate a new key, we're going to have to modify
+        * the keyring */
+       ret = -EACCES;
+       if (!key_permission(keyring, KEY_WRITE))
+               goto error_3;
+
+       /* decide on the permissions we want */
+       perm = KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
+
+       if (ktype->read)
+               perm |= KEY_USR_READ;
+
+       if (ktype == &key_type_keyring || ktype->update)
+               perm |= KEY_USR_WRITE;
+
+       /* allocate a new key */
+       key = key_alloc(ktype, description, current->fsuid, current->fsgid,
+                       perm, not_in_quota);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error_3;
+       }
+
+       /* instantiate it and link it into the target keyring */
+       ret = __key_instantiate_and_link(key, payload, plen, keyring);
+       if (ret < 0) {
+               key_put(key);
+               key = ERR_PTR(ret);
+       }
+
+ error_3:
+       up_write(&keyring->sem);
+ error_2:
+       key_type_put(ktype);
+ error:
+       return key;
+
+ found_matching_key:
+       /* we found a matching key, so we're going to try to update it
+        * - we can drop the locks first as we have the key pinned
+        */
+       up_write(&keyring->sem);
+       key_type_put(ktype);
+
+       key = __key_update(key, payload, plen);
+       goto error;
+
+} /* end key_create_or_update() */
+
+EXPORT_SYMBOL(key_create_or_update);
+
+/*****************************************************************************/
+/*
+ * update a key
+ */
+int key_update(struct key *key, const void *payload, size_t plen)
+{
+       int ret;
+
+       key_check(key);
+
+       /* the key must be writable */
+       ret = -EACCES;
+       if (!key_permission(key, KEY_WRITE))
+               goto error;
+
+       /* attempt to update it if supported */
+       ret = -EOPNOTSUPP;
+       if (key->type->update) {
+               down_write(&key->sem);
+               ret = key->type->update(key, payload, plen);
+
+               if (ret == 0) {
+                       /* updating a negative key instantiates it */
+                       write_lock(&key->lock);
+                       key->flags &= ~KEY_FLAG_NEGATIVE;
+                       write_unlock(&key->lock);
+               }
+
+               up_write(&key->sem);
+       }
+
+ error:
+       return ret;
+
+} /* end key_update() */
+
+EXPORT_SYMBOL(key_update);
+
+/*****************************************************************************/
+/*
+ * duplicate a key, potentially with a revised description
+ * - must be supported by the keytype (keyrings for instance can be duplicated)
+ */
+struct key *key_duplicate(struct key *source, const char *desc)
+{
+       struct key *key;
+       int ret;
+
+       key_check(source);
+
+       if (!desc)
+               desc = source->description;
+
+       down_read(&key_types_sem);
+
+       ret = -EINVAL;
+       if (!source->type->duplicate)
+               goto error;
+
+       /* allocate and instantiate a key */
+       key = key_alloc(source->type, desc, current->fsuid, current->fsgid,
+                       source->perm, 0);
+       if (IS_ERR(key))
+               goto error_k;
+
+       down_read(&source->sem);
+       ret = key->type->duplicate(key, source);
+       up_read(&source->sem);
+       if (ret < 0)
+               goto error2;
+
+       atomic_inc(&key->user->nikeys);
+
+       write_lock(&key->lock);
+       key->flags |= KEY_FLAG_INSTANTIATED;
+       write_unlock(&key->lock);
+
+ error_k:
+       up_read(&key_types_sem);
+ out:
+       return key;
+
+ error2:
+       key_put(key);
+ error:
+       up_read(&key_types_sem);
+       key = ERR_PTR(ret);
+       goto out;
+
+} /* end key_duplicate() */
+
+/*****************************************************************************/
+/*
+ * revoke a key
+ */
+void key_revoke(struct key *key)
+{
+       key_check(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);
+       up_write(&key->sem);
+
+} /* end key_revoke() */
+
+EXPORT_SYMBOL(key_revoke);
+
+/*****************************************************************************/
+/*
+ * register a type of key
+ */
+int register_key_type(struct key_type *ktype)
+{
+       struct key_type *p;
+       int ret;
+
+       ret = -EEXIST;
+       down_write(&key_types_sem);
+
+       /* disallow key types with the same name */
+       list_for_each_entry(p, &key_types_list, link) {
+               if (strcmp(p->name, ktype->name) == 0)
+                       goto out;
+       }
+
+       /* store the type */
+       list_add(&ktype->link, &key_types_list);
+       ret = 0;
+
+ out:
+       up_write(&key_types_sem);
+       return ret;
+
+} /* end register_key_type() */
+
+EXPORT_SYMBOL(register_key_type);
+
+/*****************************************************************************/
+/*
+ * unregister a type of key
+ */
+void unregister_key_type(struct key_type *ktype)
+{
+       struct rb_node *_n;
+       struct key *key;
+
+       down_write(&key_types_sem);
+
+       /* withdraw the key type */
+       list_del_init(&ktype->link);
+
+       /* need to withdraw all keys of this type */
+       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;
+
+               write_lock(&key->lock);
+               key->type = &key_type_dead;
+               write_unlock(&key->lock);
+
+               /* 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));
+       }
+
+       spin_unlock(&key_serial_lock);
+       up_write(&key_types_sem);
+
+} /* end unregister_key_type() */
+
+EXPORT_SYMBOL(unregister_key_type);
+
+/*****************************************************************************/
+/*
+ * initialise the key management stuff
+ */
+void __init key_init(void)
+{
+       /* allocate a slab in which we can store keys */
+       key_jar = kmem_cache_create("key_jar", sizeof(struct key),
+                       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+
+       /* add the special key types */
+       list_add_tail(&key_type_keyring.link, &key_types_list);
+       list_add_tail(&key_type_dead.link, &key_types_list);
+       list_add_tail(&key_type_user.link, &key_types_list);
+
+       /* record the root user tracking */
+       rb_link_node(&root_key_user.node,
+                    NULL,
+                    &key_user_tree.rb_node);
+
+       rb_insert_color(&root_key_user.node,
+                       &key_user_tree);
+
+       /* record root's user standard keyrings */
+       key_check(&root_user_keyring);
+       key_check(&root_session_keyring);
+
+       __key_insert_serial(&root_user_keyring);
+       __key_insert_serial(&root_session_keyring);
+
+       keyring_publish_name(&root_user_keyring);
+       keyring_publish_name(&root_session_keyring);
+
+       /* link the two root keyrings together */
+       key_link(&root_session_keyring, &root_user_keyring);
+} /* end key_init() */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
new file mode 100644 (file)
index 0000000..4d95fdb
--- /dev/null
@@ -0,0 +1,987 @@
+/* keyctl.c: userspace keyctl operations
+ *
+ * Copyright (C) 2004 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/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/keyctl.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include "internal.h"
+
+/*****************************************************************************/
+/*
+ * extract the description of a new key from userspace and either add it as a
+ * new key to the specified keyring or update a matching key in that keyring
+ * - the keyring must be writable
+ * - returns the new key's serial number
+ * - implements add_key()
+ */
+asmlinkage long sys_add_key(const char __user *_type,
+                           const char __user *_description,
+                           const void __user *_payload,
+                           size_t plen,
+                           key_serial_t ringid)
+{
+       struct key *keyring, *key;
+       char type[32], *description;
+       void *payload;
+       long dlen, ret;
+
+       ret = -EINVAL;
+       if (plen > 32767)
+               goto error;
+
+       /* draw all the data into kernel space */
+       ret = strncpy_from_user(type, _type, sizeof(type) - 1);
+       if (ret < 0)
+               goto error;
+       type[31] = '\0';
+
+       ret = -EFAULT;
+       dlen = strnlen_user(_description, PAGE_SIZE - 1);
+       if (dlen <= 0)
+               goto error;
+
+       ret = -EINVAL;
+       if (dlen > PAGE_SIZE - 1)
+               goto error;
+
+       ret = -ENOMEM;
+       description = kmalloc(dlen + 1, GFP_KERNEL);
+       if (!description)
+               goto error;
+
+       ret = -EFAULT;
+       if (copy_from_user(description, _description, dlen + 1) != 0)
+               goto error2;
+
+       /* pull the payload in if one was supplied */
+       payload = NULL;
+
+       if (_payload) {
+               ret = -ENOMEM;
+               payload = kmalloc(plen, GFP_KERNEL);
+               if (!payload)
+                       goto error2;
+
+               ret = -EFAULT;
+               if (copy_from_user(payload, _payload, plen) != 0)
+                       goto error3;
+       }
+
+       /* find the target keyring (which must be writable) */
+       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error3;
+       }
+
+       /* create or update the requested key and add it to the target
+        * keyring */
+       key = key_create_or_update(keyring, type, description,
+                                  payload, plen, 0);
+       if (!IS_ERR(key)) {
+               ret = key->serial;
+               key_put(key);
+       }
+       else {
+               ret = PTR_ERR(key);
+       }
+
+       key_put(keyring);
+ error3:
+       kfree(payload);
+ error2:
+       kfree(description);
+ error:
+       return ret;
+
+} /* end sys_add_key() */
+
+/*****************************************************************************/
+/*
+ * search the process keyrings for a matching key
+ * - nested keyrings may also be searched if they have Search permission
+ * - if a key is found, it will be attached to the destination keyring if
+ *   there's one specified
+ * - /sbin/request-key will be invoked if _callout_info is non-NULL
+ *   - the _callout_info string will be passed to /sbin/request-key
+ *   - if the _callout_info string is empty, it will be rendered as "-"
+ * - implements request_key()
+ */
+asmlinkage long sys_request_key(const char __user *_type,
+                               const char __user *_description,
+                               const char __user *_callout_info,
+                               key_serial_t destringid)
+{
+       struct key_type *ktype;
+       struct key *key, *dest;
+       char type[32], *description, *callout_info;
+       long dlen, ret;
+
+       /* pull the type into kernel space */
+       ret = strncpy_from_user(type, _type, sizeof(type) - 1);
+       if (ret < 0)
+               goto error;
+       type[31] = '\0';
+
+       /* pull the description into kernel space */
+       ret = -EFAULT;
+       dlen = strnlen_user(_description, PAGE_SIZE - 1);
+       if (dlen <= 0)
+               goto error;
+
+       ret = -EINVAL;
+       if (dlen > PAGE_SIZE - 1)
+               goto error;
+
+       ret = -ENOMEM;
+       description = kmalloc(dlen + 1, GFP_KERNEL);
+       if (!description)
+               goto error;
+
+       ret = -EFAULT;
+       if (copy_from_user(description, _description, dlen + 1) != 0)
+               goto error2;
+
+       /* pull the callout info into kernel space */
+       callout_info = NULL;
+       if (_callout_info) {
+               ret = -EFAULT;
+               dlen = strnlen_user(_callout_info, PAGE_SIZE - 1);
+               if (dlen <= 0)
+                       goto error2;
+
+               ret = -EINVAL;
+               if (dlen > PAGE_SIZE - 1)
+                       goto error2;
+
+               ret = -ENOMEM;
+               callout_info = kmalloc(dlen + 1, GFP_KERNEL);
+               if (!callout_info)
+                       goto error2;
+
+               ret = -EFAULT;
+               if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0)
+                       goto error3;
+       }
+
+       /* get the destination keyring if specified */
+       dest = NULL;
+       if (destringid) {
+               dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(dest)) {
+                       ret = PTR_ERR(dest);
+                       goto error3;
+               }
+       }
+
+       /* find the key type */
+       ktype = key_type_lookup(type);
+       if (IS_ERR(ktype)) {
+               ret = PTR_ERR(ktype);
+               goto error4;
+       }
+
+       /* do the search */
+       key = request_key(ktype, description, callout_info);
+       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);
+ error5:
+       key_type_put(ktype);
+ error4:
+       key_put(dest);
+ error3:
+       kfree(callout_info);
+ error2:
+       kfree(description);
+ error:
+       return ret;
+
+} /* end sys_request_key() */
+
+/*****************************************************************************/
+/*
+ * get the ID of the specified process keyring
+ * - the keyring must have search permission to be found
+ * - implements keyctl(KEYCTL_GET_KEYRING_ID)
+ */
+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);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error;
+       }
+
+       ret = key->serial;
+       key_put(key);
+ error:
+       return ret;
+
+} /* end keyctl_get_keyring_ID() */
+
+/*****************************************************************************/
+/*
+ * join the session keyring
+ * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING)
+ */
+long keyctl_join_session_keyring(const char __user *_name)
+{
+       char *name;
+       long nlen, ret;
+
+       /* fetch the name from userspace */
+       name = NULL;
+       if (_name) {
+               ret = -EFAULT;
+               nlen = strnlen_user(_name, PAGE_SIZE - 1);
+               if (nlen <= 0)
+                       goto error;
+
+               ret = -EINVAL;
+               if (nlen > PAGE_SIZE - 1)
+                       goto error;
+
+               ret = -ENOMEM;
+               name = kmalloc(nlen + 1, GFP_KERNEL);
+               if (!name)
+                       goto error;
+
+               ret = -EFAULT;
+               if (copy_from_user(name, _name, nlen + 1) != 0)
+                       goto error2;
+       }
+
+       /* join the session */
+       ret = join_session_keyring(name);
+
+ error2:
+       kfree(name);
+ error:
+       return ret;
+
+} /* end keyctl_join_session_keyring() */
+
+/*****************************************************************************/
+/*
+ * update a key's data payload
+ * - the key must be writable
+ * - implements keyctl(KEYCTL_UPDATE)
+ */
+long keyctl_update_key(key_serial_t id,
+                      const void __user *_payload,
+                      size_t plen)
+{
+       struct key *key;
+       void *payload;
+       long ret;
+
+       ret = -EINVAL;
+       if (plen > PAGE_SIZE)
+               goto error;
+
+       /* pull the payload in if one was supplied */
+       payload = NULL;
+       if (_payload) {
+               ret = -ENOMEM;
+               payload = kmalloc(plen, GFP_KERNEL);
+               if (!payload)
+                       goto error;
+
+               ret = -EFAULT;
+               if (copy_from_user(payload, _payload, plen) != 0)
+                       goto error2;
+       }
+
+       /* find the target key (which must be writable) */
+       key = lookup_user_key(id, 0, 0, KEY_WRITE);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error2;
+       }
+
+       /* update the key */
+       ret = key_update(key, payload, plen);
+
+       key_put(key);
+ error2:
+       kfree(payload);
+ error:
+       return ret;
+
+} /* end keyctl_update_key() */
+
+/*****************************************************************************/
+/*
+ * revoke a key
+ * - the key must be writable
+ * - implements keyctl(KEYCTL_REVOKE)
+ */
+long keyctl_revoke_key(key_serial_t id)
+{
+       struct key *key;
+       long ret;
+
+       key = lookup_user_key(id, 0, 0, KEY_WRITE);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error;
+       }
+
+       key_revoke(key);
+       ret = 0;
+
+       key_put(key);
+ error:
+       return 0;
+
+} /* end keyctl_revoke_key() */
+
+/*****************************************************************************/
+/*
+ * clear the specified process keyring
+ * - the keyring must be writable
+ * - implements keyctl(KEYCTL_CLEAR)
+ */
+long keyctl_keyring_clear(key_serial_t ringid)
+{
+       struct key *keyring;
+       long ret;
+
+       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error;
+       }
+
+       ret = keyring_clear(keyring);
+
+       key_put(keyring);
+ error:
+       return ret;
+
+} /* end keyctl_keyring_clear() */
+
+/*****************************************************************************/
+/*
+ * link a key into a keyring
+ * - the keyring must be writable
+ * - the key must be linkable
+ * - implements keyctl(KEYCTL_LINK)
+ */
+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);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error;
+       }
+
+       key = lookup_user_key(id, 1, 0, KEY_LINK);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error2;
+       }
+
+       ret = key_link(keyring, key);
+
+       key_put(key);
+ error2:
+       key_put(keyring);
+ error:
+       return ret;
+
+} /* end keyctl_keyring_link() */
+
+/*****************************************************************************/
+/*
+ * unlink the first attachment of a key from a keyring
+ * - the keyring must be writable
+ * - we don't need any permissions on the key
+ * - implements keyctl(KEYCTL_UNLINK)
+ */
+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);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error;
+       }
+
+       key = lookup_user_key(id, 0, 0, 0);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error2;
+       }
+
+       ret = key_unlink(keyring, key);
+
+       key_put(key);
+ error2:
+       key_put(keyring);
+ error:
+       return ret;
+
+} /* end keyctl_keyring_unlink() */
+
+/*****************************************************************************/
+/*
+ * describe a user key
+ * - the key must have view permission
+ * - if there's a buffer, we place up to buflen bytes of data into it
+ * - unless there's an error, we return the amount of description available,
+ *   irrespective of how much we may have copied
+ * - the description is formatted thus:
+ *     type;uid;gid;perm;description<NUL>
+ * - implements keyctl(KEYCTL_DESCRIBE)
+ */
+long keyctl_describe_key(key_serial_t keyid,
+                        char __user *buffer,
+                        size_t buflen)
+{
+       struct key *key;
+       char *tmpbuf;
+       long ret;
+
+       key = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error;
+       }
+
+       /* calculate how much description we're going to return */
+       ret = -ENOMEM;
+       tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!tmpbuf)
+               goto error2;
+
+       ret = snprintf(tmpbuf, PAGE_SIZE - 1,
+                      "%s;%d;%d;%06x;%s",
+                      key->type->name,
+                      key->uid,
+                      key->gid,
+                      key->perm,
+                      key->description ? key->description :""
+                      );
+
+       /* include a NUL char at the end of the data */
+       if (ret > PAGE_SIZE - 1)
+               ret = PAGE_SIZE - 1;
+       tmpbuf[ret] = 0;
+       ret++;
+
+       /* consider returning the data */
+       if (buffer && buflen > 0) {
+               if (buflen > ret)
+                       buflen = ret;
+
+               if (copy_to_user(buffer, tmpbuf, buflen) != 0)
+                       ret = -EFAULT;
+       }
+
+       kfree(tmpbuf);
+ error2:
+       key_put(key);
+ error:
+       return ret;
+
+} /* end keyctl_describe_key() */
+
+/*****************************************************************************/
+/*
+ * search the specified keyring for a matching key
+ * - the start keyring must be searchable
+ * - nested keyrings may also be searched if they are searchable
+ * - only keys with search permission may be found
+ * - if a key is found, it will be attached to the destination keyring if
+ *   there's one specified
+ * - implements keyctl(KEYCTL_SEARCH)
+ */
+long keyctl_keyring_search(key_serial_t ringid,
+                          const char __user *_type,
+                          const char __user *_description,
+                          key_serial_t destringid)
+{
+       struct key_type *ktype;
+       struct key *keyring, *key, *dest;
+       char type[32], *description;
+       long dlen, ret;
+
+       /* pull the type and description into kernel space */
+       ret = strncpy_from_user(type, _type, sizeof(type) - 1);
+       if (ret < 0)
+               goto error;
+       type[31] = '\0';
+
+       ret = -EFAULT;
+       dlen = strnlen_user(_description, PAGE_SIZE - 1);
+       if (dlen <= 0)
+               goto error;
+
+       ret = -EINVAL;
+       if (dlen > PAGE_SIZE - 1)
+               goto error;
+
+       ret = -ENOMEM;
+       description = kmalloc(dlen + 1, GFP_KERNEL);
+       if (!description)
+               goto error;
+
+       ret = -EFAULT;
+       if (copy_from_user(description, _description, dlen + 1) != 0)
+               goto error2;
+
+       /* get the keyring at which to begin the search */
+       keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error2;
+       }
+
+       /* get the destination keyring if specified */
+       dest = NULL;
+       if (destringid) {
+               dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(dest)) {
+                       ret = PTR_ERR(dest);
+                       goto error3;
+               }
+       }
+
+       /* find the key type */
+       ktype = key_type_lookup(type);
+       if (IS_ERR(ktype)) {
+               ret = PTR_ERR(ktype);
+               goto error4;
+       }
+
+       /* do the search */
+       key = keyring_search(keyring, ktype, description);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+
+               /* treat lack or presence of a negative key the same */
+               if (ret == -EAGAIN)
+                       ret = -ENOKEY;
+               goto error5;
+       }
+
+       /* link the resulting key to the destination keyring if we can */
+       if (dest) {
+               ret = -EACCES;
+               if (!key_permission(key, KEY_LINK))
+                       goto error6;
+
+               ret = key_link(dest, key);
+               if (ret < 0)
+                       goto error6;
+       }
+
+       ret = key->serial;
+
+ error6:
+       key_put(key);
+ error5:
+       key_type_put(ktype);
+ error4:
+       key_put(dest);
+ error3:
+       key_put(keyring);
+ error2:
+       kfree(description);
+ error:
+       return ret;
+
+} /* end keyctl_keyring_search() */
+
+/*****************************************************************************/
+/*
+ * see if the key we're looking at is the target key
+ */
+static int keyctl_read_key_same(const struct key *key, const void *target)
+{
+       return key == target;
+
+} /* end keyctl_read_key_same() */
+
+/*****************************************************************************/
+/*
+ * read a user key's payload
+ * - the keyring must be readable or the key must be searchable from the
+ *   process's keyrings
+ * - if there's a buffer, we place up to buflen bytes of data into it
+ * - unless there's an error, we return the amount of data in the key,
+ *   irrespective of how much we may have copied
+ * - implements keyctl(KEYCTL_READ)
+ */
+long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
+{
+       struct key *key, *skey;
+       long ret;
+
+       /* find the key first */
+       key = lookup_user_key(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;
+               }
+
+               goto error2;
+       }
+
+       ret = -ENOKEY;
+       goto error;
+
+       /* the key is probably readable - now try to read it */
+ can_read_key2:
+       key_put(skey);
+ can_read_key:
+       ret = key_validate(key);
+       if (ret == 0) {
+               ret = -EOPNOTSUPP;
+               if (key->type->read) {
+                       /* read the data with the semaphore held (since we
+                        * might sleep) */
+                       down_read(&key->sem);
+                       ret = key->type->read(key, buffer, buflen);
+                       up_read(&key->sem);
+               }
+       }
+
+ error2:
+       key_put(key);
+ error:
+       return ret;
+
+} /* end keyctl_read_key() */
+
+/*****************************************************************************/
+/*
+ * change the ownership of a key
+ * - the keyring owned by the changer
+ * - if the uid or gid is -1, then that parameter is not changed
+ * - implements keyctl(KEYCTL_CHOWN)
+ */
+long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
+{
+       struct key *key;
+       long ret;
+
+       ret = 0;
+       if (uid == (uid_t) -1 && gid == (gid_t) -1)
+               goto error;
+
+       key = lookup_user_key(id, 1, 1, 0);
+       if (IS_ERR(key)) {
+               ret = PTR_ERR(key);
+               goto error;
+       }
+
+       /* 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 */
+               if (uid != (uid_t) -1 && key->uid != uid)
+                       goto no_access;
+
+               /* only the sysadmin can set the key's GID to a group other
+                * than one of those that the current process subscribes to */
+               if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
+                       goto no_access;
+       }
+
+       /* change the UID (have to update the quotas) */
+       if (uid != (uid_t) -1 && uid != key->uid) {
+               /* don't support UID changing yet */
+               ret = -EOPNOTSUPP;
+               goto no_access;
+       }
+
+       /* change the GID */
+       if (gid != (gid_t) -1)
+               key->gid = gid;
+
+       ret = 0;
+
+ no_access:
+       write_unlock(&key->lock);
+       up_write(&key->sem);
+       key_put(key);
+ error:
+       return ret;
+
+} /* end keyctl_chown_key() */
+
+/*****************************************************************************/
+/*
+ * change the permission mask on a key
+ * - the keyring owned by the changer
+ * - implements keyctl(KEYCTL_SETPERM)
+ */
+long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
+{
+       struct key *key;
+       long ret;
+
+       ret = -EINVAL;
+       if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
+               goto error;
+
+       key = lookup_user_key(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 */
+       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;
+
+ no_access:
+       write_unlock(&key->lock);
+       up_write(&key->sem);
+       key_put(key);
+ error:
+       return ret;
+
+} /* end keyctl_setperm_key() */
+
+/*****************************************************************************/
+/*
+ * instantiate the key with the specified payload, and, if one is given, link
+ * the key into the keyring
+ */
+long keyctl_instantiate_key(key_serial_t id,
+                           const void __user *_payload,
+                           size_t plen,
+                           key_serial_t ringid)
+{
+       struct key *key, *keyring;
+       void *payload;
+       long ret;
+
+       ret = -EINVAL;
+       if (plen > 32767)
+               goto error;
+
+       /* pull the payload in if one was supplied */
+       payload = NULL;
+
+       if (_payload) {
+               ret = -ENOMEM;
+               payload = kmalloc(plen, GFP_KERNEL);
+               if (!payload)
+                       goto error;
+
+               ret = -EFAULT;
+               if (copy_from_user(payload, _payload, plen) != 0)
+                       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);
+               goto error2;
+       }
+
+       /* find the destination keyring if present (which must also be
+        * writable) */
+       keyring = NULL;
+       if (ringid) {
+               keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(keyring)) {
+                       ret = PTR_ERR(keyring);
+                       goto error3;
+               }
+       }
+
+       /* instantiate the key and link it into a keyring */
+       ret = key_instantiate_and_link(key, payload, plen, keyring);
+
+       key_put(keyring);
+ error3:
+       key_put(key);
+ error2:
+       kfree(payload);
+ error:
+       return ret;
+
+} /* end keyctl_instantiate_key() */
+
+/*****************************************************************************/
+/*
+ * negatively instantiate the key with the given timeout (in seconds), and, if
+ * one is given, link the key into the keyring
+ */
+long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
+{
+       struct key *key, *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);
+               goto error;
+       }
+
+       /* find the destination keyring if present (which must also be
+        * writable) */
+       keyring = NULL;
+       if (ringid) {
+               keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(keyring)) {
+                       ret = PTR_ERR(keyring);
+                       goto error2;
+               }
+       }
+
+       /* instantiate the key and link it into a keyring */
+       ret = key_negate_and_link(key, timeout, keyring);
+
+       key_put(keyring);
+ error2:
+       key_put(key);
+ error:
+       return ret;
+
+} /* end keyctl_negate_key() */
+
+/*****************************************************************************/
+/*
+ * the key control system call
+ */
+asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
+                          unsigned long arg4, unsigned long arg5)
+{
+       switch (option) {
+       case KEYCTL_GET_KEYRING_ID:
+               return keyctl_get_keyring_ID((key_serial_t) arg2,
+                                            (int) arg3);
+
+       case KEYCTL_JOIN_SESSION_KEYRING:
+               return keyctl_join_session_keyring((const char __user *) arg3);
+
+       case KEYCTL_UPDATE:
+               return keyctl_update_key((key_serial_t) arg2,
+                                        (const void __user *) arg3,
+                                        (size_t) arg4);
+
+       case KEYCTL_REVOKE:
+               return keyctl_revoke_key((key_serial_t) arg2);
+
+       case KEYCTL_DESCRIBE:
+               return keyctl_describe_key((key_serial_t) arg2,
+                                          (char __user *) arg3,
+                                          (unsigned) arg4);
+
+       case KEYCTL_CLEAR:
+               return keyctl_keyring_clear((key_serial_t) arg2);
+
+       case KEYCTL_LINK:
+               return keyctl_keyring_link((key_serial_t) arg2,
+                                          (key_serial_t) arg3);
+
+       case KEYCTL_UNLINK:
+               return keyctl_keyring_unlink((key_serial_t) arg2,
+                                            (key_serial_t) arg3);
+
+       case KEYCTL_SEARCH:
+               return keyctl_keyring_search((key_serial_t) arg2,
+                                            (const char __user *) arg3,
+                                            (const char __user *) arg4,
+                                            (key_serial_t) arg5);
+
+       case KEYCTL_READ:
+               return keyctl_read_key((key_serial_t) arg2,
+                                      (char __user *) arg3,
+                                      (size_t) arg4);
+
+       case KEYCTL_CHOWN:
+               return keyctl_chown_key((key_serial_t) arg2,
+                                       (uid_t) arg3,
+                                       (gid_t) arg4);
+
+       case KEYCTL_SETPERM:
+               return keyctl_setperm_key((key_serial_t) arg2,
+                                         (key_perm_t) arg3);
+
+       case KEYCTL_INSTANTIATE:
+               return keyctl_instantiate_key((key_serial_t) arg2,
+                                             (const void __user *) arg3,
+                                             (size_t) arg4,
+                                             (key_serial_t) arg5);
+
+       case KEYCTL_NEGATE:
+               return keyctl_negate_key((key_serial_t) arg2,
+                                        (unsigned) arg3,
+                                        (key_serial_t) arg4);
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+} /* end sys_keyctl() */
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
new file mode 100644 (file)
index 0000000..98d4b0b
--- /dev/null
@@ -0,0 +1,895 @@
+/* keyring.c: keyring handling
+ *
+ * Copyright (C) 2004 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/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include "internal.h"
+
+/*
+ * when plumbing the depths of the key tree, this sets a hard limit set on how
+ * deep we're willing to go
+ */
+#define KEYRING_SEARCH_MAX_DEPTH 6
+
+/*
+ * we keep all named keyrings in a hash to speed looking them up
+ */
+#define KEYRING_NAME_HASH_SIZE (1 << 5)
+
+static struct list_head        keyring_name_hash[KEYRING_NAME_HASH_SIZE];
+static rwlock_t                keyring_name_lock = RW_LOCK_UNLOCKED;
+
+static inline unsigned keyring_hash(const char *desc)
+{
+       unsigned bucket = 0;
+
+       for (; *desc; desc++)
+               bucket += (unsigned char) *desc;
+
+       return bucket & (KEYRING_NAME_HASH_SIZE - 1);
+}
+
+/*
+ * the keyring type definition
+ */
+static int keyring_instantiate(struct key *keyring,
+                              const void *data, size_t datalen);
+static int keyring_duplicate(struct key *keyring, const struct key *source);
+static int keyring_match(const struct key *keyring, const void *criterion);
+static void keyring_destroy(struct key *keyring);
+static void keyring_describe(const struct key *keyring, struct seq_file *m);
+static long keyring_read(const struct key *keyring,
+                        char __user *buffer, size_t buflen);
+
+struct key_type key_type_keyring = {
+       .name           = "keyring",
+       .def_datalen    = sizeof(struct keyring_list),
+       .instantiate    = keyring_instantiate,
+       .duplicate      = keyring_duplicate,
+       .match          = keyring_match,
+       .destroy        = keyring_destroy,
+       .describe       = keyring_describe,
+       .read           = keyring_read,
+};
+
+/*
+ * semaphore to serialise link/link calls to prevent two link calls in parallel
+ * introducing a cycle
+ */
+DECLARE_RWSEM(keyring_serialise_link_sem);
+
+/*****************************************************************************/
+/*
+ * publish the name of a keyring so that it can be found by name (if it has
+ * one)
+ */
+void keyring_publish_name(struct key *keyring)
+{
+       int bucket;
+
+       if (keyring->description) {
+               bucket = keyring_hash(keyring->description);
+
+               write_lock(&keyring_name_lock);
+
+               if (!keyring_name_hash[bucket].next)
+                       INIT_LIST_HEAD(&keyring_name_hash[bucket]);
+
+               list_add_tail(&keyring->type_data.link,
+                             &keyring_name_hash[bucket]);
+
+               write_unlock(&keyring_name_lock);
+       }
+
+} /* end keyring_publish_name() */
+
+/*****************************************************************************/
+/*
+ * initialise a keyring
+ * - we object if we were given any data
+ */
+static int keyring_instantiate(struct key *keyring,
+                              const void *data, size_t datalen)
+{
+       int ret;
+
+       ret = -EINVAL;
+       if (datalen == 0) {
+               /* make the keyring available by name if it has one */
+               keyring_publish_name(keyring);
+               ret = 0;
+       }
+
+       return ret;
+
+} /* end keyring_instantiate() */
+
+/*****************************************************************************/
+/*
+ * duplicate the list of subscribed keys from a source keyring into this one
+ */
+static int keyring_duplicate(struct key *keyring, const struct key *source)
+{
+       struct keyring_list *sklist, *klist;
+       unsigned max;
+       size_t size;
+       int loop, ret;
+
+       const unsigned limit =
+               (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
+
+       ret = 0;
+       sklist = source->payload.subscriptions;
+
+       if (sklist && sklist->nkeys > 0) {
+               max = sklist->nkeys;
+               BUG_ON(max > limit);
+
+               max = (max + 3) & ~3;
+               if (max > limit)
+                       max = limit;
+
+               ret = -ENOMEM;
+               size = sizeof(*klist) + sizeof(struct key) * max;
+               klist = kmalloc(size, GFP_KERNEL);
+               if (!klist)
+                       goto error;
+
+               klist->maxkeys = max;
+               klist->nkeys = sklist->nkeys;
+               memcpy(klist->keys,
+                      sklist->keys,
+                      sklist->nkeys * sizeof(struct key));
+
+               for (loop = klist->nkeys - 1; loop >= 0; loop--)
+                       atomic_inc(&klist->keys[loop]->usage);
+
+               keyring->payload.subscriptions = klist;
+               ret = 0;
+       }
+
+ error:
+       return ret;
+
+} /* end keyring_duplicate() */
+
+/*****************************************************************************/
+/*
+ * match keyrings on their name
+ */
+static int keyring_match(const struct key *keyring, const void *description)
+{
+       return keyring->description &&
+               strcmp(keyring->description, description) == 0;
+
+} /* end keyring_match() */
+
+/*****************************************************************************/
+/*
+ * dispose of the data dangling from the corpse of a keyring
+ */
+static void keyring_destroy(struct key *keyring)
+{
+       struct keyring_list *klist;
+       int loop;
+
+       if (keyring->description) {
+               write_lock(&keyring_name_lock);
+               list_del(&keyring->type_data.link);
+               write_unlock(&keyring_name_lock);
+       }
+
+       klist = keyring->payload.subscriptions;
+       if (klist) {
+               for (loop = klist->nkeys - 1; loop >= 0; loop--)
+                       key_put(klist->keys[loop]);
+               kfree(klist);
+       }
+
+} /* end keyring_destroy() */
+
+/*****************************************************************************/
+/*
+ * describe the keyring
+ */
+static void keyring_describe(const struct key *keyring, struct seq_file *m)
+{
+       struct keyring_list *klist;
+
+       if (keyring->description) {
+               seq_puts(m, keyring->description);
+       }
+       else {
+               seq_puts(m, "[anon]");
+       }
+
+       klist = keyring->payload.subscriptions;
+       if (klist)
+               seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
+       else
+               seq_puts(m, ": empty");
+
+} /* end keyring_describe() */
+
+/*****************************************************************************/
+/*
+ * read a list of key IDs from the keyring's contents
+ */
+static long keyring_read(const struct key *keyring,
+                        char __user *buffer, size_t buflen)
+{
+       struct keyring_list *klist;
+       struct key *key;
+       size_t qty, tmp;
+       int loop, ret;
+
+       ret = 0;
+       klist = keyring->payload.subscriptions;
+
+       if (klist) {
+               /* calculate how much data we could return */
+               qty = klist->nkeys * sizeof(key_serial_t);
+
+               if (buffer && buflen > 0) {
+                       if (buflen > qty)
+                               buflen = qty;
+
+                       /* copy the IDs of the subscribed keys into the
+                        * buffer */
+                       ret = -EFAULT;
+
+                       for (loop = 0; loop < klist->nkeys; loop++) {
+                               key = klist->keys[loop];
+
+                               tmp = sizeof(key_serial_t);
+                               if (tmp > buflen)
+                                       tmp = buflen;
+
+                               if (copy_to_user(buffer,
+                                                &key->serial,
+                                                tmp) != 0)
+                                       goto error;
+
+                               buflen -= tmp;
+                               if (buflen == 0)
+                                       break;
+                               buffer += tmp;
+                       }
+               }
+
+               ret = qty;
+       }
+
+ error:
+       return ret;
+
+} /* end keyring_read() */
+
+/*****************************************************************************/
+/*
+ * allocate a keyring and link into the destination keyring
+ */
+struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
+                         int not_in_quota, struct key *dest)
+{
+       struct key *keyring;
+       int ret;
+
+       keyring = key_alloc(&key_type_keyring, description,
+                           uid, gid, KEY_USR_ALL, not_in_quota);
+
+       if (!IS_ERR(keyring)) {
+               ret = key_instantiate_and_link(keyring, NULL, 0, dest);
+               if (ret < 0) {
+                       key_put(keyring);
+                       keyring = ERR_PTR(ret);
+               }
+       }
+
+       return keyring;
+
+} /* end keyring_alloc() */
+
+/*****************************************************************************/
+/*
+ * search the supplied keyring tree for a key that matches the criterion
+ * - perform a breadth-then-depth search up to the prescribed limit
+ * - 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 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 key_type *type,
+                              const void *description,
+                              key_match_func_t match)
+{
+       struct {
+               struct key *keyring;
+               int kix;
+       } stack[KEYRING_SEARCH_MAX_DEPTH];
+
+       struct keyring_list *keylist;
+       struct timespec now;
+       struct key *key;
+       long err;
+       int sp, psp, kix;
+
+       key_check(keyring);
+
+       /* top keyring must have search permission to begin the search */
+       key = ERR_PTR(-EACCES);
+       if (!key_permission(keyring, KEY_SEARCH))
+               goto error;
+
+       key = ERR_PTR(-ENOTDIR);
+       if (keyring->type != &key_type_keyring)
+               goto error;
+
+       now = current_kernel_time();
+       err = -EAGAIN;
+       sp = 0;
+
+       /* start processing a new keyring */
+ descend:
+       read_lock(&keyring->lock);
+       if (keyring->flags & KEY_FLAG_REVOKED)
+               goto not_this_keyring;
+
+       keylist = keyring->payload.subscriptions;
+       if (!keylist)
+               goto not_this_keyring;
+
+       /* iterate through the keys in this keyring first */
+       for (kix = 0; kix < keylist->nkeys; kix++) {
+               key = keylist->keys[kix];
+
+               /* ignore keys not of this type */
+               if (key->type != type)
+                       continue;
+
+               /* skip revoked keys and expired keys */
+               if (key->flags & KEY_FLAG_REVOKED)
+                       continue;
+
+               if (key->expiry && now.tv_sec >= key->expiry)
+                       continue;
+
+               /* keys that don't match */
+               if (!match(key, description))
+                       continue;
+
+               /* key must have search permissions */
+               if (!key_permission(key, KEY_SEARCH))
+                       continue;
+
+               /* we set a different error code if we find a negative key */
+               if (key->flags & KEY_FLAG_NEGATIVE) {
+                       err = -ENOKEY;
+                       continue;
+               }
+
+               goto found;
+       }
+
+       /* search through the keyrings nested in this one */
+       kix = 0;
+ ascend:
+       while (kix < keylist->nkeys) {
+               key = keylist->keys[kix];
+               if (key->type != &key_type_keyring)
+                       goto next;
+
+               /* 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;
+
+               /* evade loops in the keyring tree */
+               for (psp = 0; psp < sp; psp++)
+                       if (stack[psp].keyring == keyring)
+                               goto next;
+
+               /* stack the current position */
+               stack[sp].keyring = keyring;
+               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;
+               kix = stack[sp].kix + 1;
+               goto ascend;
+       }
+
+       key = ERR_PTR(err);
+       goto error;
+
+       /* 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:
+       return key;
+
+} /* end keyring_search_aux() */
+
+/*****************************************************************************/
+/*
+ * search the supplied keyring tree for a key that matches the criterion
+ * - perform a breadth-then-depth search up to the prescribed limit
+ * - we only find keys on which we have search permission
+ * - we readlock the keyrings as we search down the tree
+ * - 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(struct key *keyring,
+                          struct key_type *type,
+                          const char *description)
+{
+       return keyring_search_aux(keyring, type, description, type->match);
+
+} /* end keyring_search() */
+
+EXPORT_SYMBOL(keyring_search);
+
+/*****************************************************************************/
+/*
+ * search the given keyring only (no recursion)
+ * - keyring must be locked by caller
+ */
+struct key *__keyring_search_one(struct key *keyring,
+                                const struct key_type *ktype,
+                                const char *description,
+                                key_perm_t perm)
+{
+       struct keyring_list *klist;
+       struct key *key;
+       int loop;
+
+       klist = 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_permission(key, perm) &&
+                           !(key->flags & KEY_FLAG_REVOKED)
+                           )
+                               goto found;
+               }
+       }
+
+       key = ERR_PTR(-ENOKEY);
+       goto error;
+
+ found:
+       atomic_inc(&key->usage);
+ error:
+       return key;
+
+} /* end __keyring_search_one() */
+
+/*****************************************************************************/
+/*
+ * find a keyring with the specified name
+ * - all named keyrings are searched
+ * - only find keyrings with search permission for the process
+ * - only find keyrings with a serial number greater than the one specified
+ */
+struct key *find_keyring_by_name(const char *name, key_serial_t bound)
+{
+       struct key *keyring;
+       int bucket;
+
+       keyring = ERR_PTR(-EINVAL);
+       if (!name)
+               goto error;
+
+       bucket = keyring_hash(name);
+
+       read_lock(&keyring_name_lock);
+
+       if (keyring_name_hash[bucket].next) {
+               /* search this hash bucket for a keyring with a matching name
+                * that's readable and that hasn't been revoked */
+               list_for_each_entry(keyring,
+                                   &keyring_name_hash[bucket],
+                                   type_data.link
+                                   ) {
+                       if (keyring->flags & KEY_FLAG_REVOKED)
+                               continue;
+
+                       if (strcmp(keyring->description, name) != 0)
+                               continue;
+
+                       if (!key_permission(keyring, KEY_SEARCH))
+                               continue;
+
+                       /* found a potential candidate, but we still need to
+                        * check the serial number */
+                       if (keyring->serial <= bound)
+                               continue;
+
+                       /* we've got a match */
+                       atomic_inc(&keyring->usage);
+                       read_unlock(&keyring_name_lock);
+                       goto error;
+               }
+       }
+
+       read_unlock(&keyring_name_lock);
+       keyring = ERR_PTR(-ENOKEY);
+
+ error:
+       return keyring;
+
+} /* end find_keyring_by_name() */
+
+/*****************************************************************************/
+/*
+ * see if a cycle will will be created by inserting acyclic tree B in acyclic
+ * tree A at the topmost level (ie: as a direct child of A)
+ * - since we are adding B to A at the top level, checking for cycles should
+ *   just be a matter of seeing if node A is somewhere in tree B
+ */
+static int keyring_detect_cycle(struct key *A, struct key *B)
+{
+       struct {
+               struct key *subtree;
+               int kix;
+       } stack[KEYRING_SEARCH_MAX_DEPTH];
+
+       struct keyring_list *keylist;
+       struct key *subtree, *key;
+       int sp, kix, ret;
+
+       ret = -EDEADLK;
+       if (A == B)
+               goto error;
+
+       subtree = B;
+       sp = 0;
+
+       /* start processing a new keyring */
+ descend:
+       read_lock(&subtree->lock);
+       if (subtree->flags & KEY_FLAG_REVOKED)
+               goto not_this_keyring;
+
+       keylist = subtree->payload.subscriptions;
+       if (!keylist)
+               goto not_this_keyring;
+       kix = 0;
+
+ ascend:
+       /* iterate through the remaining keys in this keyring */
+       for (; kix < keylist->nkeys; kix++) {
+               key = keylist->keys[kix];
+
+               if (key == A)
+                       goto cycle_detected;
+
+               /* recursively check nested keyrings */
+               if (key->type == &key_type_keyring) {
+                       if (sp >= KEYRING_SEARCH_MAX_DEPTH)
+                               goto too_deep;
+
+                       /* stack the current position */
+                       stack[sp].subtree = subtree;
+                       stack[sp].kix = kix;
+                       sp++;
+
+                       /* begin again with the new keyring */
+                       subtree = key;
+                       goto descend;
+               }
+       }
+
+       /* 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;
+               kix = stack[sp].kix + 1;
+               goto ascend;
+       }
+
+       ret = 0; /* no cycles detected */
+
+ error:
+       return ret;
+
+ too_deep:
+       ret = -ELOOP;
+       goto error_unwind;
+ 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() */
+
+/*****************************************************************************/
+/*
+ * link a key into to a keyring
+ * - must be called with the keyring's semaphore held
+ */
+int __key_link(struct key *keyring, struct key *key)
+{
+       struct keyring_list *klist, *nklist;
+       unsigned max;
+       size_t size;
+       int ret;
+
+       ret = -EKEYREVOKED;
+       if (keyring->flags & KEY_FLAG_REVOKED)
+               goto error;
+
+       ret = -ENOTDIR;
+       if (keyring->type != &key_type_keyring)
+               goto error;
+
+       /* serialise link/link calls to prevent parallel calls causing a
+        * cycle when applied to two keyring in opposite orders */
+       down_write(&keyring_serialise_link_sem);
+
+       /* check that we aren't going to create a cycle adding one keyring to
+        * another */
+       if (key->type == &key_type_keyring) {
+               ret = keyring_detect_cycle(keyring, key);
+               if (ret < 0)
+                       goto error2;
+       }
+
+       /* check that we aren't going to overrun the user's quota */
+       ret = key_payload_reserve(keyring,
+                                 keyring->datalen + KEYQUOTA_LINK_BYTES);
+       if (ret < 0)
+               goto error2;
+
+       klist = keyring->payload.subscriptions;
+
+       if (klist && klist->nkeys < klist->maxkeys) {
+               /* 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);
+
+               ret = 0;
+       }
+       else {
+               /* grow the key list */
+               max = 4;
+               if (klist)
+                       max += klist->maxkeys;
+
+               ret = -ENFILE;
+               size = sizeof(*klist) + sizeof(*key) * max;
+               if (size > PAGE_SIZE)
+                       goto error3;
+
+               ret = -ENOMEM;
+               nklist = kmalloc(size, GFP_KERNEL);
+               if (!nklist)
+                       goto error3;
+               nklist->maxkeys = max;
+               nklist->nkeys = 0;
+
+               if (klist) {
+                       nklist->nkeys = klist->nkeys;
+                       memcpy(nklist->keys,
+                              klist->keys,
+                              sizeof(struct key *) * klist->nkeys);
+               }
+
+               /* 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);
+
+               /* dispose of the old keyring list */
+               kfree(klist);
+
+               ret = 0;
+       }
+
+ error2:
+       up_write(&keyring_serialise_link_sem);
+ error:
+       return ret;
+
+ error3:
+       /* undo the quota changes */
+       key_payload_reserve(keyring,
+                           keyring->datalen - KEYQUOTA_LINK_BYTES);
+       goto error2;
+
+} /* end __key_link() */
+
+/*****************************************************************************/
+/*
+ * link a key to a keyring
+ */
+int key_link(struct key *keyring, struct key *key)
+{
+       int ret;
+
+       key_check(keyring);
+       key_check(key);
+
+       down_write(&keyring->sem);
+       ret = __key_link(keyring, key);
+       up_write(&keyring->sem);
+
+       return ret;
+
+} /* end key_link() */
+
+EXPORT_SYMBOL(key_link);
+
+/*****************************************************************************/
+/*
+ * unlink the first link to a key from a keyring
+ */
+int key_unlink(struct key *keyring, struct key *key)
+{
+       struct keyring_list *klist;
+       int loop, ret;
+
+       key_check(keyring);
+       key_check(key);
+
+       ret = -ENOTDIR;
+       if (keyring->type != &key_type_keyring)
+               goto error;
+
+       down_write(&keyring->sem);
+
+       klist = keyring->payload.subscriptions;
+       if (klist) {
+               /* search the keyring for the key */
+               for (loop = 0; loop < klist->nkeys; loop++)
+                       if (klist->keys[loop] == key)
+                               goto key_is_present;
+       }
+
+       up_write(&keyring->sem);
+       ret = -ENOENT;
+       goto error;
+
+ key_is_present:
+       /* 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);
+
+       klist->nkeys--;
+       if (loop < klist->nkeys)
+               memcpy(&klist->keys[loop],
+                      &klist->keys[loop + 1],
+                      (klist->nkeys - loop) * sizeof(struct key *));
+
+       write_unlock(&keyring->lock);
+
+       up_write(&keyring->sem);
+       key_put(key);
+       ret = 0;
+
+ error:
+       return ret;
+
+} /* end key_unlink() */
+
+EXPORT_SYMBOL(key_unlink);
+
+/*****************************************************************************/
+/*
+ * clear the specified process keyring
+ * - implements keyctl(KEYCTL_CLEAR)
+ */
+int keyring_clear(struct key *keyring)
+{
+       struct keyring_list *klist;
+       int loop, ret;
+
+       ret = -ENOTDIR;
+       if (keyring->type == &key_type_keyring) {
+               /* detach the pointer block with the locks held */
+               down_write(&keyring->sem);
+
+               klist = keyring->payload.subscriptions;
+               if (klist) {
+                       /* adjust the quota */
+                       key_payload_reserve(keyring,
+                                           sizeof(struct keyring_list));
+
+                       write_lock(&keyring->lock);
+                       keyring->payload.subscriptions = NULL;
+                       write_unlock(&keyring->lock);
+               }
+
+               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);
+               }
+
+               ret = 0;
+       }
+
+       return ret;
+
+} /* end keyring_clear() */
+
+EXPORT_SYMBOL(keyring_clear);
diff --git a/security/keys/proc.c b/security/keys/proc.c
new file mode 100644 (file)
index 0000000..91343b8
--- /dev/null
@@ -0,0 +1,251 @@
+/* proc.c: proc files for key database enumeration
+ *
+ * Copyright (C) 2004 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/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/errno.h>
+#include "internal.h"
+
+#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
+static int proc_keys_open(struct inode *inode, struct file *file);
+static void *proc_keys_start(struct seq_file *p, loff_t *_pos);
+static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
+static void proc_keys_stop(struct seq_file *p, void *v);
+static int proc_keys_show(struct seq_file *m, void *v);
+
+static struct seq_operations proc_keys_ops = {
+       .start  = proc_keys_start,
+       .next   = proc_keys_next,
+       .stop   = proc_keys_stop,
+       .show   = proc_keys_show,
+};
+
+static struct file_operations proc_keys_fops = {
+       .open           = proc_keys_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+#endif
+
+static int proc_key_users_open(struct inode *inode, struct file *file);
+static void *proc_key_users_start(struct seq_file *p, loff_t *_pos);
+static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos);
+static void proc_key_users_stop(struct seq_file *p, void *v);
+static int proc_key_users_show(struct seq_file *m, void *v);
+
+static struct seq_operations proc_key_users_ops = {
+       .start  = proc_key_users_start,
+       .next   = proc_key_users_next,
+       .stop   = proc_key_users_stop,
+       .show   = proc_key_users_show,
+};
+
+static struct file_operations proc_key_users_fops = {
+       .open           = proc_key_users_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/*****************************************************************************/
+/*
+ * declare the /proc files
+ */
+static int __init key_proc_init(void)
+{
+       struct proc_dir_entry *p;
+
+#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
+       p = create_proc_entry("keys", 0, NULL);
+       if (!p)
+               panic("Cannot create /proc/keys\n");
+
+       p->proc_fops = &proc_keys_fops;
+#endif
+
+       p = create_proc_entry("key-users", 0, NULL);
+       if (!p)
+               panic("Cannot create /proc/key-users\n");
+
+       p->proc_fops = &proc_key_users_fops;
+
+       return 0;
+
+} /* end key_proc_init() */
+
+__initcall(key_proc_init);
+
+/*****************************************************************************/
+/*
+ * implement "/proc/keys" to provides a list of the keys on the system
+ */
+#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
+
+static int proc_keys_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &proc_keys_ops);
+
+}
+
+static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
+{
+       struct rb_node *_p;
+       loff_t pos = *_pos;
+
+       spin_lock(&key_serial_lock);
+
+       _p = rb_first(&key_serial_tree);
+       while (pos > 0 && _p) {
+               pos--;
+               _p = rb_next(_p);
+       }
+
+       return _p;
+
+}
+
+static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+       (*_pos)++;
+       return rb_next((struct rb_node *) v);
+
+}
+
+static void proc_keys_stop(struct seq_file *p, void *v)
+{
+       spin_unlock(&key_serial_lock);
+}
+
+static int proc_keys_show(struct seq_file *m, void *v)
+{
+       struct rb_node *_p = v;
+       struct key *key = rb_entry(_p, struct key, serial_node);
+       struct timespec now;
+       unsigned long timo;
+       char xbuf[12];
+
+       now = current_kernel_time();
+
+       read_lock(&key->lock);
+
+       /* come up with a suitable timeout value */
+       if (key->expiry == 0) {
+               memcpy(xbuf, "perm", 5);
+       }
+       else if (now.tv_sec >= key->expiry) {
+               memcpy(xbuf, "expd", 5);
+       }
+       else {
+               timo = key->expiry - now.tv_sec;
+
+               if (timo < 60)
+                       sprintf(xbuf, "%lus", timo);
+               else if (timo < 60*60)
+                       sprintf(xbuf, "%lum", timo / 60);
+               else if (timo < 60*60*24)
+                       sprintf(xbuf, "%luh", timo / (60*60));
+               else if (timo < 60*60*24*7)
+                       sprintf(xbuf, "%lud", timo / (60*60*24));
+               else
+                       sprintf(xbuf, "%luw", timo / (60*60*24*7));
+       }
+
+       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' : '-',
+                  atomic_read(&key->usage),
+                  xbuf,
+                  key->perm,
+                  key->uid,
+                  key->gid,
+                  key->type->name);
+
+       if (key->type->describe)
+               key->type->describe(key, m);
+       seq_putc(m, '\n');
+
+       read_unlock(&key->lock);
+
+       return 0;
+
+}
+
+#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
+
+/*****************************************************************************/
+/*
+ * implement "/proc/key-users" to provides a list of the key users
+ */
+static int proc_key_users_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &proc_key_users_ops);
+
+}
+
+static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
+{
+       struct rb_node *_p;
+       loff_t pos = *_pos;
+
+       spin_lock(&key_user_lock);
+
+       _p = rb_first(&key_user_tree);
+       while (pos > 0 && _p) {
+               pos--;
+               _p = rb_next(_p);
+       }
+
+       return _p;
+
+}
+
+static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+       (*_pos)++;
+       return rb_next((struct rb_node *) v);
+
+}
+
+static void proc_key_users_stop(struct seq_file *p, void *v)
+{
+       spin_unlock(&key_user_lock);
+}
+
+static int proc_key_users_show(struct seq_file *m, void *v)
+{
+       struct rb_node *_p = v;
+       struct key_user *user = rb_entry(_p, struct key_user, node);
+
+       seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
+                  user->uid,
+                  atomic_read(&user->usage),
+                  atomic_read(&user->nkeys),
+                  atomic_read(&user->nikeys),
+                  user->qnkeys,
+                  KEYQUOTA_MAX_KEYS,
+                  user->qnbytes,
+                  KEYQUOTA_MAX_BYTES
+                  );
+
+       return 0;
+
+}
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
new file mode 100644 (file)
index 0000000..e5bd7b9
--- /dev/null
@@ -0,0 +1,640 @@
+/* process_keys.c: management of a process's keyrings
+ *
+ * Copyright (C) 2004 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/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/keyctl.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include "internal.h"
+
+/* session keyring create vs join semaphore */
+static DECLARE_MUTEX(key_session_sem);
+
+/* the root user's tracking struct */
+struct key_user root_key_user = {
+       .usage          = ATOMIC_INIT(3),
+       .consq          = LIST_HEAD_INIT(root_key_user.consq),
+       .lock           = SPIN_LOCK_UNLOCKED,
+       .nkeys          = ATOMIC_INIT(2),
+       .nikeys         = ATOMIC_INIT(2),
+       .uid            = 0,
+};
+
+/* the root user's UID keyring */
+struct key root_user_keyring = {
+       .usage          = ATOMIC_INIT(1),
+       .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,
+       .description    = "_uid.0",
+#ifdef KEY_DEBUGGING
+       .magic          = KEY_DEBUG_MAGIC,
+#endif
+};
+
+/* the root user's default session keyring */
+struct key root_session_keyring = {
+       .usage          = ATOMIC_INIT(1),
+       .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,
+       .description    = "_uid_ses.0",
+#ifdef KEY_DEBUGGING
+       .magic          = KEY_DEBUG_MAGIC,
+#endif
+};
+
+/*****************************************************************************/
+/*
+ * allocate the keyrings to be associated with a UID
+ */
+int alloc_uid_keyring(struct user_struct *user)
+{
+       struct key *uid_keyring, *session_keyring;
+       char buf[20];
+       int ret;
+
+       /* concoct a default session keyring */
+       sprintf(buf, "_uid_ses.%u", user->uid);
+
+       session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
+       if (IS_ERR(session_keyring)) {
+               ret = PTR_ERR(session_keyring);
+               goto error;
+       }
+
+       /* and a UID specific keyring, pointed to by the default session
+        * keyring */
+       sprintf(buf, "_uid.%u", user->uid);
+
+       uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
+                                   session_keyring);
+       if (IS_ERR(uid_keyring)) {
+               key_put(session_keyring);
+               ret = PTR_ERR(uid_keyring);
+               goto error;
+       }
+
+       /* install the keyrings */
+       user->uid_keyring = uid_keyring;
+       user->session_keyring = session_keyring;
+       ret = 0;
+
+ error:
+       return ret;
+
+} /* end alloc_uid_keyring() */
+
+/*****************************************************************************/
+/*
+ * deal with the UID changing
+ */
+void switch_uid_keyring(struct user_struct *new_user)
+{
+#if 0 /* do nothing for now */
+       struct key *old;
+
+       /* switch to the new user's session keyring if we were running under
+        * root's default session keyring */
+       if (new_user->uid != 0 &&
+           current->session_keyring == &root_session_keyring
+           ) {
+               atomic_inc(&new_user->session_keyring->usage);
+
+               task_lock(current);
+               old = current->session_keyring;
+               current->session_keyring = new_user->session_keyring;
+               task_unlock(current);
+
+               key_put(old);
+       }
+#endif
+
+} /* end switch_uid_keyring() */
+
+/*****************************************************************************/
+/*
+ * install a fresh thread keyring, discarding the old one
+ */
+int install_thread_keyring(struct task_struct *tsk)
+{
+       struct key *keyring, *old;
+       char buf[20];
+       int ret;
+
+       sprintf(buf, "_tid.%u", tsk->pid);
+
+       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error;
+       }
+
+       task_lock(tsk);
+       old = tsk->thread_keyring;
+       tsk->thread_keyring = keyring;
+       task_unlock(tsk);
+
+       ret = 0;
+
+       key_put(old);
+ error:
+       return ret;
+
+} /* end install_thread_keyring() */
+
+/*****************************************************************************/
+/*
+ * install a fresh process keyring, discarding the old one
+ */
+static int install_process_keyring(struct task_struct *tsk)
+{
+       struct key *keyring, *old;
+       char buf[20];
+       int ret;
+
+       sprintf(buf, "_pid.%u", tsk->tgid);
+
+       keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error;
+       }
+
+       task_lock(tsk);
+       old = tsk->process_keyring;
+       tsk->process_keyring = keyring;
+       task_unlock(tsk);
+
+       ret = 0;
+
+       key_put(old);
+ error:
+       return ret;
+
+} /* end install_process_keyring() */
+
+/*****************************************************************************/
+/*
+ * install a session keyring, discarding the old one
+ * - if a keyring is not supplied, an empty one is invented
+ */
+static int install_session_keyring(struct task_struct *tsk,
+                                  struct key *keyring)
+{
+       struct key *old;
+       char buf[20];
+       int ret;
+
+       /* create an empty session keyring */
+       if (!keyring) {
+               sprintf(buf, "_ses.%u", tsk->tgid);
+
+               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+               if (IS_ERR(keyring)) {
+                       ret = PTR_ERR(keyring);
+                       goto error;
+               }
+       }
+       else {
+               atomic_inc(&keyring->usage);
+       }
+
+       /* install the keyring */
+       task_lock(tsk);
+       old = tsk->session_keyring;
+       tsk->session_keyring = keyring;
+       task_unlock(tsk);
+
+       ret = 0;
+
+       key_put(old);
+ error:
+       return ret;
+
+} /* end install_session_keyring() */
+
+/*****************************************************************************/
+/*
+ * copy the keys for fork
+ */
+int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+{
+       int ret = 0;
+
+       key_check(tsk->session_keyring);
+       key_check(tsk->process_keyring);
+       key_check(tsk->thread_keyring);
+
+       if (tsk->session_keyring)
+               atomic_inc(&tsk->session_keyring->usage);
+
+       if (tsk->process_keyring) {
+               if (clone_flags & CLONE_THREAD) {
+                       atomic_inc(&tsk->process_keyring->usage);
+               }
+               else {
+                       tsk->process_keyring = NULL;
+                       ret = install_process_keyring(tsk);
+               }
+       }
+
+       tsk->thread_keyring = NULL;
+       return ret;
+
+} /* end copy_keys() */
+
+/*****************************************************************************/
+/*
+ * dispose of keys upon exit
+ */
+void exit_keys(struct task_struct *tsk)
+{
+       key_put(tsk->session_keyring);
+       key_put(tsk->process_keyring);
+       key_put(tsk->thread_keyring);
+
+} /* end exit_keys() */
+
+/*****************************************************************************/
+/*
+ * deal with execve()
+ */
+int exec_keys(struct task_struct *tsk)
+{
+       struct key *old;
+
+       /* newly exec'd tasks don't get a thread keyring */
+       task_lock(tsk);
+       old = tsk->thread_keyring;
+       tsk->thread_keyring = NULL;
+       task_unlock(tsk);
+
+       key_put(old);
+
+       /* newly exec'd tasks get a fresh process keyring */
+       return install_process_keyring(tsk);
+
+} /* end exec_keys() */
+
+/*****************************************************************************/
+/*
+ * deal with SUID programs
+ * - we might want to make this invent a new session keyring
+ */
+int suid_keys(struct task_struct *tsk)
+{
+       return 0;
+
+} /* end suid_keys() */
+
+/*****************************************************************************/
+/*
+ * the filesystem user ID changed
+ */
+void key_fsuid_changed(struct task_struct *tsk)
+{
+       /* update the ownership of the process keyring */
+       if (tsk->process_keyring) {
+               down_write(&tsk->process_keyring->sem);
+               write_lock(&tsk->process_keyring->lock);
+               tsk->process_keyring->uid = tsk->fsuid;
+               write_unlock(&tsk->process_keyring->lock);
+               up_write(&tsk->process_keyring->sem);
+       }
+
+       /* 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);
+       }
+
+} /* end key_fsuid_changed() */
+
+/*****************************************************************************/
+/*
+ * the filesystem group ID changed
+ */
+void key_fsgid_changed(struct task_struct *tsk)
+{
+       /* update the ownership of the process keyring */
+       if (tsk->process_keyring) {
+               down_write(&tsk->process_keyring->sem);
+               write_lock(&tsk->process_keyring->lock);
+               tsk->process_keyring->gid = tsk->fsgid;
+               write_unlock(&tsk->process_keyring->lock);
+               up_write(&tsk->process_keyring->sem);
+       }
+
+       /* 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);
+       }
+
+} /* end key_fsgid_changed() */
+
+/*****************************************************************************/
+/*
+ * search the process keyrings for the first matching key
+ * - we use the supplied match function to see if the description (or other
+ *   feature of interest) matches
+ * - 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 task_struct *tsk = current;
+       struct key *key, *ret, *err, *session;
+
+       /* 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;
+        * otherwise we want to return a sample error (probably -EACCES) if
+        * none of the keyrings were searchable
+        *
+        * in terms of priority: success > -ENOKEY > -EAGAIN > other error
+        */
+       key = NULL;
+       ret = NULL;
+       err = ERR_PTR(-EAGAIN);
+
+       /* search the thread keyring first */
+       if (tsk->thread_keyring) {
+               key = keyring_search_aux(tsk->thread_keyring, 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;
+               }
+       }
+
+       /* search the process keyring second */
+       if (tsk->process_keyring) {
+               key = keyring_search_aux(tsk->process_keyring, 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;
+               }
+       }
+
+       /* search the session keyring last */
+       session = tsk->session_keyring;
+       if (!session)
+               session = tsk->user->session_keyring;
+
+       key = keyring_search_aux(session, 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 - decide on the error we're going to go for */
+       key = ret ? ret : err;
+
+ 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() */
+
+/*****************************************************************************/
+/*
+ * lookup a key given a key ID from userspace with a given permissions mask
+ * - 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 task_struct *tsk = current;
+       struct key *key;
+       int ret;
+
+       key = ERR_PTR(-ENOKEY);
+
+       switch (id) {
+       case KEY_SPEC_THREAD_KEYRING:
+               if (!tsk->thread_keyring) {
+                       if (!create)
+                               goto error;
+
+                       ret = install_thread_keyring(tsk);
+                       if (ret < 0) {
+                               key = ERR_PTR(ret);
+                               goto error;
+                       }
+               }
+
+               key = tsk->thread_keyring;
+               atomic_inc(&key->usage);
+               break;
+
+       case KEY_SPEC_PROCESS_KEYRING:
+               if (!tsk->process_keyring) {
+                       if (!create)
+                               goto error;
+
+                       ret = install_process_keyring(tsk);
+                       if (ret < 0) {
+                               key = ERR_PTR(ret);
+                               goto error;
+                       }
+               }
+
+               key = tsk->process_keyring;
+               atomic_inc(&key->usage);
+               break;
+
+       case KEY_SPEC_SESSION_KEYRING:
+               if (!tsk->session_keyring) {
+                       /* always install a session keyring upon access if one
+                        * doesn't exist yet */
+                       ret = install_session_keyring(
+                              tsk, tsk->user->session_keyring);
+                       if (ret < 0)
+                               goto error;
+               }
+
+               key = tsk->session_keyring;
+               atomic_inc(&key->usage);
+               break;
+
+       case KEY_SPEC_USER_KEYRING:
+               key = tsk->user->uid_keyring;
+               atomic_inc(&key->usage);
+               break;
+
+       case KEY_SPEC_USER_SESSION_KEYRING:
+               key = tsk->user->session_keyring;
+               atomic_inc(&key->usage);
+               break;
+
+       case KEY_SPEC_GROUP_KEYRING:
+               /* group keyrings are not yet supported */
+               key = ERR_PTR(-EINVAL);
+               goto error;
+
+       default:
+               key = ERR_PTR(-EINVAL);
+               if (id < 1)
+                       goto error;
+
+               key = key_lookup(id);
+               if (IS_ERR(key))
+                       goto error;
+               break;
+       }
+
+       /* check the status and permissions */
+       if (perm) {
+               ret = key_validate(key);
+               if (ret < 0)
+                       goto invalid_key;
+       }
+
+       ret = -EIO;
+       if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED))
+               goto invalid_key;
+
+       ret = -EACCES;
+       if (!key_permission(key, perm))
+               goto invalid_key;
+
+ error:
+       return key;
+
+ invalid_key:
+       key_put(key);
+       key = ERR_PTR(ret);
+       goto error;
+
+} /* end lookup_user_key() */
+
+/*****************************************************************************/
+/*
+ * join the named keyring as the session keyring if possible, or attempt to
+ * create a new one of that name if not
+ * - if the name is NULL, an empty anonymous keyring is installed instead
+ * - named session keyring joining is done with a semaphore held
+ */
+long join_session_keyring(const char *name)
+{
+       struct task_struct *tsk = current;
+       struct key *keyring;
+       long ret;
+
+       /* if no name is provided, install an anonymous keyring */
+       if (!name) {
+               ret = install_session_keyring(tsk, NULL);
+               if (ret < 0)
+                       goto error;
+
+               ret = tsk->session_keyring->serial;
+               goto error;
+       }
+
+       /* allow the user to join or create a named keyring */
+       down(&key_session_sem);
+
+       /* look for an existing keyring of this name */
+       keyring = find_keyring_by_name(name, 0);
+       if (PTR_ERR(keyring) == -ENOKEY) {
+               /* not found - try and create a new one */
+               keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
+               if (IS_ERR(keyring)) {
+                       ret = PTR_ERR(keyring);
+                       goto error;
+               }
+       }
+       else if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error2;
+       }
+
+       /* we've got a keyring - now to install it */
+       ret = install_session_keyring(tsk, keyring);
+       if (ret < 0)
+               goto error2;
+
+       key_put(keyring);
+
+       ret = tsk->session_keyring->serial;
+
+ error2:
+       up(&key_session_sem);
+ error:
+       return ret;
+
+} /* end join_session_keyring() */
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
new file mode 100644 (file)
index 0000000..fd6ba06
--- /dev/null
@@ -0,0 +1,337 @@
+/* request_key.c: request a key from userspace
+ *
+ * Copyright (C) 2004 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/kmod.h>
+#include <linux/err.h>
+#include "internal.h"
+
+struct key_construction {
+       struct list_head        link;   /* link in construction queue */
+       struct key              *key;   /* key being constructed */
+};
+
+/* when waiting for someone else's keys, you get added to this */
+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;
+       char *argv[10], *envp[3], uid_str[12], gid_str[12];
+       char key_str[12], keyring_str[3][12];
+       int i;
+
+       /* record the UID and GID */
+       sprintf(uid_str, "%d", current->fsuid);
+       sprintf(gid_str, "%d", current->fsgid);
+
+       /* we say which key is under construction */
+       sprintf(key_str, "%d", key->serial);
+
+       /* we specify the process's default keyrings */
+       task_lock(current);
+       sprintf(keyring_str[0], "%d",
+               tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
+       sprintf(keyring_str[1], "%d",
+               tsk->process_keyring ? tsk->process_keyring->serial : 0);
+       sprintf(keyring_str[2], "%d",
+               (tsk->session_keyring ?
+                tsk->session_keyring->serial :
+                tsk->user->session_keyring->serial));
+       task_unlock(tsk);
+
+       /* set up a minimal environment */
+       i = 0;
+       envp[i++] = "HOME=/";
+       envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+       envp[i] = NULL;
+
+       /* set up the argument list */
+       i = 0;
+       argv[i++] = "/sbin/request-key";
+       argv[i++] = (char *) op;
+       argv[i++] = key_str;
+       argv[i++] = uid_str;
+       argv[i++] = gid_str;
+       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] = NULL;
+
+       /* do it */
+       return call_usermodehelper(argv[0], argv, envp, 1);
+
+} /* end call_request_key() */
+
+/*****************************************************************************/
+/*
+ * call out to userspace for the key
+ * - called with the construction sem held, but the sem is dropped here
+ * - we ignore program failure and go on key status instead
+ */
+static struct key *__request_key_construction(struct key_type *type,
+                                             const char *description,
+                                             const char *callout_info)
+{
+       struct key_construction cons;
+       struct timespec now;
+       struct key *key;
+       int ret, negative;
+
+       /* create a key and add it to the queue */
+       key = key_alloc(type, description,
+                       current->fsuid, current->fsgid, KEY_USR_ALL, 0);
+       if (IS_ERR(key))
+               goto alloc_failed;
+
+       write_lock(&key->lock);
+       key->flags |= KEY_FLAG_USER_CONSTRUCT;
+       write_unlock(&key->lock);
+
+       cons.key = key;
+       list_add_tail(&cons.link, &key->user->consq);
+
+       /* we drop the construction sem here on behalf of the caller */
+       up_write(&key_construction_sem);
+
+       /* make the call */
+       ret = call_request_key(key, "create", callout_info);
+       if (ret < 0)
+               goto request_failed;
+
+       /* if the key wasn't instantiated, then we want to give an error */
+       ret = -ENOKEY;
+       if (!(key->flags & KEY_FLAG_INSTANTIATED))
+               goto request_failed;
+
+       down_write(&key_construction_sem);
+       list_del(&cons.link);
+       up_write(&key_construction_sem);
+
+       /* also give an error if the key was negatively instantiated */
+ check_not_negative:
+       if (key->flags & KEY_FLAG_NEGATIVE) {
+               key_put(key);
+               key = ERR_PTR(-ENOKEY);
+       }
+
+ out:
+       return key;
+
+ request_failed:
+       /* it wasn't instantiated
+        * - remove from construction queue
+        * - mark the key as dead
+        */
+       negative = 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;
+       }
+
+       write_unlock(&key->lock);
+       up_write(&key_construction_sem);
+
+       if (!negative)
+               goto check_not_negative; /* surprisingly, the key got
+                                         * instantiated */
+
+       /* set the timeout and store in the session keyring if we can */
+       now = current_kernel_time();
+       key->expiry = now.tv_sec + key_negative_timeout;
+
+       if (current->session_keyring)
+               key_link(current->session_keyring, key);
+       key_put(key);
+
+       /* notify anyone who was waiting */
+       wake_up_all(&request_key_conswq);
+
+       key = ERR_PTR(ret);
+       goto out;
+
+ alloc_failed:
+       up_write(&key_construction_sem);
+       goto out;
+
+} /* end __request_key_construction() */
+
+/*****************************************************************************/
+/*
+ * call out to userspace to request the key
+ * - we check the construction queue first to see if an appropriate key is
+ *   already being constructed by userspace
+ */
+static struct key *request_key_construction(struct key_type *type,
+                                           const char *description,
+                                           struct key_user *user,
+                                           const char *callout_info)
+{
+       struct key_construction *pcons;
+       struct key *key, *ckey;
+
+       DECLARE_WAITQUEUE(myself, current);
+
+       /* see if there's such a key under construction already */
+       down_write(&key_construction_sem);
+
+       list_for_each_entry(pcons, &user->consq, link) {
+               ckey = pcons->key;
+
+               if (ckey->type != type)
+                       continue;
+
+               if (type->match(ckey, description))
+                       goto found_key_under_construction;
+       }
+
+       /* see about getting userspace to construct the key */
+       key = __request_key_construction(type, description, callout_info);
+ error:
+       return key;
+
+       /* someone else has the same key under construction
+        * - we want to keep an eye on their key
+        */
+ found_key_under_construction:
+       atomic_inc(&ckey->usage);
+       up_write(&key_construction_sem);
+
+       /* wait for the key to be completed one way or another */
+       add_wait_queue(&request_key_conswq, &myself);
+
+       for (;;) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT))
+                       break;
+               schedule();
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&request_key_conswq, &myself);
+
+       /* we'll need to search this process's keyrings to see if the key is
+        * now there since we can't automatically assume it's also available
+        * there */
+       key_put(ckey);
+       ckey = NULL;
+
+       key = NULL; /* request a retry */
+       goto error;
+
+} /* end request_key_construction() */
+
+/*****************************************************************************/
+/*
+ * 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)
+ */
+struct key *request_key(struct key_type *type,
+                       const char *description,
+                       const char *callout_info)
+{
+       struct key_user *user;
+       struct key *key;
+
+       /* search all the process keyrings for a key */
+       key = search_process_keyrings_aux(type, description, type->match);
+
+       if (PTR_ERR(key) == -EAGAIN) {
+               /* the search failed, but the keyrings were searchable, so we
+                * should consult userspace if we can */
+               key = ERR_PTR(-ENOKEY);
+               if (!callout_info)
+                       goto error;
+
+               /* - get hold of the user's construction queue */
+               user = key_user_lookup(current->fsuid);
+               if (IS_ERR(user)) {
+                       key = ERR_PTR(PTR_ERR(user));
+                       goto error;
+               }
+
+               for (;;) {
+                       /* ask userspace (returns NULL if it waited on a key
+                        * being constructed) */
+                       key = request_key_construction(type, description,
+                                                      user, callout_info);
+                       if (key)
+                               break;
+
+                       /* 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_user_put(user);
+       }
+
+ error:
+       return key;
+
+} /* end request_key() */
+
+EXPORT_SYMBOL(request_key);
+
+/*****************************************************************************/
+/*
+ * validate a key
+ */
+int key_validate(struct key *key)
+{
+       struct timespec now;
+       int ret = 0;
+
+       if (key) {
+               /* check it's still accessible */
+               ret = -EKEYREVOKED;
+               if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD))
+                       goto error;
+
+               /* check it hasn't expired */
+               ret = 0;
+               if (key->expiry) {
+                       now = current_kernel_time();
+                       if (now.tv_sec >= key->expiry)
+                               ret = -EKEYEXPIRED;
+               }
+       }
+
+ error:
+       return ret;
+
+} /* end key_validate() */
+
+EXPORT_SYMBOL(key_validate);
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
new file mode 100644 (file)
index 0000000..8d65b3a
--- /dev/null
@@ -0,0 +1,191 @@
+/* user_defined.c: user defined key type
+ *
+ * Copyright (C) 2004 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/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include "internal.h"
+
+static int user_instantiate(struct key *key, const void *data, size_t datalen);
+static int user_duplicate(struct key *key, const struct key *source);
+static int user_update(struct key *key, const void *data, size_t datalen);
+static int user_match(const struct key *key, const void *criterion);
+static void user_destroy(struct key *key);
+static void user_describe(const struct key *user, struct seq_file *m);
+static long user_read(const struct key *key,
+                     char __user *buffer, size_t buflen);
+
+/*
+ * user defined keys take an arbitrary string as the description and an
+ * arbitrary blob of data as the payload
+ */
+struct key_type key_type_user = {
+       .name           = "user",
+       .instantiate    = user_instantiate,
+       .duplicate      = user_duplicate,
+       .update         = user_update,
+       .match          = user_match,
+       .destroy        = user_destroy,
+       .describe       = user_describe,
+       .read           = user_read,
+};
+
+/*****************************************************************************/
+/*
+ * instantiate a user defined key
+ */
+static int user_instantiate(struct key *key, const void *data, size_t datalen)
+{
+       int ret;
+
+       ret = -EINVAL;
+       if (datalen <= 0 || datalen > 32767 || !data)
+               goto error;
+
+       ret = key_payload_reserve(key, datalen);
+       if (ret < 0)
+               goto error;
+
+       /* attach the data */
+       ret = -ENOMEM;
+       key->payload.data = kmalloc(datalen, GFP_KERNEL);
+       if (!key->payload.data)
+               goto error;
+
+       memcpy(key->payload.data, data, datalen);
+       ret = 0;
+
+ error:
+       return ret;
+
+} /* end user_instantiate() */
+
+/*****************************************************************************/
+/*
+ * duplicate a user defined key
+ */
+static int user_duplicate(struct key *key, const struct key *source)
+{
+       int ret;
+
+       /* just copy the payload */
+       ret = -ENOMEM;
+       key->payload.data = kmalloc(source->datalen, GFP_KERNEL);
+
+       if (key->payload.data) {
+               key->datalen = source->datalen;
+               memcpy(key->payload.data, source->payload.data, source->datalen);
+               ret = 0;
+       }
+
+       return ret;
+
+} /* end user_duplicate() */
+
+/*****************************************************************************/
+/*
+ * update a user defined key
+ */
+static int user_update(struct key *key, const void *data, size_t datalen)
+{
+       void *new, *zap;
+       int ret;
+
+       ret = -EINVAL;
+       if (datalen <= 0 || datalen > 32767 || !data)
+               goto error;
+
+       /* copy the data */
+       ret = -ENOMEM;
+       new = kmalloc(datalen, GFP_KERNEL);
+       if (!new)
+               goto error;
+
+       memcpy(new, data, datalen);
+
+       /* check the quota and attach the new data */
+       zap = new;
+       write_lock(&key->lock);
+
+       ret = key_payload_reserve(key, datalen);
+
+       if (ret == 0) {
+               /* attach the new data, displacing the old */
+               zap = key->payload.data;
+               key->payload.data = new;
+               key->expiry = 0;
+       }
+
+       write_unlock(&key->lock);
+       kfree(zap);
+
+ error:
+       return ret;
+
+} /* end user_update() */
+
+/*****************************************************************************/
+/*
+ * match users on their name
+ */
+static int user_match(const struct key *key, const void *description)
+{
+       return strcmp(key->description, description) == 0;
+
+} /* end user_match() */
+
+/*****************************************************************************/
+/*
+ * dispose of the data dangling from the corpse of a user
+ */
+static void user_destroy(struct key *key)
+{
+       kfree(key->payload.data);
+
+} /* end user_destroy() */
+
+/*****************************************************************************/
+/*
+ * describe the user
+ */
+static void user_describe(const struct key *key, struct seq_file *m)
+{
+       seq_puts(m, key->description);
+
+       seq_printf(m, ": %u", key->datalen);
+
+} /* end user_describe() */
+
+/*****************************************************************************/
+/*
+ * read the key data
+ */
+static long user_read(const struct key *key,
+                     char __user *buffer, size_t buflen)
+{
+       long ret = key->datalen;
+
+       /* we can return the data as is */
+       if (buffer && buflen > 0) {
+               if (buflen > key->datalen)
+                       buflen = key->datalen;
+
+               if (copy_to_user(buffer, key->payload.data, buflen) != 0)
+                       ret = -EFAULT;
+       }
+
+       return ret;
+
+} /* end user_read() */
diff --git a/security/seclvl.c b/security/seclvl.c
new file mode 100644 (file)
index 0000000..6a06bb2
--- /dev/null
@@ -0,0 +1,747 @@
+/**
+ * BSD Secure Levels LSM
+ *
+ * Maintainers:
+ *     Michael A. Halcrow <mike@halcrow.us>
+ *     Serge Hallyn <hallyn@cs.wm.edu>
+ *
+ * Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com>
+ * Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2002 International Business Machines <robb@austin.ibm.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/netlink.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/capability.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
+#include <linux/kobject.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include <linux/gfp.h>
+#include <linux/sysfs.h>
+
+#define SHA1_DIGEST_SIZE 20
+
+/**
+ * Module parameter that defines the initial secure level.
+ *
+ * When built as a module, it defaults to seclvl 1, which is the
+ * behavior of BSD secure levels.  Note that this default behavior
+ * wrecks havoc on a machine when the seclvl module is compiled into
+ * the kernel. In that case, we default to seclvl 0.
+ */
+#ifdef CONFIG_SECURITY_SECLVL_MODULE
+static int initlvl = 1;
+#else
+static int initlvl;
+#endif
+module_param(initlvl, int, 0);
+MODULE_PARM_DESC(initlvl, "Initial secure level (defaults to 1)");
+
+/* Module parameter that defines the verbosity level */
+static int verbosity;
+module_param(verbosity, int, 0);
+MODULE_PARM_DESC(verbosity, "Initial verbosity level (0 or 1; defaults to "
+                "0, which is Quiet)");
+
+/**
+ * Optional password which can be passed in to bring seclvl to 0
+ * (i.e., for halt/reboot).  Defaults to NULL (the passwd attribute
+ * file will not be registered in sysfs).
+ *
+ * This gets converted to its SHA1 hash when stored.  It's probably
+ * not a good idea to use this parameter when loading seclvl from a
+ * script; use sha1_passwd instead.
+ */
+
+#define MAX_PASSWD_SIZE        32
+static char passwd[MAX_PASSWD_SIZE];
+module_param_string(passwd, passwd, sizeof(passwd), 0);
+MODULE_PARM_DESC(passwd,
+                "Plaintext of password that sets seclvl=0 when written to "
+                "(sysfs mount point)/seclvl/passwd\n");
+
+/**
+ * SHA1 hashed version of the optional password which can be passed in
+ * to bring seclvl to 0 (i.e., for halt/reboot).  Must be in
+ * hexadecimal format (40 characters). Defaults to NULL (the passwd
+ * attribute file will not be registered in sysfs).
+ *
+ * Use the sha1sum utility to generate the SHA1 hash of a password:
+ *
+ * echo -n "secret" | sha1sum
+ */
+#define MAX_SHA1_PASSWD        41
+static char sha1_passwd[MAX_SHA1_PASSWD];
+module_param_string(sha1_passwd, sha1_passwd, sizeof(sha1_passwd), 0);
+MODULE_PARM_DESC(sha1_passwd,
+                "SHA1 hash (40 hexadecimal characters) of password that "
+                "sets seclvl=0 when plaintext password is written to "
+                "(sysfs mount point)/seclvl/passwd\n");
+
+static int hideHash = 1;
+module_param(hideHash, int, 0);
+MODULE_PARM_DESC(hideHash, "When set to 0, reading seclvl/passwd from sysfs "
+                "will return the SHA1-hashed value of the password that "
+                "lowers the secure level to 0.\n");
+
+#define MY_NAME "seclvl"
+
+/**
+ * This time-limits log writes to one per second.
+ */
+#define seclvl_printk(verb, type, fmt, arg...)                 \
+       do {                                                    \
+               if (verbosity >= verb) {                        \
+                       static unsigned long _prior;            \
+                       unsigned long _now = jiffies;           \
+                       if ((_now - _prior) > HZ) {             \
+                               printk(type "%s: %s: " fmt,     \
+                                       MY_NAME, __FUNCTION__ , \
+                                       ## arg);                \
+                               _prior = _now;                  \
+                       }                                       \
+               }                                               \
+       } while (0)
+
+/**
+ * kobject stuff
+ */
+
+struct subsystem seclvl_subsys;
+
+struct seclvl_obj {
+       char *name;
+       struct list_head slot_list;
+       struct kobject kobj;
+};
+
+/**
+ * There is a seclvl_attribute struct for each file in sysfs.
+ *
+ * In our case, we have one of these structs for "passwd" and another
+ * for "seclvl".
+ */
+struct seclvl_attribute {
+       struct attribute attr;
+       ssize_t(*show) (struct seclvl_obj *, char *);
+       ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
+};
+
+/**
+ * When this function is called, one of the files in sysfs is being
+ * written to.  attribute->store is a function pointer to whatever the
+ * struct seclvl_attribute store function pointer points to.  It is
+ * unique for "passwd" and "seclvl".
+ */
+static ssize_t
+seclvl_attr_store(struct kobject *kobj,
+                 struct attribute *attr, const char *buf, size_t len)
+{
+       struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
+       struct seclvl_attribute *attribute =
+           container_of(attr, struct seclvl_attribute, attr);
+       return (attribute->store ? attribute->store(obj, buf, len) : 0);
+}
+
+static ssize_t
+seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+       struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
+       struct seclvl_attribute *attribute =
+           container_of(attr, struct seclvl_attribute, attr);
+       return (attribute->show ? attribute->show(obj, buf) : 0);
+}
+
+/**
+ * Callback function pointers for show and store
+ */
+struct sysfs_ops seclvlfs_sysfs_ops = {
+       .show = seclvl_attr_show,
+       .store = seclvl_attr_store,
+};
+
+static struct kobj_type seclvl_ktype = {
+       .sysfs_ops = &seclvlfs_sysfs_ops
+};
+
+decl_subsys(seclvl, &seclvl_ktype, NULL);
+
+/**
+ * The actual security level.  Ranges between -1 and 2 inclusive.
+ */
+static int seclvl;
+
+/**
+ * flag to keep track of how we were registered
+ */
+static int secondary;
+
+/**
+ * Verifies that the requested secure level is valid, given the current
+ * secure level.
+ */
+static int seclvl_sanity(int reqlvl)
+{
+       if ((reqlvl < -1) || (reqlvl > 2)) {
+               seclvl_printk(1, KERN_WARNING, "Attempt to set seclvl out of "
+                             "range: [%d]\n", reqlvl);
+               return -EINVAL;
+       }
+       if ((seclvl == 0) && (reqlvl == -1))
+               return 0;
+       if (reqlvl < seclvl) {
+               seclvl_printk(1, KERN_WARNING, "Attempt to lower seclvl to "
+                             "[%d]\n", reqlvl);
+               return -EPERM;
+       }
+       return 0;
+}
+
+/**
+ * Called whenever the user reads the sysfs handle to this kernel
+ * object
+ */
+static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
+{
+       return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
+}
+
+/**
+ * security level advancement rules:
+ *   Valid levels are -1 through 2, inclusive.
+ *   From -1, stuck.  [ in case compiled into kernel ]
+ *   From 0 or above, can only increment.
+ */
+static int do_seclvl_advance(int newlvl)
+{
+       if (newlvl <= seclvl) {
+               seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
+                             "[%d]\n", newlvl);
+               return -EINVAL;
+       }
+       if (newlvl > 2) {
+               seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
+                             "[%d]\n", newlvl);
+               return -EINVAL;
+       }
+       if (seclvl == -1) {
+               seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
+                             "seclvl [%d]\n", seclvl);
+               return -EPERM;
+       }
+       seclvl = newlvl;
+       return 0;
+}
+
+/**
+ * Called whenever the user writes to the sysfs handle to this kernel
+ * object (seclvl/seclvl).  It expects a single-digit number.
+ */
+static ssize_t
+seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
+{
+       unsigned long val;
+       if (count > 2 || (count == 2 && buff[1] != '\n')) {
+               seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
+                             "seclvl: [%s]\n", buff);
+               return -EINVAL;
+       }
+       val = buff[0] - 48;
+       if (seclvl_sanity(val)) {
+               seclvl_printk(1, KERN_WARNING, "Illegal secure level "
+                             "requested: [%d]\n", (int)val);
+               return -EPERM;
+       }
+       if (do_seclvl_advance(val)) {
+               seclvl_printk(0, KERN_ERR, "Failure advancing security level "
+                             "to %lu\n", val);
+       }
+       return count;
+}
+
+/* Generate sysfs_attr_seclvl */
+struct seclvl_attribute sysfs_attr_seclvl =
+__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
+       seclvl_write_file);
+
+static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
+
+/**
+ * Called whenever the user reads the sysfs passwd handle.
+ */
+static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
+{
+       /* So just how good *is* your password? :-) */
+       char tmp[3];
+       int i = 0;
+       buff[0] = '\0';
+       if (hideHash) {
+               /* Security through obscurity */
+               return 0;
+       }
+       while (i < SHA1_DIGEST_SIZE) {
+               snprintf(tmp, 3, "%02x", hashedPassword[i]);
+               strncat(buff, tmp, 2);
+               i++;
+       }
+       strcat(buff, "\n");
+       return ((SHA1_DIGEST_SIZE * 2) + 1);
+}
+
+/**
+ * Converts a block of plaintext of into its SHA1 hashed value.
+ *
+ * It would be nice if crypto had a wrapper to do this for us linear
+ * people...
+ */
+static int
+plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len)
+{
+       char *pgVirtAddr;
+       struct crypto_tfm *tfm;
+       struct scatterlist sg[1];
+       if (len > PAGE_SIZE) {
+               seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
+                             "characters).  Largest possible is %lu "
+                             "bytes.\n", len, PAGE_SIZE);
+               return -ENOMEM;
+       }
+       tfm = crypto_alloc_tfm("sha1", 0);
+       if (tfm == NULL) {
+               seclvl_printk(0, KERN_ERR,
+                             "Failed to load transform for SHA1\n");
+               return -ENOSYS;
+       }
+       // Just get a new page; don't play around with page boundaries
+       // and scatterlists.
+       pgVirtAddr = (char *)__get_free_page(GFP_KERNEL);
+       sg[0].page = virt_to_page(pgVirtAddr);
+       sg[0].offset = 0;
+       sg[0].length = len;
+       strncpy(pgVirtAddr, plaintext, len);
+       crypto_digest_init(tfm);
+       crypto_digest_update(tfm, sg, 1);
+       crypto_digest_final(tfm, hash);
+       crypto_free_tfm(tfm);
+       free_page((unsigned long)pgVirtAddr);
+       return 0;
+}
+
+/**
+ * Called whenever the user writes to the sysfs passwd handle to this kernel
+ * object.  It hashes the password and compares the hashed results.
+ */
+static ssize_t
+seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
+{
+       int i;
+       unsigned char tmp[SHA1_DIGEST_SIZE];
+       int rc;
+       int len;
+       if (!*passwd && !*sha1_passwd) {
+               seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
+                             "seclvl module, but neither a plain text "
+                             "password nor a SHA1 hashed password was "
+                             "passed in as a module parameter!  This is a "
+                             "bug, since it should not be possible to be in "
+                             "this part of the module; please tell a "
+                             "maintainer about this event.\n");
+               return -EINVAL;
+       }
+       len = strlen(buff);
+       /* ``echo "secret" > seclvl/passwd'' includes a newline */
+       if (buff[len - 1] == '\n') {
+               len--;
+       }
+       /* Hash the password, then compare the hashed values */
+       if ((rc = plaintext_to_sha1(tmp, buff, len))) {
+               seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
+                             "[%d]\n", rc);
+               return rc;
+       }
+       for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+               if (hashedPassword[i] != tmp[i]) {
+                       return -EPERM;
+               }
+       }
+       seclvl_printk(0, KERN_INFO,
+                     "Password accepted; seclvl reduced to 0.\n");
+       seclvl = 0;
+       return count;
+}
+
+/* Generate sysfs_attr_passwd */
+struct seclvl_attribute sysfs_attr_passwd =
+__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
+       seclvl_write_passwd);
+
+/**
+ * Explicitely disallow ptrace'ing the init process.
+ */
+static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
+{
+       if (seclvl >= 0) {
+               if (child->pid == 1) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
+                                     "the init process dissallowed in "
+                                     "secure level %d\n", seclvl);
+                       return -EPERM;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Capability checks for seclvl.  The majority of the policy
+ * enforcement for seclvl takes place here.
+ */
+static int seclvl_capable(struct task_struct *tsk, int cap)
+{
+       /* init can do anything it wants */
+       if (tsk->pid == 1)
+               return 0;
+
+       switch (seclvl) {
+       case 2:
+               /* fall through */
+       case 1:
+               if (cap == CAP_LINUX_IMMUTABLE) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to modify "
+                                     "the IMMUTABLE and/or APPEND extended "
+                                     "attribute on a file with the IMMUTABLE "
+                                     "and/or APPEND extended attribute set "
+                                     "denied in seclvl [%d]\n", seclvl);
+                       return -EPERM;
+               } else if (cap == CAP_SYS_RAWIO) {      // Somewhat broad...
+                       seclvl_printk(1, KERN_WARNING, "Attempt to perform "
+                                     "raw I/O while in secure level [%d] "
+                                     "denied\n", seclvl);
+                       return -EPERM;
+               } else if (cap == CAP_NET_ADMIN) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to perform "
+                                     "network administrative task while "
+                                     "in secure level [%d] denied\n", seclvl);
+                       return -EPERM;
+               } else if (cap == CAP_SETUID) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
+                                     "while in secure level [%d] denied\n",
+                                     seclvl);
+                       return -EPERM;
+               } else if (cap == CAP_SETGID) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
+                                     "while in secure level [%d] denied\n",
+                                     seclvl);
+               } else if (cap == CAP_SYS_MODULE) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to perform "
+                                     "a module operation while in secure "
+                                     "level [%d] denied\n", seclvl);
+                       return -EPERM;
+               }
+               break;
+       default:
+               break;
+       }
+       /* from dummy.c */
+       if (cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0)
+               return 0;       /* capability granted */
+       seclvl_printk(1, KERN_WARNING, "Capability denied\n");
+       return -EPERM;          /* capability denied */
+}
+
+/**
+ * Disallow reversing the clock in seclvl > 1
+ */
+static int seclvl_settime(struct timespec *tv, struct timezone *tz)
+{
+       struct timespec now;
+       if (seclvl > 1) {
+               now = current_kernel_time();
+               if (tv->tv_sec < now.tv_sec ||
+                   (tv->tv_sec == now.tv_sec && tv->tv_nsec < now.tv_nsec)) {
+                       seclvl_printk(1, KERN_WARNING, "Attempt to decrement "
+                                     "time in secure level %d denied: "
+                                     "current->pid = [%d], "
+                                     "current->group_leader->pid = [%d]\n",
+                                     seclvl, current->pid,
+                                     current->group_leader->pid);
+                       return -EPERM;
+               }               /* if attempt to decrement time */
+       }                       /* if seclvl > 1 */
+       return 0;
+}
+
+/* claim the blockdev to exclude mounters, release on file close */
+static int seclvl_bd_claim(struct inode *inode)
+{
+       int holder;
+       struct block_device *bdev = NULL;
+       dev_t dev = inode->i_rdev;
+       bdev = open_by_devnum(dev, FMODE_WRITE);
+       if (bdev) {
+               if (bd_claim(bdev, &holder)) {
+                       blkdev_put(bdev);
+                       return -EPERM;
+               }
+               /* claimed, mark it to release on close */
+               inode->i_security = current;
+       }
+       return 0;
+}
+
+/* release the blockdev if you claimed it */
+static void seclvl_bd_release(struct inode *inode)
+{
+       if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
+               struct block_device *bdev = inode->i_bdev;
+               if (bdev) {
+                       bd_release(bdev);
+                       blkdev_put(bdev);
+                       inode->i_security = NULL;
+               }
+       }
+}
+
+/**
+ * Security for writes to block devices is regulated by this seclvl
+ * function.  Deny all writes to block devices in seclvl 2.  In
+ * seclvl 1, we only deny writes to *mounted* block devices.
+ */
+static int
+seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+       if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
+               switch (seclvl) {
+               case 2:
+                       seclvl_printk(1, KERN_WARNING, "Write to block device "
+                                     "denied in secure level [%d]\n", seclvl);
+                       return -EPERM;
+               case 1:
+                       if (seclvl_bd_claim(inode)) {
+                               seclvl_printk(1, KERN_WARNING,
+                                             "Write to mounted block device "
+                                             "denied in secure level [%d]\n",
+                                             seclvl);
+                               return -EPERM;
+                       }
+               }
+       }
+       return 0;
+}
+
+/**
+ * The SUID and SGID bits cannot be set in seclvl >= 1
+ */
+static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       if (seclvl > 0) {
+               if (iattr->ia_valid & ATTR_MODE)
+                       if (iattr->ia_mode & S_ISUID ||
+                           iattr->ia_mode & S_ISGID) {
+                               seclvl_printk(1, KERN_WARNING, "Attempt to "
+                                             "modify SUID or SGID bit "
+                                             "denied in seclvl [%d]\n",
+                                             seclvl);
+                               return -EPERM;
+                       }
+       }
+       return 0;
+}
+
+/* release busied block devices */
+static void seclvl_file_free_security(struct file *filp)
+{
+       struct dentry *dentry = filp->f_dentry;
+       struct inode *inode = NULL;
+
+       if (dentry) {
+               inode = dentry->d_inode;
+               seclvl_bd_release(inode);
+       }
+}
+
+/**
+ * Cannot unmount in secure level 2
+ */
+static int seclvl_umount(struct vfsmount *mnt, int flags)
+{
+       if (current->pid == 1) {
+               return 0;
+       }
+       if (seclvl == 2) {
+               seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
+                             "level %d\n", seclvl);
+               return -EPERM;
+       }
+       return 0;
+}
+
+static struct security_operations seclvl_ops = {
+       .ptrace = seclvl_ptrace,
+       .capable = seclvl_capable,
+       .inode_permission = seclvl_inode_permission,
+       .inode_setattr = seclvl_inode_setattr,
+       .file_free_security = seclvl_file_free_security,
+       .settime = seclvl_settime,
+       .sb_umount = seclvl_umount,
+};
+
+/**
+ * Process the password-related module parameters
+ */
+static int processPassword(void)
+{
+       int rc = 0;
+       hashedPassword[0] = '\0';
+       if (*passwd) {
+               if (*sha1_passwd) {
+                       seclvl_printk(0, KERN_ERR, "Error: Both "
+                                     "passwd and sha1_passwd "
+                                     "were set, but they are mutually "
+                                     "exclusive.\n");
+                       return -EINVAL;
+               }
+               if ((rc = plaintext_to_sha1(hashedPassword, passwd,
+                                           strlen(passwd)))) {
+                       seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
+                                     "in kernel\n");
+                       return rc;
+               }
+               /* All static data goes to the BSS, which zero's the
+                * plaintext password out for us. */
+       } else if (*sha1_passwd) {      // Base 16
+               int i;
+               i = strlen(sha1_passwd);
+               if (i != (SHA1_DIGEST_SIZE * 2)) {
+                       seclvl_printk(0, KERN_ERR, "Received [%d] bytes; "
+                                     "expected [%d] for the hexadecimal "
+                                     "representation of the SHA1 hash of "
+                                     "the password.\n",
+                                     i, (SHA1_DIGEST_SIZE * 2));
+                       return -EINVAL;
+               }
+               while ((i -= 2) + 2) {
+                       unsigned char tmp;
+                       tmp = sha1_passwd[i + 2];
+                       sha1_passwd[i + 2] = '\0';
+                       hashedPassword[i / 2] = (unsigned char)
+                           simple_strtol(&sha1_passwd[i], NULL, 16);
+                       sha1_passwd[i + 2] = tmp;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Sysfs registrations
+ */
+static int doSysfsRegistrations(void)
+{
+       int rc = 0;
+       if ((rc = subsystem_register(&seclvl_subsys))) {
+               seclvl_printk(0, KERN_WARNING,
+                             "Error [%d] registering seclvl subsystem\n", rc);
+               return rc;
+       }
+       sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+       if (*passwd || *sha1_passwd) {
+               sysfs_create_file(&seclvl_subsys.kset.kobj,
+                                 &sysfs_attr_passwd.attr);
+       }
+       return 0;
+}
+
+/**
+ * Initialize the seclvl module.
+ */
+static int __init seclvl_init(void)
+{
+       int rc = 0;
+       if (verbosity < 0 || verbosity > 1) {
+               printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 "
+                      "are valid values\n", verbosity);
+               rc = -EINVAL;
+               goto exit;
+       }
+       sysfs_attr_seclvl.attr.owner = THIS_MODULE;
+       sysfs_attr_passwd.attr.owner = THIS_MODULE;
+       if (initlvl < -1 || initlvl > 2) {
+               seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
+                             "[%d].\n", initlvl);
+               rc = -EINVAL;
+               goto exit;
+       }
+       seclvl = initlvl;
+       if ((rc = processPassword())) {
+               seclvl_printk(0, KERN_ERR, "Error processing the password "
+                             "module parameter(s): rc = [%d]\n", rc);
+               goto exit;
+       }
+       /* register ourselves with the security framework */
+       if (register_security(&seclvl_ops)) {
+               seclvl_printk(0, KERN_ERR,
+                             "seclvl: Failure registering with the "
+                             "kernel.\n");
+               /* try registering with primary module */
+               rc = mod_reg_security(MY_NAME, &seclvl_ops);
+               if (rc) {
+                       seclvl_printk(0, KERN_ERR, "seclvl: Failure "
+                                     "registering with primary security "
+                                     "module.\n");
+                       goto exit;
+               }               /* if primary module registered */
+               secondary = 1;
+       }                       /* if we registered ourselves with the security framework */
+       if ((rc = doSysfsRegistrations())) {
+               seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
+               goto exit;
+       }
+       seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
+ exit:
+       if (rc) {
+               printk(KERN_ERR "seclvl: Error during initialization: rc = "
+                      "[%d]\n", rc);
+       }
+       return rc;
+}
+
+/**
+ * Remove the seclvl module.
+ */
+static void __exit seclvl_exit(void)
+{
+       sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+       if (*passwd || *sha1_passwd) {
+               sysfs_remove_file(&seclvl_subsys.kset.kobj,
+                                 &sysfs_attr_passwd.attr);
+       }
+       subsystem_unregister(&seclvl_subsys);
+       if (secondary == 1) {
+               mod_unreg_security(MY_NAME, &seclvl_ops);
+       } else if (unregister_security(&seclvl_ops)) {
+               seclvl_printk(0, KERN_INFO,
+                             "seclvl: Failure unregistering with the "
+                             "kernel\n");
+       }
+}
+
+module_init(seclvl_init);
+module_exit(seclvl_exit);
+
+MODULE_AUTHOR("Michael A. Halcrow <mike@halcrow.us>");
+MODULE_DESCRIPTION("LSM implementation of the BSD Secure Levels");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
new file mode 100644 (file)
index 0000000..bec2052
--- /dev/null
@@ -0,0 +1,1351 @@
+/*
+ *   ALSA driver for ATI IXP 150/200/250 AC97 modem controllers
+ *
+ *     Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("ATI IXP MC97 controller");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
+static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
+static int boot_devs;
+
+module_param_array(index, int, boot_devs, 0444);
+MODULE_PARM_DESC(index, "Index value for ATI IXP controller.");
+module_param_array(id, charp, boot_devs, 0444);
+MODULE_PARM_DESC(id, "ID string for ATI IXP controller.");
+module_param_array(enable, bool, boot_devs, 0444);
+MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller.");
+module_param_array(ac97_clock, int, boot_devs, 0444);
+MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
+
+
+/*
+ */
+
+#define ATI_REG_ISR                    0x00    /* interrupt source */
+#define  ATI_REG_ISR_MODEM_IN_XRUN     (1U<<0)
+#define  ATI_REG_ISR_MODEM_IN_STATUS   (1U<<1)
+#define  ATI_REG_ISR_MODEM_OUT1_XRUN   (1U<<2)
+#define  ATI_REG_ISR_MODEM_OUT1_STATUS (1U<<3)
+#define  ATI_REG_ISR_MODEM_OUT2_XRUN   (1U<<4)
+#define  ATI_REG_ISR_MODEM_OUT2_STATUS (1U<<5)
+#define  ATI_REG_ISR_MODEM_OUT3_XRUN   (1U<<6)
+#define  ATI_REG_ISR_MODEM_OUT3_STATUS (1U<<7)
+#define  ATI_REG_ISR_PHYS_INTR         (1U<<8)
+#define  ATI_REG_ISR_PHYS_MISMATCH     (1U<<9)
+#define  ATI_REG_ISR_CODEC0_NOT_READY  (1U<<10)
+#define  ATI_REG_ISR_CODEC1_NOT_READY  (1U<<11)
+#define  ATI_REG_ISR_CODEC2_NOT_READY  (1U<<12)
+#define  ATI_REG_ISR_NEW_FRAME         (1U<<13)
+#define  ATI_REG_ISR_MODEM_GPIO_DATA   (1U<<14)
+
+#define ATI_REG_IER                    0x04    /* interrupt enable */
+#define  ATI_REG_IER_MODEM_IN_XRUN_EN  (1U<<0)
+#define  ATI_REG_IER_MODEM_STATUS_EN   (1U<<1)
+#define  ATI_REG_IER_MODEM_OUT1_XRUN_EN        (1U<<2)
+#define  ATI_REG_IER_MODEM_OUT2_XRUN_EN        (1U<<4)
+#define  ATI_REG_IER_MODEM_OUT3_XRUN_EN        (1U<<6)
+#define  ATI_REG_IER_PHYS_INTR_EN      (1U<<8)
+#define  ATI_REG_IER_PHYS_MISMATCH_EN  (1U<<9)
+#define  ATI_REG_IER_CODEC0_INTR_EN    (1U<<10)
+#define  ATI_REG_IER_CODEC1_INTR_EN    (1U<<11)
+#define  ATI_REG_IER_CODEC2_INTR_EN    (1U<<12)
+#define  ATI_REG_IER_NEW_FRAME_EN      (1U<<13)        /* (RO */
+#define  ATI_REG_IER_MODEM_GPIO_DATA_EN        (1U<<14)        /* (WO) modem is running */
+#define  ATI_REG_IER_MODEM_SET_BUS_BUSY        (1U<<15)
+
+#define ATI_REG_CMD                    0x08    /* command */
+#define  ATI_REG_CMD_POWERDOWN (1U<<0)
+#define  ATI_REG_CMD_MODEM_RECEIVE_EN  (1U<<1) /* modem only */
+#define  ATI_REG_CMD_MODEM_SEND1_EN    (1U<<2) /* modem only */
+#define  ATI_REG_CMD_MODEM_SEND2_EN    (1U<<3) /* modem only */
+#define  ATI_REG_CMD_MODEM_SEND3_EN    (1U<<4) /* modem only */
+#define  ATI_REG_CMD_MODEM_STATUS_MEM  (1U<<5) /* modem only */
+#define  ATI_REG_CMD_MODEM_IN_DMA_EN   (1U<<8) /* modem only */
+#define  ATI_REG_CMD_MODEM_OUT_DMA1_EN (1U<<9) /* modem only */
+#define  ATI_REG_CMD_MODEM_OUT_DMA2_EN (1U<<10)        /* modem only */
+#define  ATI_REG_CMD_MODEM_OUT_DMA3_EN (1U<<11)        /* modem only */
+#define  ATI_REG_CMD_AUDIO_PRESENT     (1U<<20)
+#define  ATI_REG_CMD_MODEM_GPIO_THRU_DMA       (1U<<22)        /* modem only */
+#define  ATI_REG_CMD_LOOPBACK_EN       (1U<<23)
+#define  ATI_REG_CMD_PACKED_DIS                (1U<<24)
+#define  ATI_REG_CMD_BURST_EN          (1U<<25)
+#define  ATI_REG_CMD_PANIC_EN          (1U<<26)
+#define  ATI_REG_CMD_MODEM_PRESENT     (1U<<27)
+#define  ATI_REG_CMD_ACLINK_ACTIVE     (1U<<28)
+#define  ATI_REG_CMD_AC_SOFT_RESET     (1U<<29)
+#define  ATI_REG_CMD_AC_SYNC           (1U<<30)
+#define  ATI_REG_CMD_AC_RESET          (1U<<31)
+
+#define ATI_REG_PHYS_OUT_ADDR          0x0c
+#define  ATI_REG_PHYS_OUT_CODEC_MASK   (3U<<0)
+#define  ATI_REG_PHYS_OUT_RW           (1U<<2)
+#define  ATI_REG_PHYS_OUT_ADDR_EN      (1U<<8)
+#define  ATI_REG_PHYS_OUT_ADDR_SHIFT   9
+#define  ATI_REG_PHYS_OUT_DATA_SHIFT   16
+
+#define ATI_REG_PHYS_IN_ADDR           0x10
+#define  ATI_REG_PHYS_IN_READ_FLAG     (1U<<8)
+#define  ATI_REG_PHYS_IN_ADDR_SHIFT    9
+#define  ATI_REG_PHYS_IN_DATA_SHIFT    16
+
+#define ATI_REG_SLOTREQ                        0x14
+
+#define ATI_REG_COUNTER                        0x18
+#define  ATI_REG_COUNTER_SLOT          (3U<<0) /* slot # */
+#define  ATI_REG_COUNTER_BITCLOCK      (31U<<8)
+
+#define ATI_REG_IN_FIFO_THRESHOLD      0x1c
+
+#define ATI_REG_MODEM_IN_DMA_LINKPTR   0x20
+#define ATI_REG_MODEM_IN_DMA_DT_START  0x24    /* RO */
+#define ATI_REG_MODEM_IN_DMA_DT_NEXT   0x28    /* RO */
+#define ATI_REG_MODEM_IN_DMA_DT_CUR    0x2c    /* RO */
+#define ATI_REG_MODEM_IN_DMA_DT_SIZE   0x30
+#define ATI_REG_MODEM_OUT_FIFO         0x34    /* output threshold */
+#define  ATI_REG_MODEM_OUT1_DMA_THRESHOLD_MASK (0xf<<16)
+#define  ATI_REG_MODEM_OUT1_DMA_THRESHOLD_SHIFT        16
+#define ATI_REG_MODEM_OUT_DMA1_LINKPTR 0x38
+#define ATI_REG_MODEM_OUT_DMA2_LINKPTR 0x3c
+#define ATI_REG_MODEM_OUT_DMA3_LINKPTR 0x40
+#define ATI_REG_MODEM_OUT_DMA1_DT_START        0x44
+#define ATI_REG_MODEM_OUT_DMA1_DT_NEXT 0x48
+#define ATI_REG_MODEM_OUT_DMA1_DT_CUR  0x4c
+#define ATI_REG_MODEM_OUT_DMA2_DT_START        0x50
+#define ATI_REG_MODEM_OUT_DMA2_DT_NEXT 0x54
+#define ATI_REG_MODEM_OUT_DMA2_DT_CUR  0x58
+#define ATI_REG_MODEM_OUT_DMA3_DT_START        0x5c
+#define ATI_REG_MODEM_OUT_DMA3_DT_NEXT 0x60
+#define ATI_REG_MODEM_OUT_DMA3_DT_CUR  0x64
+#define ATI_REG_MODEM_OUT_DMA12_DT_SIZE        0x68
+#define ATI_REG_MODEM_OUT_DMA3_DT_SIZE 0x6c
+#define ATI_REG_MODEM_OUT_FIFO_USED     0x70
+#define ATI_REG_MODEM_OUT_GPIO         0x74
+#define  ATI_REG_MODEM_OUT_GPIO_EN        1
+#define  ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT 5
+#define ATI_REG_MODEM_IN_GPIO          0x78
+
+#define ATI_REG_MODEM_MIRROR           0x7c
+#define ATI_REG_AUDIO_MIRROR           0x80
+
+#define ATI_REG_MODEM_FIFO_FLUSH       0x88
+#define  ATI_REG_MODEM_FIFO_OUT1_FLUSH (1U<<0)
+#define  ATI_REG_MODEM_FIFO_OUT2_FLUSH (1U<<1)
+#define  ATI_REG_MODEM_FIFO_OUT3_FLUSH (1U<<2)
+#define  ATI_REG_MODEM_FIFO_IN_FLUSH   (1U<<3)
+
+/* LINKPTR */
+#define  ATI_REG_LINKPTR_EN            (1U<<0)
+
+#define ATI_MAX_DESCRIPTORS    256     /* max number of descriptor packets */
+
+
+/*
+ */
+
+typedef struct snd_atiixp atiixp_t;
+typedef struct snd_atiixp_dma atiixp_dma_t;
+typedef struct snd_atiixp_dma_ops atiixp_dma_ops_t;
+
+
+/*
+ * DMA packate descriptor
+ */
+
+typedef struct atiixp_dma_desc {
+       u32 addr;       /* DMA buffer address */
+       u16 status;     /* status bits */
+       u16 size;       /* size of the packet in dwords */
+       u32 next;       /* address of the next packet descriptor */
+} atiixp_dma_desc_t;
+
+/*
+ * stream enum
+ */
+enum { ATI_DMA_PLAYBACK, ATI_DMA_CAPTURE, NUM_ATI_DMAS }; /* DMAs */
+enum { ATI_PCM_OUT, ATI_PCM_IN, NUM_ATI_PCMS }; /* AC97 pcm slots */
+enum { ATI_PCMDEV_ANALOG, NUM_ATI_PCMDEVS }; /* pcm devices */
+
+#define NUM_ATI_CODECS 3
+
+
+/*
+ * constants and callbacks for each DMA type
+ */
+struct snd_atiixp_dma_ops {
+       int type;                       /* ATI_DMA_XXX */
+       unsigned int llp_offset;        /* LINKPTR offset */
+       unsigned int dt_cur;            /* DT_CUR offset */
+       void (*enable_dma)(atiixp_t *chip, int on);     /* called from open callback */
+       void (*enable_transfer)(atiixp_t *chip, int on); /* called from trigger (START/STOP) */
+       void (*flush_dma)(atiixp_t *chip);              /* called from trigger (STOP only) */
+};
+
+/*
+ * DMA stream
+ */
+struct snd_atiixp_dma {
+       const atiixp_dma_ops_t *ops;
+       struct snd_dma_buffer desc_buf;
+       snd_pcm_substream_t *substream; /* assigned PCM substream */
+       unsigned int buf_addr, buf_bytes;       /* DMA buffer address, bytes */
+       unsigned int period_bytes, periods;
+       int opened;
+       int running;
+       int pcm_open_flag;
+       int ac97_pcm_type;      /* index # of ac97_pcm to access, -1 = not used */
+};
+
+/*
+ * ATI IXP chip
+ */
+struct snd_atiixp {
+       snd_card_t *card;
+       struct pci_dev *pci;
+
+       struct resource *res;           /* memory i/o */
+       unsigned long addr;
+       void __iomem *remap_addr;
+       int irq;
+       
+       ac97_bus_t *ac97_bus;
+       ac97_t *ac97[NUM_ATI_CODECS];
+
+       spinlock_t reg_lock;
+       spinlock_t ac97_lock;
+
+       atiixp_dma_t dmas[NUM_ATI_DMAS];
+       struct ac97_pcm *pcms[NUM_ATI_PCMS];
+       snd_pcm_t *pcmdevs[NUM_ATI_PCMDEVS];
+
+       int max_channels;               /* max. channels for PCM out */
+
+       unsigned int codec_not_ready_bits;      /* for codec detection */
+
+       int spdif_over_aclink;          /* passed from the module option */
+       struct semaphore open_mutex;    /* playback open mutex */
+};
+
+
+/*
+ */
+static struct pci_device_id snd_atiixp_ids[] = {
+       { 0x1002, 0x434d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
+
+
+/*
+ * lowlevel functions
+ */
+
+/*
+ * update the bits of the given register.
+ * return 1 if the bits changed.
+ */
+static int snd_atiixp_update_bits(atiixp_t *chip, unsigned int reg,
+                                unsigned int mask, unsigned int value)
+{
+       void __iomem *addr = chip->remap_addr + reg;
+       unsigned int data, old_data;
+       old_data = data = readl(addr);
+       data &= ~mask;
+       data |= value;
+       if (old_data == data)
+               return 0;
+       writel(data, addr);
+       return 1;
+}
+
+/*
+ * macros for easy use
+ */
+#define atiixp_write(chip,reg,value) \
+       writel(value, chip->remap_addr + ATI_REG_##reg)
+#define atiixp_read(chip,reg) \
+       readl(chip->remap_addr + ATI_REG_##reg)
+#define atiixp_update(chip,reg,mask,val) \
+       snd_atiixp_update_bits(chip, ATI_REG_##reg, mask, val)
+
+/* delay for one tick */
+#define do_delay() do { \
+       set_current_state(TASK_UNINTERRUPTIBLE); \
+       schedule_timeout(1); \
+} while (0)
+
+
+/*
+ * handling DMA packets
+ *
+ * we allocate a linear buffer for the DMA, and split it to  each packet.
+ * in a future version, a scatter-gather buffer should be implemented.
+ */
+
+#define ATI_DESC_LIST_SIZE \
+       PAGE_ALIGN(ATI_MAX_DESCRIPTORS * sizeof(atiixp_dma_desc_t))
+
+/*
+ * build packets ring for the given buffer size.
+ *
+ * IXP handles the buffer descriptors, which are connected as a linked
+ * list.  although we can change the list dynamically, in this version,
+ * a static RING of buffer descriptors is used.
+ *
+ * the ring is built in this function, and is set up to the hardware. 
+ */
+static int atiixp_build_dma_packets(atiixp_t *chip, atiixp_dma_t *dma,
+                                  snd_pcm_substream_t *substream,
+                                  unsigned int periods,
+                                  unsigned int period_bytes)
+{
+       unsigned int i;
+       u32 addr, desc_addr;
+       unsigned long flags;
+
+       if (periods > ATI_MAX_DESCRIPTORS)
+               return -ENOMEM;
+
+       if (dma->desc_buf.area == NULL) {
+               if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
+                                       ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0)
+                       return -ENOMEM;
+               dma->period_bytes = dma->periods = 0; /* clear */
+       }
+
+       if (dma->periods == periods && dma->period_bytes == period_bytes)
+               return 0;
+
+       /* reset DMA before changing the descriptor table */
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       writel(0, chip->remap_addr + dma->ops->llp_offset);
+       dma->ops->enable_dma(chip, 0);
+       dma->ops->enable_dma(chip, 1);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       /* fill the entries */
+       addr = (u32)substream->runtime->dma_addr;
+       desc_addr = (u32)dma->desc_buf.addr;
+       for (i = 0; i < periods; i++) {
+               atiixp_dma_desc_t *desc = &((atiixp_dma_desc_t *)dma->desc_buf.area)[i];
+               desc->addr = cpu_to_le32(addr);
+               desc->status = 0;
+               desc->size = period_bytes >> 2; /* in dwords */
+               desc_addr += sizeof(atiixp_dma_desc_t);
+               if (i == periods - 1)
+                       desc->next = cpu_to_le32((u32)dma->desc_buf.addr);
+               else
+                       desc->next = cpu_to_le32(desc_addr);
+               addr += period_bytes;
+       }
+
+       writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
+              chip->remap_addr + dma->ops->llp_offset);
+
+       dma->period_bytes = period_bytes;
+       dma->periods = periods;
+
+       return 0;
+}
+
+/*
+ * remove the ring buffer and release it if assigned
+ */
+static void atiixp_clear_dma_packets(atiixp_t *chip, atiixp_dma_t *dma, snd_pcm_substream_t *substream)
+{
+       if (dma->desc_buf.area) {
+               writel(0, chip->remap_addr + dma->ops->llp_offset);
+               snd_dma_free_pages(&dma->desc_buf);
+               dma->desc_buf.area = NULL;
+       }
+}
+
+/*
+ * AC97 interface
+ */
+static int snd_atiixp_acquire_codec(atiixp_t *chip)
+{
+       int timeout = 1000;
+
+       while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) {
+               if (! timeout--) {
+                       snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n");
+                       return -EBUSY;
+               }
+               udelay(1);
+       }
+       return 0;
+}
+
+static unsigned short snd_atiixp_codec_read(atiixp_t *chip, unsigned short codec, unsigned short reg)
+{
+       unsigned int data;
+       int timeout;
+
+       if (snd_atiixp_acquire_codec(chip) < 0)
+               return 0xffff;
+       data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
+               ATI_REG_PHYS_OUT_ADDR_EN |
+               ATI_REG_PHYS_OUT_RW |
+               codec;
+       atiixp_write(chip, PHYS_OUT_ADDR, data);
+       if (snd_atiixp_acquire_codec(chip) < 0)
+               return 0xffff;
+       timeout = 1000;
+       do {
+               data = atiixp_read(chip, PHYS_IN_ADDR);
+               if (data & ATI_REG_PHYS_IN_READ_FLAG)
+                       return data >> ATI_REG_PHYS_IN_DATA_SHIFT;
+               udelay(1);
+       } while (--timeout);
+       /* time out may happen during reset */
+       if (reg < 0x7c)
+               snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg);
+       return 0xffff;
+}
+
+
+static void snd_atiixp_codec_write(atiixp_t *chip, unsigned short codec, unsigned short reg, unsigned short val)
+{
+       unsigned int data;
+    
+       if (snd_atiixp_acquire_codec(chip) < 0)
+               return;
+       data = ((unsigned int)val << ATI_REG_PHYS_OUT_DATA_SHIFT) |
+               ((unsigned int)reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
+               ATI_REG_PHYS_OUT_ADDR_EN | codec;
+       atiixp_write(chip, PHYS_OUT_ADDR, data);
+}
+
+
+static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+       atiixp_t *chip = ac97->private_data;
+       unsigned short data;
+       spin_lock(&chip->ac97_lock);
+       data = snd_atiixp_codec_read(chip, ac97->num, reg);
+       spin_unlock(&chip->ac97_lock);
+       return data;
+    
+}
+
+static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+       atiixp_t *chip = ac97->private_data;
+       spin_lock(&chip->ac97_lock);
+       snd_atiixp_codec_write(chip, ac97->num, reg, val);
+       spin_unlock(&chip->ac97_lock);
+}
+
+/*
+ * reset AC link
+ */
+static int snd_atiixp_aclink_reset(atiixp_t *chip)
+{
+       int timeout;
+
+       /* reset powerdoewn */
+       if (atiixp_update(chip, CMD, ATI_REG_CMD_POWERDOWN, 0))
+               udelay(10);
+
+       /* perform a software reset */
+       atiixp_update(chip, CMD, ATI_REG_CMD_AC_SOFT_RESET, ATI_REG_CMD_AC_SOFT_RESET);
+       atiixp_read(chip, CMD);
+       udelay(10);
+       atiixp_update(chip, CMD, ATI_REG_CMD_AC_SOFT_RESET, 0);
+    
+       timeout = 10;
+       while (! (atiixp_read(chip, CMD) & ATI_REG_CMD_ACLINK_ACTIVE)) {
+               /* do a hard reset */
+               atiixp_update(chip, CMD, ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET,
+                             ATI_REG_CMD_AC_SYNC);
+               atiixp_read(chip, CMD);
+               do_delay();
+               atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
+               if (--timeout) {
+                       snd_printk(KERN_ERR "atiixp: codec reset timeout\n");
+                       break;
+               }
+       }
+
+       /* deassert RESET and assert SYNC to make sure */
+       atiixp_update(chip, CMD, ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET,
+                     ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_atiixp_aclink_down(atiixp_t *chip)
+{
+       // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
+       //      return -EBUSY;
+       atiixp_update(chip, CMD,
+                    ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET,
+                    ATI_REG_CMD_POWERDOWN);
+       return 0;
+}
+#endif
+
+/*
+ * auto-detection of codecs
+ *
+ * the IXP chip can generate interrupts for the non-existing codecs.
+ * NEW_FRAME interrupt is used to make sure that the interrupt is generated
+ * even if all three codecs are connected.
+ */
+
+#define ALL_CODEC_NOT_READY \
+           (ATI_REG_ISR_CODEC0_NOT_READY |\
+            ATI_REG_ISR_CODEC1_NOT_READY |\
+            ATI_REG_ISR_CODEC2_NOT_READY)
+#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
+
+static int snd_atiixp_codec_detect(atiixp_t *chip)
+{
+       int timeout;
+
+       chip->codec_not_ready_bits = 0;
+       atiixp_write(chip, IER, CODEC_CHECK_BITS);
+       /* wait for the interrupts */
+       timeout = HZ / 10;
+       while (timeout-- > 0) {
+               do_delay();
+               if (chip->codec_not_ready_bits)
+                       break;
+       }
+       atiixp_write(chip, IER, 0); /* disable irqs */
+
+       if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) {
+               snd_printk(KERN_ERR "atiixp: no codec detected!\n");
+               return -ENXIO;
+       }
+       return 0;
+}
+
+
+/*
+ * enable DMA and irqs
+ */
+static int snd_atiixp_chip_start(atiixp_t *chip)
+{
+       unsigned int reg;
+
+       /* set up spdif, enable burst mode */
+       reg = atiixp_read(chip, CMD);
+       reg |= ATI_REG_CMD_BURST_EN;
+       if(!(reg & ATI_REG_CMD_MODEM_PRESENT))
+               reg |= ATI_REG_CMD_MODEM_PRESENT;
+       atiixp_write(chip, CMD, reg);
+
+       /* clear all interrupt source */
+       atiixp_write(chip, ISR, 0xffffffff);
+       /* enable irqs */
+       atiixp_write(chip, IER,
+                    ATI_REG_IER_MODEM_STATUS_EN |
+                    ATI_REG_IER_MODEM_IN_XRUN_EN |
+                    ATI_REG_IER_MODEM_OUT1_XRUN_EN);
+       return 0;
+}
+
+
+/*
+ * disable DMA and IRQs
+ */
+static int snd_atiixp_chip_stop(atiixp_t *chip)
+{
+       /* clear interrupt source */
+       atiixp_write(chip, ISR, atiixp_read(chip, ISR));
+       /* disable irqs */
+       atiixp_write(chip, IER, 0);
+       return 0;
+}
+
+
+/*
+ * PCM section
+ */
+
+/*
+ * pointer callback simplly reads XXX_DMA_DT_CUR register as the current
+ * position.  when SG-buffer is implemented, the offset must be calculated
+ * correctly...
+ */
+static snd_pcm_uframes_t snd_atiixp_pcm_pointer(snd_pcm_substream_t *substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       atiixp_dma_t *dma = (atiixp_dma_t *)runtime->private_data;
+       unsigned int curptr;
+
+       spin_lock(&chip->reg_lock);
+       curptr = readl(chip->remap_addr + dma->ops->dt_cur);
+       if (curptr < dma->buf_addr) {
+               snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr);
+               curptr = 0;
+       } else {
+               curptr -= dma->buf_addr;
+               if (curptr >= dma->buf_bytes) {
+                       snd_printdd("curptr = %x, size = %x\n", curptr, dma->buf_bytes);
+                       curptr = 0;
+               }
+       }
+       spin_unlock(&chip->reg_lock);
+       return bytes_to_frames(runtime, curptr);
+}
+
+/*
+ * XRUN detected, and stop the PCM substream
+ */
+static void snd_atiixp_xrun_dma(atiixp_t *chip, atiixp_dma_t *dma)
+{
+       if (! dma->substream || ! dma->running)
+               return;
+       snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type);
+       snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
+}
+
+/*
+ * the period ack.  update the substream.
+ */
+static void snd_atiixp_update_dma(atiixp_t *chip, atiixp_dma_t *dma)
+{
+       if (! dma->substream || ! dma->running)
+               return;
+       snd_pcm_period_elapsed(dma->substream);
+}
+
+/* set BUS_BUSY interrupt bit if any DMA is running */
+/* call with spinlock held */
+static void snd_atiixp_check_bus_busy(atiixp_t *chip)
+{
+       unsigned int bus_busy;
+       if (atiixp_read(chip, CMD) & (ATI_REG_CMD_MODEM_SEND1_EN |
+                                     ATI_REG_CMD_MODEM_RECEIVE_EN))
+               bus_busy = ATI_REG_IER_MODEM_SET_BUS_BUSY;
+       else
+               bus_busy = 0;
+       atiixp_update(chip, IER, ATI_REG_IER_MODEM_SET_BUS_BUSY, bus_busy);
+}
+
+/* common trigger callback
+ * calling the lowlevel callbacks in it
+ */
+static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
+       unsigned int reg = 0;
+       int i;
+
+       snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL);
+
+       if (cmd != SNDRV_PCM_TRIGGER_START && cmd != SNDRV_PCM_TRIGGER_STOP)
+               return -EINVAL;
+
+       spin_lock(&chip->reg_lock);
+
+       /* hook off/on: via GPIO_OUT */
+       for (i = 0; i < NUM_ATI_CODECS; i++) {
+               if (chip->ac97[i]) {
+                       reg = snd_ac97_read(chip->ac97[i], AC97_GPIO_STATUS);
+                       break;
+       }
+       }
+       if(cmd == SNDRV_PCM_TRIGGER_START)
+               reg |= AC97_GPIO_LINE1_OH;
+       else
+               reg &= ~AC97_GPIO_LINE1_OH;
+       reg = (reg << ATI_REG_MODEM_OUT_GPIO_DATA_SHIFT) | ATI_REG_MODEM_OUT_GPIO_EN ;
+       atiixp_write(chip, MODEM_OUT_GPIO, reg);
+
+       if (cmd == SNDRV_PCM_TRIGGER_START) {
+               dma->ops->enable_transfer(chip, 1);
+               dma->running = 1;
+       } else {
+               dma->ops->enable_transfer(chip, 0);
+               dma->running = 0;
+       }
+       snd_atiixp_check_bus_busy(chip);
+       if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+               dma->ops->flush_dma(chip);
+               snd_atiixp_check_bus_busy(chip);
+       }
+       spin_unlock(&chip->reg_lock);
+       return 0;
+}
+
+
+/*
+ * lowlevel callbacks for each DMA type
+ *
+ * every callback is supposed to be called in chip->reg_lock spinlock
+ */
+
+/* flush FIFO of analog OUT DMA */
+static void atiixp_out_flush_dma(atiixp_t *chip)
+{
+       atiixp_write(chip, MODEM_FIFO_FLUSH, ATI_REG_MODEM_FIFO_OUT1_FLUSH);
+}
+
+/* enable/disable analog OUT DMA */
+static void atiixp_out_enable_dma(atiixp_t *chip, int on)
+{
+       unsigned int data;
+       data = atiixp_read(chip, CMD);
+       if (on) {
+               if (data & ATI_REG_CMD_MODEM_OUT_DMA1_EN)
+                       return;
+               atiixp_out_flush_dma(chip);
+               data |= ATI_REG_CMD_MODEM_OUT_DMA1_EN;
+       } else
+               data &= ~ATI_REG_CMD_MODEM_OUT_DMA1_EN;
+       atiixp_write(chip, CMD, data);
+}
+
+/* start/stop transfer over OUT DMA */
+static void atiixp_out_enable_transfer(atiixp_t *chip, int on)
+{
+       atiixp_update(chip, CMD, ATI_REG_CMD_MODEM_SEND1_EN,
+                     on ? ATI_REG_CMD_MODEM_SEND1_EN : 0);
+}
+
+/* enable/disable analog IN DMA */
+static void atiixp_in_enable_dma(atiixp_t *chip, int on)
+{
+       atiixp_update(chip, CMD, ATI_REG_CMD_MODEM_IN_DMA_EN,
+                     on ? ATI_REG_CMD_MODEM_IN_DMA_EN : 0);
+}
+
+/* start/stop analog IN DMA */
+static void atiixp_in_enable_transfer(atiixp_t *chip, int on)
+{
+       if (on) {
+               unsigned int data = atiixp_read(chip, CMD);
+               if (! (data & ATI_REG_CMD_MODEM_RECEIVE_EN)) {
+                       data |= ATI_REG_CMD_MODEM_RECEIVE_EN;
+                       atiixp_write(chip, CMD, data);
+               }
+       } else
+               atiixp_update(chip, CMD, ATI_REG_CMD_MODEM_RECEIVE_EN, 0);
+}
+
+/* flush FIFO of analog IN DMA */
+static void atiixp_in_flush_dma(atiixp_t *chip)
+{
+       atiixp_write(chip, MODEM_FIFO_FLUSH, ATI_REG_MODEM_FIFO_IN_FLUSH);
+}
+
+/* set up slots and formats for analog OUT */
+static int snd_atiixp_playback_prepare(snd_pcm_substream_t *substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       unsigned int data;
+
+       spin_lock_irq(&chip->reg_lock);
+       /* set output threshold */
+       data = atiixp_read(chip, MODEM_OUT_FIFO);
+       data &= ~ATI_REG_MODEM_OUT1_DMA_THRESHOLD_MASK;
+       data |= 0x04 << ATI_REG_MODEM_OUT1_DMA_THRESHOLD_SHIFT;
+       atiixp_write(chip, MODEM_OUT_FIFO, data);
+       spin_unlock_irq(&chip->reg_lock);
+       return 0;
+}
+
+/* set up slots and formats for analog IN */
+static int snd_atiixp_capture_prepare(snd_pcm_substream_t *substream)
+{
+       return 0;
+}
+
+/*
+ * hw_params - allocate the buffer and set up buffer descriptors
+ */
+static int snd_atiixp_pcm_hw_params(snd_pcm_substream_t *substream,
+                                  snd_pcm_hw_params_t *hw_params)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
+       int err;
+       int i;
+
+       err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+       dma->buf_addr = substream->runtime->dma_addr;
+       dma->buf_bytes = params_buffer_bytes(hw_params);
+
+       err = atiixp_build_dma_packets(chip, dma, substream,
+                                      params_periods(hw_params),
+                                      params_period_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       /* set up modem rate */
+       for (i = 0; i < NUM_ATI_CODECS; i++) {
+               if (! chip->ac97[i])
+                       continue;
+               snd_ac97_write(chip->ac97[i], AC97_LINE1_RATE, params_rate(hw_params));
+               snd_ac97_write(chip->ac97[i], AC97_LINE1_LEVEL, 0);
+       }
+
+       return err;
+}
+
+static int snd_atiixp_pcm_hw_free(snd_pcm_substream_t * substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data;
+
+       atiixp_clear_dma_packets(chip, dma, substream);
+       snd_pcm_lib_free_pages(substream);
+       return 0;
+}
+
+
+/*
+ * pcm hardware definition, identical for all DMA types
+ */
+static snd_pcm_hardware_t snd_atiixp_pcm_hw =
+{
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
+       .rates =                SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,
+       .rate_min =             8000,
+       .rate_max =             16000,
+       .channels_min =         2,
+       .channels_max =         2,
+       .buffer_bytes_max =     256 * 1024,
+       .period_bytes_min =     32,
+       .period_bytes_max =     128 * 1024,
+       .periods_min =          2,
+       .periods_max =          ATI_MAX_DESCRIPTORS,
+};
+
+static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma, int pcm_type)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       int err;
+       static unsigned int rates[] = { 8000,  9600, 12000, 16000 };
+       static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list = rates,
+               .mask = 0,
+       };
+
+       snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+
+       if (dma->opened)
+               return -EBUSY;
+       dma->substream = substream;
+       runtime->hw = snd_atiixp_pcm_hw;
+       dma->ac97_pcm_type = pcm_type;
+       if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)
+               return err;
+       if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+               return err;
+       runtime->private_data = dma;
+
+       /* enable DMA bits */
+       spin_lock_irq(&chip->reg_lock);
+       dma->ops->enable_dma(chip, 1);
+       spin_unlock_irq(&chip->reg_lock);
+       dma->opened = 1;
+
+       return 0;
+}
+
+static int snd_atiixp_pcm_close(snd_pcm_substream_t *substream, atiixp_dma_t *dma)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       /* disable DMA bits */
+       snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL);
+       spin_lock_irq(&chip->reg_lock);
+       dma->ops->enable_dma(chip, 0);
+       spin_unlock_irq(&chip->reg_lock);
+       dma->substream = NULL;
+       dma->opened = 0;
+       return 0;
+}
+
+/*
+ */
+static int snd_atiixp_playback_open(snd_pcm_substream_t *substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       down(&chip->open_mutex);
+       err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
+       up(&chip->open_mutex);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int snd_atiixp_playback_close(snd_pcm_substream_t *substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       int err;
+       down(&chip->open_mutex);
+       err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
+       up(&chip->open_mutex);
+       return err;
+}
+
+static int snd_atiixp_capture_open(snd_pcm_substream_t *substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1);
+}
+
+static int snd_atiixp_capture_close(snd_pcm_substream_t *substream)
+{
+       atiixp_t *chip = snd_pcm_substream_chip(substream);
+       return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]);
+}
+
+
+/* AC97 playback */
+static snd_pcm_ops_t snd_atiixp_playback_ops = {
+       .open =         snd_atiixp_playback_open,
+       .close =        snd_atiixp_playback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_atiixp_pcm_hw_params,
+       .hw_free =      snd_atiixp_pcm_hw_free,
+       .prepare =      snd_atiixp_playback_prepare,
+       .trigger =      snd_atiixp_pcm_trigger,
+       .pointer =      snd_atiixp_pcm_pointer,
+};
+
+/* AC97 capture */
+static snd_pcm_ops_t snd_atiixp_capture_ops = {
+       .open =         snd_atiixp_capture_open,
+       .close =        snd_atiixp_capture_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_atiixp_pcm_hw_params,
+       .hw_free =      snd_atiixp_pcm_hw_free,
+       .prepare =      snd_atiixp_capture_prepare,
+       .trigger =      snd_atiixp_pcm_trigger,
+       .pointer =      snd_atiixp_pcm_pointer,
+};
+
+static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = {
+       .type = ATI_DMA_PLAYBACK,
+       .llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR,
+       .dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR,
+       .enable_dma = atiixp_out_enable_dma,
+       .enable_transfer = atiixp_out_enable_transfer,
+       .flush_dma = atiixp_out_flush_dma,
+};
+       
+static atiixp_dma_ops_t snd_atiixp_capture_dma_ops = {
+       .type = ATI_DMA_CAPTURE,
+       .llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR,
+       .dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR,
+       .enable_dma = atiixp_in_enable_dma,
+       .enable_transfer = atiixp_in_enable_transfer,
+       .flush_dma = atiixp_in_flush_dma,
+};
+
+static int __devinit snd_atiixp_pcm_new(atiixp_t *chip)
+{
+       snd_pcm_t *pcm;
+       int err;
+
+       /* initialize constants */
+       chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops;
+       chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops;
+
+       /* PCM #0: analog I/O */
+       err = snd_pcm_new(chip->card, "ATI IXP MC97", ATI_PCMDEV_ANALOG, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);
+       pcm->private_data = chip;
+       strcpy(pcm->name, "ATI IXP MC97");
+       chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                             snd_dma_pci_data(chip->pci), 64*1024, 128*1024);
+
+       return 0;
+}
+
+
+
+/*
+ * interrupt handler
+ */
+static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       atiixp_t *chip = dev_id;
+       unsigned int status;
+
+       status = atiixp_read(chip, ISR);
+
+       if (! status)
+               return IRQ_NONE;
+
+       /* process audio DMA */
+       if (status & ATI_REG_ISR_MODEM_OUT1_XRUN)
+               snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_PLAYBACK]);
+       else if (status & ATI_REG_ISR_MODEM_OUT1_STATUS)
+               snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]);
+       if (status & ATI_REG_ISR_MODEM_IN_XRUN)
+               snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_CAPTURE]);
+       else if (status & ATI_REG_ISR_MODEM_IN_STATUS)
+               snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]);
+
+       /* for codec detection */
+       if (status & CODEC_CHECK_BITS) {
+               unsigned int detected;
+               detected = status & CODEC_CHECK_BITS;
+               spin_lock(&chip->reg_lock);
+               chip->codec_not_ready_bits |= detected;
+               atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */
+               spin_unlock(&chip->reg_lock);
+       }
+
+       /* ack */
+       atiixp_write(chip, ISR, status);
+
+       return IRQ_HANDLED;
+}
+
+
+/*
+ * ac97 mixer section
+ */
+
+static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock)
+{
+       ac97_bus_t *pbus;
+       ac97_template_t ac97;
+       int i, err;
+       int codec_count;
+       static ac97_bus_ops_t ops = {
+               .write = snd_atiixp_ac97_write,
+               .read = snd_atiixp_ac97_read,
+       };
+       static unsigned int codec_skip[NUM_ATI_CODECS] = {
+               ATI_REG_ISR_CODEC0_NOT_READY,
+               ATI_REG_ISR_CODEC1_NOT_READY,
+               ATI_REG_ISR_CODEC2_NOT_READY,
+       };
+
+       if (snd_atiixp_codec_detect(chip) < 0)
+               return -ENXIO;
+
+       if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0)
+               return err;
+       pbus->clock = clock;
+       pbus->shared_type = AC97_SHARED_TYPE_ATIIXP;    /* shared with audio driver */
+       chip->ac97_bus = pbus;
+
+       codec_count = 0;
+       for (i = 0; i < NUM_ATI_CODECS; i++) {
+               if (chip->codec_not_ready_bits & codec_skip[i])
+                       continue;
+               memset(&ac97, 0, sizeof(ac97));
+               ac97.private_data = chip;
+               ac97.pci = chip->pci;
+               ac97.num = i;
+               ac97.scaps = AC97_SCAP_SKIP_AUDIO;
+               if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
+                       chip->ac97[i] = NULL; /* to be sure */
+                       snd_printdd("atiixp: codec %d not available for modem\n", i);
+                       continue;
+               }
+               codec_count++;
+       }
+
+       if (! codec_count) {
+               snd_printk(KERN_ERR "atiixp: no codec available\n");
+               return -ENODEV;
+       }
+
+       /* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */
+
+       return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * power management
+ */
+static int snd_atiixp_suspend(snd_card_t *card, unsigned int state)
+{
+       atiixp_t *chip = card->pm_private_data;
+       int i;
+
+       for (i = 0; i < NUM_ATI_PCMDEVS; i++)
+               if (chip->pcmdevs[i])
+                       snd_pcm_suspend_all(chip->pcmdevs[i]);
+       for (i = 0; i < NUM_ATI_CODECS; i++)
+               if (chip->ac97[i])
+                       snd_ac97_suspend(chip->ac97[i]);
+       snd_atiixp_aclink_down(chip);
+       snd_atiixp_chip_stop(chip);
+
+       pci_set_power_state(chip->pci, 3);
+       pci_disable_device(chip->pci);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       return 0;
+}
+
+static int snd_atiixp_resume(snd_card_t *card, unsigned int state)
+{
+       atiixp_t *chip = card->pm_private_data;
+       int i;
+
+       pci_enable_device(chip->pci);
+       pci_set_power_state(chip->pci, 0);
+
+       snd_atiixp_aclink_reset(chip);
+       snd_atiixp_chip_start(chip);
+
+       for (i = 0; i < NUM_ATI_CODECS; i++)
+               if (chip->ac97[i])
+                       snd_ac97_resume(chip->ac97[i]);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+
+/*
+ * proc interface for register dump
+ */
+
+static void snd_atiixp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+       atiixp_t *chip = entry->private_data;
+       int i;
+
+       for (i = 0; i < 256; i += 4)
+               snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i));
+}
+
+static void __devinit snd_atiixp_proc_init(atiixp_t *chip)
+{
+       snd_info_entry_t *entry;
+
+       if (! snd_card_proc_new(chip->card, "atiixp", &entry))
+               snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);
+}
+
+
+
+/*
+ * destructor
+ */
+
+static int snd_atiixp_free(atiixp_t *chip)
+{
+       if (chip->irq < 0)
+               goto __hw_end;
+       snd_atiixp_chip_stop(chip);
+       synchronize_irq(chip->irq);
+      __hw_end:
+       if (chip->irq >= 0)
+               free_irq(chip->irq, (void *)chip);
+       if (chip->remap_addr)
+               iounmap(chip->remap_addr);
+       pci_release_regions(chip->pci);
+       kfree(chip);
+       return 0;
+}
+
+static int snd_atiixp_dev_free(snd_device_t *device)
+{
+       atiixp_t *chip = device->device_data;
+       return snd_atiixp_free(chip);
+}
+
+/*
+ * constructor for chip instance
+ */
+static int __devinit snd_atiixp_create(snd_card_t *card,
+                                     struct pci_dev *pci,
+                                     atiixp_t **r_chip)
+{
+       static snd_device_ops_t ops = {
+               .dev_free =     snd_atiixp_dev_free,
+       };
+       atiixp_t *chip;
+       int err;
+
+       if ((err = pci_enable_device(pci)) < 0)
+               return err;
+
+       chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       spin_lock_init(&chip->reg_lock);
+       spin_lock_init(&chip->ac97_lock);
+       init_MUTEX(&chip->open_mutex);
+       chip->card = card;
+       chip->pci = pci;
+       chip->irq = -1;
+       if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) {
+               kfree(chip);
+               return err;
+       }
+       chip->addr = pci_resource_start(pci, 0);
+       chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci, 0));
+       if (chip->remap_addr == 0) {
+               snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+               snd_atiixp_free(chip);
+               return -EIO;
+       }
+
+       if (request_irq(pci->irq, snd_atiixp_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) {
+               snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+               snd_atiixp_free(chip);
+               return -EBUSY;
+       }
+       chip->irq = pci->irq;
+       pci_set_master(pci);
+       synchronize_irq(chip->irq);
+
+       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+               snd_atiixp_free(chip);
+               return err;
+       }
+
+       snd_card_set_dev(card, &pci->dev);
+
+       *r_chip = chip;
+       return 0;
+}
+
+
+static int __devinit snd_atiixp_probe(struct pci_dev *pci,
+                                     const struct pci_device_id *pci_id)
+{
+       static int dev;
+       snd_card_t *card;
+       atiixp_t *chip;
+       unsigned char revision;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+       if (card == NULL)
+               return -ENOMEM;
+
+       pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
+
+       strcpy(card->driver, "ATIIXP-MODEM");
+       strcpy(card->shortname, "ATI IXP Modem");
+       if ((err = snd_atiixp_create(card, pci, &chip)) < 0)
+               goto __error;
+
+       if ((err = snd_atiixp_aclink_reset(chip)) < 0)
+               goto __error;
+
+       if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev])) < 0)
+               goto __error;
+
+       if ((err = snd_atiixp_pcm_new(chip)) < 0)
+               goto __error;
+       
+       snd_atiixp_proc_init(chip);
+
+       snd_atiixp_chip_start(chip);
+
+       sprintf(card->longname, "%s rev %x at 0x%lx, irq %i",
+               card->shortname, revision, chip->addr, chip->irq);
+
+       snd_card_set_pm_callback(card, snd_atiixp_suspend, snd_atiixp_resume, chip);
+
+       if ((err = snd_card_register(card)) < 0)
+               goto __error;
+
+       pci_set_drvdata(pci, card);
+       dev++;
+       return 0;
+
+ __error:
+       snd_card_free(card);
+       return err;
+}
+
+static void __devexit snd_atiixp_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+       .name = "ATI IXP MC97 controller",
+       .id_table = snd_atiixp_ids,
+       .probe = snd_atiixp_probe,
+       .remove = __devexit_p(snd_atiixp_remove),
+       SND_PCI_PM_CALLBACKS
+};
+
+
+static int __init alsa_card_atiixp_init(void)
+{
+       return pci_module_init(&driver);
+}
+
+static void __exit alsa_card_atiixp_exit(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_atiixp_init)
+module_exit(alsa_card_atiixp_exit)
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
new file mode 100644 (file)
index 0000000..25f827d
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for Pontis MS300
+ *
+ *     Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/info.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "pontis.h"
+
+/* I2C addresses */
+#define WM_DEV         0x34
+#define CS_DEV         0x20
+
+/* WM8776 registers */
+#define WM_HP_ATTEN_L          0x00    /* headphone left attenuation */
+#define WM_HP_ATTEN_R          0x01    /* headphone left attenuation */
+#define WM_HP_MASTER           0x02    /* headphone master (both channels), override LLR */
+#define WM_DAC_ATTEN_L         0x03    /* digital left attenuation */
+#define WM_DAC_ATTEN_R         0x04
+#define WM_DAC_MASTER          0x05
+#define WM_PHASE_SWAP          0x06    /* DAC phase swap */
+#define WM_DAC_CTRL1           0x07
+#define WM_DAC_MUTE            0x08
+#define WM_DAC_CTRL2           0x09
+#define WM_DAC_INT             0x0a
+#define WM_ADC_INT             0x0b
+#define WM_MASTER_CTRL         0x0c
+#define WM_POWERDOWN           0x0d
+#define WM_ADC_ATTEN_L         0x0e
+#define WM_ADC_ATTEN_R         0x0f
+#define WM_ALC_CTRL1           0x10
+#define WM_ALC_CTRL2           0x11
+#define WM_ALC_CTRL3           0x12
+#define WM_NOISE_GATE          0x13
+#define WM_LIMITER             0x14
+#define WM_ADC_MUX             0x15
+#define WM_OUT_MUX             0x16
+#define WM_RESET               0x17
+
+/*
+ * GPIO
+ */
+#define PONTIS_CS_CS           (1<<4)  /* CS */
+#define PONTIS_CS_CLK          (1<<5)  /* CLK */
+#define PONTIS_CS_RDATA                (1<<6)  /* CS8416 -> VT1720 */
+#define PONTIS_CS_WDATA                (1<<7)  /* VT1720 -> CS8416 */
+
+
+/*
+ * get the current register value of WM codec
+ */
+static unsigned short wm_get(ice1712_t *ice, int reg)
+{
+       reg <<= 1;
+       return ((unsigned short)ice->akm[0].images[reg] << 8) |
+               ice->akm[0].images[reg + 1];
+}
+
+/*
+ * set the register value of WM codec and remember it
+ */
+static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val)
+{
+       unsigned short cval;
+       cval = (reg << 9) | val;
+       snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);
+}
+
+static void wm_put(ice1712_t *ice, int reg, unsigned short val)
+{
+       wm_put_nocache(ice, reg, val);
+       reg <<= 1;
+       ice->akm[0].images[reg] = val >> 8;
+       ice->akm[0].images[reg + 1] = val;
+}
+
+/*
+ * DAC volume attenuation mixer control (-64dB to 0dB)
+ */
+
+#define DAC_0dB        0xff
+#define DAC_RES        128
+#define DAC_MIN        (DAC_0dB - DAC_RES)
+
+static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;   /* mute */
+       uinfo->value.integer.max = DAC_RES;     /* 0dB, 0.5dB step */
+       return 0;
+}
+
+static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val;
+       int i;
+
+       down(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff;
+               val = val > DAC_MIN ? (val - DAC_MIN) : 0;
+               ucontrol->value.integer.value[i] = val;
+       }
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short oval, nval;
+       int i, idx, change = 0;
+
+       down(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               nval = ucontrol->value.integer.value[i];
+               nval = (nval ? (nval + DAC_MIN) : 0) & 0xff;
+               idx = WM_DAC_ATTEN_L + i;
+               oval = wm_get(ice, idx) & 0xff;
+               if (oval != nval) {
+                       wm_put(ice, idx, nval);
+                       wm_put_nocache(ice, idx, nval | 0x100);
+                       change = 1;
+               }
+       }
+       up(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * ADC gain mixer control (-64dB to 0dB)
+ */
+
+#define ADC_0dB        0xcf
+#define ADC_RES        128
+#define ADC_MIN        (ADC_0dB - ADC_RES)
+
+static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;   /* mute (-64dB) */
+       uinfo->value.integer.max = ADC_RES;     /* 0dB, 0.5dB step */
+       return 0;
+}
+
+static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val;
+       int i;
+
+       down(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
+               val = val > ADC_MIN ? (val - ADC_MIN) : 0;
+               ucontrol->value.integer.value[i] = val;
+       }
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short ovol, nvol;
+       int i, idx, change = 0;
+
+       down(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               nvol = ucontrol->value.integer.value[i];
+               nvol = nvol ? (nvol + ADC_MIN) : 0;
+               idx  = WM_ADC_ATTEN_L + i;
+               ovol = wm_get(ice, idx) & 0xff;
+               if (ovol != nvol) {
+                       wm_put(ice, idx, nvol);
+                       change = 1;
+               }
+       }
+       up(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * ADC input mux mixer control
+ */
+static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int bit = kcontrol->private_value;
+
+       down(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int bit = kcontrol->private_value;
+       unsigned short oval, nval;
+       int change;
+
+       down(&ice->gpio_mutex);
+       nval = oval = wm_get(ice, WM_ADC_MUX);
+       if (ucontrol->value.integer.value[0])
+               nval |= (1 << bit);
+       else
+               nval &= ~(1 << bit);
+       change = nval != oval;
+       if (change) {
+               wm_put(ice, WM_ADC_MUX, nval);
+       }
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+/*
+ * Analog bypass (In -> Out)
+ */
+static int wm_bypass_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm_bypass_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+       down(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_bypass_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val, oval;
+       int change = 0;
+
+       down(&ice->gpio_mutex);
+       val = oval = wm_get(ice, WM_OUT_MUX);
+       if (ucontrol->value.integer.value[0])
+               val |= 0x04;
+       else
+               val &= ~0x04;
+       if (val != oval) {
+               wm_put(ice, WM_OUT_MUX, val);
+               change = 1;
+       }
+       up(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * Left/Right swap
+ */
+static int wm_chswap_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm_chswap_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+       down(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_chswap_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val, oval;
+       int change = 0;
+
+       down(&ice->gpio_mutex);
+       oval = wm_get(ice, WM_DAC_CTRL1);
+       val = oval & 0x0f;
+       if (ucontrol->value.integer.value[0])
+               val |= 0x60;
+       else
+               val |= 0x90;
+       if (val != oval) {
+               wm_put(ice, WM_DAC_CTRL1, val);
+               wm_put_nocache(ice, WM_DAC_CTRL1, val);
+               change = 1;
+       }
+       up(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * write data in the SPI mode
+ */
+static void set_gpio_bit(ice1712_t *ice, unsigned int bit, int val)
+{
+       unsigned int tmp = snd_ice1712_gpio_read(ice);
+       if (val)
+               tmp |= bit;
+       else
+               tmp &= ~bit;
+       snd_ice1712_gpio_write(ice, tmp);
+}
+
+static void spi_send_byte(ice1712_t *ice, unsigned char data)
+{
+       int i;
+       for (i = 0; i < 8; i++) {
+               set_gpio_bit(ice, PONTIS_CS_CLK, 0);
+               udelay(1);
+               set_gpio_bit(ice, PONTIS_CS_WDATA, data & 0x80);
+               udelay(1);
+               set_gpio_bit(ice, PONTIS_CS_CLK, 1);
+               udelay(1);
+               data <<= 1;
+       }
+}
+
+static unsigned int spi_read_byte(ice1712_t *ice)
+{
+       int i;
+       unsigned int val = 0;
+
+       for (i = 0; i < 8; i++) {
+               val <<= 1;
+               set_gpio_bit(ice, PONTIS_CS_CLK, 0);
+               udelay(1);
+               if (snd_ice1712_gpio_read(ice) & PONTIS_CS_RDATA)
+                       val |= 1;
+               udelay(1);
+               set_gpio_bit(ice, PONTIS_CS_CLK, 1);
+               udelay(1);
+       }
+       return val;
+}
+
+
+static void spi_write(ice1712_t *ice, unsigned int dev, unsigned int reg, unsigned int data)
+{
+       snd_ice1712_gpio_set_dir(ice, PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK);
+       snd_ice1712_gpio_set_mask(ice, ~(PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK));
+       set_gpio_bit(ice, PONTIS_CS_CS, 0);
+       spi_send_byte(ice, dev & ~1); /* WRITE */
+       spi_send_byte(ice, reg); /* MAP */
+       spi_send_byte(ice, data); /* DATA */
+       /* trigger */
+       set_gpio_bit(ice, PONTIS_CS_CS, 1);
+       udelay(1);
+       /* restore */
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+}
+
+static unsigned int spi_read(ice1712_t *ice, unsigned int dev, unsigned int reg)
+{
+       unsigned int val;
+       snd_ice1712_gpio_set_dir(ice, PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK);
+       snd_ice1712_gpio_set_mask(ice, ~(PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK));
+       set_gpio_bit(ice, PONTIS_CS_CS, 0);
+       spi_send_byte(ice, dev & ~1); /* WRITE */
+       spi_send_byte(ice, reg); /* MAP */
+       /* trigger */
+       set_gpio_bit(ice, PONTIS_CS_CS, 1);
+       udelay(1);
+       set_gpio_bit(ice, PONTIS_CS_CS, 0);
+       spi_send_byte(ice, dev | 1); /* READ */
+       val = spi_read_byte(ice);
+       /* trigger */
+       set_gpio_bit(ice, PONTIS_CS_CS, 1);
+       udelay(1);
+       /* restore */
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+       return val;
+}
+
+
+/*
+ * SPDIF input source
+ */
+static int cs_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       static char *texts[] = {
+               "Coax",         /* RXP0 */
+               "Optical",      /* RXP1 */
+               "CD",           /* RXP2 */
+       };
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 3;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int cs_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+       down(&ice->gpio_mutex);
+       ucontrol->value.enumerated.item[0] = ice->gpio.saved[0];
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int cs_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned char val;
+       int change = 0;
+
+       down(&ice->gpio_mutex);
+       if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) {
+               ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3;
+               val = 0x80 | (ice->gpio.saved[0] << 3);
+               spi_write(ice, CS_DEV, 0x04, val);
+               change = 1;
+       }
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+
+/*
+ * GPIO controls
+ */
+static int pontis_gpio_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0xffff; /* 16bit */
+       return 0;
+}
+
+static int pontis_gpio_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       down(&ice->gpio_mutex);
+       /* 4-7 reserved */
+       ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0;
+       up(&ice->gpio_mutex);
+       return 0;
+}
+       
+static int pontis_gpio_mask_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       int changed;
+       down(&ice->gpio_mutex);
+       /* 4-7 reserved */
+       val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0;
+       changed = val != ice->gpio.write_mask;
+       ice->gpio.write_mask = val;
+       up(&ice->gpio_mutex);
+       return changed;
+}
+
+static int pontis_gpio_dir_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       down(&ice->gpio_mutex);
+       /* 4-7 reserved */
+       ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f;
+       up(&ice->gpio_mutex);
+       return 0;
+}
+       
+static int pontis_gpio_dir_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       int changed;
+       down(&ice->gpio_mutex);
+       /* 4-7 reserved */
+       val = ucontrol->value.integer.value[0] & 0xff0f;
+       changed = (val != ice->gpio.direction);
+       ice->gpio.direction = val;
+       up(&ice->gpio_mutex);
+       return changed;
+}
+
+static int pontis_gpio_data_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       down(&ice->gpio_mutex);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
+       ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff;
+       up(&ice->gpio_mutex);
+       return 0;
+}
+
+static int pontis_gpio_data_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned int val, nval;
+       int changed = 0;
+       down(&ice->gpio_mutex);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
+       val = snd_ice1712_gpio_read(ice) & 0xffff;
+       nval = ucontrol->value.integer.value[0] & 0xffff;
+       if (val != nval) {
+               snd_ice1712_gpio_write(ice, nval);
+               changed = 1;
+       }
+       up(&ice->gpio_mutex);
+       return changed;
+}
+
+/*
+ * mixers
+ */
+
+static snd_kcontrol_new_t pontis_controls[] __devinitdata = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "PCM Playback Volume",
+               .info = wm_dac_vol_info,
+               .get = wm_dac_vol_get,
+               .put = wm_dac_vol_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Volume",
+               .info = wm_adc_vol_info,
+               .get = wm_adc_vol_get,
+               .put = wm_adc_vol_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "CD Capture Switch",
+               .info = wm_adc_mux_info,
+               .get = wm_adc_mux_get,
+               .put = wm_adc_mux_put,
+               .private_value = 0,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Line Capture Switch",
+               .info = wm_adc_mux_info,
+               .get = wm_adc_mux_get,
+               .put = wm_adc_mux_put,
+               .private_value = 1,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Bypass Switch",
+               .info = wm_bypass_info,
+               .get = wm_bypass_get,
+               .put = wm_bypass_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Swap Output Channels",
+               .info = wm_chswap_info,
+               .get = wm_chswap_get,
+               .put = wm_chswap_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "IEC958 Input Source",
+               .info = cs_source_info,
+               .get = cs_source_get,
+               .put = cs_source_put,
+       },
+       /* FIXME: which interface? */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .name = "GPIO Mask",
+               .info = pontis_gpio_mask_info,
+               .get = pontis_gpio_mask_get,
+               .put = pontis_gpio_mask_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .name = "GPIO Direction",
+               .info = pontis_gpio_mask_info,
+               .get = pontis_gpio_dir_get,
+               .put = pontis_gpio_dir_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .name = "GPIO Data",
+               .info = pontis_gpio_mask_info,
+               .get = pontis_gpio_data_get,
+               .put = pontis_gpio_data_put,
+       },
+};
+
+
+/*
+ * WM codec registers
+ */
+static void wm_proc_regs_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+       ice1712_t *ice = (ice1712_t *)entry->private_data;
+       char line[64];
+       unsigned int reg, val;
+       down(&ice->gpio_mutex);
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "%x %x", &reg, &val) != 2)
+                       continue;
+               if (reg <= 0x17 && val <= 0xffff)
+                       wm_put(ice, reg, val);
+       }
+       up(&ice->gpio_mutex);
+}
+
+static void wm_proc_regs_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+       ice1712_t *ice = (ice1712_t *)entry->private_data;
+       int reg, val;
+
+       down(&ice->gpio_mutex);
+       for (reg = 0; reg <= 0x17; reg++) {
+               val = wm_get(ice, reg);
+               snd_iprintf(buffer, "%02x = %04x\n", reg, val);
+       }
+       up(&ice->gpio_mutex);
+}
+
+static void wm_proc_init(ice1712_t *ice)
+{
+       snd_info_entry_t *entry;
+       if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) {
+               snd_info_set_text_ops(entry, ice, 1024, wm_proc_regs_read);
+               entry->mode |= S_IWUSR;
+               entry->c.text.write_size = 1024;
+               entry->c.text.write = wm_proc_regs_write;
+       }
+}
+
+static void cs_proc_regs_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+       ice1712_t *ice = (ice1712_t *)entry->private_data;
+       int reg, val;
+
+       down(&ice->gpio_mutex);
+       for (reg = 0; reg <= 0x26; reg++) {
+               val = spi_read(ice, CS_DEV, reg);
+               snd_iprintf(buffer, "%02x = %02x\n", reg, val);
+       }
+       val = spi_read(ice, CS_DEV, 0x7f);
+       snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val);
+       up(&ice->gpio_mutex);
+}
+
+static void cs_proc_init(ice1712_t *ice)
+{
+       snd_info_entry_t *entry;
+       if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) {
+               snd_info_set_text_ops(entry, ice, 1024, cs_proc_regs_read);
+       }
+}
+
+
+static int __devinit pontis_add_controls(ice1712_t *ice)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(pontis_controls); i++) {
+               err = snd_ctl_add(ice->card, snd_ctl_new1(&pontis_controls[i], ice));
+               if (err < 0)
+                       return err;
+       }
+
+       wm_proc_init(ice);
+       cs_proc_init(ice);
+
+       return 0;
+}
+
+
+/*
+ * initialize the chip
+ */
+static int __devinit pontis_init(ice1712_t *ice)
+{
+       static unsigned short wm_inits[] = {
+               /* These come first to reduce init pop noise */
+               WM_ADC_MUX,     0x00c0, /* ADC mute */
+               WM_DAC_MUTE,    0x0001, /* DAC softmute */
+               WM_DAC_CTRL1,   0x0000, /* DAC mute */
+
+               WM_POWERDOWN,   0x0008, /* All power-up except HP */
+               WM_RESET,       0x0000, /* reset */
+       };
+       static unsigned short wm_inits2[] = {
+               WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */
+               WM_DAC_INT,     0x0022, /* I2S, normal polarity, 24bit */
+               WM_ADC_INT,     0x0022, /* I2S, normal polarity, 24bit */
+               WM_DAC_CTRL1,   0x0090, /* DAC L/R */
+               WM_OUT_MUX,     0x0001, /* OUT DAC */
+               WM_HP_ATTEN_L,  0x0179, /* HP 0dB */
+               WM_HP_ATTEN_R,  0x0179, /* HP 0dB */
+               WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */
+               WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */
+               WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */
+               WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */
+               // WM_DAC_MASTER,       0x0100, /* DAC master muted */
+               WM_PHASE_SWAP,  0x0000, /* phase normal */
+               WM_DAC_CTRL2,   0x0000, /* no deemphasis, no ZFLG */
+               WM_ADC_ATTEN_L, 0x0000, /* ADC muted */
+               WM_ADC_ATTEN_R, 0x0000, /* ADC muted */
+#if 0
+               WM_ALC_CTRL1,   0x007b, /* */
+               WM_ALC_CTRL2,   0x0000, /* */
+               WM_ALC_CTRL3,   0x0000, /* */
+               WM_NOISE_GATE,  0x0000, /* */
+#endif
+               WM_DAC_MUTE,    0x0000, /* DAC unmute */
+               WM_ADC_MUX,     0x0003, /* ADC unmute, both CD/Line On */
+       };
+       static unsigned char cs_inits[] = {
+               0x04,   0x80,   /* RUN, RXP0 */
+               0x05,   0x05,   /* slave, 24bit */
+               0x01,   0x00,
+               0x02,   0x00,
+               0x03,   0x00,
+       };
+       unsigned int i;
+
+       ice->vt1720 = 1;
+       ice->num_total_dacs = 2;
+       ice->num_total_adcs = 2;
+
+       /* to remeber the register values */
+       ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL);
+       if (! ice->akm)
+               return -ENOMEM;
+       ice->akm_codecs = 1;
+
+       /* HACK - use this as the SPDIF source.
+        * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
+        */
+       ice->gpio.saved[0] = 0;
+
+       /* initialize WM8776 codec */
+       for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
+               wm_put(ice, wm_inits[i], wm_inits[i+1]);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(1);
+       for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2)
+               wm_put(ice, wm_inits2[i], wm_inits2[i+1]);
+
+       /* initialize CS8416 codec */
+       /* assert PRST#; MT05 bit 7 */
+       outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
+       mdelay(5);
+       /* deassert PRST# */
+       outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
+
+       for (i = 0; i < ARRAY_SIZE(cs_inits); i += 2)
+               spi_write(ice, CS_DEV, cs_inits[i], cs_inits[i+1]);
+
+       return 0;
+}
+
+
+/*
+ * Pontis boards don't provide the EEPROM data at all.
+ * hence the driver needs to sets up it properly.
+ */
+
+static unsigned char pontis_eeprom[] __devinitdata = {
+       0x08,   /* SYSCONF: clock 256, mpu401, spdif-in/ADC, 1DAC */
+       0x80,   /* ACLINK: I2S */
+       0xf8,   /* I2S: vol, 96k, 24bit, 192k */
+       0xc3,   /* SPDIF: out-en, out-int, spdif-in */
+       0x07,   /* GPIO_DIR */
+       0x00,   /* GPIO_DIR1 */
+       0x00,   /* GPIO_DIR2 (ignored) */
+       0x0f,   /* GPIO_MASK (4-7 reserved for CS8416) */
+       0xff,   /* GPIO_MASK1 */
+       0x00,   /* GPIO_MASK2 (ignored) */
+       0x06,   /* GPIO_STATE (0-low, 1-high, 2-high) */
+       0x00,   /* GPIO_STATE1 */
+       0x00,   /* GPIO_STATE2 (ignored) */
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = {
+       {
+               .subvendor = VT1720_SUBDEVICE_PONTIS_MS300,
+               .name = "Pontis MS300",
+               .model = "ms300",
+               .chip_init = pontis_init,
+               .build_controls = pontis_add_controls,
+               .eeprom_size = sizeof(pontis_eeprom),
+               .eeprom_data = pontis_eeprom,
+       },
+       { } /* terminator */
+};
diff --git a/sound/pci/ice1712/pontis.h b/sound/pci/ice1712/pontis.h
new file mode 100644 (file)
index 0000000..d0d1378
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __SOUND_PONTIS_H
+#define __SOUND_PONTIS_H
+
+/*
+ *   ALSA driver for VIA VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for Pontis MS300 boards
+ *
+ *     Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#define PONTIS_DEVICE_DESC            "{Pontis,MS300},"
+
+#define VT1720_SUBDEVICE_PONTIS_MS300  0x00020002      /* a dummy id for MS300 */
+
+extern struct snd_ice1712_card_info  snd_vt1720_pontis_cards[];
+
+#endif /* __SOUND_PONTIS_H */
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
new file mode 100644 (file)
index 0000000..c8f59a2
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for AudioTrak Prodigy 192 cards
+ *
+ *     Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
+ *      Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
+ *      Copyright (c) 2004 Kouichi ONO <co2b@ceres.dti.ne.jp>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "prodigy192.h"
+#include "stac946x.h"
+
+static void stac9460_put(ice1712_t *ice, int reg, unsigned char val)
+{
+       snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val);
+}
+
+static unsigned char stac9460_get(ice1712_t *ice, int reg)
+{
+       return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg);
+}
+
+/*
+ * DAC mute control
+ */
+static int stac9460_dac_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int stac9460_dac_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned char val;
+       int idx;
+
+       if (kcontrol->private_value)
+               idx = STAC946X_MASTER_VOLUME;
+       else
+               idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
+       val = stac9460_get(ice, idx);
+       ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
+       return 0;
+}
+
+static int stac9460_dac_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned char new, old;
+       int idx;
+       int change;
+
+       if (kcontrol->private_value)
+               idx = STAC946X_MASTER_VOLUME;
+       else
+               idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
+       old = stac9460_get(ice, idx);
+       new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
+       change = (new != old);
+       if (change)
+               stac9460_put(ice, idx, new);
+
+       return change;
+}
+
+/*
+ * DAC volume attenuation mixer control
+ */
+static int stac9460_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;                   /* mute */
+       uinfo->value.integer.max = 0x7f;                /* 0dB */
+       return 0;
+}
+
+static int stac9460_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int idx;
+       unsigned char vol;
+
+       if (kcontrol->private_value)
+               idx = STAC946X_MASTER_VOLUME;
+       else
+               idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
+       vol = stac9460_get(ice, idx) & 0x7f;
+       ucontrol->value.integer.value[0] = 0x7f - vol;
+
+       return 0;
+}
+
+static int stac9460_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int idx;
+       unsigned char tmp, ovol, nvol;
+       int change;
+
+       if (kcontrol->private_value)
+               idx = STAC946X_MASTER_VOLUME;
+       else
+               idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
+       nvol = ucontrol->value.integer.value[0];
+       tmp = stac9460_get(ice, idx);
+       ovol = 0x7f - (tmp & 0x7f);
+       change = (ovol != nvol);
+       if (change) {
+               stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
+       }
+       return change;
+}
+
+/*
+ * ADC mute control
+ */
+static int stac9460_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int stac9460_adc_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned char val;
+       int i;
+
+       for (i = 0; i < 2; ++i) {
+               val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
+               ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
+       }
+
+       return 0;
+}
+
+static int stac9460_adc_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       unsigned char new, old;
+       int i, reg;
+       int change;
+
+       for (i = 0; i < 2; ++i) {
+               reg = STAC946X_MIC_L_VOLUME + i;
+               old = stac9460_get(ice, reg);
+               new = (~ucontrol->value.integer.value[i]<<7&0x80) | (old&~0x80);
+               change = (new != old);
+               if (change)
+                       stac9460_put(ice, reg, new);
+       }
+
+       return change;
+}
+
+/*
+ * ADC gain mixer control
+ */
+static int stac9460_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;           /* 0dB */
+       uinfo->value.integer.max = 0x0f;        /* 22.5dB */
+       return 0;
+}
+
+static int stac9460_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int i, reg;
+       unsigned char vol;
+
+       for (i = 0; i < 2; ++i) {
+               reg = STAC946X_MIC_L_VOLUME + i;
+               vol = stac9460_get(ice, reg) & 0x0f;
+               ucontrol->value.integer.value[i] = 0x0f - vol;
+       }
+
+       return 0;
+}
+
+static int stac9460_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int i, reg;
+       unsigned char ovol, nvol;
+       int change;
+
+       for (i = 0; i < 2; ++i) {
+               reg = STAC946X_MIC_L_VOLUME + i;
+               nvol = ucontrol->value.integer.value[i];
+               ovol = 0x0f - stac9460_get(ice, reg);
+               change = ((ovol & 0x0f)  != nvol);
+               if (change)
+                       stac9460_put(ice, reg, (0x0f - nvol) | (ovol & ~0x0f));
+       }
+
+       return change;
+}
+
+#if 0
+/*
+ * Headphone Amplifier
+ */
+static int aureon_set_headphone_amp(ice1712_t *ice, int enable)
+{
+       unsigned int tmp, tmp2;
+
+       tmp2 = tmp = snd_ice1712_gpio_read(ice);
+       if (enable)
+               tmp |= AUREON_HP_SEL;
+       else
+               tmp &= ~ AUREON_HP_SEL;
+       if (tmp != tmp2) {
+               snd_ice1712_gpio_write(ice, tmp);
+               return 1;
+       }
+       return 0;
+}
+
+static int aureon_get_headphone_amp(ice1712_t *ice)
+{
+       unsigned int tmp = snd_ice1712_gpio_read(ice);
+
+       return ( tmp & AUREON_HP_SEL )!= 0;
+}
+
+static int aureon_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int aureon_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
+       return 0;
+}
+
+
+static int aureon_hpamp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+       return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
+}
+
+/*
+ * Deemphasis
+ */
+static int aureon_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
+       return 0;
+}
+
+static int aureon_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       int temp, temp2;
+       temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
+       if (ucontrol->value.integer.value[0])
+               temp |= 0xf;
+       else
+               temp &= ~0xf;
+       if (temp != temp2) {
+               wm_put(ice, WM_DAC_CTRL2, temp);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * ADC Oversampling
+ */
+static int aureon_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo)
+{
+       static char *texts[2] = { "128x", "64x" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+
+        return 0;
+}
+
+static int aureon_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
+       return 0;
+}
+
+static int aureon_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       int temp, temp2;
+       ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+
+       temp2 = temp = wm_get(ice, WM_MASTER);
+
+       if (ucontrol->value.enumerated.item[0])
+               temp |= 0x8;
+       else
+               temp &= ~0x8;
+
+       if (temp != temp2) {
+               wm_put(ice, WM_MASTER, temp);
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/*
+ * mixers
+ */
+
+static snd_kcontrol_new_t stac_controls[] __devinitdata = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = stac9460_dac_mute_info,
+               .get = stac9460_dac_mute_get,
+               .put = stac9460_dac_mute_put,
+               .private_value = 1,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Volume",
+               .info = stac9460_dac_vol_info,
+               .get = stac9460_dac_vol_get,
+               .put = stac9460_dac_vol_put,
+               .private_value = 1,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DAC Switch",
+               .count = 6,
+               .info = stac9460_dac_mute_info,
+               .get = stac9460_dac_mute_get,
+               .put = stac9460_dac_mute_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DAC Volume",
+               .count = 6,
+               .info = stac9460_dac_vol_info,
+               .get = stac9460_dac_vol_get,
+               .put = stac9460_dac_vol_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC Switch",
+               .count = 1,
+               .info = stac9460_adc_mute_info,
+               .get = stac9460_adc_mute_get,
+               .put = stac9460_adc_mute_put,
+
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC Volume",
+               .count = 1,
+               .info = stac9460_adc_vol_info,
+               .get = stac9460_adc_vol_get,
+               .put = stac9460_adc_vol_put,
+       },
+#if 0
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Route",
+               .info = wm_adc_mux_info,
+               .get = wm_adc_mux_get,
+               .put = wm_adc_mux_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphone Amplifier Switch",
+               .info = aureon_bool_info,
+               .get = aureon_hpamp_get,
+               .put = aureon_hpamp_put
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DAC Deemphasis Switch",
+               .info = aureon_bool_info,
+               .get = aureon_deemp_get,
+               .put = aureon_deemp_put
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC Oversampling",
+               .info = aureon_oversampling_info,
+               .get = aureon_oversampling_get,
+               .put = aureon_oversampling_put
+       },
+#endif
+};
+
+static int __devinit prodigy192_add_controls(ice1712_t *ice)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(stac_controls); i++) {
+               err = snd_ctl_add(ice->card, snd_ctl_new1(&stac_controls[i], ice));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+
+/*
+ * initialize the chip
+ */
+static int __devinit prodigy192_init(ice1712_t *ice)
+{
+       static unsigned short stac_inits_prodigy[] = {
+               STAC946X_RESET, 0,
+/*             STAC946X_MASTER_VOLUME, 0,
+               STAC946X_LF_VOLUME, 0,
+               STAC946X_RF_VOLUME, 0,
+               STAC946X_LR_VOLUME, 0,
+               STAC946X_RR_VOLUME, 0,
+               STAC946X_CENTER_VOLUME, 0,
+               STAC946X_LFE_VOLUME, 0,*/
+               (unsigned short)-1
+       };
+       unsigned short *p;
+
+       /* prodigy 192 */
+       ice->num_total_dacs = 6;
+       ice->num_total_adcs = 2;
+       
+       /* initialize codec */
+       p = stac_inits_prodigy;
+       for (; *p != (unsigned short)-1; p += 2)
+               stac9460_put(ice, p[0], p[1]);
+
+       return 0;
+}
+
+
+/*
+ * Aureon boards don't provide the EEPROM data except for the vendor IDs.
+ * hence the driver needs to sets up it properly.
+ */
+
+static unsigned char prodigy71_eeprom[] __devinitdata = {
+       0x2b,   /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */
+       0x80,   /* ACLINK: I2S */
+       0xf8,   /* I2S: vol, 96k, 24bit, 192k */
+       0xc3,   /* SPDIF: out-en, out-int, spdif-in */
+       0xff,   /* GPIO_DIR */
+       0xff,   /* GPIO_DIR1 */
+       0xbf,   /* GPIO_DIR2 */
+       0x00,   /* GPIO_MASK */
+       0x00,   /* GPIO_MASK1 */
+       0x00,   /* GPIO_MASK2 */
+       0x00,   /* GPIO_STATE */
+       0x00,   /* GPIO_STATE1 */
+       0x00,   /* GPIO_STATE2 */
+};
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
+       {
+               .subvendor = VT1724_SUBDEVICE_PRODIGY192VE,
+               .name = "Audiotrak Prodigy 192",
+               .model = "prodigy192",
+               .chip_init = prodigy192_init,
+               .build_controls = prodigy192_add_controls,
+               .eeprom_size = sizeof(prodigy71_eeprom),
+               .eeprom_data = prodigy71_eeprom,
+       },
+       { } /* terminator */
+};
diff --git a/sound/pci/ice1712/prodigy192.h b/sound/pci/ice1712/prodigy192.h
new file mode 100644 (file)
index 0000000..94c824e
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __SOUND_PRODIGY192_H
+#define __SOUND_PRODIGY192_H
+
+#define PRODIGY192_DEVICE_DESC                "{AudioTrak,Prodigy 192},"
+#define PRODIGY192_STAC9460_ADDR       0x54
+
+#define VT1724_SUBDEVICE_PRODIGY192VE   0x34495345     /* PRODIGY 192 VE */
+
+extern struct snd_ice1712_card_info  snd_vt1724_prodigy192_cards[];
+
+#endif /* __SOUND_PRODIGY192_H */
diff --git a/sound/pci/ice1712/stac946x.h b/sound/pci/ice1712/stac946x.h
new file mode 100644 (file)
index 0000000..5b39095
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __SOUND_STAC946X_H
+#define __SOUND_STAC946X_H
+
+#define STAC946X_RESET                 0x00
+#define STAC946X_STATUS                        0x01
+#define STAC946X_MASTER_VOLUME         0x02
+#define STAC946X_LF_VOLUME             0x03
+#define STAC946X_RF_VOLUME             0x04
+#define STAC946X_LR_VOLUME             0x05
+#define STAC946X_RR_VOLUME             0x06
+#define STAC946X_CENTER_VOLUME         0x07
+#define STAC946X_LFE_VOLUME            0x08
+#define STAC946X_MIC_L_VOLUME          0x09
+#define STAC946X_MIC_R_VOLUME          0x0a
+#define STAC946X_DEEMPHASIS            0x0c
+#define STAC946X_GENERAL_PURPOSE       0x0d
+#define STAC946X_AUDIO_PORT_CONTROL    0x0e
+#define STAC946X_MASTER_CLOCKING       0x0f
+#define STAC946X_POWERDOWN_CTRL1       0x10
+#define STAC946X_POWERDOWN_CTRL2       0x11
+#define STAC946X_REVISION_CODE         0x12
+#define STAC946X_ADDRESS_CONTROL       0x13
+#define STAC946X_ADDRESS               0x14
+
+#endif  /*  __SOUND_STAC946X_H */
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c
new file mode 100644 (file)
index 0000000..868f6fe
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *   ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT)
+ *
+ *   Lowlevel functions for VT1720-based motherboards
+ *
+ *     Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "vt1720_mobo.h"
+
+
+static int __devinit k8x800_init(ice1712_t *ice)
+{
+       ice->vt1720 = 1;
+
+       /* VT1616 codec */
+       ice->num_total_dacs = 6;
+       ice->num_total_adcs = 2;
+
+       /* WM8728 codec */
+       /* FIXME: TODO */
+
+       return 0;
+}
+
+static int __devinit k8x800_add_controls(ice1712_t *ice)
+{
+       /* FIXME: needs some quirks for VT1616? */
+       return 0;
+}
+
+/* EEPROM image */
+
+static unsigned char k8x800_eeprom[] __devinitdata = {
+       0x01,   /* SYSCONF: clock 256, 1ADC, 2DACs */
+       0x02,   /* ACLINK: ACLINK, packed */
+       0x00,   /* I2S: - */
+       0x00,   /* SPDIF: - */
+       0xff,   /* GPIO_DIR */
+       0xff,   /* GPIO_DIR1 */
+       0x00,   /* - */
+       0xff,   /* GPIO_MASK */
+       0xff,   /* GPIO_MASK1 */
+       0x00,   /* - */
+       0x00,   /* GPIO_STATE */
+       0x00,   /* GPIO_STATE1 */
+       0x00,   /* - */
+};
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
+       {
+               .subvendor = VT1720_SUBDEVICE_K8X800,
+               .name = "Albatron K8X800 Pro II",
+               .model = "k8x800",
+               .chip_init = k8x800_init,
+               .build_controls = k8x800_add_controls,
+               .eeprom_size = sizeof(k8x800_eeprom),
+               .eeprom_data = k8x800_eeprom,
+       },
+       {
+               .subvendor = VT1720_SUBDEVICE_ZNF3_150,
+               .name = "Chaintech ZNF3-150",
+               /* identical with k8x800 */
+               .chip_init = k8x800_init,
+               .build_controls = k8x800_add_controls,
+               .eeprom_size = sizeof(k8x800_eeprom),
+               .eeprom_data = k8x800_eeprom,
+       },
+       {
+               .subvendor = VT1720_SUBDEVICE_ZNF3_250,
+               .name = "Chaintech ZNF3-250",
+               /* identical with k8x800 */
+               .chip_init = k8x800_init,
+               .build_controls = k8x800_add_controls,
+               .eeprom_size = sizeof(k8x800_eeprom),
+               .eeprom_data = k8x800_eeprom,
+       },
+       { } /* terminator */
+};
+
diff --git a/sound/pci/ice1712/vt1720_mobo.h b/sound/pci/ice1712/vt1720_mobo.h
new file mode 100644 (file)
index 0000000..552be2c
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __SOUND_VT1720_MOBO_H
+#define __SOUND_VT1720_MOBO_H
+
+/*
+ *   ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT)
+ *
+ *   Lowlevel functions for VT1720-based motherboards
+ *
+ *     Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#define VT1720_MOBO_DEVICE_DESC        "{Albatron,K8X800 Pro II},"\
+                                      "{Chaintech,ZNF3-150},"\
+                                      "{Chaintech,ZNF3-250},"
+
+#define VT1720_SUBDEVICE_K8X800                0xf217052c
+#define VT1720_SUBDEVICE_ZNF3_150      0x0f2741f6
+#define VT1720_SUBDEVICE_ZNF3_250      0x0f2745f6
+
+extern struct snd_ice1712_card_info  snd_vt1720_mobo_cards[];
+
+#endif /* __SOUND_VT1720_MOBO_H */
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
new file mode 100644 (file)
index 0000000..c23f601
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Beep using pcm
+ *
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include "pmac.h"
+
+struct snd_pmac_beep {
+       int running;    /* boolean */
+       int volume;     /* mixer volume: 0-100 */
+       int volume_play;        /* currently playing volume */
+       int hz;
+       int nsamples;
+       short *buf;             /* allocated wave buffer */
+       unsigned long addr;     /* physical address of buffer */
+       struct input_dev dev;
+};
+
+/*
+ * stop beep if running
+ */
+void snd_pmac_beep_stop(pmac_t *chip)
+{
+       pmac_beep_t *beep = chip->beep;
+       if (beep && beep->running) {
+               beep->running = 0;
+               snd_pmac_beep_dma_stop(chip);
+       }
+}
+
+/*
+ * Stuff for outputting a beep.  The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+       0,      40,     79,     117,    153,    187,    218,    245,
+       269,    288,    304,    316,    323,    327,    327,    324,
+       318,    310,    299,    288,    275,    262,    249,    236,
+       224,    213,    204,    196,    190,    186,    183,    182,
+       182,    183,    186,    189,    192,    196,    200,    203,
+       206,    208,    209,    209,    209,    207,    204,    201,
+       197,    193,    188,    183,    179,    174,    170,    166,
+       163,    161,    160,    159,    159,    160,    161,    162,
+       164,    166,    168,    169,    171,    171,    171,    170,
+       169,    167,    163,    159,    155,    150,    144,    139,
+       133,    128,    122,    117,    113,    110,    107,    105,
+       103,    103,    103,    103,    104,    104,    105,    105,
+       105,    103,    101,    97,     92,     86,     78,     68,
+       58,     45,     32,     18,     3,      -11,    -26,    -41,
+       -55,    -68,    -79,    -88,    -95,    -100,   -102,   -102,
+       -99,    -93,    -85,    -75,    -62,    -48,    -33,    -16,
+       0,      16,     33,     48,     62,     75,     85,     93,
+       99,     102,    102,    100,    95,     88,     79,     68,
+       55,     41,     26,     11,     -3,     -18,    -32,    -45,
+       -58,    -68,    -78,    -86,    -92,    -97,    -101,   -103,
+       -105,   -105,   -105,   -104,   -104,   -103,   -103,   -103,
+       -103,   -105,   -107,   -110,   -113,   -117,   -122,   -128,
+       -133,   -139,   -144,   -150,   -155,   -159,   -163,   -167,
+       -169,   -170,   -171,   -171,   -171,   -169,   -168,   -166,
+       -164,   -162,   -161,   -160,   -159,   -159,   -160,   -161,
+       -163,   -166,   -170,   -174,   -179,   -183,   -188,   -193,
+       -197,   -201,   -204,   -207,   -209,   -209,   -209,   -208,
+       -206,   -203,   -200,   -196,   -192,   -189,   -186,   -183,
+       -182,   -182,   -183,   -186,   -190,   -196,   -204,   -213,
+       -224,   -236,   -249,   -262,   -275,   -288,   -299,   -310,
+       -318,   -324,   -327,   -327,   -323,   -316,   -304,   -288,
+       -269,   -245,   -218,   -187,   -153,   -117,   -79,    -40,
+};
+
+#define BEEP_SRATE     22050   /* 22050 Hz sample rate */
+#define BEEP_BUFLEN    512
+#define BEEP_VOLUME    15      /* 0 - 100 */
+
+static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, unsigned int code, int hz)
+{
+       pmac_t *chip;
+       pmac_beep_t *beep;
+       unsigned long flags;
+       int beep_speed = 0;
+       int srate;
+       int period, ncycles, nsamples;
+       int i, j, f;
+       short *p;
+
+       if (type != EV_SND)
+               return -1;
+
+       switch (code) {
+       case SND_BELL: if (hz) hz = 1000;
+       case SND_TONE: break;
+       default: return -1;
+       }
+
+       chip = dev->private;
+       if (! chip || (beep = chip->beep) == NULL)
+               return -1;
+
+       if (! hz) {
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               if (beep->running)
+                       snd_pmac_beep_stop(chip);
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               return 0;
+       }
+
+       beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
+       srate = chip->freq_table[beep_speed];
+
+       if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
+               hz = 1000;
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       if (chip->playback.running || chip->capture.running || beep->running) {
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               return 0;
+       }
+       beep->running = 1;
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+       if (hz == beep->hz && beep->volume == beep->volume_play) {
+               nsamples = beep->nsamples;
+       } else {
+               period = srate * 256 / hz;      /* fixed point */
+               ncycles = BEEP_BUFLEN * 256 / period;
+               nsamples = (period * ncycles) >> 8;
+               f = ncycles * 65536 / nsamples;
+               j = 0;
+               p = beep->buf;
+               for (i = 0; i < nsamples; ++i, p += 2) {
+                       p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
+                       j = (j + f) & 0xffff;
+               }
+               beep->hz = hz;
+               beep->volume_play = beep->volume;
+               beep->nsamples = nsamples;
+       }
+
+       spin_lock_irqsave(&chip->reg_lock, flags);
+       snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
+       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       return 0;
+}
+
+/*
+ * beep volume mixer
+ */
+
+#define chip_t pmac_t
+
+static int snd_pmac_info_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 100;
+       return 0;
+}
+
+static int snd_pmac_get_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       pmac_t *chip = snd_kcontrol_chip(kcontrol);
+       snd_assert(chip->beep, return -ENXIO);
+       ucontrol->value.integer.value[0] = chip->beep->volume;
+       return 0;
+}
+
+static int snd_pmac_put_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+       pmac_t *chip = snd_kcontrol_chip(kcontrol);
+       int oval;
+       snd_assert(chip->beep, return -ENXIO);
+       oval = chip->beep->volume;
+       chip->beep->volume = ucontrol->value.integer.value[0];
+       return oval != chip->beep->volume;
+}
+
+static snd_kcontrol_new_t snd_pmac_beep_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Beep Playback Volume",
+       .info = snd_pmac_info_beep,
+       .get = snd_pmac_get_beep,
+       .put = snd_pmac_put_beep,
+};
+
+/* Initialize beep stuff */
+int __init snd_pmac_attach_beep(pmac_t *chip)
+{
+       pmac_beep_t *beep;
+       int err;
+
+       beep = kmalloc(sizeof(*beep), GFP_KERNEL);
+       if (! beep)
+               return -ENOMEM;
+
+       memset(beep, 0, sizeof(*beep));
+       beep->buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+       if (! beep->buf) {
+               kfree(beep);
+               return -ENOMEM;
+       }
+       beep->addr = virt_to_bus(beep->buf);
+
+       beep->dev.evbit[0] = BIT(EV_SND);
+       beep->dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+       beep->dev.event = snd_pmac_beep_event;
+       beep->dev.private = chip;
+
+       /* FIXME: set more better values */
+       beep->dev.name = "PowerMac Beep";
+       beep->dev.phys = "powermac/beep";
+       beep->dev.id.bustype = BUS_ADB;
+       beep->dev.id.vendor = 0x001f;
+       beep->dev.id.product = 0x0001;
+       beep->dev.id.version = 0x0100;
+
+       beep->volume = BEEP_VOLUME;
+       beep->running = 0;
+       if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip))) < 0) {
+               kfree(beep->buf);
+               kfree(beep);
+               return err;
+       }
+
+       chip->beep = beep;
+       input_register_device(&beep->dev);
+
+       return 0;
+}
+
+void snd_pmac_detach_beep(pmac_t *chip)
+{
+       if (chip->beep) {
+               input_unregister_device(&chip->beep->dev);
+               kfree(chip->beep->buf);
+               kfree(chip->beep);
+               chip->beep = NULL;
+       }
+}
diff --git a/sound/usb/usx2y/Makefile b/sound/usb/usx2y/Makefile
new file mode 100644 (file)
index 0000000..97d2bf2
--- /dev/null
@@ -0,0 +1,3 @@
+snd-usb-usx2y-objs := usbusx2y.o usbusx2yaudio.o usX2Yhwdep.o
+
+obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
new file mode 100644 (file)
index 0000000..e6717f3
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Driver for Tascam US-X2Y USB soundcards
+ *
+ * FPGA Loader + ALSA Startup
+ *
+ * Copyright (c) 2003 by Karsten Wiese <annabellesgarden@yahoo.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+#include <sound/memalloc.h>
+#include <sound/pcm.h>
+#include <sound/hwdep.h>
+#include "usx2y.h"
+#include "usbusx2y.h"
+#include "usX2Yhwdep.h"
+
+
+static struct page * snd_us428ctls_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
+{
+       unsigned long offset;
+       struct page * page;
+       void *vaddr;
+
+       snd_printdd("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n",
+                  area->vm_start,
+                  address - area->vm_start,
+                  (address - area->vm_start) >> PAGE_SHIFT,
+                  address);
+       
+       offset = area->vm_pgoff << PAGE_SHIFT;
+       offset += address - area->vm_start;
+       snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
+       vaddr = (char*)((usX2Ydev_t*)area->vm_private_data)->us428ctls_sharedmem + offset;
+       page = virt_to_page(vaddr);
+       get_page(page);
+       snd_printdd( "vaddr=%p made us428ctls_vm_nopage() return %p; offset=%lX\n", vaddr, page, offset);
+
+       if (type)
+               *type = VM_FAULT_MINOR;
+
+       return page;
+}
+
+static struct vm_operations_struct us428ctls_vm_ops = {
+       .nopage = snd_us428ctls_vm_nopage,
+};
+
+static int snd_us428ctls_mmap(snd_hwdep_t * hw, struct file *filp, struct vm_area_struct *area)
+{
+       unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
+       usX2Ydev_t      *us428 = (usX2Ydev_t*)hw->private_data;
+
+       // FIXME this hwdep interface is used twice: fpga download and mmap for controlling Lights etc. Maybe better using 2 hwdep devs?
+       // so as long as the device isn't fully initialised yet we return -EBUSY here.
+       if (!(((usX2Ydev_t*)hw->private_data)->chip_status & USX2Y_STAT_CHIP_INIT))
+               return -EBUSY;
+
+       /* if userspace tries to mmap beyond end of our buffer, fail */ 
+        if (size > ((PAGE_SIZE - 1 + sizeof(us428ctls_sharedmem_t)) / PAGE_SIZE) * PAGE_SIZE) {
+               snd_printd( "%lu > %lu\n", size, (unsigned long)sizeof(us428ctls_sharedmem_t)); 
+                return -EINVAL;
+       }
+
+       if (!us428->us428ctls_sharedmem) {
+               init_waitqueue_head(&us428->us428ctls_wait_queue_head);
+               if(!(us428->us428ctls_sharedmem = snd_malloc_pages(sizeof(us428ctls_sharedmem_t), GFP_KERNEL)))
+                       return -ENOMEM;
+               memset(us428->us428ctls_sharedmem, -1, sizeof(us428ctls_sharedmem_t));
+               us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
+       }
+       area->vm_ops = &us428ctls_vm_ops;
+       area->vm_flags |= VM_RESERVED;
+       area->vm_private_data = hw->private_data;
+       return 0;
+}
+
+static unsigned int snd_us428ctls_poll(snd_hwdep_t *hw, struct file *file, poll_table *wait)
+{
+       unsigned int    mask = 0;
+       usX2Ydev_t      *us428 = (usX2Ydev_t*)hw->private_data;
+       static unsigned LastN;
+
+       if (us428->chip_status & USX2Y_STAT_CHIP_HUP)
+               return POLLHUP;
+
+       poll_wait(file, &us428->us428ctls_wait_queue_head, wait);
+
+       down(&us428->open_mutex);
+       if (us428->us428ctls_sharedmem
+           && us428->us428ctls_sharedmem->CtlSnapShotLast != LastN) {
+               mask |= POLLIN;
+               LastN = us428->us428ctls_sharedmem->CtlSnapShotLast;
+       }
+       up(&us428->open_mutex);
+
+       return mask;
+}
+
+
+static int snd_usX2Y_hwdep_open(snd_hwdep_t *hw, struct file *file)
+{
+       return 0;
+}
+
+static int snd_usX2Y_hwdep_release(snd_hwdep_t *hw, struct file *file)
+{
+       return 0;
+}
+
+static int snd_usX2Y_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
+{
+       static char *type_ids[USX2Y_TYPE_NUMS] = {
+               [USX2Y_TYPE_122] = "us122",
+               [USX2Y_TYPE_224] = "us224",
+               [USX2Y_TYPE_428] = "us428",
+       };
+       int id = -1;
+
+       switch (((usX2Ydev_t*)hw->private_data)->chip.dev->descriptor.idProduct) {
+       case USB_ID_US122:
+               id = USX2Y_TYPE_122;
+               break;
+       case USB_ID_US224:
+               id = USX2Y_TYPE_224;
+               break;
+       case USB_ID_US428:
+               id = USX2Y_TYPE_428;
+               break;
+       }
+       if (0 > id)
+               return -ENODEV;
+       strcpy(info->id, type_ids[id]);
+       info->num_dsps = 2;             // 0: Prepad Data, 1: FPGA Code
+       if (((usX2Ydev_t*)hw->private_data)->chip_status & USX2Y_STAT_CHIP_INIT) 
+               info->chip_ready = 1;
+       info->version = USX2Y_DRIVER_VERSION; 
+       return 0;
+}
+
+
+static int usX2Y_create_usbmidi(snd_card_t* card )
+{
+       static snd_usb_midi_endpoint_info_t quirk_data_1 = {
+               .out_ep =0x06,
+               .in_ep = 0x06,
+               .out_cables =   0x001,
+               .in_cables =    0x001
+       };
+       static snd_usb_audio_quirk_t quirk_1 = {
+               .vendor_name =  "TASCAM",
+               .product_name = NAME_ALLCAPS,
+               .ifnum =        0,
+                       .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = &quirk_data_1
+       };
+       static snd_usb_midi_endpoint_info_t quirk_data_2 = {
+               .out_ep =0x06,
+               .in_ep = 0x06,
+               .out_cables =   0x003,
+               .in_cables =    0x003
+       };
+       static snd_usb_audio_quirk_t quirk_2 = {
+               .vendor_name =  "TASCAM",
+               .product_name = "US428",
+               .ifnum =        0,
+                       .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = &quirk_data_2
+       };
+       struct usb_device *dev = usX2Y(card)->chip.dev;
+       struct usb_interface *iface = usb_ifnum_to_if(dev, 0);
+       snd_usb_audio_quirk_t *quirk = dev->descriptor.idProduct == USB_ID_US428 ? &quirk_2 : &quirk_1;
+
+       snd_printdd("usX2Y_create_usbmidi \n");
+       return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk);
+}
+
+static int usX2Y_create_alsa_devices(snd_card_t* card)
+{
+       int err;
+
+       do {
+               if ((err = usX2Y_create_usbmidi(card)) < 0) {
+                       snd_printk("usX2Y_create_alsa_devices: usX2Y_create_usbmidi error %i \n", err);
+                       break;
+               }
+               if ((err = usX2Y_audio_create(card)) < 0) 
+                       break;
+               if ((err = snd_card_register(card)) < 0)
+                       break;
+       } while (0);
+
+       return err;
+} 
+
+static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
+{
+       usX2Ydev_t *priv = hw->private_data;
+       int     lret, err = -EINVAL;
+       snd_printdd( "dsp_load %s\n", dsp->name);
+
+       if (access_ok(VERIFY_READ, dsp->image, dsp->length)) {
+               struct usb_device* dev = priv->chip.dev;
+               char *buf = kmalloc(dsp->length, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+               if (copy_from_user(buf, dsp->image, dsp->length)) {
+                       kfree(buf);
+                       return -EFAULT;
+               }
+               err = usb_set_interface(dev, 0, 1);
+               if (err)
+                       snd_printk("usb_set_interface error \n");
+               else
+                       err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6*HZ);
+               kfree(buf);
+       }
+       if (err)
+               return err;
+       if (dsp->index == 1) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(HZ/4);                 // give the device some time 
+               err = usX2Y_AsyncSeq04_init(priv);
+               if (err) {
+                       snd_printk("usX2Y_AsyncSeq04_init error \n");
+                       return err;
+               }
+               err = usX2Y_In04_init(priv);
+               if (err) {
+                       snd_printk("usX2Y_In04_init error \n");
+                       return err;
+               }
+               err = usX2Y_create_alsa_devices(hw->card);
+               if (err) {
+                       snd_printk("usX2Y_create_alsa_devices error %i \n", err);
+                       snd_card_free(hw->card);
+                       return err;
+               }
+               priv->chip_status |= USX2Y_STAT_CHIP_INIT; 
+               snd_printdd("%s: alsa all started\n", hw->name);
+       }
+       return err;
+}
+
+
+int usX2Y_hwdep_new(snd_card_t* card, struct usb_device* device)
+{
+       int err;
+       snd_hwdep_t *hw;
+
+       if ((err = snd_hwdep_new(card, SND_USX2Y_LOADER_ID, 0, &hw)) < 0)
+               return err;
+
+       hw->iface = SNDRV_HWDEP_IFACE_USX2Y;
+       hw->private_data = usX2Y(card);
+       hw->ops.open = snd_usX2Y_hwdep_open;
+       hw->ops.release = snd_usX2Y_hwdep_release;
+       hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status;
+       hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load;
+       hw->ops.mmap = snd_us428ctls_mmap;
+       hw->ops.poll = snd_us428ctls_poll;
+       hw->exclusive = 1;
+       sprintf(hw->name, "/proc/bus/usb/%03d/%03d", device->bus->busnum, device->devnum);
+       return 0;
+}
+
diff --git a/sound/usb/usx2y/usX2Yhwdep.h b/sound/usb/usx2y/usX2Yhwdep.h
new file mode 100644 (file)
index 0000000..d612a26
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef USX2YHWDEP_H
+#define USX2YHWDEP_H
+
+int usX2Y_hwdep_new(snd_card_t* card, struct usb_device* device);
+
+#endif
diff --git a/sound/usb/usx2y/usbus428ctldefs.h b/sound/usb/usx2y/usbus428ctldefs.h
new file mode 100644 (file)
index 0000000..6af1643
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright (c) 2003 by Karsten Wiese <annabellesgarden@yahoo.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+enum E_In84{
+       eFader0 = 0,
+       eFader1,
+       eFader2,
+       eFader3,
+       eFader4,
+       eFader5,
+       eFader6,
+       eFader7,
+       eFaderM,
+       eTransport,
+       eModifier = 10,
+       eFilterSelect,
+       eSelect,
+       eMute,
+
+       eSwitch   = 15,
+       eWheelGain,
+       eWheelFreq,
+       eWheelQ,
+       eWheelPan,
+       eWheel    = 20
+};
+
+#define T_RECORD   1
+#define T_PLAY     2
+#define T_STOP     4
+#define T_F_FWD    8
+#define T_REW   0x10
+#define T_SOLO  0x20
+#define T_REC   0x40
+#define T_NULL  0x80
+
+
+struct us428_ctls{
+       unsigned char   Fader[9];
+       unsigned char   Transport;
+       unsigned char   Modifier;
+       unsigned char   FilterSelect;
+       unsigned char   Select;
+       unsigned char   Mute;
+       unsigned char   UNKNOWN;
+       unsigned char   Switch;      
+       unsigned char   Wheel[5];
+};
+
+typedef struct us428_ctls us428_ctls_t;
+
+typedef struct us428_setByte{
+       unsigned char Offset,
+               Value;
+}us428_setByte_t;
+
+enum {
+       eLT_Volume = 0,
+       eLT_Light
+};
+
+typedef struct usX2Y_volume {
+       unsigned char Channel,
+               LH,
+               LL,
+               RH,
+               RL;
+} usX2Y_volume_t;
+
+struct us428_lights{
+       us428_setByte_t Light[7];
+};
+typedef struct us428_lights us428_lights_t;
+
+typedef struct {
+       char type;
+       union {
+               usX2Y_volume_t  vol;
+               us428_lights_t  lights;
+       } val;
+} us428_p4out_t;
+
+#define N_us428_ctl_BUFS 16
+#define N_us428_p4out_BUFS 16
+struct us428ctls_sharedmem{
+       us428_ctls_t    CtlSnapShot[N_us428_ctl_BUFS];
+       int             CtlSnapShotDiffersAt[N_us428_ctl_BUFS];
+       int             CtlSnapShotLast, CtlSnapShotRed;
+       us428_p4out_t   p4out[N_us428_p4out_BUFS];
+       int             p4outLast, p4outSent;
+};
+typedef struct us428ctls_sharedmem us428ctls_sharedmem_t;
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
new file mode 100644 (file)
index 0000000..44a7381
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * usbus428.c - ALSA USB US-428 Driver
+ *
+2004-07-13 Karsten Wiese
+       Version 0.7.1:
+       Don't sleep in START/STOP callbacks anymore.
+       us428 channels C/D not handled just for this version, sorry.
+
+2004-06-21 Karsten Wiese
+       Version 0.6.4:
+       Temporarely suspend midi input
+       to sanely call usb_set_interface() when setting format.
+
+2004-06-12 Karsten Wiese
+       Version 0.6.3:
+       Made it thus the following rule is enforced:
+       "All pcm substreams of one usX2Y have to operate at the same rate & format."
+
+2004-04-06 Karsten Wiese
+       Version 0.6.0:
+       Runs on 2.6.5 kernel without any "--with-debug=" things.
+       us224 reported running.
+
+2004-01-14 Karsten Wiese
+       Version 0.5.1:
+       Runs with 2.6.1 kernel.
+
+2003-12-30 Karsten Wiese
+       Version 0.4.1:
+       Fix 24Bit 4Channel capturing for the us428.
+
+2003-11-27 Karsten Wiese, Martin Langer
+       Version 0.4:
+       us122 support.
+       us224 could be tested by uncommenting the sections containing USB_ID_US224
+
+2003-11-03 Karsten Wiese
+       Version 0.3:
+       24Bit support. 
+       "arecord -D hw:1 -c 2 -r 48000 -M -f S24_3LE|aplay -D hw:1 -c 2 -r 48000 -M -f S24_3LE" works.
+
+2003-08-22 Karsten Wiese
+       Version 0.0.8:
+       Removed EZUSB Firmware. First Stage Firmwaredownload is now done by tascam-firmware downloader.
+       See:
+       http://usb-midi-fw.sourceforge.net/tascam-firmware.tar.gz
+
+2003-06-18 Karsten Wiese
+       Version 0.0.5:
+       changed to compile with kernel 2.4.21 and alsa 0.9.4
+
+2002-10-16 Karsten Wiese
+       Version 0.0.4:
+       compiles again with alsa-current.
+       USB_ISO_ASAP not used anymore (most of the time), instead
+       urb->start_frame is calculated here now, some calls inside usb-driver don't need to happen anymore.
+
+       To get the best out of this:
+       Disable APM-support in the kernel as APM-BIOS calls (once each second) hard disable interrupt for many precious milliseconds.
+       This helped me much on my slowish PII 400 & PIII 500.
+       ACPI yet untested but might cause the same bad behaviour.
+       Use a kernel with lowlatency and preemptiv patches applied.
+       To autoload snd-usb-midi append a line 
+               post-install snd-usb-us428 modprobe snd-usb-midi
+       to /etc/modules.conf.
+
+       known problems:
+       sliders, knobs, lights not yet handled except MASTER Volume slider.
+               "pcm -c 2" doesn't work. "pcm -c 2 -m direct_interleaved" does.
+       KDE3: "Enable full duplex operation" deadlocks.
+
+       
+2002-08-31 Karsten Wiese
+       Version 0.0.3: audio also simplex;
+       simplifying: iso urbs only 1 packet, melted structs.
+       ASYNC_UNLINK not used anymore: no more crashes so far.....
+       for alsa 0.9 rc3.
+
+2002-08-09 Karsten Wiese
+       Version 0.0.2: midi works with snd-usb-midi, audio (only fullduplex now) with i.e. bristol.
+       The firmware has been sniffed from win2k us-428 driver 3.09.
+
+ *   Copyright (c) 2002 Karsten Wiese
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#include <sound/rawmidi.h>
+#include "usx2y.h"
+#include "usbusx2y.h"
+#include "usX2Yhwdep.h"
+
+
+
+MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
+MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.7.2");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
+static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
+static int boot_devs;
+
+module_param_array(index, int, boot_devs, 0444);
+MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
+module_param_array(id, charp, boot_devs, 0444);
+MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
+module_param_array(enable, bool, boot_devs, 0444);
+MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
+
+
+static int snd_usX2Y_card_used[SNDRV_CARDS];
+
+static void usX2Y_usb_disconnect(struct usb_device* usb_device, void* ptr);
+static void snd_usX2Y_card_private_free(snd_card_t *card);
+
+/* 
+ * pipe 4 is used for switching the lamps, setting samplerate, volumes ....   
+ */
+static void i_usX2Y_Out04Int(struct urb* urb, struct pt_regs *regs)
+{
+#ifdef CONFIG_SND_DEBUG
+       if (urb->status) {
+               int             i;
+               usX2Ydev_t*     usX2Y = urb->context;
+               for (i = 0; i < 10 && usX2Y->AS04.urb[i] != urb; i++);
+               snd_printdd("i_usX2Y_Out04Int() urb %i status=%i\n", i, urb->status);
+       }
+#endif
+}
+
+static void i_usX2Y_In04Int(struct urb* urb, struct pt_regs *regs)
+{
+       int                     err = 0;
+       usX2Ydev_t              *usX2Y = urb->context;
+       us428ctls_sharedmem_t   *us428ctls = usX2Y->us428ctls_sharedmem;
+
+       usX2Y->In04IntCalls++;
+
+       if (urb->status) {
+               snd_printdd("Interrupt Pipe 4 came back with status=%i\n", urb->status);
+               return;
+       }
+
+       //      printk("%i:0x%02X ", 8, (int)((unsigned char*)usX2Y->In04Buf)[8]); Master volume shows 0 here if fader is at max during boot ?!?
+       if (us428ctls) {
+               int diff = -1;
+               if (-2 == us428ctls->CtlSnapShotLast) {
+                       diff = 0;
+                       memcpy(usX2Y->In04Last, usX2Y->In04Buf, sizeof(usX2Y->In04Last));
+                       us428ctls->CtlSnapShotLast = -1;
+               } else {
+                       int i;
+                       for (i = 0; i < 21; i++) {
+                               if (usX2Y->In04Last[i] != ((char*)usX2Y->In04Buf)[i]) {
+                                       if (diff < 0)
+                                               diff = i;
+                                       usX2Y->In04Last[i] = ((char*)usX2Y->In04Buf)[i];
+                               }
+                       }
+               }
+               if (0 <= diff) {
+                       int n = us428ctls->CtlSnapShotLast + 1;
+                       if (n >= N_us428_ctl_BUFS  ||  n < 0)
+                               n = 0;
+                       memcpy(us428ctls->CtlSnapShot + n, usX2Y->In04Buf, sizeof(us428ctls->CtlSnapShot[0]));
+                       us428ctls->CtlSnapShotDiffersAt[n] = diff;
+                       us428ctls->CtlSnapShotLast = n;
+                       wake_up(&usX2Y->us428ctls_wait_queue_head);
+               }
+       }
+       
+       
+       if (usX2Y->US04) {
+               if (0 == usX2Y->US04->submitted)
+                       do
+                               err = usb_submit_urb(usX2Y->US04->urb[usX2Y->US04->submitted++], GFP_ATOMIC);
+                       while (!err && usX2Y->US04->submitted < usX2Y->US04->len);
+       } else
+               if (us428ctls && us428ctls->p4outLast >= 0 && us428ctls->p4outLast < N_us428_p4out_BUFS) {
+                       if (us428ctls->p4outLast != us428ctls->p4outSent) {
+                               int j, send = us428ctls->p4outSent + 1;
+                               if (send >= N_us428_p4out_BUFS)
+                                       send = 0;
+                               for (j = 0; j < URBS_AsyncSeq  &&  !err; ++j)
+                                       if (0 == usX2Y->AS04.urb[j]->status) {
+                                               us428_p4out_t *p4out = us428ctls->p4out + send; // FIXME if more then 1 p4out is new, 1 gets lost.
+                                               usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev,
+                                                                 usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, 
+                                                                 p4out->type == eLT_Light ? sizeof(us428_lights_t) : 5,
+                                                                 i_usX2Y_Out04Int, usX2Y);
+                                               err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC);
+                                               us428ctls->p4outSent = send;
+                                               break;
+                                       }
+                       }
+               }
+
+       if (err) {
+               snd_printk("In04Int() usb_submit_urb err=%i\n", err);
+       }
+
+       urb->dev = usX2Y->chip.dev;
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Prepare some urbs
+ */
+int usX2Y_AsyncSeq04_init(usX2Ydev_t* usX2Y)
+{
+       int     err = 0,
+               i;
+
+       if (NULL == (usX2Y->AS04.buffer = kmalloc(URB_DataLen_AsyncSeq*URBS_AsyncSeq, GFP_KERNEL))) {
+               err = -ENOMEM;
+       } else
+               for (i = 0; i < URBS_AsyncSeq; ++i) {
+                       if (NULL == (usX2Y->AS04.urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       usb_fill_bulk_urb(      usX2Y->AS04.urb[i], usX2Y->chip.dev,
+                                               usb_sndbulkpipe(usX2Y->chip.dev, 0x04),
+                                               usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0,
+                                               i_usX2Y_Out04Int, usX2Y
+                               );
+               }
+       return err;
+}
+
+int usX2Y_In04_init(usX2Ydev_t* usX2Y)
+{
+       int     err = 0;
+       if (! (usX2Y->In04urb = usb_alloc_urb(0, GFP_KERNEL)))
+               return -ENOMEM;
+
+       if (! (usX2Y->In04Buf = kmalloc(21, GFP_KERNEL))) {
+               usb_free_urb(usX2Y->In04urb);
+               return -ENOMEM;
+       }
+        
+       init_waitqueue_head(&usX2Y->In04WaitQueue);
+       usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4),
+                        usX2Y->In04Buf, 21,
+                        i_usX2Y_In04Int, usX2Y,
+                        10);
+       err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL);
+       return err;
+}
+
+static void usX2Y_unlinkSeq(snd_usX2Y_AsyncSeq_t* S)
+{
+       int     i;
+       for (i = 0; i < URBS_AsyncSeq; ++i) {
+               if (S[i].urb) {
+                       usb_unlink_urb(S->urb[i]);
+                       usb_free_urb(S->urb[i]);
+                       S->urb[i] = NULL;
+               }
+       }
+       if (S->buffer)
+               kfree(S->buffer);
+}
+
+
+static struct usb_device_id snd_usX2Y_usb_id_table[] = {
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     0x1604,
+               .idProduct =    USB_ID_US428 
+       },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     0x1604,
+               .idProduct =    USB_ID_US122 
+       },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     0x1604,
+               .idProduct =    USB_ID_US224
+       },
+       { /* terminator */ }
+};
+
+static snd_card_t* usX2Y_create_card(struct usb_device* device)
+{
+       int             dev;
+       snd_card_t*     card;
+       for (dev = 0; dev < SNDRV_CARDS; ++dev)
+               if (enable[dev] && !snd_usX2Y_card_used[dev])
+                       break;
+       if (dev >= SNDRV_CARDS)
+               return NULL;
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(usX2Ydev_t));
+       if (!card)
+               return NULL;
+       snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1;
+       card->private_free = snd_usX2Y_card_private_free;
+       usX2Y(card)->chip.dev = device;
+       usX2Y(card)->chip.card = card;
+       init_MUTEX (&usX2Y(card)->open_mutex);
+       INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list);
+       strcpy(card->driver, "USB "NAME_ALLCAPS"");
+       sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
+       sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
+               card->shortname, 
+               device->descriptor.idVendor, device->descriptor.idProduct,
+               0,//us428(card)->usbmidi.ifnum,
+               usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
+               );
+       snd_card_set_dev(card, &device->dev);
+       return card;
+}
+
+
+static void* usX2Y_usb_probe(struct usb_device* device, struct usb_interface *intf, const struct usb_device_id* device_id)
+{
+       int             err;
+       snd_card_t*     card;
+       if (device->descriptor.idVendor != 0x1604 ||
+           (device->descriptor.idProduct != USB_ID_US122 &&
+            device->descriptor.idProduct != USB_ID_US224 &&
+            device->descriptor.idProduct != USB_ID_US428) ||
+           !(card = usX2Y_create_card(device)))
+               return NULL;
+       if ((err = usX2Y_hwdep_new(card, device)) < 0  ||
+           (err = snd_card_register(card)) < 0) {
+               snd_card_free(card);
+               return NULL;
+       }
+       return card;
+}
+
+/*
+ * new 2.5 USB kernel API
+ */
+static int snd_usX2Y_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       void *chip;
+       chip = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id);
+       if (chip) {
+               dev_set_drvdata(&intf->dev, chip);
+               return 0;
+       } else
+               return -EIO;
+}
+
+static void snd_usX2Y_disconnect(struct usb_interface *intf)
+{
+       usX2Y_usb_disconnect(interface_to_usbdev(intf),
+                                dev_get_drvdata(&intf->dev));
+}
+
+MODULE_DEVICE_TABLE(usb, snd_usX2Y_usb_id_table);
+static struct usb_driver snd_usX2Y_usb_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "snd-usb-usx2y",
+       .probe =        snd_usX2Y_probe,
+       .disconnect =   snd_usX2Y_disconnect,
+       .id_table =     snd_usX2Y_usb_id_table,
+};
+
+static void snd_usX2Y_card_private_free(snd_card_t *card)
+{
+       if (usX2Y(card)->In04Buf)
+               kfree(usX2Y(card)->In04Buf);
+       usb_free_urb(usX2Y(card)->In04urb);
+       if (usX2Y(card)->us428ctls_sharedmem)
+               snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem));
+       if (usX2Y(card)->chip.index >= 0  &&  usX2Y(card)->chip.index < SNDRV_CARDS)
+               snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0;
+}
+
+/*
+ * Frees the device.
+ */
+static void usX2Y_usb_disconnect(struct usb_device* device, void* ptr)
+{
+       if (ptr) {
+               usX2Ydev_t* usX2Y = usX2Y((snd_card_t*)ptr);
+               struct list_head* p;
+               if (usX2Y->chip_status == USX2Y_STAT_CHIP_HUP)  // on 2.6.1 kernel snd_usbmidi_disconnect()
+                       return;                                 // calls us back. better leave :-) .
+               usX2Y->chip.shutdown = 1;
+               usX2Y->chip_status = USX2Y_STAT_CHIP_HUP;
+               usX2Y_unlinkSeq(&usX2Y->AS04);
+               usb_unlink_urb(usX2Y->In04urb);
+               snd_card_disconnect((snd_card_t*)ptr);
+               /* release the midi resources */
+               list_for_each(p, &usX2Y->chip.midi_list) {
+                       snd_usbmidi_disconnect(p, &snd_usX2Y_usb_driver);
+               }
+               if (usX2Y->us428ctls_sharedmem) 
+                       wake_up(&usX2Y->us428ctls_wait_queue_head);
+               snd_card_free_in_thread((snd_card_t*)ptr);
+       }
+}
+
+static int __init snd_usX2Y_module_init(void)
+{
+       return usb_register(&snd_usX2Y_usb_driver);
+}
+
+static void __exit snd_usX2Y_module_exit(void)
+{
+       usb_deregister(&snd_usX2Y_usb_driver);
+}
+
+module_init(snd_usX2Y_module_init)
+module_exit(snd_usX2Y_module_exit)
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
new file mode 100644 (file)
index 0000000..71883dc
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef USBUSX2Y_H
+#define USBUSX2Y_H
+#include "../usbaudio.h"
+#include "usbus428ctldefs.h" 
+
+#define NRURBS         2       /* */
+#define NRPACKS                1       /* FIXME: Currently only 1 works.
+                                  usb-frames/ms per urb: 1 and 2 are supported.
+                                  setting to 2 will PERHAPS make it easier for slow machines.
+                                  Jitter will be higher though.
+                                  On my PIII 500Mhz Laptop setting to 1 is the only way to go 
+                                  for PLAYING synths. i.e. Jack & Aeolus sound quit nicely 
+                                  at 4 periods 64 frames. 
+                               */
+
+#define URBS_AsyncSeq 10
+#define URB_DataLen_AsyncSeq 32
+typedef struct {
+       struct urb*     urb[URBS_AsyncSeq];
+       char*   buffer;
+} snd_usX2Y_AsyncSeq_t;
+
+typedef struct {
+       int     submitted;
+       int     len;
+       struct urb*     urb[0];
+} snd_usX2Y_urbSeq_t;
+
+typedef struct snd_usX2Y_substream snd_usX2Y_substream_t;
+
+typedef struct {
+       snd_usb_audio_t         chip;
+       int                     stride;
+       struct urb              *In04urb;
+       void                    *In04Buf;
+       char                    In04Last[24];
+       unsigned                In04IntCalls;
+       snd_usX2Y_urbSeq_t      *US04;
+       wait_queue_head_t       In04WaitQueue;
+       snd_usX2Y_AsyncSeq_t    AS04;
+       unsigned int            rate,
+                               format;
+       int                     refframes;
+       int                     chip_status;
+       struct semaphore        open_mutex;
+       us428ctls_sharedmem_t   *us428ctls_sharedmem;
+       wait_queue_head_t       us428ctls_wait_queue_head;
+       snd_usX2Y_substream_t   *substream[4];
+} usX2Ydev_t;
+
+
+#define usX2Y(c) ((usX2Ydev_t*)(c)->private_data)
+
+int usX2Y_audio_create(snd_card_t* card);
+
+int usX2Y_AsyncSeq04_init(usX2Ydev_t* usX2Y);
+int usX2Y_In04_init(usX2Ydev_t* usX2Y);
+
+#define NAME_ALLCAPS "US-X2Y"
+
+#endif
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
new file mode 100644 (file)
index 0000000..d860c73
--- /dev/null
@@ -0,0 +1,1027 @@
+/*
+ *   US-428 AUDIO
+
+ *   Copyright (c) 2002-2003 by Karsten Wiese
+ *   based on
+
+ *   (Tentative) USB Audio Driver for ALSA
+ *
+ *   Main and PCM part
+ *
+ *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
+ *
+ *   Many codes borrowed from audio.c by 
+ *         Alan Cox (alan@lxorguk.ukuu.org.uk)
+ *         Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+#include <sound/driver.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "usx2y.h"
+#include "usbusx2y.h"
+
+
+struct snd_usX2Y_substream {
+       usX2Ydev_t      *usX2Y;
+       snd_pcm_substream_t *pcm_substream;
+
+       unsigned char           endpoint;               
+       unsigned int            datapipe;               /* the data i/o pipe */
+       unsigned int            maxpacksize;            /* max packet size in bytes */
+
+       char                    prepared,
+                               running,
+                               stalled;
+
+       int                     hwptr;                  /* free frame position in the buffer (only for playback) */
+       int                     hwptr_done;             /* processed frame position in the buffer */
+       int                     transfer_done;          /* processed frames since last period update */
+
+       struct urb              *urb[NRURBS];   /* data urb table */
+       int                     next_urb_complete;
+       struct urb              *completed_urb;
+       char                    *tmpbuf;                        /* temporary buffer for playback */
+       volatile int            submitted_urbs;
+       wait_queue_head_t       wait_queue;
+};
+
+
+
+
+
+
+static int usX2Y_urb_capt_retire(snd_usX2Y_substream_t *subs)
+{
+       struct urb      *urb = subs->completed_urb;
+       snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
+       unsigned char   *cp;
+       int             i, len, lens = 0, hwptr_done = subs->hwptr_done;
+       usX2Ydev_t      *usX2Y = subs->usX2Y;
+
+       for (i = 0; i < NRPACKS; i++) {
+               cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
+                       snd_printdd("activ frame status %i\n", urb->iso_frame_desc[i].status);
+                       return urb->iso_frame_desc[i].status;
+               }
+               len = urb->iso_frame_desc[i].actual_length / usX2Y->stride;
+               if (! len) {
+                       snd_printk("0 == len ERROR!\n");
+                       continue;
+               }
+
+               /* copy a data chunk */
+               if ((hwptr_done + len) > runtime->buffer_size) {
+                       int cnt = runtime->buffer_size - hwptr_done;
+                       int blen = cnt * usX2Y->stride;
+                       memcpy(runtime->dma_area + hwptr_done * usX2Y->stride, cp, blen);
+                       memcpy(runtime->dma_area, cp + blen, len * usX2Y->stride - blen);
+               } else {
+                       memcpy(runtime->dma_area + hwptr_done * usX2Y->stride, cp, len * usX2Y->stride);
+               }
+               lens += len;
+               if ((hwptr_done += len) >= runtime->buffer_size)
+                       hwptr_done -= runtime->buffer_size;
+       }
+
+       subs->hwptr_done = hwptr_done;
+       subs->transfer_done += lens;
+       /* update the pointer, call callback if necessary */
+       if (subs->transfer_done >= runtime->period_size) {
+               subs->transfer_done -= runtime->period_size;
+               snd_pcm_period_elapsed(subs->pcm_substream);
+       }
+       return 0;
+}
+/*
+ * prepare urb for playback data pipe
+ *
+ * we copy the data directly from the pcm buffer.
+ * the current position to be copied is held in hwptr field.
+ * since a urb can handle only a single linear buffer, if the total
+ * transferred area overflows the buffer boundary, we cannot send
+ * it directly from the buffer.  thus the data is once copied to
+ * a temporary buffer and urb points to that.
+ */
+static int usX2Y_urb_play_prepare(snd_usX2Y_substream_t *subs,
+                                 struct urb *cap_urb,
+                                 struct urb *urb)
+{
+       int count, counts, pack;
+       usX2Ydev_t* usX2Y = subs->usX2Y;
+       snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
+
+       count = 0;
+       for (pack = 0; pack < NRPACKS; pack++) {
+               /* calculate the size of a packet */
+               counts = cap_urb->iso_frame_desc[pack].actual_length / usX2Y->stride;
+               count += counts;
+               if (counts < 43 || counts > 50) {
+                       snd_printk("should not be here with counts=%i\n", counts);
+                       return -EPIPE;
+               }
+
+               /* set up descriptor */
+               urb->iso_frame_desc[pack].offset = pack ? urb->iso_frame_desc[pack - 1].offset + urb->iso_frame_desc[pack - 1].length : 0;
+               urb->iso_frame_desc[pack].length = counts * usX2Y->stride;
+       }
+       if (subs->hwptr + count > runtime->buffer_size) {
+               /* err, the transferred area goes over buffer boundary.
+                * copy the data to the temp buffer.
+                */
+               int len;
+               len = runtime->buffer_size - subs->hwptr;
+               urb->transfer_buffer = subs->tmpbuf;
+               memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * usX2Y->stride, len * usX2Y->stride);
+               memcpy(subs->tmpbuf + len * usX2Y->stride, runtime->dma_area, (count - len) * usX2Y->stride);
+               subs->hwptr += count;
+               subs->hwptr -= runtime->buffer_size;
+       } else {
+               /* set the buffer pointer */
+               urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride;
+               if ((subs->hwptr += count) >= runtime->buffer_size)
+                       subs->hwptr -= runtime->buffer_size;                    
+       }
+       urb->transfer_buffer_length = count * usX2Y->stride;
+       return 0;
+}
+
+/*
+ * process after playback data complete
+ *
+ * update the current position and call callback if a period is processed.
+ */
+inline static int usX2Y_urb_play_retire(snd_usX2Y_substream_t *subs, struct urb *urb)
+{
+       snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
+       int             len = (urb->iso_frame_desc[0].actual_length
+#if NRPACKS > 1
+                              + urb->iso_frame_desc[1].actual_length
+#endif
+                              ) / subs->usX2Y->stride;
+
+       subs->transfer_done += len;
+       subs->hwptr_done +=  len;
+       if (subs->hwptr_done >= runtime->buffer_size)
+               subs->hwptr_done -= runtime->buffer_size;
+       if (subs->transfer_done >= runtime->period_size) {
+               subs->transfer_done -= runtime->period_size;
+               snd_pcm_period_elapsed(subs->pcm_substream);
+       }
+       return 0;
+}
+
+inline static int usX2Y_urb_submit(snd_usX2Y_substream_t *subs, struct urb *urb, int frame)
+{
+       int err;
+       if (!urb)
+               return -ENODEV;
+       urb->start_frame = (frame + NRURBS*NRPACKS) & (1024 - 1);
+       urb->hcpriv = NULL;
+       urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */
+       if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+               snd_printk("%i\n", err);
+               return err;
+       } else {
+               subs->submitted_urbs++;
+               if (subs->next_urb_complete < 0) 
+                       subs->next_urb_complete = 0;
+       }
+       return 0;
+}
+
+
+static inline int frame_distance(int from, int to)
+{
+       int distance = to - from;
+       if (distance < -512)
+               distance += 1024;
+       else
+               if (distance > 511)
+                       distance -= 1024;
+       return distance;
+}
+
+
+static void usX2Y_subs_set_next_urb_complete(snd_usX2Y_substream_t *subs)
+{
+       int next_urb_complete = subs->next_urb_complete + 1;
+       int distance;
+       if (next_urb_complete >= NRURBS)
+               next_urb_complete = 0;
+       distance = frame_distance(subs->completed_urb->start_frame,
+                                 subs->urb[next_urb_complete]->start_frame);
+       if (1 == distance) {
+               subs->next_urb_complete = next_urb_complete;
+       } else {
+               snd_printdd("distance %i not set_nuc %i %i %i \n", distance, subs->endpoint, next_urb_complete, subs->urb[next_urb_complete]->status);
+               subs->next_urb_complete = -1;
+       }
+}
+
+
+static inline void usX2Y_usbframe_complete(snd_usX2Y_substream_t *capsubs, snd_usX2Y_substream_t *playbacksubs, int frame)
+{
+       {
+               struct urb *urb;
+               if ((urb = playbacksubs->completed_urb)) {
+                       if (playbacksubs->prepared)
+                               usX2Y_urb_play_retire(playbacksubs, urb);
+                       usX2Y_subs_set_next_urb_complete(playbacksubs);
+               }
+               if (playbacksubs->running) {
+                       if (NULL == urb)
+                               urb = playbacksubs->urb[playbacksubs->next_urb_complete + 1];
+                       if (urb && 0 == usX2Y_urb_play_prepare(playbacksubs,
+                                                              capsubs->completed_urb,
+                                                              urb)) {
+                               if (usX2Y_urb_submit(playbacksubs, urb, frame) < 0)
+                                       return;
+                       } else
+                               snd_pcm_stop(playbacksubs->pcm_substream, SNDRV_PCM_STATE_XRUN);
+               }
+               playbacksubs->completed_urb = NULL;
+       }
+       if (capsubs->running)
+               usX2Y_urb_capt_retire(capsubs);
+       usX2Y_subs_set_next_urb_complete(capsubs);
+       if (capsubs->prepared)
+               usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame);
+       capsubs->completed_urb = NULL;
+}
+
+
+static void usX2Y_clients_stop(snd_usX2Y_substream_t *subs)
+{
+       usX2Ydev_t *usX2Y = subs->usX2Y;
+       int i;
+       for (i = 0; i < 4; i++) {
+               snd_usX2Y_substream_t *substream = usX2Y->substream[i];
+               if (substream && substream->running)
+                       snd_pcm_stop(substream->pcm_substream, SNDRV_PCM_STATE_XRUN);
+       }
+}
+
+
+static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
+{
+       snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
+
+       subs->submitted_urbs--;
+       if (urb->status) {
+               snd_printk("ep=%i stalled with status=%i\n", subs->endpoint, urb->status);
+               subs->stalled = 1;
+               usX2Y_clients_stop(subs);
+               urb->status = 0;
+               return;
+       }
+       if (urb == subs->urb[subs->next_urb_complete]) {
+               subs->completed_urb = urb;
+       } else {
+               snd_printk("Sequence Error!(ep=%i;nuc=%i,frame=%i)\n",
+                          subs->endpoint, subs->next_urb_complete, urb->start_frame);
+               subs->stalled = 1;
+               usX2Y_clients_stop(subs);
+               return;
+       }
+       if (waitqueue_active(&subs->wait_queue))
+               wake_up(&subs->wait_queue);
+       {
+               snd_usX2Y_substream_t *capsubs = subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE],
+                       *playbacksubs = subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK];
+               if (capsubs->completed_urb &&
+                   (playbacksubs->completed_urb ||
+                    !playbacksubs->prepared ||
+                    (playbacksubs->prepared && (playbacksubs->next_urb_complete < 0 || // not started yet
+                                                frame_distance(capsubs->completed_urb->start_frame,
+                                                               playbacksubs->urb[playbacksubs->next_urb_complete]->start_frame)
+                                                > 0 ||                                 // other expected later
+                                                playbacksubs->stalled))))
+                       usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame);
+       }
+}
+
+
+static int usX2Y_urbs_capt_start(snd_usX2Y_substream_t *subs)
+{
+       int i, err;
+
+       for (i = 0; i < NRURBS; i++) {
+               unsigned long pack;
+               struct urb *urb = subs->urb[i];
+               urb->dev = subs->usX2Y->chip.dev;
+               urb->transfer_flags = URB_ISO_ASAP;
+               for (pack = 0; pack < NRPACKS; pack++) {
+                       urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
+                       urb->iso_frame_desc[pack].length = subs->maxpacksize;
+               }
+               urb->transfer_buffer_length = subs->maxpacksize * NRPACKS; 
+               if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+                       snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+                       return -EPIPE;
+               } else {
+                       subs->submitted_urbs++;
+               }
+               urb->transfer_flags = 0;
+       }
+       subs->stalled = 0;
+       subs->next_urb_complete = 0;
+       subs->prepared = 1;
+       return 0;
+}
+
+/* 
+ *  wait until all urbs are processed.
+ */
+static int usX2Y_urbs_wait_clear(snd_usX2Y_substream_t *subs)
+{
+       int timeout = HZ;
+
+       do {
+               if (0 == subs->submitted_urbs)
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               snd_printdd("snd_usX2Y_urbs_wait_clear waiting\n");
+               schedule_timeout(1);
+       } while (--timeout > 0);
+       if (subs->submitted_urbs)
+               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", subs->submitted_urbs);
+       return 0;
+}
+/*
+ * return the current pcm pointer.  just return the hwptr_done value.
+ */
+static snd_pcm_uframes_t snd_usX2Y_pcm_pointer(snd_pcm_substream_t *substream)
+{
+       snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;
+       return subs->hwptr_done;
+}
+/*
+ * start/stop substream
+ */
+static int snd_usX2Y_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+       snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)substream->runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               snd_printdd("snd_usX2Y_pcm_trigger(START)\n");
+               if (subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE]->stalled)
+                       return -EPIPE;
+               else
+                       subs->running = 1;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               snd_printdd("snd_usX2Y_pcm_trigger(STOP)\n");
+               subs->running = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+
+static void usX2Y_urb_release(struct urb** urb, int free_tb)
+{
+       if (*urb) {
+               if (free_tb)
+                       kfree((*urb)->transfer_buffer);
+               usb_free_urb(*urb);
+               *urb = NULL;
+       }
+}
+/*
+ * release a substream
+ */
+static void usX2Y_urbs_release(snd_usX2Y_substream_t *subs)
+{
+       int i;
+       snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
+       usX2Y_urbs_wait_clear(subs);
+       for (i = 0; i < NRURBS; i++)
+               usX2Y_urb_release(subs->urb + i, subs != subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK]);
+
+       if (subs->tmpbuf) {
+               kfree(subs->tmpbuf);
+               subs->tmpbuf = NULL;
+       }
+}
+
+static void usX2Y_substream_prepare(snd_usX2Y_substream_t *subs)
+{
+       snd_printdd("usX2Y_substream_prepare() ep=%i urb0=%p urb1=%p\n", subs->endpoint, subs->urb[0], subs->urb[1]);
+       /* reset the pointer */
+       subs->hwptr = 0;
+       subs->hwptr_done = 0;
+       subs->transfer_done = 0;
+}
+
+
+/*
+ * initialize a substream's urbs
+ */
+static int usX2Y_urbs_allocate(snd_usX2Y_substream_t *subs)
+{
+       int i;
+       int is_playback = subs == subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK];
+       struct usb_device *dev = subs->usX2Y->chip.dev;
+
+       snd_assert(!subs->prepared, return 0);
+
+       if (is_playback) {      /* allocate a temporary buffer for playback */
+               subs->datapipe = usb_sndisocpipe(dev, subs->endpoint);
+               subs->maxpacksize = dev->epmaxpacketout[subs->endpoint];
+               if (NULL == subs->tmpbuf) {
+                       subs->tmpbuf = kcalloc(NRPACKS, subs->maxpacksize, GFP_KERNEL);
+                       if (NULL == subs->tmpbuf) {
+                               snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
+                               return -ENOMEM;
+                       }
+               }
+       } else {
+               subs->datapipe = usb_rcvisocpipe(dev, subs->endpoint);
+               subs->maxpacksize = dev->epmaxpacketin[subs->endpoint];
+       }
+
+       /* allocate and initialize data urbs */
+       for (i = 0; i < NRURBS; i++) {
+               struct urb** purb = subs->urb + i;
+               if (*purb)
+                       continue;
+               *purb = usb_alloc_urb(NRPACKS, GFP_KERNEL);
+               if (NULL == *purb) {
+                       usX2Y_urbs_release(subs);
+                       return -ENOMEM;
+               }
+               if (!is_playback && !(*purb)->transfer_buffer) {
+                       /* allocate a capture buffer per urb */
+                       (*purb)->transfer_buffer = kmalloc(subs->maxpacksize*NRPACKS, GFP_KERNEL);
+                       if (NULL == (*purb)->transfer_buffer) {
+                               usX2Y_urbs_release(subs);
+                               return -ENOMEM;
+                       }
+               }
+               (*purb)->dev = dev;
+               (*purb)->pipe = subs->datapipe;
+               (*purb)->number_of_packets = NRPACKS;
+               (*purb)->context = subs;
+               (*purb)->interval = 1;
+               (*purb)->complete = snd_usb_complete_callback(i_usX2Y_urb_complete);
+       }
+       return 0;
+}
+
+static void i_usX2Y_04Int(struct urb* urb, struct pt_regs *regs)
+{
+       usX2Ydev_t*     usX2Y = urb->context;
+       
+       if (urb->status) {
+               snd_printk("snd_usX2Y_04Int() urb->status=%i\n", urb->status);
+               return;
+       }
+       if (0 == --usX2Y->US04->len)
+               wake_up(&usX2Y->In04WaitQueue);
+}
+/*
+ * allocate a buffer, setup samplerate
+ *
+ * so far we use a physically linear buffer although packetize transfer
+ * doesn't need a continuous area.
+ * if sg buffer is supported on the later version of alsa, we'll follow
+ * that.
+ */
+static struct s_c2
+{
+       char c1, c2;
+}
+       SetRate44100[] =
+{
+       { 0x14, 0x08},  // this line sets 44100, well actually a little less
+       { 0x18, 0x40},  // only tascam / frontier design knows the further lines .......
+       { 0x18, 0x42},
+       { 0x18, 0x45},
+       { 0x18, 0x46},
+       { 0x18, 0x48},
+       { 0x18, 0x4A},
+       { 0x18, 0x4C},
+       { 0x18, 0x4E},
+       { 0x18, 0x50},
+       { 0x18, 0x52},
+       { 0x18, 0x54},
+       { 0x18, 0x56},
+       { 0x18, 0x58},
+       { 0x18, 0x5A},
+       { 0x18, 0x5C},
+       { 0x18, 0x5E},
+       { 0x18, 0x60},
+       { 0x18, 0x62},
+       { 0x18, 0x64},
+       { 0x18, 0x66},
+       { 0x18, 0x68},
+       { 0x18, 0x6A},
+       { 0x18, 0x6C},
+       { 0x18, 0x6E},
+       { 0x18, 0x70},
+       { 0x18, 0x72},
+       { 0x18, 0x74},
+       { 0x18, 0x76},
+       { 0x18, 0x78},
+       { 0x18, 0x7A},
+       { 0x18, 0x7C},
+       { 0x18, 0x7E}
+};
+static struct s_c2 SetRate48000[] =
+{
+       { 0x14, 0x09},  // this line sets 48000, well actually a little less
+       { 0x18, 0x40},  // only tascam / frontier design knows the further lines .......
+       { 0x18, 0x42},
+       { 0x18, 0x45},
+       { 0x18, 0x46},
+       { 0x18, 0x48},
+       { 0x18, 0x4A},
+       { 0x18, 0x4C},
+       { 0x18, 0x4E},
+       { 0x18, 0x50},
+       { 0x18, 0x52},
+       { 0x18, 0x54},
+       { 0x18, 0x56},
+       { 0x18, 0x58},
+       { 0x18, 0x5A},
+       { 0x18, 0x5C},
+       { 0x18, 0x5E},
+       { 0x18, 0x60},
+       { 0x18, 0x62},
+       { 0x18, 0x64},
+       { 0x18, 0x66},
+       { 0x18, 0x68},
+       { 0x18, 0x6A},
+       { 0x18, 0x6C},
+       { 0x18, 0x6E},
+       { 0x18, 0x70},
+       { 0x18, 0x73},
+       { 0x18, 0x74},
+       { 0x18, 0x76},
+       { 0x18, 0x78},
+       { 0x18, 0x7A},
+       { 0x18, 0x7C},
+       { 0x18, 0x7E}
+};
+#define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000)
+
+static int usX2Y_rate_set(usX2Ydev_t *usX2Y, int rate)
+{
+       int                     err = 0, i;
+       snd_usX2Y_urbSeq_t      *us = NULL;
+       int                     *usbdata = NULL;
+       DECLARE_WAITQUEUE(wait, current);
+       struct s_c2             *ra = rate == 48000 ? SetRate48000 : SetRate44100;
+
+       if (usX2Y->rate != rate) {
+               do {
+                       us = kmalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);
+                       if (NULL == us) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       memset(us, 0, sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS); 
+                       usbdata = kmalloc(sizeof(int)*NOOF_SETRATE_URBS, GFP_KERNEL);
+                       if (NULL == usbdata) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
+                               if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {
+                                       err = -ENOMEM;
+                                       break;
+                               }
+                               ((char*)(usbdata + i))[0] = ra[i].c1;
+                               ((char*)(usbdata + i))[1] = ra[i].c2;
+                               usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4),
+                                                 usbdata + i, 2, i_usX2Y_04Int, usX2Y);
+#ifdef OLD_USB
+                               us->urb[i]->transfer_flags = USB_QUEUE_BULK;
+#endif
+                       }
+                       if (err)
+                               break;
+
+                       add_wait_queue(&usX2Y->In04WaitQueue, &wait);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       us->submitted = 0;
+                       us->len =       NOOF_SETRATE_URBS;
+                       usX2Y->US04 =   us;
+               
+                       do {
+                               signed long     timeout = schedule_timeout(HZ/2);
+                       
+                               if (signal_pending(current)) {
+                                       err = -ERESTARTSYS;
+                                       break;
+                               }
+                               if (0 == timeout) {
+                                       err = -ENODEV;
+                                       break;
+                               }
+                               usX2Y->rate = rate;
+                               usX2Y->refframes = rate == 48000 ? 47 : 44;
+                       } while (0);
+               
+                       remove_wait_queue(&usX2Y->In04WaitQueue, &wait);
+               } while (0);
+
+               if (us) {
+                       us->submitted = 2*NOOF_SETRATE_URBS;
+                       for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
+                               usb_unlink_urb(us->urb[i]);
+                               usb_free_urb(us->urb[i]);
+                       }
+                       usX2Y->US04 = NULL;
+                       kfree(usbdata);
+                       kfree(us);
+               }
+       }
+
+       return err;
+}
+
+
+static int usX2Y_format_set(usX2Ydev_t *usX2Y, snd_pcm_format_t format)
+{
+       int alternate, unlink_err, err;
+       struct list_head* p;
+       if (format == SNDRV_PCM_FORMAT_S24_3LE) {
+               alternate = 2;
+               usX2Y->stride = 6;
+       } else {
+               alternate = 1;
+               usX2Y->stride = 4;
+       }
+       list_for_each(p, &usX2Y->chip.midi_list) {
+               snd_usbmidi_input_stop(p);
+       }
+       unlink_err = usb_unlink_urb(usX2Y->In04urb);
+       if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) {
+               snd_printk("usb_set_interface error \n");
+               return err;
+       }
+       if (0 == unlink_err) {
+               usX2Y->In04urb->dev = usX2Y->chip.dev;
+               err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL);
+       }
+       list_for_each(p, &usX2Y->chip.midi_list) {
+               snd_usbmidi_input_start(p);
+       }
+       usX2Y->format = format;
+       usX2Y->rate = 0;
+       return err;
+}
+
+
+static int snd_usX2Y_pcm_hw_params(snd_pcm_substream_t *substream,
+                                  snd_pcm_hw_params_t *hw_params)
+{
+       int                     err = 0;
+       unsigned int            rate = params_rate(hw_params);
+       snd_pcm_format_t        format = params_format(hw_params);
+       snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params);
+
+       {       // all pcm substreams off one usX2Y have to operate at the same rate & format
+               snd_card_t *card = substream->pstr->pcm->card;
+               struct list_head *list;
+               list_for_each(list, &card->devices) {
+                       snd_device_t *dev;
+                       snd_pcm_t *pcm;
+                       int s;
+                       dev = snd_device(list);
+                       if (dev->type != SNDRV_DEV_PCM)
+                               continue;
+                       pcm = dev->device_data;
+                       for (s = 0; s < 2; ++s) {
+                               snd_pcm_substream_t *test_substream;
+                               test_substream = pcm->streams[s].substream;
+                               if (test_substream && test_substream != substream  &&
+                                   test_substream->runtime &&
+                                   ((test_substream->runtime->format &&
+                                     test_substream->runtime->format != format) ||
+                                    (test_substream->runtime->rate &&
+                                     test_substream->runtime->rate != rate)))
+                                       return -EINVAL;
+                       }
+               }
+       }
+       if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) {
+               snd_printk("snd_pcm_lib_malloc_pages(%p, %i) returned %i\n", substream, params_buffer_bytes(hw_params), err);
+               return err;
+       }
+       return 0;
+}
+
+/*
+ * free the buffer
+ */
+static int snd_usX2Y_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
+       snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
+
+       if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
+               snd_usX2Y_substream_t *cap_subs = subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE];
+               subs->prepared = 0;
+               usX2Y_urbs_release(subs);
+               if (!cap_subs->pcm_substream ||
+                   !cap_subs->pcm_substream->runtime ||
+                   !cap_subs->pcm_substream->runtime->status ||
+                   cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
+                       cap_subs->prepared = 0;
+                       usX2Y_urbs_release(cap_subs);
+               }
+       } else {
+               snd_usX2Y_substream_t *playback_subs = subs->usX2Y->substream[SNDRV_PCM_STREAM_PLAYBACK];
+               if (!playback_subs->prepared) {
+                       subs->prepared = 0;
+                       usX2Y_urbs_release(subs);
+               }
+       }
+
+       return snd_pcm_lib_free_pages(substream);
+}
+/*
+ * prepare callback
+ *
+ * set format and initialize urbs
+ */
+static int snd_usX2Y_pcm_prepare(snd_pcm_substream_t *substream)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
+       snd_usX2Y_substream_t *capsubs = subs->usX2Y->substream[SNDRV_PCM_STREAM_CAPTURE];
+       int err = 0;
+       snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
+
+// Start hardware streams
+// SyncStream first....
+       if (! capsubs->prepared) {
+               if (subs->usX2Y->format != runtime->format)
+                       if ((err = usX2Y_format_set(subs->usX2Y, runtime->format)) < 0)
+                               return err;
+               if (subs->usX2Y->rate != runtime->rate)
+                       if ((err = usX2Y_rate_set(subs->usX2Y, runtime->rate)) < 0)
+                               return err;
+               snd_printdd("starting capture pipe for playpipe\n");
+               usX2Y_urbs_allocate(capsubs);
+               capsubs->completed_urb = NULL;
+               {
+                       DECLARE_WAITQUEUE(wait, current);
+                       add_wait_queue(&capsubs->wait_queue, &wait);
+                       if (0 <= (err = usX2Y_urbs_capt_start(capsubs))) {
+                               signed long timeout;
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               timeout = schedule_timeout(HZ/4);
+                               if (signal_pending(current))
+                                       err = -ERESTARTSYS;
+                               else {
+                                       snd_printdd("%li\n", HZ/4 - timeout);
+                                       if (0 == timeout)
+                                               err = -EPIPE;
+                               }
+                       }
+                       remove_wait_queue(&capsubs->wait_queue, &wait);
+                       if (0 > err)
+                               return err;
+               }
+       }
+
+       if (subs != capsubs) {
+               int u;
+               if (!subs->prepared) {
+                       if ((err = usX2Y_urbs_allocate(subs)) < 0)
+                               return err;
+                       subs->prepared = 1;
+               }
+               while (subs->submitted_urbs)
+               for (u = 0; u < NRURBS; u++) {
+                       snd_printdd("%i\n", subs->urb[u]->status);
+                       while(subs->urb[u]->status  ||  NULL != subs->urb[u]->hcpriv) {
+                               signed long timeout;
+                               snd_printdd("ep=%i waiting for urb=%p status=%i hcpriv=%p\n",
+                                          subs->endpoint, subs->urb[u],
+                                          subs->urb[u]->status, subs->urb[u]->hcpriv);
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               timeout = schedule_timeout(HZ/10);
+                               if (signal_pending(current)) {
+                                       return -ERESTARTSYS;
+                               }
+                       }
+               }
+               subs->completed_urb = NULL;
+               subs->next_urb_complete = -1;
+               subs->stalled = 0;
+       }
+
+       usX2Y_substream_prepare(subs);
+       return err;
+}
+
+static snd_pcm_hardware_t snd_usX2Y_2c =
+{
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
+       .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+       .rate_min =                44100,
+       .rate_max =                48000,
+       .channels_min =            2,
+       .channels_max =            2,
+       .buffer_bytes_max =     (2*128*1024),
+       .period_bytes_min =     64,
+       .period_bytes_max =     (128*1024),
+       .periods_min =          2,
+       .periods_max =          1024,
+       .fifo_size =              0
+};
+
+
+
+static int snd_usX2Y_pcm_open(snd_pcm_substream_t *substream)
+{
+       snd_usX2Y_substream_t   *subs = ((snd_usX2Y_substream_t **)
+                                        snd_pcm_substream_chip(substream))[substream->stream];
+       snd_pcm_runtime_t       *runtime = substream->runtime;
+
+       runtime->hw = snd_usX2Y_2c;
+       runtime->private_data = subs;
+       subs->pcm_substream = substream;
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
+       return 0;
+}
+
+
+
+static int snd_usX2Y_pcm_close(snd_pcm_substream_t *substream)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
+       int err = 0;
+
+       subs->pcm_substream = NULL;
+
+       return err;
+}
+
+
+static snd_pcm_ops_t snd_usX2Y_pcm_ops = 
+{
+       .open =         snd_usX2Y_pcm_open,
+       .close =        snd_usX2Y_pcm_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_usX2Y_pcm_hw_params,
+       .hw_free =      snd_usX2Y_pcm_hw_free,
+       .prepare =      snd_usX2Y_pcm_prepare,
+       .trigger =      snd_usX2Y_pcm_trigger,
+       .pointer =      snd_usX2Y_pcm_pointer,
+};
+
+
+/*
+ * free a usb stream instance
+ */
+static void usX2Y_audio_stream_free(snd_usX2Y_substream_t **usX2Y_substream)
+{
+       if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) {
+               kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
+               usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
+       }
+       kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]);
+       usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL;
+}
+
+static void snd_usX2Y_pcm_private_free(snd_pcm_t *pcm)
+{
+       snd_usX2Y_substream_t **usX2Y_stream = pcm->private_data;
+       if (usX2Y_stream) {
+               snd_pcm_lib_preallocate_free_for_all(pcm);
+               usX2Y_audio_stream_free(usX2Y_stream);
+       }
+}
+
+static int usX2Y_audio_stream_new(snd_card_t *card, int playback_endpoint, int capture_endpoint)
+{
+       snd_pcm_t *pcm;
+       int err, i;
+       snd_usX2Y_substream_t **usX2Y_substream =
+               usX2Y(card)->substream + 2 * usX2Y(card)->chip.pcm_devs;
+
+       for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
+            i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {
+               usX2Y_substream[i] = kcalloc(1, sizeof(snd_usX2Y_substream_t), GFP_KERNEL);
+               if (NULL == usX2Y_substream[i]) {
+                       snd_printk(KERN_ERR "cannot malloc\n");
+                       return -ENOMEM;
+               }
+               init_waitqueue_head(&usX2Y_substream[i]->wait_queue);
+               usX2Y_substream[i]->usX2Y = usX2Y(card);
+       }
+
+       if (playback_endpoint)
+               usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint;
+       usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint;
+
+       err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs,
+                         playback_endpoint ? 1 : 0, 1,
+                         &pcm);
+       if (err < 0) {
+               usX2Y_audio_stream_free(usX2Y_substream);
+               return err;
+       }
+
+       if (playback_endpoint)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_pcm_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_pcm_ops);
+
+       pcm->private_data = usX2Y_substream;
+       pcm->private_free = snd_usX2Y_pcm_private_free;
+       pcm->info_flags = 0;
+
+       sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs);
+
+       if ((playback_endpoint &&
+            0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+                                                    SNDRV_DMA_TYPE_CONTINUOUS,
+                                                    snd_dma_continuous_data(GFP_KERNEL),
+                                                    64*1024, 128*1024))) ||
+           0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+                                                    SNDRV_DMA_TYPE_CONTINUOUS,
+                                                    snd_dma_continuous_data(GFP_KERNEL),
+                                                    64*1024, 128*1024))) {
+               snd_usX2Y_pcm_private_free(pcm);
+               return err;
+       }
+       usX2Y(card)->chip.pcm_devs++;
+
+       return 0;
+}
+
+/*
+ * free the chip instance
+ *
+ * here we have to do not much, since pcm and controls are already freed
+ *
+ */
+static int snd_usX2Y_device_dev_free(snd_device_t *device)
+{
+       return 0;
+}
+
+
+/*
+ * create a chip instance and set its names.
+ */
+int usX2Y_audio_create(snd_card_t* card)
+{
+       int err = 0;
+       static snd_device_ops_t ops = {
+               .dev_free = snd_usX2Y_device_dev_free,
+       };
+       
+       INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list);
+
+       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, usX2Y(card), &ops)) < 0) {
+//             snd_usX2Y_audio_free(usX2Y(card));
+               return err;
+       }
+
+       if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8)))
+               return err;
+       if (usX2Y(card)->chip.dev->descriptor.idProduct == USB_ID_US428)
+            if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA)))
+                    return err;
+       if (usX2Y(card)->chip.dev->descriptor.idProduct != USB_ID_US122)
+               err = usX2Y_rate_set(usX2Y(card), 44100);       // Lets us428 recognize output-volume settings, disturbs us122.
+       return err;
+}
diff --git a/sound/usb/usx2y/usx2y.h b/sound/usb/usx2y/usx2y.h
new file mode 100644 (file)
index 0000000..78457e7
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Driver for Tascam US-X2Y USB soundcards
+ *
+ * Copyright (c) 2003 by Karsten Wiese <annabellesgarden@yahoo.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_USX2Y_COMMON_H
+#define __SOUND_USX2Y_COMMON_H
+
+
+#define USX2Y_DRIVER_VERSION   0x0100  /* 0.1.0 */
+
+
+/* hwdep id string */
+#define SND_USX2Y_LOADER_ID            "USX2Y Loader"
+
+/* hardware type */
+enum {
+       USX2Y_TYPE_122,
+       USX2Y_TYPE_224,
+       USX2Y_TYPE_428,
+       USX2Y_TYPE_NUMS
+};
+
+#define USB_ID_US122 0x8007
+#define USB_ID_US224 0x8005
+#define USB_ID_US428 0x8001
+
+/* chip status */
+enum {
+       USX2Y_STAT_CHIP_INIT    = (1 << 0),     /* all operational */
+       USX2Y_STAT_CHIP_HUP     = (1 << 31),    /* all operational */
+};
+
+#endif /* __SOUND_USX2Y_COMMON_H */